1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sourceforge.osgi.deployment.maven.manifest;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.jar.JarInputStream;
29 import java.util.jar.Manifest;
30 import java.util.regex.Pattern;
31
32 import net.sourceforge.osgi.deployment.maven.IDeploymentPluginContext;
33 import net.sourceforge.osgi.deployment.maven.container.BundleResource;
34 import net.sourceforge.osgi.deployment.maven.container.DeploymentPackageInfo;
35 import net.sourceforge.osgi.deployment.maven.container.ProcessedResource;
36
37 import org.apache.maven.model.License;
38 import org.apache.maven.project.MavenProject;
39
40
41
42
43
44
45
46
47 public class DeploymentPackageManifest extends OrderedManifest {
48
49 public static final String CREATED_BY = "Created-By";
50
51 public static final String TOOL = "Tool";
52
53 public static final String CREATED_AT = "Created-At";
54
55
56 public static final String DP_MANIFESTVERSION = "DeploymentPackage-ManifestVersion";
57
58
59 public static final String DP_CONTENT_TYPE = "application/vnd.osgi.dp";
60
61
62 public static final String DP_SYMBOLICNAME = "DeploymentPackage-SymbolicName";
63
64
65 public static final String DP_VERSION = "DeploymentPackage-Version";
66
67
68 public static final String DP_COPYRIGHT = "DeploymentPackage-Copyright";
69
70
71 public static final String DP_CONTACTADDRESS = "DeploymentPackage-ContactAddress";
72
73
74 public static final String DP_DESCRIPTION = "DeploymentPackage-Description";
75
76
77 public static final String DP_DOCURL = "DeploymentPackage-DocURL";
78
79
80 public static final String DP_VENDOR = "DeploymentPackage-Vendor";
81
82
83 public static final String DP_LICENSE = "DeploymentPackage-License";
84
85
86 public static final String DP_FIXPACK = "DeploymentPackage-FixPack";
87
88
89 public static final String DP_CUSTOMIZER = "DeploymentPackage-Customizer";
90
91
92 public static final String DP_NAME = "Name";
93
94
95 public static final String DP_SHA1_DIGEST = "SHA1-Digest";
96
97
98 public static final String DP_RESOURCE_PROCESSOR = "Resource-Processor";
99
100
101 public static final Pattern PATH_NAME_PATTERN = Pattern.compile("[A-Za-z0-9_\\.-]+");
102
103
104 public static final Pattern UNIQUE_NAME_PATTERN = Pattern.compile(".+(\\..+)*");
105
106
107
108
109 public static final String BUNDLE_VERSION = "Bundle-Version";
110
111
112
113
114 public static final String BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName";
115
116
117
118
119 public static final String BUNDLE_LOCALIZATION = "Bundle-Localization";
120
121
122
123
124
125 public DeploymentPackageManifest(final IDeploymentPluginContext p_context) {
126
127 try {
128 writeGlobalSection(p_context);
129 writeNameSection(p_context);
130 } catch (final ManifestException e) {
131 throw new ManifestException("The creation of the Deploymant-Package Manifest file failed", e);
132 }
133 }
134
135 private void writeNameSection(final IDeploymentPluginContext p_context) {
136 writeBundleResources(p_context);
137 writeLocalizationResources(p_context);
138 writeProcessedResources(p_context);
139 }
140
141 private void writeGlobalSection(final IDeploymentPluginContext p_context) {
142
143 add(MANIFEST_VERSION, "1.0");
144
145 writeExtraData(p_context);
146
147
148 add(DP_MANIFESTVERSION, "1");
149 add(CONTENT_TYPE, DP_CONTENT_TYPE);
150
151 final DeploymentPackageInfo deploymentPackageInfo = p_context.getDeploymentPackageInfo();
152 final MavenProject project = p_context.getProject();
153
154 writesymlobicName(deploymentPackageInfo, project);
155 writeVersion(deploymentPackageInfo, project);
156 writeFixPack(deploymentPackageInfo);
157 writeDescription(deploymentPackageInfo, project);
158 writeLicense(project);
159 writeVendor(deploymentPackageInfo, project);
160 writeCopyright(deploymentPackageInfo);
161 writeContactAdress(deploymentPackageInfo);
162 writeDocURL(deploymentPackageInfo);
163 writeBundleLocalization(deploymentPackageInfo);
164 }
165
166 private void writeProcessedResources(final IDeploymentPluginContext p_context) {
167 final DeploymentPackageInfo deploymentPackageInfo = p_context.getDeploymentPackageInfo();
168
169 for (final ProcessedResource processedResource : deploymentPackageInfo.getProcessedResources()) {
170 final String resourceId = processedResource.getResourceId();
171
172 if (!isResourceId(resourceId)) {
173 throw new ManifestException("\"" + resourceId + "\" is not a valid path name as specified in OSGi 114.3.2 Service Compendium");
174 }
175
176 add(OrderedManifest.EMPTY_LINE);
177 add(DP_NAME, resourceId);
178 add(DP_RESOURCE_PROCESSOR, processedResource.getProcessor());
179 }
180 }
181
182 private void writeLocalizationResources(final IDeploymentPluginContext p_context) {
183 final DeploymentPackageInfo deploymentPackageInfo = p_context.getDeploymentPackageInfo();
184
185 for (final ProcessedResource processedResource : deploymentPackageInfo.getLocalizationResources()) {
186 final String resourceId = processedResource.getResourceId();
187
188 if (!isResourceId(resourceId)) {
189 throw new ManifestException("\"" + resourceId + "\" is not a valid path name as specified in OSGi 114.3.2 Service Compendium");
190 }
191
192 add(OrderedManifest.EMPTY_LINE);
193 add(DP_NAME, resourceId);
194 add(DP_RESOURCE_PROCESSOR, processedResource.getProcessor());
195 }
196 }
197
198 private void writeBundleResources(final IDeploymentPluginContext p_context) {
199 final DeploymentPackageInfo deploymentPackageInfo = p_context.getDeploymentPackageInfo();
200
201 for (final BundleResource bundleResource : deploymentPackageInfo.getBundleResources()) {
202 try {
203
204
205 final File resolvedFile = bundleResource.getResolvedFile();
206 final JarInputStream jis = new JarInputStream(new FileInputStream(resolvedFile));
207 final Manifest bundleManifest = jis.getManifest();
208 final String bundleVersion = bundleManifest.getMainAttributes().getValue(BUNDLE_VERSION);
209 final String bundleSymbolicName = bundleManifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME);
210 final String resourceId = bundleResource.getResourceId();
211
212 if (!isUniqueName(bundleSymbolicName)) {
213 throw new ManifestException("\"" + bundleSymbolicName + "\" is not a valid unique-name as specified in OSGi 1.3.2 Core");
214 }
215
216 if (!isVersion(bundleVersion)) {
217 throw new ManifestException("\"" + bundleVersion + "\" is not a valid version as specified in OSGi 3.2.4 Core");
218 }
219
220 if (!isResourceId(resourceId)) {
221 throw new ManifestException("\"" + resourceId + "\" is not a valid path name as specified in OSGi 114.3.2 Service Compendium");
222 }
223
224 add(OrderedManifest.EMPTY_LINE);
225 add(DP_NAME, resourceId);
226 if (bundleResource.isCustomizer()) {
227 add(DP_CUSTOMIZER, "true");
228 }
229 add(BUNDLE_SYMBOLICNAME, bundleSymbolicName);
230 add(BUNDLE_VERSION, bundleVersion);
231 } catch (final Exception e) {
232 throw new ManifestException("Error while processing bundle resource " + bundleResource, e);
233 }
234 }
235 }
236
237 private void writeBundleLocalization(final DeploymentPackageInfo p_deploymentPackageInfo) {
238
239 if (isNotEmpty(p_deploymentPackageInfo.getBundleLocalization())) {
240 add(BUNDLE_LOCALIZATION, p_deploymentPackageInfo.getBundleLocalization());
241 }
242 }
243
244 private void writeDocURL(final DeploymentPackageInfo p_deploymentPackageInfo) {
245
246 if (isNotEmpty(p_deploymentPackageInfo.getDocURL())) {
247 add(DP_DOCURL, p_deploymentPackageInfo.getDocURL());
248 }
249 }
250
251 private void writeContactAdress(final DeploymentPackageInfo p_deploymentPackageInfo) {
252
253 if (isNotEmpty(p_deploymentPackageInfo.getContactAddress())) {
254 add(DP_CONTACTADDRESS, p_deploymentPackageInfo.getContactAddress());
255 }
256 }
257
258 private void writeCopyright(final DeploymentPackageInfo p_deploymentPackageInfo) {
259
260 if (isNotEmpty(p_deploymentPackageInfo.getCopyright())) {
261 add(DP_COPYRIGHT, p_deploymentPackageInfo.getCopyright());
262 }
263 }
264
265 private void writeVendor(final DeploymentPackageInfo p_deploymentPackageInfo, final MavenProject p_project) {
266
267 String vendor = null;
268 if (isNotEmpty(p_deploymentPackageInfo.getVendor())) {
269 vendor = p_deploymentPackageInfo.getVendor();
270 } else if (p_project.getOrganization() != null) {
271 vendor = p_project.getOrganization().getName();
272 }
273 if (isNotEmpty(vendor)) {
274 header(DP_VENDOR, vendor);
275 }
276 }
277
278 private void writeLicense(final MavenProject p_project) {
279
280 final String licenseText = printLicenses(p_project.getLicenses());
281 if (isNotEmpty(licenseText)) {
282 header(DP_LICENSE, licenseText);
283 }
284 }
285
286 private void writeDescription(final DeploymentPackageInfo p_deploymentPackageInfo, final MavenProject p_project) {
287
288 String description = null;
289 if (isNotEmpty(p_deploymentPackageInfo.getDescription())) {
290 description = p_deploymentPackageInfo.getDescription();
291 } else {
292 description = p_project.getDescription();
293 }
294 if (description != null) {
295 header(DP_DESCRIPTION, description);
296 }
297 }
298
299 private void writeFixPack(final DeploymentPackageInfo p_deploymentPackageInfo) {
300 final String fixPack = p_deploymentPackageInfo.getFixPack();
301 if (isNotEmpty(fixPack)) {
302 if (!isVersionRange(fixPack)) {
303 throw new ManifestException("\"" + fixPack + "\" is not a valid version range as specified in OSGi 3.2.5 Core");
304 }
305 add(DP_FIXPACK, fixPack);
306 }
307 }
308
309 private void writeVersion(final DeploymentPackageInfo p_deploymentPackageInfo, final MavenProject p_project) {
310
311 String version = null;
312 if (isNotEmpty(p_deploymentPackageInfo.getVersion())) {
313 version = p_deploymentPackageInfo.getVersion();
314 } else {
315 String pomVersion = p_project.getVersion();
316
317 if (!isVersion(pomVersion)) {
318 pomVersion = pomVersion.replaceAll("-", "\\.");
319 }
320 version = pomVersion;
321 }
322 if (!isVersion(version)) {
323 throw new ManifestException("\"" + version + "\" is not a valid version as specified in OSGi 3.2.4 Core");
324 }
325 add(DP_VERSION, version);
326 }
327
328 private void writesymlobicName(final DeploymentPackageInfo p_deploymentPackageInfo, final MavenProject p_project) {
329
330 String symbolicName = null;
331 if (p_deploymentPackageInfo.getSymbolicName() != null && p_deploymentPackageInfo.getSymbolicName().trim().length() > 0) {
332 symbolicName = p_deploymentPackageInfo.getSymbolicName();
333 } else {
334 symbolicName = p_project.getGroupId() + "." + p_project.getArtifactId();
335 }
336 if (!isUniqueName(symbolicName)) {
337 throw new ManifestException("\"" + symbolicName + "\" is not a valid unique-name as specified in OSGi 1.3.2 Core");
338 }
339 add(DP_SYMBOLICNAME, symbolicName);
340 }
341
342 private void writeExtraData(final IDeploymentPluginContext p_context) {
343
344 if (p_context.isWriteExtraData()) {
345 add(CREATED_BY, System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")");
346 add(TOOL, p_context.getPluginName() + " " + p_context.getPluginVersion());
347 add(CREATED_AT, "" + System.currentTimeMillis());
348 }
349 }
350
351 private void header(final String p_key, final Object p_value) {
352 if (p_value == null) {
353 return;
354 }
355
356 if (p_value instanceof Collection && ((Collection< ? >) p_value).isEmpty()) {
357 return;
358 }
359
360 add(p_key, p_value.toString().replaceAll("[\r\n]", ""));
361 }
362
363 private String printLicenses(final List< License > p_licenses) {
364 if (p_licenses == null || p_licenses.size() == 0) {
365 return null;
366 }
367 final StringBuffer sb = new StringBuffer();
368 String del = "";
369 for (final License license : p_licenses) {
370 final String url = license.getUrl();
371 if (url == null) {
372 continue;
373 }
374 sb.append(del);
375 sb.append(url);
376 del = ", ";
377 }
378 if (sb.length() == 0) {
379 return null;
380 }
381 return sb.toString();
382 }
383
384 private static boolean isNotEmpty(final String p_string) {
385 if (p_string != null && p_string.trim().length() > 0) {
386 return true;
387 }
388 return false;
389 }
390
391
392
393
394
395
396
397
398 public static boolean isVersion(final String p_versionToCheck) {
399
400 return true;
401 }
402
403
404
405
406
407
408
409
410 public static final boolean isVersionRange(final String p_versionRange) {
411
412 return true;
413 }
414
415
416
417
418
419
420
421
422 public static boolean isUniqueName(final String p_symbolicName) {
423 boolean isUniqueName = true;
424
425
426
427
428
429 for (int i = 0; i < p_symbolicName.length(); i++) {
430 final char c = p_symbolicName.charAt(i);
431 if (!(Character.isJavaIdentifierStart(c) || Character.isJavaIdentifierPart(c) || c == '.')) {
432 isUniqueName = false;
433 }
434 }
435
436 if (isUniqueName && !UNIQUE_NAME_PATTERN.matcher(p_symbolicName).matches()) {
437 isUniqueName = false;
438 }
439
440 return isUniqueName;
441 }
442
443
444
445
446
447
448
449
450 public static boolean isResourceId(final String p_resourceId) {
451 if (p_resourceId == null) {
452 return false;
453 }
454 if (p_resourceId.contains("/")) {
455
456 for (final String pathToken : p_resourceId.split("/")) {
457 if (!pathToken.equals("") && !PATH_NAME_PATTERN.matcher(pathToken).matches()) {
458 return false;
459 }
460 }
461 } else {
462 if (!PATH_NAME_PATTERN.matcher(p_resourceId).matches()) {
463 return false;
464 }
465 }
466 return true;
467 }
468
469 }