1 package org.apache.maven.index.creator;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import org.apache.lucene.document.Document;
26 import org.apache.lucene.document.Field;
27 import org.apache.maven.index.ArtifactContext;
28 import org.apache.maven.index.ArtifactInfo;
29 import org.apache.maven.index.IndexerField;
30 import org.apache.maven.index.IndexerFieldVersion;
31 import org.apache.maven.index.OSGI;
32 import org.apache.maven.index.util.zip.ZipFacade;
33 import org.apache.maven.index.util.zip.ZipHandle;
34 import org.codehaus.plexus.util.StringUtils;
35
36 import java.io.File;
37 import java.io.FileInputStream;
38 import java.io.IOException;
39 import java.security.DigestInputStream;
40 import java.security.MessageDigest;
41 import java.security.NoSuchAlgorithmException;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.List;
45 import java.util.jar.Attributes;
46 import java.util.jar.Manifest;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 @Singleton
67 @Named( OsgiArtifactIndexCreator.ID )
68 public class OsgiArtifactIndexCreator
69 extends AbstractIndexCreator
70 {
71 public static final String ID = "osgi-metadatas";
72
73 public static final IndexerField FLD_SHA256 =
74 new IndexerField( OSGI.SHA256, IndexerFieldVersion.V4, "sha256", "SHA-256 (not analyzed, stored)",
75 Field.Store.YES, Field.Index.NOT_ANALYZED );
76
77 private static final String BSN = "Bundle-SymbolicName";
78
79 public static final IndexerField FLD_BUNDLE_SYMBOLIC_NAME =
80 new IndexerField( OSGI.SYMBOLIC_NAME, IndexerFieldVersion.V4, BSN, "Bundle-SymbolicName (indexed, stored)",
81 Field.Store.YES, Field.Index.ANALYZED );
82
83 private static final String BV = "Bundle-Version";
84
85 public static final IndexerField FLD_BUNDLE_VERSION =
86 new IndexerField( OSGI.VERSION, IndexerFieldVersion.V4, BV, "Bundle-Version (indexed, stored)", Field.Store.YES,
87 Field.Index.ANALYZED );
88
89 private static final String BEP = "Export-Package";
90
91 public static final IndexerField FLD_BUNDLE_EXPORT_PACKAGE =
92 new IndexerField( OSGI.EXPORT_PACKAGE, IndexerFieldVersion.V4, BEP, "Export-Package (indexed, stored)",
93 Field.Store.YES, Field.Index.ANALYZED );
94
95 @Deprecated
96 private static final String BES = "Export-Service";
97 @Deprecated
98 public static final IndexerField FLD_BUNDLE_EXPORT_SERVIVE =
99 new IndexerField( OSGI.EXPORT_SERVICE, IndexerFieldVersion.V4, BES, "Export-Service (indexed, stored)",
100 Field.Store.YES, Field.Index.ANALYZED );
101
102 private static final String BD = "Bundle-Description";
103
104 public static final IndexerField FLD_BUNDLE_DESCRIPTION =
105 new IndexerField( OSGI.DESCRIPTION, IndexerFieldVersion.V4, BD, "Bundle-Description (indexed, stored)",
106 Field.Store.YES, Field.Index.ANALYZED );
107
108 private static final String BN = "Bundle-Name";
109
110 public static final IndexerField FLD_BUNDLE_NAME =
111 new IndexerField( OSGI.NAME, IndexerFieldVersion.V4, BN, "Bundle-Name (indexed, stored)", Field.Store.YES,
112 Field.Index.ANALYZED );
113
114 private static final String BL = "Bundle-License";
115
116 public static final IndexerField FLD_BUNDLE_LICENSE =
117 new IndexerField( OSGI.LICENSE, IndexerFieldVersion.V4, BL, "Bundle-License (indexed, stored)", Field.Store.YES,
118 Field.Index.ANALYZED );
119
120 private static final String BDU = "Bundle-DocURL";
121
122 public static final IndexerField FLD_BUNDLE_DOCURL =
123 new IndexerField( OSGI.DOCURL, IndexerFieldVersion.V4, BDU, "Bundle-DocURL (indexed, stored)", Field.Store.YES,
124 Field.Index.ANALYZED );
125
126 private static final String BIP = "Import-Package";
127
128 public static final IndexerField FLD_BUNDLE_IMPORT_PACKAGE =
129 new IndexerField( OSGI.IMPORT_PACKAGE, IndexerFieldVersion.V4, BIP, "Import-Package (indexed, stored)",
130 Field.Store.YES, Field.Index.ANALYZED );
131
132
133 private static final String BRB = "Require-Bundle";
134
135 public static final IndexerField FLD_BUNDLE_REQUIRE_BUNDLE =
136 new IndexerField( OSGI.REQUIRE_BUNDLE, IndexerFieldVersion.V4, BRB, "Require-Bundle (indexed, stored)",
137 Field.Store.YES, Field.Index.ANALYZED );
138
139 private static final String PROVIDE_CAPABILITY = "Provide-Capability";
140
141 public static final IndexerField FLD_BUNDLE_PROVIDE_CAPABILITY =
142 new IndexerField( OSGI.PROVIDE_CAPABILITY, IndexerFieldVersion.V4, PROVIDE_CAPABILITY,
143 "Provide-Capability (indexed, stored)", Field.Store.YES, Field.Index.ANALYZED );
144
145 private static final String REQUIRE_CAPABILITY = "Require-Capability";
146
147 public static final IndexerField FLD_BUNDLE_REQUIRE_CAPABILITY =
148 new IndexerField( OSGI.REQUIRE_CAPABILITY, IndexerFieldVersion.V4, REQUIRE_CAPABILITY,
149 "Require-Capability (indexed, stored)", Field.Store.YES, Field.Index.ANALYZED );
150
151 private static final String FRAGMENT_HOST = "Fragment-Host";
152
153 public static final IndexerField FLD_BUNDLE_FRAGMENT_HOST =
154 new IndexerField( OSGI.FRAGMENT_HOST, IndexerFieldVersion.V4, FRAGMENT_HOST, "Fragment-Host (indexed, stored)",
155 Field.Store.YES, Field.Index.ANALYZED );
156
157 private static final String BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT = "Bundle-RequiredExecutionEnvironment";
158
159 public static final IndexerField FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT =
160 new IndexerField( OSGI.BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT, IndexerFieldVersion.V4,
161 BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT,
162 "Bundle-RequiredExecutionEnvironment (indexed, stored)", Field.Store.YES,
163 Field.Index.ANALYZED );
164
165
166 public Collection<IndexerField> getIndexerFields()
167 {
168 return Arrays.asList( FLD_BUNDLE_SYMBOLIC_NAME, FLD_BUNDLE_VERSION, FLD_BUNDLE_EXPORT_PACKAGE,
169 FLD_BUNDLE_EXPORT_SERVIVE, FLD_BUNDLE_DESCRIPTION, FLD_BUNDLE_NAME, FLD_BUNDLE_LICENSE,
170 FLD_BUNDLE_DOCURL, FLD_BUNDLE_IMPORT_PACKAGE, FLD_BUNDLE_REQUIRE_BUNDLE,
171 FLD_BUNDLE_PROVIDE_CAPABILITY, FLD_BUNDLE_REQUIRE_CAPABILITY, FLD_BUNDLE_FRAGMENT_HOST,
172 FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT, FLD_SHA256 );
173 }
174
175 public OsgiArtifactIndexCreator()
176 {
177 super( ID );
178 }
179
180 public void populateArtifactInfo( ArtifactContext artifactContext )
181 throws IOException
182 {
183 ArtifactInfo ai = artifactContext.getArtifactInfo();
184
185 File artifactFile = artifactContext.getArtifact();
186
187
188
189 if ( artifactFile != null && artifactFile.isFile() && artifactFile.getName().endsWith( ".jar" ) )
190 {
191 updateArtifactInfo( ai, artifactFile );
192 }
193 }
194
195 public void updateDocument( ArtifactInfo artifactInfo, Document document )
196 {
197
198 if ( artifactInfo.getBundleSymbolicName() != null )
199 {
200 document.add( FLD_BUNDLE_SYMBOLIC_NAME.toField( artifactInfo.getBundleSymbolicName() ) );
201 }
202
203 if ( artifactInfo.getBundleVersion() != null )
204 {
205 document.add( FLD_BUNDLE_VERSION.toField( artifactInfo.getBundleVersion() ) );
206 }
207
208 if ( artifactInfo.getBundleExportPackage() != null )
209 {
210 document.add( FLD_BUNDLE_EXPORT_PACKAGE.toField( artifactInfo.getBundleExportPackage() ) );
211 }
212
213 if ( artifactInfo.getBundleExportService() != null )
214 {
215 document.add( FLD_BUNDLE_EXPORT_SERVIVE.toField( artifactInfo.getBundleExportService() ) );
216 }
217
218 if ( artifactInfo.getBundleDescription() != null )
219 {
220 document.add( FLD_BUNDLE_DESCRIPTION.toField( artifactInfo.getBundleDescription() ) );
221 }
222
223 if ( artifactInfo.getBundleName() != null )
224 {
225 document.add( FLD_BUNDLE_NAME.toField( artifactInfo.getBundleName() ) );
226 }
227
228 if ( artifactInfo.getBundleLicense() != null )
229 {
230 document.add( FLD_BUNDLE_LICENSE.toField( artifactInfo.getBundleLicense() ) );
231 }
232
233 if ( artifactInfo.getBundleDocUrl() != null )
234 {
235 document.add( FLD_BUNDLE_DOCURL.toField( artifactInfo.getBundleDocUrl() ) );
236 }
237
238 if ( artifactInfo.getBundleImportPackage() != null )
239 {
240 document.add( FLD_BUNDLE_IMPORT_PACKAGE.toField( artifactInfo.getBundleImportPackage() ) );
241 }
242
243 if ( artifactInfo.getBundleRequireBundle() != null )
244 {
245 document.add( FLD_BUNDLE_REQUIRE_BUNDLE.toField( artifactInfo.getBundleRequireBundle() ) );
246 }
247
248 if ( artifactInfo.getBundleProvideCapability() != null )
249 {
250 document.add( FLD_BUNDLE_PROVIDE_CAPABILITY.toField( artifactInfo.getBundleProvideCapability() ) );
251 }
252
253 if ( artifactInfo.getBundleRequireCapability() != null )
254 {
255 document.add( FLD_BUNDLE_REQUIRE_CAPABILITY.toField( artifactInfo.getBundleRequireCapability() ) );
256 }
257
258 if ( artifactInfo.getBundleFragmentHost() != null )
259 {
260 document.add( FLD_BUNDLE_FRAGMENT_HOST.toField( artifactInfo.getBundleFragmentHost() ) );
261 }
262
263 String bree = artifactInfo.getBundleRequiredExecutionEnvironment();
264 if ( bree != null )
265 {
266 document.add( FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT.toField( bree ) );
267 }
268
269 if ( artifactInfo.getSha256() != null )
270 {
271 document.add( FLD_SHA256.toField( artifactInfo.getSha256() ) );
272 }
273
274 }
275
276 public boolean updateArtifactInfo( Document document, ArtifactInfo artifactInfo )
277 {
278 boolean updated = false;
279
280 String bundleSymbolicName = document.get( FLD_BUNDLE_SYMBOLIC_NAME.getKey() );
281
282 if ( bundleSymbolicName != null )
283 {
284 artifactInfo.setBundleSymbolicName( bundleSymbolicName );
285
286 updated = true;
287 }
288
289 String bundleVersion = document.get( FLD_BUNDLE_VERSION.getKey() );
290
291 if ( bundleVersion != null )
292 {
293 artifactInfo.setBundleVersion( bundleVersion );
294
295 updated = true;
296 }
297
298 String bundleExportPackage = document.get( FLD_BUNDLE_EXPORT_PACKAGE.getKey() );
299
300 if ( bundleExportPackage != null )
301 {
302 artifactInfo.setBundleExportPackage( bundleExportPackage );
303
304 updated = true;
305 }
306
307 String bundleExportService = document.get( FLD_BUNDLE_EXPORT_SERVIVE.getKey() );
308
309 if ( bundleExportService != null )
310 {
311 artifactInfo.setBundleExportService( bundleExportService );
312
313 updated = true;
314 }
315
316 String bundleDescription = document.get( FLD_BUNDLE_DESCRIPTION.getKey() );
317
318 if ( bundleDescription != null )
319 {
320 artifactInfo.setBundleDescription( bundleDescription );
321
322 updated = true;
323 }
324
325
326 String bundleName = document.get( FLD_BUNDLE_NAME.getKey() );
327
328 if ( bundleName != null )
329 {
330 artifactInfo.setBundleName( bundleName );
331
332 updated = true;
333 }
334
335
336 String bundleLicense = document.get( FLD_BUNDLE_LICENSE.getKey() );
337
338 if ( bundleLicense != null )
339 {
340 artifactInfo.setBundleLicense( bundleLicense );
341
342 updated = true;
343 }
344
345 String bundleDocUrl = document.get( FLD_BUNDLE_DOCURL.getKey() );
346
347 if ( bundleDocUrl != null )
348 {
349 artifactInfo.setBundleDocUrl( bundleDocUrl );
350
351 updated = true;
352 }
353
354 String bundleImportPackage = document.get( FLD_BUNDLE_IMPORT_PACKAGE.getKey() );
355
356 if ( bundleImportPackage != null )
357 {
358 artifactInfo.setBundleImportPackage( bundleImportPackage );
359
360 updated = true;
361 }
362
363 String bundleRequireBundle = document.get( FLD_BUNDLE_REQUIRE_BUNDLE.getKey() );
364
365 if ( bundleRequireBundle != null )
366 {
367 artifactInfo.setBundleRequireBundle( bundleRequireBundle );
368
369 updated = true;
370 }
371
372 String bundleProvideCapability = document.get( FLD_BUNDLE_PROVIDE_CAPABILITY.getKey() );
373
374 if ( bundleProvideCapability != null )
375 {
376 artifactInfo.setBundleProvideCapability( bundleProvideCapability );
377
378 updated = true;
379 }
380
381 String bundleRequireCapability = document.get( FLD_BUNDLE_REQUIRE_CAPABILITY.getKey() );
382
383 if ( bundleRequireCapability != null )
384 {
385 artifactInfo.setBundleRequireCapability( bundleRequireCapability );
386
387 updated = true;
388 }
389
390 String bundleFragmentHost = document.get( FLD_BUNDLE_FRAGMENT_HOST.getKey() );
391
392 if ( bundleFragmentHost != null )
393 {
394 artifactInfo.setBundleFragmentHost( bundleFragmentHost );
395
396 updated = true;
397 }
398
399 String bundleRequiredExecutionEnvironment = document.get( FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT.getKey() );
400
401 if ( bundleRequiredExecutionEnvironment != null )
402 {
403 artifactInfo.setBundleRequiredExecutionEnvironment( bundleRequiredExecutionEnvironment );
404
405 updated = true;
406 }
407
408 String sha256 = document.get( FLD_SHA256.getKey() );
409
410 if ( sha256 != null )
411 {
412 artifactInfo.setSha256( sha256 );
413
414 updated = true;
415 }
416
417 return updated;
418 }
419
420 private boolean updateArtifactInfo( ArtifactInfo ai, File f )
421 throws IOException
422 {
423 ZipHandle handle = null;
424
425 boolean updated = false;
426
427
428 try
429 {
430 handle = ZipFacade.getZipHandle( f );
431
432 final List<String> entries = handle.getEntries();
433
434 for ( String name : entries )
435 {
436 if ( name.equals( "META-INF/MANIFEST.MF" ) )
437 {
438 Manifest manifest = new Manifest( handle.getEntryContent( name ) );
439
440 Attributes mainAttributes = manifest.getMainAttributes();
441
442 if ( mainAttributes != null )
443 {
444 String attValue = mainAttributes.getValue( BSN );
445 if ( StringUtils.isNotBlank( attValue ) )
446 {
447 ai.setBundleSymbolicName( attValue );
448 updated = true;
449 }
450 else
451 {
452 ai.setBundleSymbolicName( null );
453 }
454
455 attValue = mainAttributes.getValue( BV );
456 if ( StringUtils.isNotBlank( attValue ) )
457 {
458 ai.setBundleVersion( attValue );
459 updated = true;
460 }
461 else
462 {
463 ai.setBundleVersion( null );
464 }
465
466 attValue = mainAttributes.getValue( BEP );
467 if ( StringUtils.isNotBlank( attValue ) )
468 {
469 ai.setBundleExportPackage( attValue );
470 updated = true;
471 }
472 else
473 {
474 ai.setBundleExportPackage( null );
475 }
476
477 attValue = mainAttributes.getValue( BES );
478 if ( StringUtils.isNotBlank( attValue ) )
479 {
480 ai.setBundleExportService( attValue );
481 updated = true;
482 }
483 else
484 {
485 ai.setBundleExportService( null );
486 }
487
488 attValue = mainAttributes.getValue( BD );
489 if ( StringUtils.isNotBlank( attValue ) )
490 {
491 ai.setBundleDescription( attValue );
492 updated = true;
493 }
494 else
495 {
496 ai.setBundleDescription( null );
497 }
498
499 attValue = mainAttributes.getValue( BN );
500 if ( StringUtils.isNotBlank( attValue ) )
501 {
502 ai.setBundleName( attValue );
503 updated = true;
504 }
505 else
506 {
507 ai.setBundleName( null );
508 }
509
510 attValue = mainAttributes.getValue( BL );
511 if ( StringUtils.isNotBlank( attValue ) )
512 {
513 ai.setBundleLicense( attValue );
514 updated = true;
515 }
516 else
517 {
518 ai.setBundleLicense( null );
519 }
520
521 attValue = mainAttributes.getValue( BDU );
522 if ( StringUtils.isNotBlank( attValue ) )
523 {
524 ai.setBundleDocUrl( attValue );
525 updated = true;
526 }
527 else
528 {
529 ai.setBundleDocUrl( null );
530 }
531
532 attValue = mainAttributes.getValue( BIP );
533 if ( StringUtils.isNotBlank( attValue ) )
534 {
535 ai.setBundleImportPackage( attValue );
536 updated = true;
537 }
538 else
539 {
540 ai.setBundleImportPackage( null );
541 }
542
543 attValue = mainAttributes.getValue( BRB );
544 if ( StringUtils.isNotBlank( attValue ) )
545 {
546 ai.setBundleRequireBundle( attValue );
547 updated = true;
548 }
549 else
550 {
551 ai.setBundleRequireBundle( null );
552 }
553
554 attValue = mainAttributes.getValue( PROVIDE_CAPABILITY );
555 if ( StringUtils.isNotBlank( attValue ) )
556 {
557 ai.setBundleProvideCapability( attValue );
558 updated = true;
559 }
560 else
561 {
562 ai.setBundleProvideCapability( null );
563 }
564
565 attValue = mainAttributes.getValue( REQUIRE_CAPABILITY );
566 if ( StringUtils.isNotBlank( attValue ) )
567 {
568 ai.setBundleRequireCapability( attValue );
569 updated = true;
570 }
571 else
572 {
573 ai.setBundleRequireCapability( null );
574 }
575
576 attValue = mainAttributes.getValue( FRAGMENT_HOST );
577 if ( StringUtils.isNotBlank( attValue ) )
578 {
579 ai.setBundleFragmentHost( attValue );
580 updated = true;
581 }
582 else
583 {
584 ai.setBundleFragmentHost( null );
585 }
586
587 attValue = mainAttributes.getValue( BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT );
588 if ( StringUtils.isNotBlank( attValue ) )
589 {
590 ai.setBundleRequiredExecutionEnvironment( attValue );
591 updated = true;
592 }
593 else
594 {
595 ai.setBundleRequiredExecutionEnvironment( null );
596 }
597 }
598 }
599 }
600
601 }
602 finally
603 {
604 try
605 {
606 ZipFacade.close( handle );
607 }
608 catch ( Exception e )
609 {
610 getLogger().error( "Could not close jar file properly.", e );
611 }
612 }
613
614
615 if ( ai.getBundleSymbolicName() != null )
616 {
617 String sha256 = computeSha256( f );
618 if ( sha256 != null )
619 {
620 ai.setSha256( sha256 );
621 updated = true;
622 }
623 else
624 {
625 ai.setSha256( null );
626 }
627 }
628
629 return updated;
630 }
631
632 private String computeSha256( File f )
633 throws IOException
634 {
635 String sha256 = null;
636 try
637 {
638 MessageDigest digest = MessageDigest.getInstance( "SHA-256" );
639 DigestInputStream in = new DigestInputStream( new FileInputStream( f ), digest );
640
641 try
642 {
643 byte buf[] = new byte[8192];
644 while ( in.read( buf ) >= 0 )
645 {
646
647 }
648 byte digestBytes[] = digest.digest();
649 StringBuilder builder = new StringBuilder( 64 );
650 for ( int b : digestBytes )
651 {
652 b &= 0xff;
653 builder.append( String.format( "%02x", b ) );
654 sha256 = builder.toString();
655 }
656 }
657 finally
658 {
659 in.close();
660 }
661
662 }
663 catch ( NoSuchAlgorithmException e )
664 {
665 }
666 return sha256;
667 }
668
669 @Override
670 public String toString()
671 {
672 return ID;
673 }
674 }