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