| package org.apache.maven.index.creator; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import org.apache.lucene.document.Document; |
| import org.apache.maven.index.ArtifactContext; |
| import org.apache.maven.index.ArtifactInfo; |
| import org.apache.maven.index.IndexerField; |
| import org.apache.maven.index.IndexerFieldVersion; |
| import org.apache.maven.index.OSGI; |
| import org.apache.maven.index.util.zip.ZipFacade; |
| import org.apache.maven.index.util.zip.ZipHandle; |
| import org.codehaus.plexus.util.StringUtils; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.security.DigestInputStream; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.jar.Attributes; |
| import java.util.jar.Manifest; |
| |
| /** |
| * This indexCreator will index some OSGI metadatas. |
| * <br/> |
| * All jars are indexed and not only the ones with packaging bundle. |
| * <br/> |
| * <p> |
| * OSGI metadatas indexed : |
| * <ul> |
| * <li>Bundle-SymbolicName</li> |
| * <li>Bundle-Version</li> |
| * <li>Export-Package</li> |
| * <li>Export-Service</li> |
| * </ul> |
| * </p> |
| * |
| * @author Olivier Lamy |
| * @since 4.1.2 |
| */ |
| @Singleton |
| @Named( OsgiArtifactIndexCreator.ID ) |
| public class OsgiArtifactIndexCreator |
| extends AbstractIndexCreator |
| { |
| public static final String ID = "osgi-metadatas"; |
| |
| public static final IndexerField FLD_SHA256 = |
| new IndexerField( OSGI.SHA256, IndexerFieldVersion.V4, "sha256", "SHA-256 (not analyzed, stored)", |
| IndexerField.KEYWORD_STORED ); |
| |
| private static final String BSN = "Bundle-SymbolicName"; |
| |
| public static final IndexerField FLD_BUNDLE_SYMBOLIC_NAME = |
| new IndexerField( OSGI.SYMBOLIC_NAME, IndexerFieldVersion.V4, BSN, "Bundle-SymbolicName (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BV = "Bundle-Version"; |
| |
| public static final IndexerField FLD_BUNDLE_VERSION = |
| new IndexerField( OSGI.VERSION, IndexerFieldVersion.V4, BV, "Bundle-Version (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BEP = "Export-Package"; |
| |
| public static final IndexerField FLD_BUNDLE_EXPORT_PACKAGE = |
| new IndexerField( OSGI.EXPORT_PACKAGE, IndexerFieldVersion.V4, BEP, "Export-Package (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| @Deprecated |
| private static final String BES = "Export-Service"; |
| @Deprecated |
| public static final IndexerField FLD_BUNDLE_EXPORT_SERVIVE = |
| new IndexerField( OSGI.EXPORT_SERVICE, IndexerFieldVersion.V4, BES, "Export-Service (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BD = "Bundle-Description"; |
| |
| public static final IndexerField FLD_BUNDLE_DESCRIPTION = |
| new IndexerField( OSGI.DESCRIPTION, IndexerFieldVersion.V4, BD, "Bundle-Description (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BN = "Bundle-Name"; |
| |
| public static final IndexerField FLD_BUNDLE_NAME = |
| new IndexerField( OSGI.NAME, IndexerFieldVersion.V4, BN, "Bundle-Name (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BL = "Bundle-License"; |
| |
| public static final IndexerField FLD_BUNDLE_LICENSE = |
| new IndexerField( OSGI.LICENSE, IndexerFieldVersion.V4, BL, "Bundle-License (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BDU = "Bundle-DocURL"; |
| |
| public static final IndexerField FLD_BUNDLE_DOCURL = |
| new IndexerField( OSGI.DOCURL, IndexerFieldVersion.V4, BDU, "Bundle-DocURL (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BIP = "Import-Package"; |
| |
| public static final IndexerField FLD_BUNDLE_IMPORT_PACKAGE = |
| new IndexerField( OSGI.IMPORT_PACKAGE, IndexerFieldVersion.V4, BIP, "Import-Package (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| |
| private static final String BRB = "Require-Bundle"; |
| |
| public static final IndexerField FLD_BUNDLE_REQUIRE_BUNDLE = |
| new IndexerField( OSGI.REQUIRE_BUNDLE, IndexerFieldVersion.V4, BRB, "Require-Bundle (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String PROVIDE_CAPABILITY = "Provide-Capability"; |
| |
| public static final IndexerField FLD_BUNDLE_PROVIDE_CAPABILITY = |
| new IndexerField( OSGI.PROVIDE_CAPABILITY, IndexerFieldVersion.V4, PROVIDE_CAPABILITY, |
| "Provide-Capability (indexed, stored)", IndexerField.ANALYZED_STORED ); |
| |
| private static final String REQUIRE_CAPABILITY = "Require-Capability"; |
| |
| public static final IndexerField FLD_BUNDLE_REQUIRE_CAPABILITY = |
| new IndexerField( OSGI.REQUIRE_CAPABILITY, IndexerFieldVersion.V4, REQUIRE_CAPABILITY, |
| "Require-Capability (indexed, stored)", IndexerField.ANALYZED_STORED ); |
| |
| private static final String FRAGMENT_HOST = "Fragment-Host"; |
| |
| public static final IndexerField FLD_BUNDLE_FRAGMENT_HOST = |
| new IndexerField( OSGI.FRAGMENT_HOST, IndexerFieldVersion.V4, FRAGMENT_HOST, "Fragment-Host (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| private static final String BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT = "Bundle-RequiredExecutionEnvironment"; |
| |
| public static final IndexerField FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT = |
| new IndexerField( OSGI.BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT, IndexerFieldVersion.V4, |
| BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT, |
| "Bundle-RequiredExecutionEnvironment (indexed, stored)", |
| IndexerField.ANALYZED_STORED ); |
| |
| |
| public Collection<IndexerField> getIndexerFields() |
| { |
| return Arrays.asList( FLD_BUNDLE_SYMBOLIC_NAME, FLD_BUNDLE_VERSION, FLD_BUNDLE_EXPORT_PACKAGE, |
| FLD_BUNDLE_EXPORT_SERVIVE, FLD_BUNDLE_DESCRIPTION, FLD_BUNDLE_NAME, FLD_BUNDLE_LICENSE, |
| FLD_BUNDLE_DOCURL, FLD_BUNDLE_IMPORT_PACKAGE, FLD_BUNDLE_REQUIRE_BUNDLE, |
| FLD_BUNDLE_PROVIDE_CAPABILITY, FLD_BUNDLE_REQUIRE_CAPABILITY, FLD_BUNDLE_FRAGMENT_HOST, |
| FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT, FLD_SHA256 ); |
| } |
| |
| public OsgiArtifactIndexCreator() |
| { |
| super( ID ); |
| } |
| |
| public void populateArtifactInfo( ArtifactContext artifactContext ) |
| throws IOException |
| { |
| ArtifactInfo ai = artifactContext.getArtifactInfo(); |
| |
| File artifactFile = artifactContext.getArtifact(); |
| |
| // TODO : olamy : supports only jars ? |
| |
| if ( artifactFile != null && artifactFile.isFile() && artifactFile.getName().endsWith( ".jar" ) ) |
| { |
| updateArtifactInfo( ai, artifactFile ); |
| } |
| } |
| |
| public void updateDocument( ArtifactInfo artifactInfo, Document document ) |
| { |
| |
| if ( artifactInfo.getBundleSymbolicName() != null ) |
| { |
| document.add( FLD_BUNDLE_SYMBOLIC_NAME.toField( artifactInfo.getBundleSymbolicName() ) ); |
| } |
| |
| if ( artifactInfo.getBundleVersion() != null ) |
| { |
| document.add( FLD_BUNDLE_VERSION.toField( artifactInfo.getBundleVersion() ) ); |
| } |
| |
| if ( artifactInfo.getBundleExportPackage() != null ) |
| { |
| document.add( FLD_BUNDLE_EXPORT_PACKAGE.toField( artifactInfo.getBundleExportPackage() ) ); |
| } |
| |
| if ( artifactInfo.getBundleExportService() != null ) |
| { |
| document.add( FLD_BUNDLE_EXPORT_SERVIVE.toField( artifactInfo.getBundleExportService() ) ); |
| } |
| |
| if ( artifactInfo.getBundleDescription() != null ) |
| { |
| document.add( FLD_BUNDLE_DESCRIPTION.toField( artifactInfo.getBundleDescription() ) ); |
| } |
| |
| if ( artifactInfo.getBundleName() != null ) |
| { |
| document.add( FLD_BUNDLE_NAME.toField( artifactInfo.getBundleName() ) ); |
| } |
| |
| if ( artifactInfo.getBundleLicense() != null ) |
| { |
| document.add( FLD_BUNDLE_LICENSE.toField( artifactInfo.getBundleLicense() ) ); |
| } |
| |
| if ( artifactInfo.getBundleDocUrl() != null ) |
| { |
| document.add( FLD_BUNDLE_DOCURL.toField( artifactInfo.getBundleDocUrl() ) ); |
| } |
| |
| if ( artifactInfo.getBundleImportPackage() != null ) |
| { |
| document.add( FLD_BUNDLE_IMPORT_PACKAGE.toField( artifactInfo.getBundleImportPackage() ) ); |
| } |
| |
| if ( artifactInfo.getBundleRequireBundle() != null ) |
| { |
| document.add( FLD_BUNDLE_REQUIRE_BUNDLE.toField( artifactInfo.getBundleRequireBundle() ) ); |
| } |
| |
| if ( artifactInfo.getBundleProvideCapability() != null ) |
| { |
| document.add( FLD_BUNDLE_PROVIDE_CAPABILITY.toField( artifactInfo.getBundleProvideCapability() ) ); |
| } |
| |
| if ( artifactInfo.getBundleRequireCapability() != null ) |
| { |
| document.add( FLD_BUNDLE_REQUIRE_CAPABILITY.toField( artifactInfo.getBundleRequireCapability() ) ); |
| } |
| |
| if ( artifactInfo.getBundleFragmentHost() != null ) |
| { |
| document.add( FLD_BUNDLE_FRAGMENT_HOST.toField( artifactInfo.getBundleFragmentHost() ) ); |
| } |
| |
| String bree = artifactInfo.getBundleRequiredExecutionEnvironment(); |
| if ( bree != null ) |
| { |
| document.add( FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT.toField( bree ) ); |
| } |
| |
| if ( artifactInfo.getSha256() != null ) |
| { |
| document.add( FLD_SHA256.toField( artifactInfo.getSha256() ) ); |
| } |
| |
| } |
| |
| public boolean updateArtifactInfo( Document document, ArtifactInfo artifactInfo ) |
| { |
| boolean updated = false; |
| |
| String bundleSymbolicName = document.get( FLD_BUNDLE_SYMBOLIC_NAME.getKey() ); |
| |
| if ( bundleSymbolicName != null ) |
| { |
| artifactInfo.setBundleSymbolicName( bundleSymbolicName ); |
| |
| updated = true; |
| } |
| |
| String bundleVersion = document.get( FLD_BUNDLE_VERSION.getKey() ); |
| |
| if ( bundleVersion != null ) |
| { |
| artifactInfo.setBundleVersion( bundleVersion ); |
| |
| updated = true; |
| } |
| |
| String bundleExportPackage = document.get( FLD_BUNDLE_EXPORT_PACKAGE.getKey() ); |
| |
| if ( bundleExportPackage != null ) |
| { |
| artifactInfo.setBundleExportPackage( bundleExportPackage ); |
| |
| updated = true; |
| } |
| |
| String bundleExportService = document.get( FLD_BUNDLE_EXPORT_SERVIVE.getKey() ); |
| |
| if ( bundleExportService != null ) |
| { |
| artifactInfo.setBundleExportService( bundleExportService ); |
| |
| updated = true; |
| } |
| |
| String bundleDescription = document.get( FLD_BUNDLE_DESCRIPTION.getKey() ); |
| |
| if ( bundleDescription != null ) |
| { |
| artifactInfo.setBundleDescription( bundleDescription ); |
| |
| updated = true; |
| } |
| |
| |
| String bundleName = document.get( FLD_BUNDLE_NAME.getKey() ); |
| |
| if ( bundleName != null ) |
| { |
| artifactInfo.setBundleName( bundleName ); |
| |
| updated = true; |
| } |
| |
| |
| String bundleLicense = document.get( FLD_BUNDLE_LICENSE.getKey() ); |
| |
| if ( bundleLicense != null ) |
| { |
| artifactInfo.setBundleLicense( bundleLicense ); |
| |
| updated = true; |
| } |
| |
| String bundleDocUrl = document.get( FLD_BUNDLE_DOCURL.getKey() ); |
| |
| if ( bundleDocUrl != null ) |
| { |
| artifactInfo.setBundleDocUrl( bundleDocUrl ); |
| |
| updated = true; |
| } |
| |
| String bundleImportPackage = document.get( FLD_BUNDLE_IMPORT_PACKAGE.getKey() ); |
| |
| if ( bundleImportPackage != null ) |
| { |
| artifactInfo.setBundleImportPackage( bundleImportPackage ); |
| |
| updated = true; |
| } |
| |
| String bundleRequireBundle = document.get( FLD_BUNDLE_REQUIRE_BUNDLE.getKey() ); |
| |
| if ( bundleRequireBundle != null ) |
| { |
| artifactInfo.setBundleRequireBundle( bundleRequireBundle ); |
| |
| updated = true; |
| } |
| |
| String bundleProvideCapability = document.get( FLD_BUNDLE_PROVIDE_CAPABILITY.getKey() ); |
| |
| if ( bundleProvideCapability != null ) |
| { |
| artifactInfo.setBundleProvideCapability( bundleProvideCapability ); |
| |
| updated = true; |
| } |
| |
| String bundleRequireCapability = document.get( FLD_BUNDLE_REQUIRE_CAPABILITY.getKey() ); |
| |
| if ( bundleRequireCapability != null ) |
| { |
| artifactInfo.setBundleRequireCapability( bundleRequireCapability ); |
| |
| updated = true; |
| } |
| |
| String bundleFragmentHost = document.get( FLD_BUNDLE_FRAGMENT_HOST.getKey() ); |
| |
| if ( bundleFragmentHost != null ) |
| { |
| artifactInfo.setBundleFragmentHost( bundleFragmentHost ); |
| |
| updated = true; |
| } |
| |
| String bundleRequiredExecutionEnvironment = document.get( FLD_BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT.getKey() ); |
| |
| if ( bundleRequiredExecutionEnvironment != null ) |
| { |
| artifactInfo.setBundleRequiredExecutionEnvironment( bundleRequiredExecutionEnvironment ); |
| |
| updated = true; |
| } |
| |
| String sha256 = document.get( FLD_SHA256.getKey() ); |
| |
| if ( sha256 != null ) |
| { |
| artifactInfo.setSha256( sha256 ); |
| |
| updated = true; |
| } |
| |
| return updated; |
| } |
| |
| private boolean updateArtifactInfo( ArtifactInfo ai, File f ) |
| throws IOException |
| { |
| ZipHandle handle = null; |
| |
| boolean updated = false; |
| |
| |
| try |
| { |
| handle = ZipFacade.getZipHandle( f ); |
| |
| final List<String> entries = handle.getEntries(); |
| |
| for ( String name : entries ) |
| { |
| if ( name.equals( "META-INF/MANIFEST.MF" ) ) |
| { |
| Manifest manifest = new Manifest( handle.getEntryContent( name ) ); |
| |
| Attributes mainAttributes = manifest.getMainAttributes(); |
| |
| if ( mainAttributes != null ) |
| { |
| String attValue = mainAttributes.getValue( BSN ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleSymbolicName( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleSymbolicName( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BV ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleVersion( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleVersion( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BEP ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleExportPackage( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleExportPackage( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BES ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleExportService( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleExportService( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BD ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleDescription( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleDescription( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BN ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleName( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleName( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BL ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleLicense( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleLicense( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BDU ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleDocUrl( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleDocUrl( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BIP ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleImportPackage( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleImportPackage( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BRB ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleRequireBundle( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleRequireBundle( null ); |
| } |
| |
| attValue = mainAttributes.getValue( PROVIDE_CAPABILITY ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleProvideCapability( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleProvideCapability( null ); |
| } |
| |
| attValue = mainAttributes.getValue( REQUIRE_CAPABILITY ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleRequireCapability( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleRequireCapability( null ); |
| } |
| |
| attValue = mainAttributes.getValue( FRAGMENT_HOST ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleFragmentHost( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleFragmentHost( null ); |
| } |
| |
| attValue = mainAttributes.getValue( BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT ); |
| if ( StringUtils.isNotBlank( attValue ) ) |
| { |
| ai.setBundleRequiredExecutionEnvironment( attValue ); |
| updated = true; |
| } |
| else |
| { |
| ai.setBundleRequiredExecutionEnvironment( null ); |
| } |
| } |
| } |
| } |
| |
| } |
| finally |
| { |
| try |
| { |
| ZipFacade.close( handle ); |
| } |
| catch ( Exception e ) |
| { |
| getLogger().error( "Could not close jar file properly.", e ); |
| } |
| } |
| |
| // only calculate sha256 digest for if we are indexing a bundle. |
| if ( ai.getBundleSymbolicName() != null ) |
| { |
| String sha256 = computeSha256( f ); |
| if ( sha256 != null ) |
| { |
| ai.setSha256( sha256 ); |
| updated = true; |
| } |
| else |
| { |
| ai.setSha256( null ); |
| } |
| } |
| |
| return updated; |
| } |
| |
| private String computeSha256( File f ) |
| throws IOException |
| { |
| String sha256 = null; |
| try |
| { |
| MessageDigest digest = MessageDigest.getInstance( "SHA-256" ); |
| DigestInputStream in = new DigestInputStream( new FileInputStream( f ), digest ); |
| |
| try |
| { |
| byte buf[] = new byte[8192]; |
| while ( in.read( buf ) >= 0 ) |
| { |
| // nop |
| } |
| byte digestBytes[] = digest.digest(); |
| StringBuilder builder = new StringBuilder( 64 ); |
| for ( int b : digestBytes ) |
| { |
| b &= 0xff; |
| builder.append( String.format( "%02x", b ) ); |
| sha256 = builder.toString(); |
| } |
| } |
| finally |
| { |
| in.close(); |
| } |
| |
| } |
| catch ( NoSuchAlgorithmException e ) |
| { |
| } |
| return sha256; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return ID; |
| } |
| } |