]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java
Adapt to changes in BND.
[gpl/argeo-slc.git] / org.argeo.slc.repo / src / org / argeo / slc / repo / osgi / ArchiveWrapper.java
1 package org.argeo.slc.repo.osgi;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.InputStream;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.TreeSet;
13 import java.util.jar.JarInputStream;
14 import java.util.zip.ZipEntry;
15 import java.util.zip.ZipInputStream;
16 import java.util.zip.ZipOutputStream;
17
18 import javax.jcr.Node;
19 import javax.jcr.Property;
20 import javax.jcr.RepositoryException;
21 import javax.jcr.Session;
22
23 import org.apache.commons.io.FilenameUtils;
24 import org.apache.commons.io.IOUtils;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.argeo.jcr.JcrUtils;
28 import org.argeo.slc.CategorizedNameVersion;
29 import org.argeo.slc.DefaultNameVersion;
30 import org.argeo.slc.ModuleSet;
31 import org.argeo.slc.NameVersion;
32 import org.argeo.slc.SlcException;
33 import org.argeo.slc.build.Distribution;
34 import org.argeo.slc.build.License;
35 import org.argeo.slc.repo.OsgiFactory;
36 import org.argeo.slc.repo.RepoUtils;
37 import org.argeo.slc.repo.maven.ArtifactIdComparator;
38 import org.eclipse.aether.artifact.Artifact;
39 import org.eclipse.aether.artifact.DefaultArtifact;
40 import org.springframework.util.AntPathMatcher;
41 import org.springframework.util.PathMatcher;
42
43 import aQute.bnd.osgi.Jar;
44
45 /**
46 * Download a software distribution and generates the related OSGi bundles from
47 * the jars, or import them directly if they are already OSGi bundles and don't
48 * need further modification.
49 */
50 public class ArchiveWrapper implements Runnable, ModuleSet, Distribution {
51 private final static Log log = LogFactory.getLog(ArchiveWrapper.class);
52
53 private OsgiFactory osgiFactory;
54 private String version;
55 private License license;
56
57 private String uri;
58
59 /** Jars to wrap as OSGi bundles */
60 private Map<String, BndWrapper> wrappers = new HashMap<String, BndWrapper>();
61
62 private SourcesProvider sourcesProvider;
63
64 // pattern of OSGi bundles to import
65 private PathMatcher pathMatcher = new AntPathMatcher();
66 private Map<String, String> includes = new HashMap<String, String>();
67 private List<String> excludes = new ArrayList<String>();
68
69 private Boolean mavenGroupIndexes = false;
70
71 public void init() {
72 for (BndWrapper wrapper : wrappers.values()) {
73 wrapper.setFactory(this);
74 if (version != null && wrapper.getVersion() == null)
75 wrapper.setVersion(version);
76 if (license != null && wrapper.getLicense() == null)
77 wrapper.setLicense(license);
78 }
79 }
80
81 public void destroy() {
82
83 }
84
85 public String getDistributionId() {
86 return uri;
87 }
88
89 public Iterator<? extends NameVersion> nameVersions() {
90 if (wrappers.size() > 0)
91 return wrappers.values().iterator();
92 else
93 return osgiNameVersions();
94 }
95
96 @SuppressWarnings("resource")
97 protected Iterator<? extends NameVersion> osgiNameVersions() {
98 List<CategorizedNameVersion> nvs = new ArrayList<CategorizedNameVersion>();
99
100 Session distSession = null;
101 ZipInputStream zin = null;
102 try {
103 distSession = osgiFactory.openDistSession();
104
105 Node distNode = osgiFactory.getDist(distSession, uri);
106 zin = new ZipInputStream(
107 distNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary().getStream());
108
109 ZipEntry zentry = null;
110 entries: while ((zentry = zin.getNextEntry()) != null) {
111 String name = zentry.getName();
112 if (log.isTraceEnabled())
113 log.trace("Zip entry " + name);
114 for (String exclude : excludes)
115 if (pathMatcher.match(exclude, name))
116 continue entries;
117
118 for (String include : includes.keySet()) {
119 if (pathMatcher.match(include, name)) {
120 String groupId = includes.get(include);
121 JarInputStream jis = new JarInputStream(zin);
122 if (jis.getManifest() == null) {
123 log.warn("No MANIFEST in entry " + name + ", skipping...");
124 continue entries;
125 }
126 NameVersion nv = RepoUtils.readNameVersion(jis.getManifest());
127 if (nv != null) {
128 if (nv.getName().endsWith(".source"))
129 continue entries;
130 CategorizedNameVersion cnv = new OsgiCategorizedNV(groupId, nv.getName(), nv.getVersion(),
131 this);
132 nvs.add(cnv);
133 // no need to process further includes
134 continue entries;
135 }
136 }
137 }
138 }
139 return nvs.iterator();
140 } catch (Exception e) {
141 throw new SlcException("Cannot wrap distribution " + uri, e);
142 } finally {
143 IOUtils.closeQuietly(zin);
144 JcrUtils.logoutQuietly(distSession);
145 }
146 }
147
148 public void run() {
149 if (mavenGroupIndexes && (version == null))
150 throw new SlcException("'mavenGroupIndexes' requires 'version' to be set");
151
152 Map<String, Set<Artifact>> binaries = new HashMap<String, Set<Artifact>>();
153 Map<String, Set<Artifact>> sources = new HashMap<String, Set<Artifact>>();
154
155 Session distSession = null;
156 Session javaSession = null;
157 ZipInputStream zin = null;
158 try {
159 javaSession = osgiFactory.openJavaSession();
160 distSession = osgiFactory.openDistSession();
161
162 if (log.isDebugEnabled())
163 log.debug("Wrapping " + uri);
164 boolean nothingWasDone = true;
165
166 Node distNode = osgiFactory.getDist(distSession, uri);
167 zin = new ZipInputStream(
168 distNode.getNode(Node.JCR_CONTENT).getProperty(Property.JCR_DATA).getBinary().getStream());
169
170 ZipEntry zentry = null;
171 entries: while ((zentry = zin.getNextEntry()) != null) {
172 String name = zentry.getName();
173
174 // sources autodetect
175 String baseName = FilenameUtils.getBaseName(name);
176 if (baseName.endsWith("-sources")) {
177 String bundle = baseName.substring(0, baseName.length() - "-sources".length());
178 // log.debug(name + "," + baseName + ", " + bundle);
179 String bundlePath = FilenameUtils.getPath(name) + bundle + ".jar";
180 if (wrappers.containsKey(bundlePath)) {
181 BndWrapper wrapper = wrappers.get(bundlePath);
182 NameVersion bundleNv = new DefaultNameVersion(wrapper.getName(), wrapper.getVersion());
183 byte[] pdeSource = RepoUtils.packageAsPdeSource(zin, bundleNv);
184 Artifact sourcesArtifact = new DefaultArtifact(wrapper.getCategory(),
185 wrapper.getName() + ".source", "jar", wrapper.getVersion());
186 Node pdeSourceNode = RepoUtils.copyBytesAsArtifact(javaSession.getRootNode(), sourcesArtifact,
187 pdeSource);
188 osgiFactory.indexNode(pdeSourceNode);
189 pdeSourceNode.getSession().save();
190 if (log.isDebugEnabled())
191 log.debug("Added sources " + sourcesArtifact + " for bundle " + wrapper.getArtifact()
192 + "from " + name + " in binary archive.");
193 }
194
195 }
196 // else if (baseName.endsWith(".source")) {
197 // }
198
199 // binaries
200 if (wrappers.containsKey(name)) {
201 BndWrapper wrapper = (BndWrapper) wrappers.get(name);
202 // we must copy since the stream is closed by BND
203 byte[] origJarBytes = IOUtils.toByteArray(zin);
204 Artifact artifact = wrapZipEntry(javaSession, zentry, origJarBytes, wrapper);
205 nothingWasDone = false;
206 addArtifactToIndex(binaries, wrapper.getGroupId(), artifact);
207 } else {
208 for (String wrapperKey : wrappers.keySet())
209 if (pathMatcher.match(wrapperKey, name)) {
210 // first matched is taken
211 BndWrapper wrapper = (BndWrapper) wrappers.get(wrapperKey);
212 // we must copy since the stream is closed by BND
213 byte[] origJarBytes = IOUtils.toByteArray(zin);
214 Artifact artifact = wrapZipEntry(javaSession, zentry, origJarBytes, wrapper);
215 nothingWasDone = false;
216 addArtifactToIndex(binaries, wrapper.getGroupId(), artifact);
217 continue entries;
218 } else {
219 if (log.isTraceEnabled())
220 log.trace(name + " not matched by " + wrapperKey);
221 }
222
223 for (String exclude : excludes)
224 if (pathMatcher.match(exclude, name))
225 continue entries;
226
227 for (String include : includes.keySet()) {
228 if (pathMatcher.match(include, name)) {
229 String groupId = includes.get(include);
230 byte[] origJarBytes = IOUtils.toByteArray(zin);
231 Artifact artifact = importZipEntry(javaSession, zentry, origJarBytes, groupId);
232 if (artifact == null) {
233 log.warn("Skipped non identified " + zentry);
234 continue entries;
235 }
236 nothingWasDone = false;
237 if (artifact.getArtifactId().endsWith(".source"))
238 addArtifactToIndex(sources, groupId, artifact);
239 else
240 addArtifactToIndex(binaries, groupId, artifact);
241 // no need to process this entry further
242 continue entries;
243 }
244 }
245 }
246 }
247
248 // indexes
249 if (mavenGroupIndexes && version != null) {
250 for (String groupId : binaries.keySet()) {
251 RepoUtils.writeGroupIndexes(javaSession, "/", groupId, version, binaries.get(groupId),
252 sources.containsKey(groupId) ? sources.get(groupId) : null);
253 }
254 }
255
256 if (nothingWasDone)
257 throw new SlcException("Nothing was done");
258
259 // FIXME Fail if not all wrappers matched
260 } catch (Exception e) {
261 throw new SlcException("Cannot wrap distribution " + uri, e);
262 } finally {
263 IOUtils.closeQuietly(zin);
264 JcrUtils.logoutQuietly(distSession);
265 JcrUtils.logoutQuietly(javaSession);
266 }
267 }
268
269 protected Artifact wrapZipEntry(Session javaSession, ZipEntry zentry, byte[] origJarBytes, BndWrapper wrapper)
270 throws RepositoryException {
271 ByteArrayOutputStream out = null;
272 ByteArrayInputStream in = null;
273 Node newJarNode;
274 Jar jar = null;
275 try {
276 out = new ByteArrayOutputStream((int) zentry.getSize());
277 in = new ByteArrayInputStream(origJarBytes);
278 wrapper.wrapJar(in, out);
279
280 Artifact artifact = wrapper.getArtifact();
281 newJarNode = RepoUtils.copyBytesAsArtifact(javaSession.getRootNode(), artifact, out.toByteArray());
282 osgiFactory.indexNode(newJarNode);
283 newJarNode.getSession().save();
284 if (log.isDebugEnabled())
285 log.debug("Wrapped jar " + zentry.getName() + " to " + newJarNode.getPath());
286
287 if (sourcesProvider != null)
288 addSource(javaSession, artifact, out.toByteArray());
289
290 return artifact;
291 } finally {
292 IOUtils.closeQuietly(in);
293 IOUtils.closeQuietly(out);
294 if (jar != null)
295 jar.close();
296 }
297 }
298
299 protected void addSource(Session javaSession, Artifact artifact, byte[] binaryJarBytes) {
300 InputStream in = null;
301 ByteArrayOutputStream out = null;
302 Jar jar = null;
303 try {
304 in = new ByteArrayInputStream(binaryJarBytes);
305 jar = new Jar(null, in);
306 List<String> packages = jar.getPackages();
307
308 out = new ByteArrayOutputStream();
309 sourcesProvider.writeSources(packages, new ZipOutputStream(out));
310
311 IOUtils.closeQuietly(in);
312 in = new ByteArrayInputStream(out.toByteArray());
313 byte[] sourcesJar = RepoUtils.packageAsPdeSource(in,
314 new DefaultNameVersion(artifact.getArtifactId(), artifact.getVersion()));
315 Artifact sourcesArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId() + ".source",
316 "jar", artifact.getVersion());
317 Node sourcesJarNode = RepoUtils.copyBytesAsArtifact(javaSession.getRootNode(), sourcesArtifact, sourcesJar);
318 sourcesJarNode.getSession().save();
319
320 if (log.isDebugEnabled())
321 log.debug("Added sources " + sourcesArtifact + " for bundle " + artifact + "from source provider "
322 + sourcesProvider);
323 } catch (Exception e) {
324 throw new SlcException("Cannot get sources for " + artifact, e);
325 } finally {
326 IOUtils.closeQuietly(in);
327 IOUtils.closeQuietly(out);
328 if (jar != null)
329 jar.close();
330 }
331 }
332
333 protected Artifact importZipEntry(Session javaSession, ZipEntry zentry, byte[] binaryJarBytes, String groupId)
334 throws RepositoryException {
335 ByteArrayInputStream in = null;
336 Node newJarNode;
337 try {
338 in = new ByteArrayInputStream(binaryJarBytes);
339 NameVersion nameVersion = RepoUtils.readNameVersion(in);
340 if (nameVersion == null) {
341 log.warn("Cannot identify " + zentry.getName());
342 return null;
343 }
344 Artifact artifact = new DefaultArtifact(groupId, nameVersion.getName(), "jar", nameVersion.getVersion());
345 newJarNode = RepoUtils.copyBytesAsArtifact(javaSession.getRootNode(), artifact, binaryJarBytes);
346 osgiFactory.indexNode(newJarNode);
347 newJarNode.getSession().save();
348 if (log.isDebugEnabled()) {
349 log.debug(zentry.getName() + " => " + artifact);
350 }
351
352 if (sourcesProvider != null)
353 addSource(javaSession, artifact, binaryJarBytes);
354
355 return artifact;
356 } finally {
357 IOUtils.closeQuietly(in);
358 }
359 }
360
361 private void addArtifactToIndex(Map<String, Set<Artifact>> index, String groupId, Artifact artifact) {
362 if (!index.containsKey(groupId))
363 index.put(groupId, new TreeSet<Artifact>(new ArtifactIdComparator()));
364 index.get(groupId).add(artifact);
365 }
366
367 public void setUri(String uri) {
368 this.uri = uri;
369 }
370
371 public void setWrappers(Map<String, BndWrapper> wrappers) {
372 this.wrappers = wrappers;
373 }
374
375 public void setOsgiFactory(OsgiFactory osgiFactory) {
376 this.osgiFactory = osgiFactory;
377 }
378
379 public void setVersion(String version) {
380 this.version = version;
381 }
382
383 public void setLicense(License license) {
384 this.license = license;
385 }
386
387 public void setPathMatcher(PathMatcher pathMatcher) {
388 this.pathMatcher = pathMatcher;
389 }
390
391 public void setIncludes(Map<String, String> includes) {
392 this.includes = includes;
393 }
394
395 public void setExcludes(List<String> excludes) {
396 this.excludes = excludes;
397 }
398
399 public void setMavenGroupIndexes(Boolean mavenGroupIndexes) {
400 this.mavenGroupIndexes = mavenGroupIndexes;
401 }
402
403 public void setSourcesProvider(SourcesProvider sourcesProvider) {
404 this.sourcesProvider = sourcesProvider;
405 }
406
407 }