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