pax_global_header 0000666 0000000 0000000 00000000064 11634455326 0014523 g ustar 00root root 0000000 0000000 52 comment=9cc94673f4fe365d1558bc153ab29409d46f9188
maven-shared-jar-1.1/ 0000775 0000000 0000000 00000000000 11634455326 0014510 5 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/pom.xml 0000664 0000000 0000000 00000010173 11634455326 0016027 0 ustar 00root root 0000000 0000000
* JarAnalyzer jar = new JarAnalyzer( jarFile ); * * try * { * // do some analysis, such as: * jarClasses = jarClassAnalyzer.analyze( jar ); * } * finally * { * jar.closeQuietly(); * } * * // use jar.getJarData() in some way, or the data returned by the JAR analyzer. jar itself can no longer be used. ** * Note: that the actual data is separated from this class by design to minimise the chance of forgetting to close the * JAR file. The {@link org.apache.maven.shared.jar.JarData} class exposed, as well as any data returned by actual * analyzers that use this class, can be used safely once this class is out of scope. * * @see org.apache.maven.shared.jar.identification.JarIdentificationAnalysis#analyze(JarAnalyzer) * @see org.apache.maven.shared.jar.classes.JarClassesAnalysis#analyze(JarAnalyzer) */ public class JarAnalyzer { /** * Pattern to filter JAR entries for class files. * * @todo why are inner classes and other potentially valid classes omitted? (It flukes it by finding everything after $) */ private static final Pattern CLASS_FILTER = Pattern.compile( "[A-Za-z0-9]*\\.class$" ); /** * Pattern to filter JAR entries for Maven POM files. */ private static final Pattern MAVEN_POM_FILTER = Pattern.compile( "META-INF/maven/.*/pom\\.xml$" ); /** * Pattern to filter JAR entries for text files that may contain a version. */ private static final Pattern VERSION_FILTER = Pattern.compile( "[Vv][Ee][Rr][Ss][Ii][Oo][Nn]" ); /** * The associated JAR file. */ private final JarFile jarFile; /** * Contains information about the data collected so far. */ private final JarData jarData; /** * Constructor. Opens the JAR file, so should be matched by a call to {@link #closeQuietly()}. * * @param file the JAR file to open * @throws java.io.IOException if there is a problem opening the JAR file, or reading the manifest. The JAR file will be closed if this occurs. */ public JarAnalyzer( File file ) throws IOException { try { this.jarFile = new JarFile( file ); } catch ( ZipException e ) { ZipException ioe = new ZipException( "Failed to open file " + file + " : " + e.getMessage() ); ioe.initCause( e ); throw ioe; } // Obtain entries list. List entries = Collections.list( jarFile.entries() ); // Sorting of list is done by name to ensure a bytecode hash is always consistent. Collections.sort( entries, new Comparator() { public int compare( Object o1, Object o2 ) { JarEntry entry1 = (JarEntry) o1; JarEntry entry2 = (JarEntry) o2; return entry1.getName().compareTo( entry2.getName() ); } } ); Manifest manifest; try { manifest = jarFile.getManifest(); } catch ( IOException e ) { closeQuietly(); throw e; } this.jarData = new JarData( file, manifest, entries ); } /** * Get the data for an individual entry in the JAR. The caller should closeQuietly the input stream, and should not retain * the stream as the JAR file may be closed elsewhere. * * @param entry the JAR entry to read from * @return the input stream of the individual JAR entry. * @throws java.io.IOException if there is a problem opening the individual entry */ public InputStream getEntryInputStream( JarEntry entry ) throws IOException { return jarFile.getInputStream( entry ); } /** * Close the associated JAR file, ignoring any errors that may occur. */ public void closeQuietly() { try { jarFile.close(); } catch ( IOException e ) { // not much we can do about it but ignore it } } /** * Filter a list of JAR entries against the pattern. * * @param pattern the pattern to filter against * @return the list of files found, in {@link java.util.jar.JarEntry} elements */ public List filterEntries( Pattern pattern ) { List ret = new ArrayList(); Iterator it = getEntries().iterator(); while ( it.hasNext() ) { JarEntry entry = (JarEntry) it.next(); Matcher mat = pattern.matcher( entry.getName() ); if ( mat.find() ) { ret.add( entry ); } } return ret; } /** * Get all the classes in the JAR. * * @return the list of files found, in {@link java.util.jar.JarEntry} elements */ public List getClassEntries() { return filterEntries( CLASS_FILTER ); } /** * Get all the Maven POM entries in the JAR. * * @return the list of files found, in {@link java.util.jar.JarEntry} elements */ public List getMavenPomEntries() { return filterEntries( MAVEN_POM_FILTER ); } /** * Get all the version text files in the JAR. * * @return the list of files found, in {@link java.util.jar.JarEntry} elements */ public List getVersionEntries() { return filterEntries( VERSION_FILTER ); } /** * Get all the contained files in the JAR. * * @return the list of files found, in {@link java.util.jar.JarEntry} elements */ public List getEntries() { return jarData.getEntries(); } /** * Get the file that was opened by this analyzer. * * @return the JAR file reference */ public File getFile() { return jarData.getFile(); } public JarData getJarData() { return jarData; } } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/JarData.java 0000664 0000000 0000000 00000010156 11634455326 0026460 0 ustar 00root root 0000000 0000000 package org.apache.maven.shared.jar; /* * 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 org.apache.maven.shared.jar.classes.JarClasses; import org.apache.maven.shared.jar.identification.JarIdentification; import org.codehaus.plexus.util.StringUtils; import java.io.File; import java.util.Collections; import java.util.List; import java.util.jar.Attributes; import java.util.jar.Manifest; /** * Class that contains details of a single JAR file and it's entries. */ public final class JarData { /** * The JAR file. */ private final File file; /** * Whether the JAR file is sealed. */ private final boolean sealed; /** * The hashcode for the entire file's contents. */ private String fileHash; /** * The hashcode for the file's class data contents. */ private String bytecodeHash; /** * The JAR's manifest. */ private final Manifest manifest; /** * Information about the JAR's classes. */ private JarClasses jarClasses; /** * The JAR entries. */ private final List entries; /** * Information about the JAR's identifying features. */ private JarIdentification jarIdentification; /** * Constructor. * * @param file the JAR file * @param manifest the JAR manifest * @param entries the JAR entries */ public JarData( File file, Manifest manifest, List entries ) { this.file = file; this.manifest = manifest; this.entries = Collections.unmodifiableList( entries ); boolean sealed = false; if ( this.manifest != null ) { String sval = this.manifest.getMainAttributes().getValue( Attributes.Name.SEALED ); if ( StringUtils.isNotEmpty( sval ) ) { sealed = "true".equalsIgnoreCase( sval.trim() ); } } this.sealed = sealed; } public List getEntries() { return entries; } public Manifest getManifest() { return manifest; } public File getFile() { return file; } public boolean isSealed() { return sealed; } public void setFileHash( String fileHash ) { this.fileHash = fileHash; } public String getFileHash() { return fileHash; } public void setBytecodeHash( String bytecodeHash ) { this.bytecodeHash = bytecodeHash; } public String getBytecodeHash() { return bytecodeHash; } public boolean isDebugPresent() { return jarClasses.isDebugPresent(); } public void setJarClasses( JarClasses jarClasses ) { this.jarClasses = jarClasses; } public int getNumEntries() { return entries.size(); } public int getNumClasses() { return jarClasses.getClassNames().size(); } public int getNumPackages() { return jarClasses.getPackages().size(); } public String getJdkRevision() { return jarClasses.getJdkRevision(); } public void setJarIdentification( JarIdentification jarIdentification ) { this.jarIdentification = jarIdentification; } public JarIdentification getJarIdentification() { return jarIdentification; } public JarClasses getJarClasses() { return jarClasses; } } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/classes/ 0000775 0000000 0000000 00000000000 11634455326 0025741 5 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/classes/ImportVisitor.java 0000664 0000000 0000000 00000012520 11634455326 0031436 0 ustar 00root root 0000000 0000000 package org.apache.maven.shared.jar.classes; /* * 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 org.apache.bcel.classfile.ConstantClass; import org.apache.bcel.classfile.ConstantUtf8; import org.apache.bcel.classfile.EmptyVisitor; import org.apache.bcel.classfile.JavaClass; import org.apache.commons.collections.list.SetUniqueList; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of a BCEL class visitor that analyzes a class and collects imports. */ public class ImportVisitor extends EmptyVisitor { /** * The list of imports discovered. */ private List imports; /** * The Java class that is being analyzed. */ private JavaClass javaClass; /** * Pattern to detect if the import is qualified and allows retrieval of the actual import name from the string via the group 1. */ private static final Pattern QUALIFIED_IMPORT_PATTERN = Pattern.compile( "L([a-zA-Z][a-zA-Z0-9\\.]+);" ); /** * Pattern that checks whether a string is valid UTF-8. Imports that are not are ignored. */ private static final Pattern VALID_UTF8_PATTERN = Pattern.compile( "^[\\(\\)\\[A-Za-z0-9;/]+$" ); /** * Create an Import visitor. * * @param javaClass the javaclass to work from */ public ImportVisitor( JavaClass javaClass ) { this.javaClass = javaClass; // Create a list that is guaranteed to be unique while retaining it's list qualities (LinkedHashSet does not // expose the list interface even if natural ordering is retained) this.imports = SetUniqueList.decorate( new ArrayList() ); } /** * Get the list of discovered imports. * * @return Returns the imports. */ public List getImports() { return imports; } /** * Find any formally declared import in the Constant Pool. * * @see org.apache.bcel.classfile.EmptyVisitor#visitConstantClass(org.apache.bcel.classfile.ConstantClass) */ public void visitConstantClass( ConstantClass constantClass ) { String name = constantClass.getBytes( javaClass.getConstantPool() ); // only strings with '/' character are to be considered. if ( name.indexOf( '/' ) == -1 ) { return; } name = name.replace( '/', '.' ); if ( name.endsWith( ".class" ) ) { name = name.substring( 0, name.length() - 6 ); } Matcher mat = QUALIFIED_IMPORT_PATTERN.matcher( name ); if ( mat.find() ) { this.imports.add( mat.group( 1 ) ); } else { this.imports.add( name ); } } /** * Find any package class Strings in the UTF8 String Pool. * * @see org.apache.bcel.classfile.EmptyVisitor#visitConstantUtf8(org.apache.bcel.classfile.ConstantUtf8) */ public void visitConstantUtf8( ConstantUtf8 constantUtf8 ) { String ret = constantUtf8.getBytes().trim(); // empty strings are not class names. if ( ret.length() <= 0 ) { return; } // Only valid characters please. if ( !VALID_UTF8_PATTERN.matcher( ret ).matches() ) { return; } // only strings with '/' character are to be considered. if ( ret.indexOf( '/' ) == -1 ) { return; } // Strings that start with '/' are bad too // Seen when Pool has regex patterns. if ( ret.charAt( 0 ) == '/' ) { return; } // Make string more class-like. ret = ret.replace( '/', '.' ); // Double ".." indicates a bad class fail-fast. // Seen when ConstantUTF8 Pool has regex patterns. if ( ret.indexOf( ".." ) != -1 ) { return; } Matcher mat = QUALIFIED_IMPORT_PATTERN.matcher( ret ); char prefix = ret.charAt( 0 ); if ( prefix == '(' ) { // A Method Declaration. // Loop for each Qualified Class found. while ( mat.find() ) { this.imports.add( mat.group( 1 ) ); } } else { // A Variable Declaration. if ( mat.find() ) { // Add a UTF8 Qualified Class reference. this.imports.add( mat.group( 1 ) ); } else { // Add a simple Class reference. this.imports.add( ret ); } } } } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/classes/JarClasses.java 0000664 0000000 0000000 00000010200 11634455326 0030627 0 ustar 00root root 0000000 0000000 package org.apache.maven.shared.jar.classes; /* * 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 org.apache.commons.collections.list.SetUniqueList; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Gathered facts about the classes within a JAR file. * * @see org.apache.maven.shared.jar.classes.JarClassesAnalysis#analyze(org.apache.maven.shared.jar.JarAnalyzer) */ public class JarClasses { /** * The list of imports in the classes in the JAR. */ private List imports; /** * A list of packages represented by classes in the JAR. */ private List packages; /** * A list of the classes that in the JAR. */ private List classNames; /** * A list of methods within the classes in the JAR. */ private List methods; /** * Whether the JAR contains any code with debug information. If there is a mix of debug and release code, this will * still be true. */ private boolean isDebugPresent; /** * The highest JVM revision available in any class files. While the JAR may work on earlier JVMs if particular * classes are not used, this is the minimum JVM that guarantees compatibility. */ private String jdkRevision; /** * Constructor to create an empty instance. */ public JarClasses() { // Unique list decorators are used to ensure natural ordering is retained, the list interface is availble, and // that duplicates are not entered. imports = SetUniqueList.decorate( new ArrayList() ); packages = SetUniqueList.decorate( new ArrayList() ); classNames = SetUniqueList.decorate( new ArrayList() ); methods = SetUniqueList.decorate( new ArrayList() ); } /** * Add a discovered class to the record. * * @param name the name of the class */ public void addClassName( String name ) { this.classNames.add( name ); } /** * Add a discovered package to the record. * * @param name the name of the package */ public void addPackage( String name ) { this.packages.add( name ); } /** * Add a discovered method to the record. * * @param name the name of the method */ public void addMethod( String name ) { this.methods.add( name ); } /** * Add a list of discovered imports to the record. * * @param imports the imports to add. Each item should be a String to avoid down the line ClassCastExceptions. */ public void addImports( List imports ) { this.imports.addAll( imports ); } public List getImports() { return Collections.unmodifiableList( imports ); } public List getClassNames() { return Collections.unmodifiableList( classNames ); } public List getPackages() { return Collections.unmodifiableList( packages ); } public boolean isDebugPresent() { return isDebugPresent; } public void setDebugPresent( boolean hasDebugSymbols ) { this.isDebugPresent = hasDebugSymbols; } public String getJdkRevision() { return jdkRevision; } public void setJdkRevision( String jdkRevision ) { this.jdkRevision = jdkRevision; } public List getMethods() { return Collections.unmodifiableList( methods ); } } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/classes/JarClassesAnalysis.java 0000664 0000000 0000000 00000015572 11634455326 0032354 0 ustar 00root root 0000000 0000000 package org.apache.maven.shared.jar.classes; /* * 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 org.apache.bcel.classfile.ClassFormatException; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.DescendingVisitor; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.LineNumberTable; import org.apache.bcel.classfile.Method; import org.apache.maven.shared.jar.JarAnalyzer; import org.codehaus.plexus.logging.AbstractLogEnabled; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.jar.JarEntry; /** * Analyze the classes in a JAR file. This class is thread safe and immutable as it retains no state. * * Note that you must first create an instance of {@link org.apache.maven.shared.jar.JarAnalyzer} - see its Javadoc for * a typical use. * * @plexus.component role="org.apache.maven.shared.jar.classes.JarClassesAnalysis" role-hint="default" * @see #analyze(org.apache.maven.shared.jar.JarAnalyzer) */ public class JarClassesAnalysis extends AbstractLogEnabled { private static final double JAVA_1_6_CLASS_VERSION = 50.0; private static final double JAVA_1_5_CLASS_VERSION = 49.0; private static final double JAVA_1_4_CLASS_VERSION = 47.0; private static final double JAVA_1_3_CLASS_VERSION = 46.0; private static final double JAVA_1_2_CLASS_VERSION = 45.65536; private static final double JAVA_1_1_CLASS_VERSION = 45.3; /** * Analyze a JAR and find any classes and their details. Note that if the provided JAR analyzer has previously * analyzed the JAR, the cached results will be returned. You must obtain a new JAR analyzer to the re-read the * contents of the file. * * @param jarAnalyzer the JAR to analyze. This must not yet have been closed. * @return the details of the classes found */ public JarClasses analyze( JarAnalyzer jarAnalyzer ) { JarClasses classes = jarAnalyzer.getJarData().getJarClasses(); if ( classes == null ) { String jarfilename = jarAnalyzer.getFile().getAbsolutePath(); classes = new JarClasses(); List classList = jarAnalyzer.getClassEntries(); classes.setDebugPresent( false ); double maxVersion = 0.0; Iterator it = classList.iterator(); while ( it.hasNext() ) { JarEntry entry = (JarEntry) it.next(); String classname = entry.getName(); try { ClassParser classParser = new ClassParser( jarfilename, classname ); JavaClass javaClass = classParser.parse(); String classSignature = javaClass.getClassName(); if ( !classes.isDebugPresent() ) { if ( hasDebugSymbols( javaClass ) ) { classes.setDebugPresent( true ); } } double classVersion = javaClass.getMajor(); if ( javaClass.getMinor() > 0 ) { classVersion = classVersion + 1 / (double) javaClass.getMinor(); } if ( classVersion > maxVersion ) { maxVersion = classVersion; } Method[] methods = javaClass.getMethods(); for ( int i = 0; i < methods.length; i++ ) { classes.addMethod( classSignature + "." + methods[i].getName() + methods[i].getSignature() ); } String classPackageName = javaClass.getPackageName(); classes.addClassName( classSignature ); classes.addPackage( classPackageName ); ImportVisitor importVisitor = new ImportVisitor( javaClass ); DescendingVisitor descVisitor = new DescendingVisitor( javaClass, importVisitor ); javaClass.accept( descVisitor ); classes.addImports( importVisitor.getImports() ); } catch ( ClassFormatException e ) { getLogger().warn( "Unable to process class " + classname + " in JarAnalyzer File " + jarfilename, e ); } catch ( IOException e ) { getLogger().warn( "Unable to process JarAnalyzer File " + jarfilename, e ); } } // TODO: check these since they are > instead of >= if ( maxVersion >= JAVA_1_6_CLASS_VERSION ) { classes.setJdkRevision( "1.6" ); } else if ( maxVersion >= JAVA_1_5_CLASS_VERSION ) { classes.setJdkRevision( "1.5" ); } else if ( maxVersion > JAVA_1_4_CLASS_VERSION ) { classes.setJdkRevision( "1.4" ); } else if ( maxVersion > JAVA_1_3_CLASS_VERSION ) { classes.setJdkRevision( "1.3" ); } else if ( maxVersion > JAVA_1_2_CLASS_VERSION ) { classes.setJdkRevision( "1.2" ); } else if ( maxVersion > JAVA_1_1_CLASS_VERSION ) { classes.setJdkRevision( "1.1" ); } else if ( maxVersion > 0 ) { classes.setJdkRevision( "1.0" ); } jarAnalyzer.getJarData().setJarClasses( classes ); } return classes; } private boolean hasDebugSymbols( JavaClass javaClass ) { boolean ret = false; Method[] methods = javaClass.getMethods(); for ( int i = 0; i < methods.length; i++ ) { LineNumberTable linenumbers = methods[i].getLineNumberTable(); if ( linenumbers != null && linenumbers.getLength() > 0 ) { ret = true; break; } } return ret; } } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/ 0000775 0000000 0000000 00000000000 11634455326 0027275 5 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/JarIdentification.java0000664 0000000 0000000 00000014333 11634455326 0033532 0 ustar 00root root 0000000 0000000 package org.apache.maven.shared.jar.identification; /* * 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 java.util.ArrayList; import java.util.List; /** * Gathered Maven information about the JAR file. Stores both assumed/validated values and potential values. * * @see org.apache.maven.shared.jar.identification.JarIdentificationAnalysis#analyze(org.apache.maven.shared.jar.JarAnalyzer) */ public class JarIdentification { /** * The group ID derived or guessed from the list of potentials of the JAR. */ private String groupId; /** * The artifact ID derived or guessed from the list of potentials of the JAR. */ private String artifactId; /** * The version derived or guessed from the list of potentials of the JAR. */ private String version; /** * The project name derived or guessed from the list of potentials of the JAR. */ private String name; /** * The vendor (organization name) derived or guessed from the list of potentials of the JAR. */ private String vendor; /** * The list of possible group IDs discovered. */ private List potentialGroupIds = new ArrayList(); /** * The list of possible artifact IDs discovered. */ private List potentialArtifactIds = new ArrayList(); /** * The list of possible versions discovered. */ private List potentialVersions = new ArrayList(); /** * The list of possible artifact names discovered. */ private List potentialNames = new ArrayList(); /** * The list of possible vendors discovered. */ private List potentialVendors = new ArrayList(); /** * Add a validated group ID. * * @param groupId the group ID discovered */ public void addAndSetGroupId( String groupId ) { if ( groupId != null ) { this.groupId = groupId; } addGroupId( groupId ); } /** * Add a potential group ID. * * @param groupId the group ID discovered */ public void addGroupId( String groupId ) { addUnique( potentialGroupIds, groupId ); } /** * Add a validated artifact ID. * * @param artifactId the artifact ID discovered */ public void addAndSetArtifactId( String artifactId ) { if ( artifactId != null ) { this.artifactId = artifactId; } addArtifactId( artifactId ); } /** * Add a potential artifact ID. * * @param artifactId the artifact ID discovered */ public void addArtifactId( String artifactId ) { addUnique( potentialArtifactIds, artifactId ); } /** * Add a validated version. * * @param version the version discovered */ public void addAndSetVersion( String version ) { if ( version != null ) { this.version = version; } addVersion( version ); } /** * Add a potential version. * * @param version the version discovered */ public void addVersion( String version ) { addUnique( potentialVersions, version ); } /** * Add a validated vendor name. * * @param name the vendor name discovered */ public void addAndSetVendor( String name ) { if ( name != null ) { vendor = name; } addVendor( name ); } /** * Add a potential vendor name. * * @param name the vendor name discovered */ public void addVendor( String name ) { addUnique( potentialVendors, name ); } /** * Add a validated artifact name. * * @param name the artifact name discovered */ public void addAndSetName( String name ) { if ( name != null ) { this.name = name; } addName( name ); } /** * Add a potential artifact name. * * @param name the artifact name discovered */ public void addName( String name ) { addUnique( potentialNames, name ); } private static void addUnique( List list, String value ) { if ( value != null ) { if ( !list.contains( value ) ) { list.add( value ); } } } public String getArtifactId() { return artifactId; } public void setArtifactId( String artifactId ) { this.artifactId = artifactId; } public String getGroupId() { return groupId; } public void setGroupId( String groupId ) { this.groupId = groupId; } public String getName() { return name; } public void setName( String name ) { this.name = name; } public String getVendor() { return vendor; } public void setVendor( String vendor ) { this.vendor = vendor; } public String getVersion() { return version; } public void setVersion( String version ) { this.version = version; } public List getPotentialVersions() { return potentialVersions; } public List getPotentialNames() { return potentialNames; } public List getPotentialGroupIds() { return potentialGroupIds; } public List getPotentialArtifactIds() { return potentialArtifactIds; } public List getPotentialVendors() { return potentialVendors; } } JarIdentificationAnalysis.java 0000664 0000000 0000000 00000012175 11634455326 0035161 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification package org.apache.maven.shared.jar.identification; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; import org.codehaus.plexus.util.StringUtils; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Analyze the JAR file to identify Maven artifact metadata. This class is thread safe and immutable as long as all * provided exposers are, as it retains no state. * * If using Plexus, the class will use all available exposers in the container. * * If not using Plexus, the exposers must be set using {@link #setExposers(java.util.List)} before calling * {@link #analyze(org.apache.maven.shared.jar.JarAnalyzer)} * * Note that you must first create an instance of {@link org.apache.maven.shared.jar.JarAnalyzer} - see its Javadoc for * a typical use. * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationAnalysis" role-hint="default" */ public class JarIdentificationAnalysis { /** * The Maven information exposers to use during identification. * * @plexus.requirement role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" */ private List exposers; /** * Analyze a JAR and find any associated Maven metadata. Note that if the provided JAR analyzer has previously * analyzed the JAR, the cached results will be returned. You must obtain a new JAR analyzer to the re-read the * contents of the file. * * @param jarAnalyzer the JAR to analyze. This must not yet have been closed. * @return the Maven metadata discovered */ public JarIdentification analyze( JarAnalyzer jarAnalyzer ) { JarIdentification taxon = jarAnalyzer.getJarData().getJarIdentification(); if ( taxon != null ) { return taxon; } taxon = new JarIdentification(); for ( Iterator i = exposers.iterator(); i.hasNext(); ) { JarIdentificationExposer exposer = (JarIdentificationExposer) i.next(); exposer.expose( taxon, jarAnalyzer ); } normalize( taxon ); jarAnalyzer.getJarData().setJarIdentification( taxon ); return taxon; } private void normalize( JarIdentification taxon ) { if ( StringUtils.isEmpty( taxon.getGroupId() ) ) { taxon.setGroupId( pickSmallest( taxon.getPotentialGroupIds() ) ); } if ( StringUtils.isEmpty( taxon.getArtifactId() ) ) { taxon.setArtifactId( pickLargest( taxon.getPotentialArtifactIds() ) ); } if ( StringUtils.isEmpty( taxon.getVersion() ) ) { taxon.setVersion( pickSmallest( taxon.getPotentialVersions() ) ); } if ( StringUtils.isEmpty( taxon.getName() ) ) { taxon.setName( pickLargest( taxon.getPotentialNames() ) ); } if ( StringUtils.isEmpty( taxon.getVendor() ) ) { taxon.setVendor( pickLargest( taxon.getPotentialVendors() ) ); } } private String pickSmallest( List list ) { String smallest = null; if ( !list.isEmpty() ) { int size = Integer.MAX_VALUE; Iterator it = list.iterator(); while ( it.hasNext() ) { String val = (String) it.next(); if ( StringUtils.isNotEmpty( val ) ) { if ( val.length() < size ) { smallest = val; size = val.length(); } } } } return smallest; } private String pickLargest( List list ) { String largest = null; if ( !list.isEmpty() ) { int size = Integer.MIN_VALUE; Iterator it = list.iterator(); while ( it.hasNext() ) { String val = (String) it.next(); if ( StringUtils.isNotEmpty( val ) ) { if ( val.length() > size ) { largest = val; size = val.length(); } } } } return largest; } public void setExposers( List exposers ) { this.exposers = Collections.unmodifiableList( exposers ); } } JarIdentificationExposer.java 0000664 0000000 0000000 00000003160 11634455326 0035015 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification package org.apache.maven.shared.jar.identification; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; /** * Expose information from a JAR during the identification process. Implementations should be made to be thread safe. * * @see org.apache.maven.shared.jar.identification.JarIdentificationAnalysis */ public interface JarIdentificationExposer { /** * Expose metadata during the identification process. * * @param identification the identification record to populate with the exposed metadata * @param jarAnalyzer the JAR to obtain the information from. Should be treated as read only, with the exception * of caching the metadata if it would be identical when run over the same file again. */ void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ); } maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers/ 0000775 0000000 0000000 00000000000 11634455326 0031145 5 ustar 00root root 0000000 0000000 EmbeddedMavenModelExposer.java 0000664 0000000 0000000 00000007200 11634455326 0036737 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.model.Model; import org.apache.maven.model.Organization; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import java.util.jar.JarEntry; /** * Exposer that examines a JAR file for any embedded Maven metadata for identification. * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="embeddedMavenModel" */ public class EmbeddedMavenModelExposer extends AbstractLogEnabled implements JarIdentificationExposer { public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ) { List entries = jarAnalyzer.getMavenPomEntries(); if ( entries.isEmpty() ) { return; } if ( entries.size() > 1 ) { getLogger().warn( "More than one Maven model entry was found in the JAR, using only the first of: " + entries ); } JarEntry pom = (JarEntry) entries.get( 0 ); MavenXpp3Reader pomreader = new MavenXpp3Reader(); InputStream is = null; try { is = jarAnalyzer.getEntryInputStream( pom ); InputStreamReader isreader = new InputStreamReader( is ); Model model = pomreader.read( isreader ); identification.addAndSetGroupId( model.getGroupId() ); identification.addAndSetArtifactId( model.getArtifactId() ); identification.addAndSetVersion( model.getVersion() ); identification.addAndSetName( model.getName() ); // TODO: suboptimal - we are reproducing Maven's built in default if ( model.getName() == null ) { identification.addAndSetName( model.getArtifactId() ); } Organization org = model.getOrganization(); if ( org != null ) { identification.addAndSetVendor( org.getName() ); } } catch ( IOException e ) { getLogger().error( "Unable to read model " + pom.getName() + " in " + jarAnalyzer.getFile() + ".", e ); } catch ( XmlPullParserException e ) { getLogger().error( "Unable to parse model " + pom.getName() + " in " + jarAnalyzer.getFile() + ".", e ); } finally { IOUtil.close( is ); } } } FilenameExposer.java 0000664 0000000 0000000 00000004356 11634455326 0035027 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import org.codehaus.plexus.util.FileUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Exposer that examines a JAR file to derive Maven metadata from the pattern of the JAR's filename. * Will match the format artifactId-version.jar. * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="filename" */ public class FilenameExposer implements JarIdentificationExposer { private static final Pattern VERSION_PATTERN = Pattern.compile( "-[0-9]" ); public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ) { String filename = FileUtils.removeExtension( jarAnalyzer.getFile().getName() ); Matcher mat = VERSION_PATTERN.matcher( filename ); if ( mat.find() ) { String prefix = filename.substring( 0, mat.start() ); identification.addArtifactId( prefix ); identification.addName( prefix ); identification.addVersion( filename.substring( mat.end() - 1 ) ); } else { identification.addArtifactId( filename ); identification.addName( filename ); } } } JarClassesExposer.java 0000664 0000000 0000000 00000004472 11634455326 0035340 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.classes.JarClasses; import org.apache.maven.shared.jar.classes.JarClassesAnalysis; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import java.util.Iterator; /** * Exposer that examines a JAR file to derive Maven metadata from the classes in a JAR. It will currently identify * potential group IDs from the class packages. * * Note: if not being used from Plexus, the {@link #setAnalyzer(org.apache.maven.shared.jar.classes.JarClassesAnalysis)} * method must be called to avoid a NullPointerException during the expose method. * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="jarClasses" */ public class JarClassesExposer implements JarIdentificationExposer { /** * @plexus.requirement */ private JarClassesAnalysis analyzer; public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ) { JarClasses jarclasses = analyzer.analyze( jarAnalyzer ); Iterator it = jarclasses.getPackages().iterator(); while ( it.hasNext() ) { String packagename = (String) it.next(); identification.addGroupId( packagename ); } } public void setAnalyzer( JarClassesAnalysis analyzer ) { this.analyzer = analyzer; } } ManifestExposer.java 0000664 0000000 0000000 00000005535 11634455326 0035055 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import java.util.Iterator; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.Manifest; /** * Exposer that examines a JAR's manifest to derive Maven metadata. * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="manifest" */ public class ManifestExposer implements JarIdentificationExposer { public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ) { Manifest manifest = jarAnalyzer.getJarData().getManifest(); if ( manifest != null ) { addManifestAttributeValues( manifest.getMainAttributes(), identification ); Map entries = manifest.getEntries(); Iterator itentries = entries.entrySet().iterator(); while ( itentries.hasNext() ) { Map.Entry entry = (Map.Entry) itentries.next(); Attributes attribs = (Attributes) entry.getValue(); addManifestAttributeValues( attribs, identification ); } } } private void addManifestAttributeValues( Attributes attribs, JarIdentification identification ) { identification.addName( attribs.getValue( Attributes.Name.IMPLEMENTATION_TITLE ) ); identification.addVersion( attribs.getValue( Attributes.Name.IMPLEMENTATION_VERSION ) ); identification.addVendor( attribs.getValue( Attributes.Name.IMPLEMENTATION_VENDOR ) ); identification.addName( attribs.getValue( Attributes.Name.SPECIFICATION_TITLE ) ); identification.addVersion( attribs.getValue( Attributes.Name.SPECIFICATION_VERSION ) ); identification.addVendor( attribs.getValue( Attributes.Name.SPECIFICATION_VENDOR ) ); identification.addGroupId( attribs.getValue( Attributes.Name.EXTENSION_NAME ) ); } } RepositorySearchExposer.java 0000664 0000000 0000000 00000010272 11634455326 0036606 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.artifact.Artifact; import org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import org.apache.maven.shared.jar.identification.hash.JarHashAnalyzer; import org.apache.maven.shared.jar.identification.repository.RepositoryHashSearch; import org.codehaus.plexus.logging.AbstractLogEnabled; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Exposer that examines a Maven repository for identical files to the JAR being analyzed. It will look for both * identical files, and files with identical classes. * * Note: if not using Plexus, you must call the following methods to be able to expose any data from the class: * {@link #setBytecodeHashAnalyzer(org.apache.maven.shared.jar.identification.hash.JarHashAnalyzer)}, * {@link #setFileHashAnalyzer(org.apache.maven.shared.jar.identification.hash.JarHashAnalyzer)}, * {@link #setRepositoryHashSearch(org.apache.maven.shared.jar.identification.repository.RepositoryHashSearch)} * * @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="repositorySearch" */ public class RepositorySearchExposer extends AbstractLogEnabled implements JarIdentificationExposer { /** * The repository searcher to use. * * @plexus.requirement * @todo this currently only provides for the 'empty' repository search, which isn't very useful */ private RepositoryHashSearch repositoryHashSearch; /** * The hash analyzer for the entire file. * * @plexus.requirement role-hint="file" */ private JarHashAnalyzer fileHashAnalyzer; /** * The hash analyzer for the file's bytecode. * * @plexus.requirement role-hint="bytecode" */ private JarHashAnalyzer bytecodeHashAnalyzer; public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer ) { List repohits = new ArrayList(); String hash = fileHashAnalyzer.computeHash( jarAnalyzer ); if ( hash != null ) { repohits.addAll( repositoryHashSearch.searchFileHash( hash ) ); } String bytecodehash = bytecodeHashAnalyzer.computeHash( jarAnalyzer ); if ( bytecodehash != null ) { repohits.addAll( repositoryHashSearch.searchBytecodeHash( bytecodehash ) ); } if ( !repohits.isEmpty() ) { // Found hits in the repository. Iterator it = repohits.iterator(); while ( it.hasNext() ) { Artifact artifact = (Artifact) it.next(); identification.addAndSetGroupId( artifact.getGroupId() ); identification.addAndSetArtifactId( artifact.getArtifactId() ); identification.addAndSetVersion( artifact.getVersion() ); } } } public void setRepositoryHashSearch( RepositoryHashSearch repo ) { this.repositoryHashSearch = repo; } public void setFileHashAnalyzer( JarHashAnalyzer fileHashAnalyzer ) { this.fileHashAnalyzer = fileHashAnalyzer; } public void setBytecodeHashAnalyzer( JarHashAnalyzer bytecodeHashAnalyzer ) { this.bytecodeHashAnalyzer = bytecodeHashAnalyzer; } } StaticMainOutputExposer.java 0000664 0000000 0000000 00000004205 11634455326 0036555 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers; /* * 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 org.apache.maven.shared.jar.JarAnalyzer; import org.apache.maven.shared.jar.identification.JarIdentification; import org.apache.maven.shared.jar.identification.JarIdentificationExposer; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Exposer that examines a a JAR for classes that have
Version
in the name and calls their
* main
method if it exists to obtain the version.
*
* @todo not currently implemented
* @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="staticMainOutput"
*/
public class StaticMainOutputExposer
implements JarIdentificationExposer
{
public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer )
{
List staticMains = findStaticMainVersions();
if ( !staticMains.isEmpty() )
{
Iterator itvers = staticMains.iterator();
while ( itvers.hasNext() )
{
String ver = (String) itvers.next();
identification.addVersion( ver );
}
}
}
private List findStaticMainVersions()
{
// TODO: Execute the static main methods of classes with 'Version' in their name.
return Collections.EMPTY_LIST;
}
}
TextFileExposer.java 0000664 0000000 0000000 00000007205 11634455326 0035027 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers;
/*
* 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 org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.identification.JarIdentification;
import org.apache.maven.shared.jar.identification.JarIdentificationExposer;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
/**
* Exposer that examines a a JAR for files that contain the text version
(case-insensitive) and
* adds the contents as potential version(s).
*
* @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="textFile"
*/
public class TextFileExposer
extends AbstractLogEnabled
implements JarIdentificationExposer
{
public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer )
{
List textFiles = findTextFileVersions( jarAnalyzer );
if ( !textFiles.isEmpty() )
{
Iterator ithits = textFiles.iterator();
while ( ithits.hasNext() )
{
String ver = (String) ithits.next();
identification.addVersion( ver );
}
}
}
private List findTextFileVersions( JarAnalyzer jarAnalyzer )
{
List textVersions = new ArrayList();
List hits = jarAnalyzer.getVersionEntries();
Iterator it = hits.iterator();
while ( it.hasNext() )
{
JarEntry entry = (JarEntry) it.next();
// skip this entry if it's a class file.
if ( !entry.getName().endsWith( ".class" ) ) //$NON-NLS-1$
{
getLogger().debug( "Version Hit: " + entry.getName() );
InputStream is = null;
try
{
is = jarAnalyzer.getEntryInputStream( entry );
BufferedReader br = new BufferedReader( new InputStreamReader( is ) );
String line = br.readLine();
// TODO: check for key=value pair.
// TODO: maybe even for groupId entries.
getLogger().debug( line );
if ( StringUtils.isNotEmpty( line ) )
{
textVersions.add( line );
}
}
catch ( IOException e )
{
getLogger().warn( "Unable to read line from " + entry.getName(), e );
}
finally
{
IOUtil.close( is );
}
}
}
return textVersions;
}
}
TimestampExposer.java 0000664 0000000 0000000 00000005236 11634455326 0035250 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/exposers package org.apache.maven.shared.jar.identification.exposers;
/*
* 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 org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.HashBag;
import org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.identification.JarIdentification;
import org.apache.maven.shared.jar.identification.JarIdentificationExposer;
import org.codehaus.plexus.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
/**
* Exposer that examines a a JAR and uses the most recent timestamp as a potential version.
*
* @plexus.component role="org.apache.maven.shared.jar.identification.JarIdentificationExposer" role-hint="timestamp"
*/
public class TimestampExposer
implements JarIdentificationExposer
{
public void expose( JarIdentification identification, JarAnalyzer jarAnalyzer )
{
List entries = jarAnalyzer.getEntries();
SimpleDateFormat tsformat = new SimpleDateFormat( "yyyyMMdd", Locale.US ); //$NON-NLS-1$
Bag timestamps = new HashBag();
Iterator it = entries.iterator();
while ( it.hasNext() )
{
JarEntry entry = (JarEntry) it.next();
long time = entry.getTime();
String timestamp = tsformat.format( new Date( time ) );
timestamps.add( timestamp );
}
it = timestamps.iterator();
String ts = "";
int tsmax = 0;
while ( it.hasNext() )
{
String timestamp = (String) it.next();
int count = timestamps.getCount( timestamp );
if ( count > tsmax )
{
ts = timestamp;
tsmax = count;
}
}
if ( StringUtils.isNotEmpty( ts ) )
{
identification.addVersion( ts );
}
}
}
maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/hash/ 0000775 0000000 0000000 00000000000 11634455326 0030220 5 ustar 00root root 0000000 0000000 JarBytecodeHashAnalyzer.java 0000664 0000000 0000000 00000006477 11634455326 0035527 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/hash package org.apache.maven.shared.jar.identification.hash;
/*
* 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 org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.JarData;
import org.codehaus.plexus.digest.DigesterException;
import org.codehaus.plexus.digest.StreamingDigester;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.IOUtil;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.jar.JarEntry;
/**
* Analyzer that calculates the hash code for the entire file. Can be used to detect an exact copy of the file's class
* data. Useful to see thru a recompile, recompression, or timestamp change.
*
* If you are not using Plexus, you must call {@link #setDigester(org.codehaus.plexus.digest.StreamingDigester)} before use
*
* @plexus.component role="org.apache.maven.shared.jar.identification.hash.JarHashAnalyzer" role-hint="bytecode"
*/
public class JarBytecodeHashAnalyzer
extends AbstractLogEnabled
implements JarHashAnalyzer
{
/**
* The streaming digester to use for computing the hash. Under Plexus, the default is SHA-1.
*
* @plexus.requirement role-hint="sha1"
*/
private StreamingDigester digester;
public String computeHash( JarAnalyzer jarAnalyzer )
{
JarData jarData = jarAnalyzer.getJarData();
String result = jarData.getBytecodeHash();
if ( result == null )
{
Iterator it = jarAnalyzer.getClassEntries().iterator();
try
{
digester.reset();
while ( it.hasNext() )
{
JarEntry entry = (JarEntry) it.next();
computeEntryBytecodeHash( jarAnalyzer.getEntryInputStream( entry ) );
}
result = digester.calc();
jarData.setBytecodeHash( result );
}
catch ( DigesterException e )
{
getLogger().warn( "Unable to calculate the hashcode.", e );
}
catch ( IOException e )
{
getLogger().warn( "Unable to calculate the hashcode.", e );
}
}
return result;
}
private void computeEntryBytecodeHash( InputStream is )
throws IOException, DigesterException
{
try
{
digester.update( is );
}
finally
{
IOUtil.close( is );
}
}
public void setDigester( StreamingDigester digester )
{
this.digester = digester;
}
}
JarFileHashAnalyzer.java 0000664 0000000 0000000 00000004524 11634455326 0034637 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/hash package org.apache.maven.shared.jar.identification.hash;
/*
* 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 org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.JarData;
import org.codehaus.plexus.digest.Digester;
import org.codehaus.plexus.digest.DigesterException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
/**
* Analyzer that calculates the hash code for the entire file. Can be used to detect an exact copy of the file.
*
* If you are not using Plexus, you must call {@link #setDigester(org.codehaus.plexus.digest.Digester)} before use
*
* @plexus.component role="org.apache.maven.shared.jar.identification.hash.JarHashAnalyzer" role-hint="file"
*/
public class JarFileHashAnalyzer
extends AbstractLogEnabled
implements JarHashAnalyzer
{
/**
* The digester to use for computing the hash. Under Plexus, the default is SHA-1.
*
* @plexus.requirement role-hint="sha1"
*/
private Digester digester;
public String computeHash( JarAnalyzer jarAnalyzer )
{
JarData jarData = jarAnalyzer.getJarData();
String result = jarData.getFileHash();
if ( result == null )
{
try
{
result = digester.calc( jarData.getFile() );
jarData.setFileHash( result );
}
catch ( DigesterException e )
{
getLogger().warn( "Unable to calculate the hashcode.", e );
}
}
return result;
}
public void setDigester( Digester digester )
{
this.digester = digester;
}
}
JarHashAnalyzer.java 0000664 0000000 0000000 00000002575 11634455326 0034043 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/hash package org.apache.maven.shared.jar.identification.hash;
/*
* 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 org.apache.maven.shared.jar.JarAnalyzer;
/**
* Classes that can calculate various hash signatures for a JAR file to later uniquely identify them.
*/
public interface JarHashAnalyzer
{
/**
* Compute the hash for the JAR. The hashcode will then be cached in the JAR data class for later use.
*
* @param jarAnalyzer the JAR analyzer to use to obtain the entries to hash
* @return the hash, or null if not able to be computed due to an exception.
*/
String computeHash( JarAnalyzer jarAnalyzer );
}
maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/repository/ 0000775 0000000 0000000 00000000000 11634455326 0031514 5 ustar 00root root 0000000 0000000 EmptyRepositoryHashSearch.java 0000664 0000000 0000000 00000003205 11634455326 0037430 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/repository package org.apache.maven.shared.jar.identification.repository;
/*
* 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 java.util.Collections;
import java.util.List;
/**
* Empty repository hash search. Always returns an empty list.
*
* Used for local only implementation of a RepositoryHashSearch. It is expected for the users of this library to provide
* an implementation of a {@link org.apache.maven.shared.jar.identification.repository.RepositoryHashSearch} against a
* real repository.
*
* @plexus.component role="org.apache.maven.shared.jar.identification.repository.RepositoryHashSearch" role-hint="empty"
*/
public class EmptyRepositoryHashSearch
implements RepositoryHashSearch
{
public List searchBytecodeHash( String hash )
{
return Collections.EMPTY_LIST;
}
public List searchFileHash( String hash )
{
return Collections.EMPTY_LIST;
}
}
RepositoryHashSearch.java 0000664 0000000 0000000 00000003144 11634455326 0036413 0 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/java/org/apache/maven/shared/jar/identification/repository package org.apache.maven.shared.jar.identification.repository;
/*
* 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 java.util.List;
/**
* Interface for Repository Hash Searches.
*/
public interface RepositoryHashSearch
{
/**
* Search the repository for artifacts matching the given hash code when consider the entire contents of the file.
*
* @param hash the hash code to use
* @return a list of {@link org.apache.maven.artifact.Artifact} instances that matched
*/
List searchFileHash( String hash );
/**
* Search the repository for artifacts matching the given hash code when consider the bytecode of the classes in the
* file.
*
* @param hash the hash code to use
* @return a list of {@link org.apache.maven.artifact.Artifact} instances that matched
*/
List searchBytecodeHash( String hash );
}
maven-shared-jar-1.1/src/main/javadoc/ 0000775 0000000 0000000 00000000000 11634455326 0017632 5 ustar 00root root 0000000 0000000 maven-shared-jar-1.1/src/main/javadoc/overview.html 0000664 0000000 0000000 00000007431 11634455326 0022373 0 ustar 00root root 0000000 0000000
The Maven Jar Analyzer components can be used to gather various pieces of information about a given JAR file. Currently, the following operations are supported:
To determine the Maven artifact metadata for a particular JAR, the {@link org.apache.maven.shared.jar.identification.JarIdentificationAnalysis} class is used. The class can be obtained through Plexus, or created standalone (in which case, see the class Javadoc for information on proper wiring).
Note that to use the class, you must first obtain a {@link org.apache.maven.shared.jar.JarAnalyzer} instance as instructed in its Javadoc.
The resulting information will be populated in the returned {@link org.apache.maven.shared.jar.identification.JarIdentification} class.
Example usage:
JarAnalyzer jar = new JarAnalyzer( jarFile ); JarIdenfitication jarIdenfitication; try { // instance must have been previously obtained through Plexus or created as instructed in its Javadoc jarIdenfitication = jarIdenfiticationAnalyzer.analyze( jar ); } finally { jar.closeQuietly(); } // continue to use jarIdenfitication or jar.getJarData()
To determine the Java class metadata for a particular JAR, the {@link org.apache.maven.shared.jar.classes.JarClassesAnalysis} class is used. The class can be obtained through Plexus, or created standalone (in which case, see the class Javadoc for information on proper wiring).
Note that to use the class, you must first obtain a {@link org.apache.maven.shared.jar.JarAnalyzer} instance as instructed in its Javadoc.
The resulting information will be populated in the returned {@link org.apache.maven.shared.jar.classes.JarClasses} class.
Example usage:
JarAnalyzer jar = new JarAnalyzer( jarFile ); JarClasses jarClasses; try { // instance must have been previously obtained through Plexus or created as instructed in its Javadoc jarClasses = jarClassAnalyzer.analyze( jar ); } finally { jar.closeQuietly(); } // continue to use jarClasses or jar.getJarData()