1 package org.argeo.slc.repo;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.File;
6 import java.io.FileWriter;
7 import java.io.IOException;
8 import java.io.Writer;
9 import java.text.DateFormat;
10 import java.text.SimpleDateFormat;
11 import java.util.Date;
12 import java.util.Iterator;
13 import java.util.jar.Attributes;
14 import java.util.jar.JarEntry;
15 import java.util.jar.JarOutputStream;
16 import java.util.jar.Manifest;
17
18 import javax.jcr.Node;
19 import javax.jcr.RepositoryException;
20 import javax.jcr.Session;
21
22 import org.apache.commons.io.FileUtils;
23 import org.apache.commons.io.IOUtils;
24 import org.argeo.jcr.JcrUtils;
25 import org.argeo.slc.CategorizedNameVersion;
26 import org.argeo.slc.NameVersion;
27 import org.argeo.slc.SlcException;
28 import org.eclipse.aether.artifact.Artifact;
29 import org.eclipse.aether.artifact.DefaultArtifact;
30 import org.osgi.framework.Constants;
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class ModularDistributionFactory implements Runnable {
45
46 private OsgiFactory osgiFactory;
47 private Session javaSession;
48 private ArgeoOsgiDistribution osgiDistribution;
49 private String modularDistributionSeparator = ",";
50 private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
51 private String artifactType = "jar";
52
53
54 private final static String CSV_FILE_NAME = "modularDistribution.csv";
55 private final DateFormat snapshotTimestamp = new SimpleDateFormat("YYYYMMddhhmm");
56
57
58
59
60
61 public ModularDistributionFactory(OsgiFactory osgiFactory, ArgeoOsgiDistribution osgiDistribution) {
62 this.osgiFactory = osgiFactory;
63 this.osgiDistribution = osgiDistribution;
64 }
65
66 @Override
67 public void run() {
68 byte[] distFile = null;
69 try {
70 javaSession = osgiFactory.openJavaSession();
71
72 if (artifactType == "jar")
73 distFile = generateJarFile();
74 else if (artifactType == "pom")
75 distFile = generatePomFile();
76 else
77 throw new SlcException("Unimplemented distribution artifact type: " + artifactType + " for "
78 + osgiDistribution.toString());
79
80
81 Artifact osgiArtifact = new DefaultArtifact(osgiDistribution.getCategory(), osgiDistribution.getName(),
82 artifactType, osgiDistribution.getVersion());
83
84 Node distNode = RepoUtils.copyBytesAsArtifact(javaSession.getNode(artifactBasePath), osgiArtifact,
85 distFile);
86
87
88 osgiFactory.indexNode(distNode);
89
90
91 javaSession.save();
92 } catch (RepositoryException e) {
93 throw new SlcException(
94 "JCR error while persisting modular distribution in JCR " + osgiDistribution.toString(), e);
95 } finally {
96 JcrUtils.logoutQuietly(javaSession);
97 }
98 }
99
100 private byte[] generateJarFile() {
101 ByteArrayOutputStream byteOut = null;
102 JarOutputStream jarOut = null;
103 try {
104 byteOut = new ByteArrayOutputStream();
105 jarOut = new JarOutputStream(byteOut, createManifest());
106
107 addToJar(createCsvDescriptor(), CSV_FILE_NAME, jarOut);
108 jarOut.close();
109 return byteOut.toByteArray();
110 } catch (IOException e) {
111 throw new SlcException("IO error while generating modular distribution " + osgiDistribution.toString(), e);
112 } finally {
113 IOUtils.closeQuietly(byteOut);
114 IOUtils.closeQuietly(jarOut);
115 }
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 private Manifest createManifest() {
139 Manifest manifest = new Manifest();
140
141
142 manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
143
144 addManifestAttribute(manifest, Constants.BUNDLE_VENDOR, "Argeo");
145 addManifestAttribute(manifest, Constants.BUNDLE_MANIFESTVERSION, "2");
146
147
148
149 addManifestAttribute(manifest, Constants.BUNDLE_NAME, osgiDistribution.getName());
150
151
152 addManifestAttribute(manifest, RepoConstants.SLC_CATEGORY_ID, osgiDistribution.getCategory());
153 addManifestAttribute(manifest, Constants.BUNDLE_SYMBOLICNAME, osgiDistribution.getName());
154 String version = osgiDistribution.getVersion();
155 if (version.endsWith("-SNAPSHOT")) {
156 version = version.substring(0, version.length() - "-SNAPSHOT".length());
157 version = version + ".SNAPSHOT-r" + snapshotTimestamp.format(new Date());
158 }
159 addManifestAttribute(manifest, Constants.BUNDLE_VERSION, version);
160
161 return manifest;
162 }
163
164 private void addManifestAttribute(Manifest manifest, String name, String value) {
165 manifest.getMainAttributes().put(new Attributes.Name(name), value);
166 }
167
168 private byte[] createCsvDescriptor() {
169 Writer writer = null;
170 try {
171
172 File tmpFile = File.createTempFile("modularDistribution", "csv");
173 tmpFile.deleteOnExit();
174 writer = new FileWriter(tmpFile);
175
176 for (Iterator<? extends NameVersion> it = osgiDistribution.nameVersions(); it.hasNext();)
177 writer.write(getCsvLine(it.next()));
178 writer.flush();
179 return FileUtils.readFileToByteArray(tmpFile);
180 } catch (Exception e) {
181 throw new SlcException("unable to create csv distribution file for " + osgiDistribution.toString(), e);
182 } finally {
183 IOUtils.closeQuietly(writer);
184 }
185 }
186
187 @SuppressWarnings("unused")
188 private byte[] createFeatureDescriptor() {
189
190
191
192
193 throw new SlcException("Unimplemented method");
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392 }
393
394
395 private byte[] generatePomFile() {
396 StringBuilder b = new StringBuilder();
397
398 b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
399 b.append(
400 "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n");
401 b.append("<modelVersion>4.0.0</modelVersion>");
402
403
404 b.append("<groupId>").append(osgiDistribution.getCategory()).append("</groupId>\n");
405 b.append("<artifactId>").append(osgiDistribution.getName()).append("</artifactId>\n");
406 b.append("<version>").append(osgiDistribution.getVersion()).append("</version>\n");
407 b.append("<packaging>pom</packaging>\n");
408
409
410
411
412
413 b.append("<dependencies>\n");
414 for (Iterator<? extends NameVersion> it = osgiDistribution.nameVersions(); it.hasNext();) {
415 NameVersion nameVersion = it.next();
416 if (!(nameVersion instanceof CategorizedNameVersion))
417 throw new SlcException("Unsupported type " + nameVersion.getClass());
418 CategorizedNameVersion nv = (CategorizedNameVersion) nameVersion;
419 b.append(getDependencySnippet(nv, false));
420 }
421 b.append("</dependencies>\n");
422
423
424 b.append("<dependencyManagement>\n");
425 b.append("<dependencies>\n");
426
427 for (Iterator<? extends NameVersion> it = osgiDistribution.nameVersions(); it.hasNext();)
428 b.append(getDependencySnippet((CategorizedNameVersion) it.next(), true));
429 b.append("</dependencies>\n");
430 b.append("</dependencyManagement>\n");
431
432 b.append("</project>\n");
433 return b.toString().getBytes();
434 }
435
436 private String getDependencySnippet(CategorizedNameVersion cnv, boolean includeVersion) {
437
438 StringBuilder b = new StringBuilder();
439 b.append("<dependency>\n");
440 b.append("\t<groupId>").append(cnv.getCategory()).append("</groupId>\n");
441 b.append("\t<artifactId>").append(cnv.getName()).append("</artifactId>\n");
442 if (includeVersion)
443 b.append("\t<version>").append(cnv.getVersion()).append("</version>\n");
444
445
446
447
448 b.append("</dependency>\n");
449 return b.toString();
450 }
451
452
453 private void addToJar(byte[] content, String name, JarOutputStream target) throws IOException {
454 ByteArrayInputStream in = null;
455 try {
456 target.putNextEntry(new JarEntry(name));
457 in = new ByteArrayInputStream(content);
458 byte[] buffer = new byte[1024];
459 while (true) {
460 int count = in.read(buffer);
461 if (count == -1)
462 break;
463 target.write(buffer, 0, count);
464 }
465 target.closeEntry();
466 } finally {
467 IOUtils.closeQuietly(in);
468 }
469 }
470
471 private String getCsvLine(NameVersion nameVersion) throws RepositoryException {
472 if (!(nameVersion instanceof CategorizedNameVersion))
473 throw new SlcException("Unsupported type " + nameVersion.getClass());
474 CategorizedNameVersion cnv = (CategorizedNameVersion) nameVersion;
475 StringBuilder builder = new StringBuilder();
476
477 builder.append(cnv.getName());
478 builder.append(modularDistributionSeparator);
479 builder.append(nameVersion.getVersion());
480 builder.append(modularDistributionSeparator);
481 builder.append(cnv.getCategory().replace('.', '/'));
482
483 builder.append('/');
484 builder.append(cnv.getName());
485 builder.append('/');
486 builder.append(cnv.getVersion());
487 builder.append('/');
488 builder.append(cnv.getName());
489 builder.append('-');
490 builder.append(cnv.getVersion());
491 builder.append('.');
492
493 builder.append("jar");
494 builder.append("\n");
495
496 return builder.toString();
497 }
498
499
500 public void setOsgiFactory(OsgiFactory osgiFactory) {
501 this.osgiFactory = osgiFactory;
502 }
503
504 public void setOsgiDistribution(ArgeoOsgiDistribution osgiDistribution) {
505 this.osgiDistribution = osgiDistribution;
506 }
507
508 public void setModularDistributionSeparator(String modularDistributionSeparator) {
509 this.modularDistributionSeparator = modularDistributionSeparator;
510 }
511
512 public void setArtifactBasePath(String artifactBasePath) {
513 this.artifactBasePath = artifactBasePath;
514 }
515
516 public void setArtifactType(String artifactType) {
517 this.artifactType = artifactType;
518 }
519 }