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