]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java
Merge repo.cnd into slc.cnd.
[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.aether.ArtifactIdComparator;
34 import org.argeo.slc.build.Distribution;
35 import org.argeo.slc.build.License;
36 import org.argeo.slc.repo.OsgiFactory;
37 import org.argeo.slc.repo.RepoUtils;
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.lib.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(distNode.getNode(Node.JCR_CONTENT)
107 .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
124 + ", skipping...");
125 continue entries;
126 }
127 NameVersion nv = RepoUtils.readNameVersion(jis
128 .getManifest());
129 if (nv != null) {
130 if (nv.getName().endsWith(".source"))
131 continue entries;
132 CategorizedNameVersion cnv = new OsgiCategorizedNV(
133 groupId, nv.getName(), nv.getVersion(),
134 this);
135 nvs.add(cnv);
136 // no need to process further includes
137 continue entries;
138 }
139 }
140 }
141 }
142 return nvs.iterator();
143 } catch (Exception e) {
144 throw new SlcException("Cannot wrap distribution " + uri, e);
145 } finally {
146 IOUtils.closeQuietly(zin);
147 JcrUtils.logoutQuietly(distSession);
148 }
149 }
150
151 public void run() {
152 if (mavenGroupIndexes && (version == null))
153 throw new SlcException(
154 "'mavenGroupIndexes' requires 'version' to be set");
155
156 Map<String, Set<Artifact>> binaries = new HashMap<String, Set<Artifact>>();
157 Map<String, Set<Artifact>> sources = new HashMap<String, Set<Artifact>>();
158
159 Session distSession = null;
160 Session javaSession = null;
161 ZipInputStream zin = null;
162 try {
163 javaSession = osgiFactory.openJavaSession();
164 distSession = osgiFactory.openDistSession();
165
166 if (log.isDebugEnabled())
167 log.debug("Wrapping " + uri);
168 boolean nothingWasDone = true;
169
170 Node distNode = osgiFactory.getDist(distSession, uri);
171 zin = new ZipInputStream(distNode.getNode(Node.JCR_CONTENT)
172 .getProperty(Property.JCR_DATA).getBinary().getStream());
173
174 ZipEntry zentry = null;
175 entries: while ((zentry = zin.getNextEntry()) != null) {
176 String name = zentry.getName();
177
178 // sources autodetect
179 String baseName = FilenameUtils.getBaseName(name);
180 if (baseName.endsWith("-sources")) {
181 String bundle = baseName.substring(0, baseName.length()
182 - "-sources".length());
183 // log.debug(name + "," + baseName + ", " + bundle);
184 String bundlePath = FilenameUtils.getPath(name) + bundle
185 + ".jar";
186 if (wrappers.containsKey(bundlePath)) {
187 BndWrapper wrapper = wrappers.get(bundlePath);
188 NameVersion bundleNv = new DefaultNameVersion(
189 wrapper.getName(), wrapper.getVersion());
190 byte[] pdeSource = RepoUtils.packageAsPdeSource(zin,
191 bundleNv);
192 Artifact sourcesArtifact = new DefaultArtifact(
193 wrapper.getCategory(), wrapper.getName()
194 + ".source", "jar",
195 wrapper.getVersion());
196 Node pdeSourceNode = RepoUtils.copyBytesAsArtifact(
197 javaSession.getRootNode(), sourcesArtifact,
198 pdeSource);
199 osgiFactory.indexNode(pdeSourceNode);
200 pdeSourceNode.getSession().save();
201 if (log.isDebugEnabled())
202 log.debug("Added sources " + sourcesArtifact
203 + " for bundle " + wrapper.getArtifact()
204 + "from " + name + " in binary archive.");
205 }
206
207 }
208 // else if (baseName.endsWith(".source")) {
209 // }
210
211 // binaries
212 if (wrappers.containsKey(name)) {
213 BndWrapper wrapper = (BndWrapper) wrappers.get(name);
214 // we must copy since the stream is closed by BND
215 byte[] origJarBytes = IOUtils.toByteArray(zin);
216 Artifact artifact = wrapZipEntry(javaSession, zentry,
217 origJarBytes, wrapper);
218 nothingWasDone = false;
219 addArtifactToIndex(binaries, wrapper.getGroupId(), artifact);
220 } else {
221 for (String wrapperKey : wrappers.keySet())
222 if (pathMatcher.match(wrapperKey, name)) {
223 // first matched is taken
224 BndWrapper wrapper = (BndWrapper) wrappers
225 .get(wrapperKey);
226 // we must copy since the stream is closed by BND
227 byte[] origJarBytes = IOUtils.toByteArray(zin);
228 Artifact artifact = wrapZipEntry(javaSession,
229 zentry, origJarBytes, wrapper);
230 nothingWasDone = false;
231 addArtifactToIndex(binaries, wrapper.getGroupId(),
232 artifact);
233 continue entries;
234 } else {
235 if (log.isTraceEnabled())
236 log.trace(name + " not matched by "
237 + wrapperKey);
238 }
239
240 for (String exclude : excludes)
241 if (pathMatcher.match(exclude, name))
242 continue entries;
243
244 for (String include : includes.keySet()) {
245 if (pathMatcher.match(include, name)) {
246 String groupId = includes.get(include);
247 byte[] origJarBytes = IOUtils.toByteArray(zin);
248 Artifact artifact = importZipEntry(javaSession,
249 zentry, origJarBytes, groupId);
250 if (artifact == null) {
251 log.warn("Skipped non identified " + zentry);
252 continue entries;
253 }
254 nothingWasDone = false;
255 if (artifact.getArtifactId().endsWith(".source"))
256 addArtifactToIndex(sources, groupId, artifact);
257 else
258 addArtifactToIndex(binaries, groupId, artifact);
259 // no need to process this entry further
260 continue entries;
261 }
262 }
263 }
264 }
265
266 // indexes
267 if (mavenGroupIndexes && version != null) {
268 for (String groupId : binaries.keySet()) {
269 RepoUtils.writeGroupIndexes(javaSession, "/", groupId,
270 version, binaries.get(groupId),
271 sources.containsKey(groupId) ? sources.get(groupId)
272 : null);
273 }
274 }
275
276 if (nothingWasDone)
277 throw new SlcException("Nothing was done");
278
279 // FIXME Fail if not all wrappers matched
280 } catch (Exception e) {
281 throw new SlcException("Cannot wrap distribution " + uri, e);
282 } finally {
283 IOUtils.closeQuietly(zin);
284 JcrUtils.logoutQuietly(distSession);
285 JcrUtils.logoutQuietly(javaSession);
286 }
287 }
288
289 protected Artifact wrapZipEntry(Session javaSession, ZipEntry zentry,
290 byte[] origJarBytes, BndWrapper wrapper) throws RepositoryException {
291 ByteArrayOutputStream out = null;
292 ByteArrayInputStream in = null;
293 Node newJarNode;
294 Jar jar = null;
295 try {
296 out = new ByteArrayOutputStream((int) zentry.getSize());
297 in = new ByteArrayInputStream(origJarBytes);
298 wrapper.wrapJar(in, out);
299
300 Artifact artifact = wrapper.getArtifact();
301 newJarNode = RepoUtils.copyBytesAsArtifact(
302 javaSession.getRootNode(), artifact, out.toByteArray());
303 osgiFactory.indexNode(newJarNode);
304 newJarNode.getSession().save();
305 if (log.isDebugEnabled())
306 log.debug("Wrapped jar " + zentry.getName() + " to "
307 + newJarNode.getPath());
308
309 if (sourcesProvider != null)
310 addSource(javaSession, artifact, out.toByteArray());
311
312 return artifact;
313 } finally {
314 IOUtils.closeQuietly(in);
315 IOUtils.closeQuietly(out);
316 if (jar != null)
317 jar.close();
318 }
319 }
320
321 protected void addSource(Session javaSession, Artifact artifact,
322 byte[] binaryJarBytes) {
323 InputStream in = null;
324 ByteArrayOutputStream out = null;
325 Jar jar = null;
326 try {
327 in = new ByteArrayInputStream(binaryJarBytes);
328 jar = new Jar(null, in);
329 List<String> packages = jar.getPackages();
330
331 out = new ByteArrayOutputStream();
332 sourcesProvider.writeSources(packages, new ZipOutputStream(out));
333
334 IOUtils.closeQuietly(in);
335 in = new ByteArrayInputStream(out.toByteArray());
336 byte[] sourcesJar = RepoUtils.packageAsPdeSource(
337 in,
338 new DefaultNameVersion(artifact.getArtifactId(), artifact
339 .getVersion()));
340 Artifact sourcesArtifact = new DefaultArtifact(
341 artifact.getGroupId(),
342 artifact.getArtifactId() + ".source", "jar",
343 artifact.getVersion());
344 Node sourcesJarNode = RepoUtils.copyBytesAsArtifact(
345 javaSession.getRootNode(), sourcesArtifact, sourcesJar);
346 sourcesJarNode.getSession().save();
347
348 if (log.isDebugEnabled())
349 log.debug("Added sources " + sourcesArtifact + " for bundle "
350 + artifact + "from source provider " + sourcesProvider);
351 } catch (Exception e) {
352 throw new SlcException("Cannot get sources for " + artifact, e);
353 } finally {
354 IOUtils.closeQuietly(in);
355 IOUtils.closeQuietly(out);
356 if (jar != null)
357 jar.close();
358 }
359 }
360
361 protected Artifact importZipEntry(Session javaSession, ZipEntry zentry,
362 byte[] binaryJarBytes, String groupId) throws RepositoryException {
363 ByteArrayInputStream in = null;
364 Node newJarNode;
365 try {
366 in = new ByteArrayInputStream(binaryJarBytes);
367 NameVersion nameVersion = RepoUtils.readNameVersion(in);
368 if (nameVersion == null) {
369 log.warn("Cannot identify " + zentry.getName());
370 return null;
371 }
372 Artifact artifact = new DefaultArtifact(groupId,
373 nameVersion.getName(), "jar", nameVersion.getVersion());
374 newJarNode = RepoUtils.copyBytesAsArtifact(
375 javaSession.getRootNode(), artifact, binaryJarBytes);
376 osgiFactory.indexNode(newJarNode);
377 newJarNode.getSession().save();
378 if (log.isDebugEnabled())
379 log.debug("Imported OSGi bundle " + zentry.getName() + " to "
380 + newJarNode.getPath());
381
382 if (sourcesProvider != null)
383 addSource(javaSession, artifact, binaryJarBytes);
384
385 return artifact;
386 } finally {
387 IOUtils.closeQuietly(in);
388 }
389 }
390
391 private void addArtifactToIndex(Map<String, Set<Artifact>> index,
392 String groupId, Artifact artifact) {
393 if (!index.containsKey(groupId))
394 index.put(groupId,
395 new TreeSet<Artifact>(new ArtifactIdComparator()));
396 index.get(groupId).add(artifact);
397 }
398
399 public void setUri(String uri) {
400 this.uri = uri;
401 }
402
403 public void setWrappers(Map<String, BndWrapper> wrappers) {
404 this.wrappers = wrappers;
405 }
406
407 public void setOsgiFactory(OsgiFactory osgiFactory) {
408 this.osgiFactory = osgiFactory;
409 }
410
411 public void setVersion(String version) {
412 this.version = version;
413 }
414
415 public void setLicense(License license) {
416 this.license = license;
417 }
418
419 public void setPathMatcher(PathMatcher pathMatcher) {
420 this.pathMatcher = pathMatcher;
421 }
422
423 public void setIncludes(Map<String, String> includes) {
424 this.includes = includes;
425 }
426
427 public void setExcludes(List<String> excludes) {
428 this.excludes = excludes;
429 }
430
431 public void setMavenGroupIndexes(Boolean mavenGroupIndexes) {
432 this.mavenGroupIndexes = mavenGroupIndexes;
433 }
434
435 public void setSourcesProvider(SourcesProvider sourcesProvider) {
436 this.sourcesProvider = sourcesProvider;
437 }
438
439 }