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