1 package org
.argeo
.slc
.repo
.osgi
;
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
;
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
;
18 import javax
.jcr
.Node
;
19 import javax
.jcr
.Property
;
20 import javax
.jcr
.RepositoryException
;
21 import javax
.jcr
.Session
;
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
;
43 import aQute
.lib
.osgi
.Jar
;
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.
50 public class ArchiveWrapper
implements Runnable
, ModuleSet
, Distribution
{
51 private final static Log log
= LogFactory
.getLog(ArchiveWrapper
.class);
53 private OsgiFactory osgiFactory
;
54 private String version
;
55 private License license
;
59 /** Jars to wrap as OSGi bundles */
60 private Map
<String
, BndWrapper
> wrappers
= new HashMap
<String
, BndWrapper
>();
62 private SourcesProvider sourcesProvider
;
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
>();
69 private Boolean mavenGroupIndexes
= false;
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
);
81 public void destroy() {
85 public String
getDistributionId() {
89 public Iterator
<?
extends NameVersion
> nameVersions() {
90 if (wrappers
.size() > 0)
91 return wrappers
.values().iterator();
93 return osgiNameVersions();
96 @SuppressWarnings("resource")
97 protected Iterator
<?
extends NameVersion
> osgiNameVersions() {
98 List
<CategorizedNameVersion
> nvs
= new ArrayList
<CategorizedNameVersion
>();
100 Session distSession
= null;
101 ZipInputStream zin
= null;
103 distSession
= osgiFactory
.openDistSession();
105 Node distNode
= osgiFactory
.getDist(distSession
, uri
);
106 zin
= new ZipInputStream(distNode
.getNode(Node
.JCR_CONTENT
)
107 .getProperty(Property
.JCR_DATA
).getBinary().getStream());
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
))
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
127 NameVersion nv
= RepoUtils
.readNameVersion(jis
130 if (nv
.getName().endsWith(".source"))
132 CategorizedNameVersion cnv
= new OsgiCategorizedNV(
133 groupId
, nv
.getName(), nv
.getVersion(),
136 // no need to process further includes
142 return nvs
.iterator();
143 } catch (Exception e
) {
144 throw new SlcException("Cannot wrap distribution " + uri
, e
);
146 IOUtils
.closeQuietly(zin
);
147 JcrUtils
.logoutQuietly(distSession
);
152 if (mavenGroupIndexes
&& (version
== null))
153 throw new SlcException(
154 "'mavenGroupIndexes' requires 'version' to be set");
156 Map
<String
, Set
<Artifact
>> binaries
= new HashMap
<String
, Set
<Artifact
>>();
157 Map
<String
, Set
<Artifact
>> sources
= new HashMap
<String
, Set
<Artifact
>>();
159 Session distSession
= null;
160 Session javaSession
= null;
161 ZipInputStream zin
= null;
163 javaSession
= osgiFactory
.openJavaSession();
164 distSession
= osgiFactory
.openDistSession();
166 if (log
.isDebugEnabled())
167 log
.debug("Wrapping " + uri
);
168 boolean nothingWasDone
= true;
170 Node distNode
= osgiFactory
.getDist(distSession
, uri
);
171 zin
= new ZipInputStream(distNode
.getNode(Node
.JCR_CONTENT
)
172 .getProperty(Property
.JCR_DATA
).getBinary().getStream());
174 ZipEntry zentry
= null;
175 entries
: while ((zentry
= zin
.getNextEntry()) != null) {
176 String name
= zentry
.getName();
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
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
,
192 Artifact sourcesArtifact
= new DefaultArtifact(
193 wrapper
.getCategory(), wrapper
.getName()
195 wrapper
.getVersion());
196 Node pdeSourceNode
= RepoUtils
.copyBytesAsArtifact(
197 javaSession
.getRootNode(), sourcesArtifact
,
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.");
208 // else if (baseName.endsWith(".source")) {
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
);
221 for (String wrapperKey
: wrappers
.keySet())
222 if (pathMatcher
.match(wrapperKey
, name
)) {
223 // first matched is taken
224 BndWrapper wrapper
= (BndWrapper
) wrappers
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(),
235 if (log
.isTraceEnabled())
236 log
.trace(name
+ " not matched by "
240 for (String exclude
: excludes
)
241 if (pathMatcher
.match(exclude
, name
))
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
);
254 nothingWasDone
= false;
255 if (artifact
.getArtifactId().endsWith(".source"))
256 addArtifactToIndex(sources
, groupId
, artifact
);
258 addArtifactToIndex(binaries
, groupId
, artifact
);
259 // no need to process this entry further
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
)
277 throw new SlcException("Nothing was done");
279 // FIXME Fail if not all wrappers matched
280 } catch (Exception e
) {
281 throw new SlcException("Cannot wrap distribution " + uri
, e
);
283 IOUtils
.closeQuietly(zin
);
284 JcrUtils
.logoutQuietly(distSession
);
285 JcrUtils
.logoutQuietly(javaSession
);
289 protected Artifact
wrapZipEntry(Session javaSession
, ZipEntry zentry
,
290 byte[] origJarBytes
, BndWrapper wrapper
) throws RepositoryException
{
291 ByteArrayOutputStream out
= null;
292 ByteArrayInputStream in
= null;
296 out
= new ByteArrayOutputStream((int) zentry
.getSize());
297 in
= new ByteArrayInputStream(origJarBytes
);
298 wrapper
.wrapJar(in
, out
);
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());
309 if (sourcesProvider
!= null)
310 addSource(javaSession
, artifact
, out
.toByteArray());
314 IOUtils
.closeQuietly(in
);
315 IOUtils
.closeQuietly(out
);
321 protected void addSource(Session javaSession
, Artifact artifact
,
322 byte[] binaryJarBytes
) {
323 InputStream in
= null;
324 ByteArrayOutputStream out
= null;
327 in
= new ByteArrayInputStream(binaryJarBytes
);
328 jar
= new Jar(null, in
);
329 List
<String
> packages
= jar
.getPackages();
331 out
= new ByteArrayOutputStream();
332 sourcesProvider
.writeSources(packages
, new ZipOutputStream(out
));
334 IOUtils
.closeQuietly(in
);
335 in
= new ByteArrayInputStream(out
.toByteArray());
336 byte[] sourcesJar
= RepoUtils
.packageAsPdeSource(
338 new DefaultNameVersion(artifact
.getArtifactId(), artifact
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();
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
);
354 IOUtils
.closeQuietly(in
);
355 IOUtils
.closeQuietly(out
);
361 protected Artifact
importZipEntry(Session javaSession
, ZipEntry zentry
,
362 byte[] binaryJarBytes
, String groupId
) throws RepositoryException
{
363 ByteArrayInputStream in
= null;
366 in
= new ByteArrayInputStream(binaryJarBytes
);
367 NameVersion nameVersion
= RepoUtils
.readNameVersion(in
);
368 if (nameVersion
== null) {
369 log
.warn("Cannot identify " + zentry
.getName());
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());
382 if (sourcesProvider
!= null)
383 addSource(javaSession
, artifact
, binaryJarBytes
);
387 IOUtils
.closeQuietly(in
);
391 private void addArtifactToIndex(Map
<String
, Set
<Artifact
>> index
,
392 String groupId
, Artifact artifact
) {
393 if (!index
.containsKey(groupId
))
395 new TreeSet
<Artifact
>(new ArtifactIdComparator()));
396 index
.get(groupId
).add(artifact
);
399 public void setUri(String uri
) {
403 public void setWrappers(Map
<String
, BndWrapper
> wrappers
) {
404 this.wrappers
= wrappers
;
407 public void setOsgiFactory(OsgiFactory osgiFactory
) {
408 this.osgiFactory
= osgiFactory
;
411 public void setVersion(String version
) {
412 this.version
= version
;
415 public void setLicense(License license
) {
416 this.license
= license
;
419 public void setPathMatcher(PathMatcher pathMatcher
) {
420 this.pathMatcher
= pathMatcher
;
423 public void setIncludes(Map
<String
, String
> includes
) {
424 this.includes
= includes
;
427 public void setExcludes(List
<String
> excludes
) {
428 this.excludes
= excludes
;
431 public void setMavenGroupIndexes(Boolean mavenGroupIndexes
) {
432 this.mavenGroupIndexes
= mavenGroupIndexes
;
435 public void setSourcesProvider(SourcesProvider sourcesProvider
) {
436 this.sourcesProvider
= sourcesProvider
;