diff options
author | Joakim Erdfelt <joakime@apache.org> | 2007-02-23 19:05:21 +0000 |
---|---|---|
committer | Joakim Erdfelt <joakime@apache.org> | 2007-02-23 19:05:21 +0000 |
commit | dee0d5a300ee0ba0240efc1277428b52cdcec9e0 (patch) | |
tree | 0f4c8d3b8b8b0468deac3c8851380a68bfa1744e /archiva-common/src/main | |
parent | 2b50a18d22ef8972d241f54c20a131e05a584ac4 (diff) | |
download | archiva-dee0d5a300ee0ba0240efc1277428b52cdcec9e0.tar.gz archiva-dee0d5a300ee0ba0240efc1277428b52cdcec9e0.zip |
Merge from archiva-MRM-239 branch to trunk. r506385:HEAD
git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/trunk@511053 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'archiva-common/src/main')
19 files changed, 1861 insertions, 0 deletions
diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/ArchivaException.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/ArchivaException.java new file mode 100644 index 000000000..c807d70c4 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/ArchivaException.java @@ -0,0 +1,40 @@ +package org.apache.maven.archiva.common; + +/* + * 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. + */ + +/** + * ArchivaException + * + * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ArchivaException + extends Exception +{ + public ArchivaException( String message, Throwable cause ) + { + super( message, cause ); + } + + public ArchivaException( String message ) + { + super( message ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/AbstractLayoutArtifactBuilder.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/AbstractLayoutArtifactBuilder.java new file mode 100644 index 000000000..b77826ad1 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/AbstractLayoutArtifactBuilder.java @@ -0,0 +1,55 @@ +package org.apache.maven.archiva.common.artifact.builder; + +/* + * 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.factory.ArtifactFactory; + +/** + * AbstractLayoutArtifactBuilder + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public abstract class AbstractLayoutArtifactBuilder + implements LayoutArtifactBuilder +{ + /** + * @plexus.requirement + */ + protected ArtifactFactory artifactFactory; + + /** + * Constructor used by plexus + */ + public AbstractLayoutArtifactBuilder() + { + + } + + /** + * Constructor used by manual process. + * + * @param artifactFactory the artifact factory to use. + */ + public AbstractLayoutArtifactBuilder( ArtifactFactory artifactFactory ) + { + this.artifactFactory = artifactFactory; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/BuilderException.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/BuilderException.java new file mode 100644 index 000000000..0845dc750 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/BuilderException.java @@ -0,0 +1,43 @@ +package org.apache.maven.archiva.common.artifact.builder; + +/* + * 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.archiva.common.ArchivaException; + +/** + * BuilderException - used to indicate a problem during the building of an object from file. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class BuilderException + extends ArchivaException +{ + + public BuilderException( String message, Throwable cause ) + { + super( message, cause ); + } + + public BuilderException( String message ) + { + super( message ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/DefaultLayoutArtifactBuilder.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/DefaultLayoutArtifactBuilder.java new file mode 100644 index 000000000..bfee01508 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/DefaultLayoutArtifactBuilder.java @@ -0,0 +1,218 @@ +package org.apache.maven.archiva.common.artifact.builder; + +/* + * 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.artifact.factory.ArtifactFactory; +import org.codehaus.plexus.util.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; + +/** + * DefaultLayoutArtifactBuilder - artifact builder for default layout repositories. + * + * @author <a href="mailto:brett@apache.org">Brett Porter</a> + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + * + * @plexus.component role="org.apache.maven.archiva.common.artifact.builder.LayoutArtifactBuilder" + * role-hint="default" + */ +public class DefaultLayoutArtifactBuilder + extends AbstractLayoutArtifactBuilder + implements LayoutArtifactBuilder +{ + public DefaultLayoutArtifactBuilder() + { + super(); + } + + public DefaultLayoutArtifactBuilder( ArtifactFactory artifactFactory ) + { + super( artifactFactory ); + } + + public Artifact build( String pathToArtifact ) + throws BuilderException + { + if( artifactFactory == null ) + { + throw new IllegalStateException( "Unable to build artifact with a null artifactFactory." ); + } + + List pathParts = new ArrayList(); + StringTokenizer st = new StringTokenizer( pathToArtifact, "/\\" ); + while ( st.hasMoreTokens() ) + { + pathParts.add( st.nextToken() ); + } + + Collections.reverse( pathParts ); + + Artifact artifact; + if ( pathParts.size() >= 4 ) + { + // maven 2.x path + + // the actual artifact filename. + String filename = (String) pathParts.remove( 0 ); + + // the next one is the version. + String version = (String) pathParts.remove( 0 ); + + // the next one is the artifactId. + String artifactId = (String) pathParts.remove( 0 ); + + // the remaining are the groupId. + Collections.reverse( pathParts ); + String groupId = StringUtils.join( pathParts.iterator(), "." ); + + String remainingFilename = filename; + if ( remainingFilename.startsWith( artifactId + "-" ) ) + { + remainingFilename = remainingFilename.substring( artifactId.length() + 1 ); + + String classifier = null; + + // TODO: use artifact handler, share with legacy discoverer + String type; + if ( remainingFilename.endsWith( ".tar.gz" ) ) + { + type = "distribution-tgz"; + remainingFilename = remainingFilename + .substring( 0, remainingFilename.length() - ".tar.gz".length() ); + } + else if ( remainingFilename.endsWith( ".zip" ) ) + { + type = "distribution-zip"; + remainingFilename = remainingFilename.substring( 0, remainingFilename.length() - ".zip".length() ); + } + else if ( remainingFilename.endsWith( "-test-sources.jar" ) ) + { + type = "java-source"; + classifier = "test-sources"; + remainingFilename = remainingFilename.substring( 0, remainingFilename.length() + - "-test-sources.jar".length() ); + } + else if ( remainingFilename.endsWith( "-sources.jar" ) ) + { + type = "java-source"; + classifier = "sources"; + remainingFilename = remainingFilename.substring( 0, remainingFilename.length() + - "-sources.jar".length() ); + } + else + { + int index = remainingFilename.lastIndexOf( "." ); + if ( index >= 0 ) + { + type = remainingFilename.substring( index + 1 ); + remainingFilename = remainingFilename.substring( 0, index ); + } + else + { + throw new BuilderException( "Path filename does not have an extension." ); + } + } + + Artifact result; + if ( classifier == null ) + { + result = artifactFactory + .createArtifact( groupId, artifactId, version, Artifact.SCOPE_RUNTIME, type ); + } + else + { + result = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, + classifier ); + } + + if ( result.isSnapshot() ) + { + // version is *-SNAPSHOT, filename is *-yyyyMMdd.hhmmss-b + int classifierIndex = remainingFilename.indexOf( '-', version.length() + 8 ); + if ( classifierIndex >= 0 ) + { + classifier = remainingFilename.substring( classifierIndex + 1 ); + remainingFilename = remainingFilename.substring( 0, classifierIndex ); + result = artifactFactory.createArtifactWithClassifier( groupId, artifactId, remainingFilename, + type, classifier ); + } + else + { + result = artifactFactory.createArtifact( groupId, artifactId, remainingFilename, + Artifact.SCOPE_RUNTIME, type ); + } + + // poor encapsulation requires we do this to populate base version + if ( !result.isSnapshot() ) + { + throw new BuilderException( "Failed to create a snapshot artifact: " + result ); + } + else if ( !result.getBaseVersion().equals( version ) ) + { + throw new BuilderException( + "Built snapshot artifact base version does not match path version: " + + result.getBaseVersion() + "; should have been version: " + + version ); + } + else + { + artifact = result; + } + } + else if ( !remainingFilename.startsWith( version ) ) + { + throw new BuilderException( "Built artifact version does not match path version" ); + } + else if ( !remainingFilename.equals( version ) ) + { + if ( remainingFilename.charAt( version.length() ) == '-' ) + { + classifier = remainingFilename.substring( version.length() + 1 ); + artifact = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, + classifier ); + } + else + { + throw new BuilderException( "Path version does not corresspond to an artifact version" ); + } + } + else + { + artifact = result; + } + } + else + { + throw new BuilderException( "Path filename does not correspond to an artifact." ); + } + } + else + { + throw new BuilderException( "Path is too short to build an artifact from." ); + } + + return artifact; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LayoutArtifactBuilder.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LayoutArtifactBuilder.java new file mode 100644 index 000000000..494a4a7c1 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LayoutArtifactBuilder.java @@ -0,0 +1,36 @@ +package org.apache.maven.archiva.common.artifact.builder; + +/* + * 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.artifact.repository.layout.ArtifactRepositoryLayout; + +/** + * LayoutArtifactBuilder + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + * + * @todo this concept should really exist inside of the {@link ArtifactRepositoryLayout} object in maven itself. + */ +public interface LayoutArtifactBuilder +{ + public Artifact build( String pathToArtifact ) throws BuilderException; +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LegacyLayoutArtifactBuilder.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LegacyLayoutArtifactBuilder.java new file mode 100644 index 000000000..e3436e966 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/builder/LegacyLayoutArtifactBuilder.java @@ -0,0 +1,303 @@ +package org.apache.maven.archiva.common.artifact.builder; + +/* + * 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.artifact.factory.ArtifactFactory; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.StringTokenizer; + +/** + * LegacyLayoutArtifactBuilder + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + * + * @plexus.component role="org.apache.maven.archiva.common.artifact.builder.LayoutArtifactBuilder" + * role-hint="legacy" + */ +public class LegacyLayoutArtifactBuilder + extends AbstractLayoutArtifactBuilder + implements LayoutArtifactBuilder +{ + public LegacyLayoutArtifactBuilder() + { + super(); + } + + public LegacyLayoutArtifactBuilder( ArtifactFactory artifactFactory ) + { + super( artifactFactory ); + } + + public Artifact build( String pathToArtifact ) + throws BuilderException + { + if( artifactFactory == null ) + { + throw new IllegalStateException( "Unable to build legacy artifact with a null artifactFactory." ); + } + + StringTokenizer tokens = new StringTokenizer( pathToArtifact, "/\\" ); + + Artifact result; + + int numberOfTokens = tokens.countTokens(); + + if ( numberOfTokens == 3 ) + { + String groupId = tokens.nextToken(); + + String type = tokens.nextToken(); + + if ( type.endsWith( "s" ) ) + { + type = type.substring( 0, type.length() - 1 ); + + // contains artifactId, version, classifier, and extension. + String avceGlob = tokens.nextToken(); + + //noinspection CollectionDeclaredAsConcreteClass + LinkedList avceTokenList = new LinkedList(); + + StringTokenizer avceTokenizer = new StringTokenizer( avceGlob, "-" ); + while ( avceTokenizer.hasMoreTokens() ) + { + avceTokenList.addLast( avceTokenizer.nextToken() ); + } + + String lastAvceToken = (String) avceTokenList.removeLast(); + + // TODO: share with other discoverer, use artifact handlers instead + if ( lastAvceToken.endsWith( ".tar.gz" ) ) + { + type = "distribution-tgz"; + + lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".tar.gz".length() ); + + avceTokenList.addLast( lastAvceToken ); + } + else if ( lastAvceToken.endsWith( "sources.jar" ) ) + { + type = "java-source"; + + lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".jar".length() ); + + avceTokenList.addLast( lastAvceToken ); + } + else if ( lastAvceToken.endsWith( "javadoc.jar" ) ) + { + type = "javadoc.jar"; + + lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".jar".length() ); + + avceTokenList.addLast( lastAvceToken ); + } + else if ( lastAvceToken.endsWith( ".zip" ) ) + { + type = "distribution-zip"; + + lastAvceToken = lastAvceToken.substring( 0, lastAvceToken.length() - ".zip".length() ); + + avceTokenList.addLast( lastAvceToken ); + } + else + { + int extPos = lastAvceToken.lastIndexOf( '.' ); + + if ( extPos > 0 ) + { + String ext = lastAvceToken.substring( extPos + 1 ); + if ( type.equals( ext ) || "plugin".equals( type ) ) + { + lastAvceToken = lastAvceToken.substring( 0, extPos ); + + avceTokenList.addLast( lastAvceToken ); + } + else + { + throw new BuilderException( "Path type does not match the extension" ); + } + } + else + { + throw new BuilderException( "Path filename does not have an extension" ); + } + } + + // let's discover the version, and whatever's leftover will be either + // a classifier, or part of the artifactId, depending on position. + // Since version is at the end, we have to move in from the back. + Collections.reverse( avceTokenList ); + + // TODO: this is obscene - surely a better way? + String validVersionParts = "([Dd][Ee][Vv][_.0-9]*)|" + "([Ss][Nn][Aa][Pp][Ss][Hh][Oo][Tt])|" + + "([0-9][_.0-9a-zA-Z]*)|" + "([Gg]?[_.0-9ab]*([Pp][Rr][Ee]|[Rr][Cc]|[Gg]|[Mm])[_.0-9]*)|" + + "([Aa][Ll][Pp][Hh][Aa][_.0-9]*)|" + "([Bb][Ee][Tt][Aa][_.0-9]*)|" + "([Rr][Cc][_.0-9]*)|" + + "([Tt][Ee][Ss][Tt][_.0-9]*)|" + "([Dd][Ee][Bb][Uu][Gg][_.0-9]*)|" + + "([Uu][Nn][Oo][Ff][Ff][Ii][Cc][Ii][Aa][Ll][_.0-9]*)|" + "([Cc][Uu][Rr][Rr][Ee][Nn][Tt])|" + + "([Ll][Aa][Tt][Ee][Ss][Tt])|" + "([Ff][Cc][Ss])|" + "([Rr][Ee][Ll][Ee][Aa][Ss][Ee][_.0-9]*)|" + + "([Nn][Ii][Gg][Hh][Tt][Ll][Yy])|" + "[Ff][Ii][Nn][Aa][Ll]|" + "([AaBb][_.0-9]*)"; + + StringBuffer classifierBuffer = new StringBuffer(); + StringBuffer versionBuffer = new StringBuffer(); + + boolean firstVersionTokenEncountered = false; + boolean firstToken = true; + + int tokensIterated = 0; + for ( Iterator it = avceTokenList.iterator(); it.hasNext(); ) + { + String token = (String) it.next(); + + boolean tokenIsVersionPart = token.matches( validVersionParts ); + + StringBuffer bufferToUpdate; + + // NOTE: logic in code is reversed, since we're peeling off the back + // Any token after the last versionPart will be in the classifier. + // Any token UP TO first non-versionPart is part of the version. + if ( !tokenIsVersionPart ) + { + if ( firstVersionTokenEncountered ) + { + //noinspection BreakStatement + break; + } + else + { + bufferToUpdate = classifierBuffer; + } + } + else + { + firstVersionTokenEncountered = true; + + bufferToUpdate = versionBuffer; + } + + if ( firstToken ) + { + firstToken = false; + } + else + { + bufferToUpdate.insert( 0, '-' ); + } + + bufferToUpdate.insert( 0, token ); + + tokensIterated++; + } + + // Now, restore the proper ordering so we can build the artifactId. + Collections.reverse( avceTokenList ); + + // if we didn't find a version, then punt. Use the last token + // as the version, and set the classifier empty. + if ( versionBuffer.length() < 1 ) + { + if ( avceTokenList.size() > 1 ) + { + int lastIdx = avceTokenList.size() - 1; + + versionBuffer.append( avceTokenList.get( lastIdx ) ); + avceTokenList.remove( lastIdx ); + } + + classifierBuffer.setLength( 0 ); + } + else + { + // if everything is kosher, then pop off all the classifier and + // version tokens, leaving the naked artifact id in the list. + avceTokenList = new LinkedList( avceTokenList.subList( 0, avceTokenList.size() - tokensIterated ) ); + } + + StringBuffer artifactIdBuffer = new StringBuffer(); + + firstToken = true; + for ( Iterator it = avceTokenList.iterator(); it.hasNext(); ) + { + String token = (String) it.next(); + + if ( firstToken ) + { + firstToken = false; + } + else + { + artifactIdBuffer.append( '-' ); + } + + artifactIdBuffer.append( token ); + } + + String artifactId = artifactIdBuffer.toString(); + + if ( artifactId.length() > 0 ) + { + int lastVersionCharIdx = versionBuffer.length() - 1; + if ( lastVersionCharIdx > -1 && versionBuffer.charAt( lastVersionCharIdx ) == '-' ) + { + versionBuffer.setLength( lastVersionCharIdx ); + } + + String version = versionBuffer.toString(); + + if ( version.length() > 0 ) + { + if ( classifierBuffer.length() > 0 ) + { + result = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, + classifierBuffer.toString() ); + } + else + { + result = artifactFactory.createArtifact( groupId, artifactId, version, + Artifact.SCOPE_RUNTIME, type ); + } + } + else + { + throw new BuilderException( "Path filename version is empty" ); + } + } + else + { + throw new BuilderException( "Path filename artifactId is empty" ); + } + } + else + { + throw new BuilderException( "Path artifact type does not corresspond to an artifact type" ); + } + } + else + { + throw new BuilderException( "Path does not match a legacy repository path for an artifact" ); + } + + return result; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifact.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifact.java new file mode 100644 index 000000000..8e3c67838 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifact.java @@ -0,0 +1,76 @@ +package org.apache.maven.archiva.common.artifact.managed; + +/* + * 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 java.util.HashMap; +import java.util.Map; + +/** + * ManagedArtifact + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ManagedArtifact +{ + private String repositoryId; + + private Artifact artifact; + + private String path; + + protected Map attached; + + public ManagedArtifact( String repoId, Artifact artifact, String path ) + { + super(); + this.repositoryId = repoId; + this.artifact = artifact; + this.path = path; + this.attached = new HashMap(); + } + + public Artifact getArtifact() + { + return artifact; + } + + public String getPath() + { + return path; + } + + public String getRepositoryId() + { + return repositoryId; + } + + public Map getAttached() + { + return attached; + } + + public void setAttached( Map attached ) + { + this.attached = attached; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifactTypes.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifactTypes.java new file mode 100644 index 000000000..b653d160a --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedArtifactTypes.java @@ -0,0 +1,81 @@ +package org.apache.maven.archiva.common.artifact.managed; + +/* + * 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.lang.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * ManagedArtifactTypes - provides place to test an unknown artifact type. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ManagedArtifactTypes +{ + public static final int GENERIC = 0; + + public static final int JAVA = 1; + + public static final int EJB = 2; + + private static List javaArtifacts; + + private static List ejbArtifacts; + + static + { + javaArtifacts = new ArrayList(); + javaArtifacts.add( "jar" ); + javaArtifacts.add( "war" ); + javaArtifacts.add( "sar" ); + javaArtifacts.add( "rar" ); + javaArtifacts.add( "ear" ); + + ejbArtifacts = new ArrayList(); + ejbArtifacts.add( "ejb" ); + ejbArtifacts.add( "ejb-client" ); + } + + public static int whichType( String type ) + { + if ( StringUtils.isBlank( type ) ) + { + // TODO: is an empty type even possible? + return GENERIC; + } + + type = type.toLowerCase(); + + if ( ejbArtifacts.contains( type ) ) + { + return EJB; + } + + if ( javaArtifacts.contains( type ) ) + { + return JAVA; + } + + return GENERIC; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedEjbArtifact.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedEjbArtifact.java new file mode 100644 index 000000000..1759df2db --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedEjbArtifact.java @@ -0,0 +1,49 @@ +package org.apache.maven.archiva.common.artifact.managed; + +/* + * 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; + +/** + * ManagedEjbArtifact - adds the ability to reference the ejb-client jar too. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ManagedEjbArtifact + extends ManagedJavaArtifact +{ + public static final String CLIENT = "client"; + + public ManagedEjbArtifact( String repoId, Artifact artifact, String path ) + { + super( repoId, artifact, path ); + } + + public String getClientPath() + { + return (String) super.attached.get( CLIENT ); + } + + public void setClientPath( String clientPath ) + { + super.attached.put( CLIENT, clientPath ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedJavaArtifact.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedJavaArtifact.java new file mode 100644 index 000000000..203234b06 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/artifact/managed/ManagedJavaArtifact.java @@ -0,0 +1,62 @@ +package org.apache.maven.archiva.common.artifact.managed; + +/* + * 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; + +/** + * ManagedJavaArtifact - a ManagedArtifact with optional javadoc and source + * reference jars. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ManagedJavaArtifact + extends ManagedArtifact +{ + public static final String JAVADOC = "javadoc"; + + public static final String SOURCES = "sources"; + + public ManagedJavaArtifact( String repoId, Artifact artifact, String path ) + { + super( repoId, artifact, path ); + } + + public String getJavadocPath() + { + return (String) super.attached.get( JAVADOC ); + } + + public void setJavadocPath( String javadocPath ) + { + super.attached.put( JAVADOC, javadocPath ); + } + + public String getSourcesPath() + { + return (String) super.attached.get( SOURCES ); + } + + public void setSourcesPath( String sourcesPath ) + { + super.attached.put( SOURCES, sourcesPath ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/AbstractConsumer.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/AbstractConsumer.java new file mode 100644 index 000000000..603434630 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/AbstractConsumer.java @@ -0,0 +1,66 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.codehaus.plexus.logging.AbstractLogEnabled; + +import java.util.Collections; +import java.util.List; + +/** + * AbstractDiscovererConsumer + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public abstract class AbstractConsumer + extends AbstractLogEnabled + implements Consumer +{ + /** + * @plexus.requirement + */ + protected ArtifactFactory artifactFactory; + + protected ArtifactRepository repository; + + protected AbstractConsumer() + { + /* do nothing */ + } + + public List getExcludePatterns() + { + return Collections.EMPTY_LIST; + } + + public boolean init( ArtifactRepository repository ) + { + this.repository = repository; + return isEnabled(); + } + + protected boolean isEnabled() + { + return true; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/Consumer.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/Consumer.java new file mode 100644 index 000000000..fad6f2fa8 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/Consumer.java @@ -0,0 +1,90 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.archiva.common.utils.BaseFile; +import org.apache.maven.artifact.repository.ArtifactRepository; + +import java.util.List; + +/** + * DiscovererConsumer + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public interface Consumer +{ + public static final String ROLE = Consumer.class.getName(); + + /** + * This is the human readable name for the discoverer. + * + * @return the human readable discoverer name. + */ + public String getName(); + + /** + * This is used to initialize any internals in the consumer before it is used. + * + * This method is called by the internals of archiva and is not meant to be used by other developers. + * This method is called once per repository. + * + * @param repository the repository to initialize the consumer against. + * @return true if the repository is valid for this consumer. false will result in consumer being disabled + * for the provided repository. + */ + public boolean init( ArtifactRepository repository ); + + /** + * Get the List of excluded file patterns for this consumer. + * + * @return the list of excluded file patterns for this consumer. + */ + public List getExcludePatterns(); + + /** + * Get the List of included file patterns for this consumer. + * + * @return the list of included file patterns for this consumer. + */ + public List getIncludePatterns(); + + /** + * Called by archiva framework to indicate that there is a file suitable for consuming, + * This method will only be called if the {@link #init(ArtifactRepository)} and {@link #getExcludePatterns()} + * and {@link #getIncludePatterns()} all pass for this consumer. + * + * @param file the file to process. + * @throws ConsumerException if there was a problem processing this file. + */ + public void processFile( BaseFile file ) throws ConsumerException; + + /** + * Called by archiva framework to indicate that there has been a problem detected + * on a specific file. + * + * NOTE: It is very possible for 1 file to have more than 1 problem associated with it. + * + * @param file the file to process. + * @param message the message describing the problem. + */ + public void processFileProblem( BaseFile file, String message ); +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerException.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerException.java new file mode 100644 index 000000000..0c4c6451a --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerException.java @@ -0,0 +1,52 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.archiva.common.ArchivaException; +import org.apache.maven.archiva.common.utils.BaseFile; + +/** + * ConsumerException - details about the failure of a consumer. + * + * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> + * @version $Id$ + */ +public class ConsumerException + extends ArchivaException +{ + private BaseFile file; + + public ConsumerException( BaseFile file, String message, Throwable cause ) + { + super( message, cause ); + this.file = file; + } + + public ConsumerException( BaseFile file, String message ) + { + super( message ); + this.file = file; + } + + public BaseFile getFile() + { + return file; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerFactory.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerFactory.java new file mode 100644 index 000000000..2b2343c0f --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/ConsumerFactory.java @@ -0,0 +1,70 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.codehaus.plexus.PlexusConstants; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.context.Context; +import org.codehaus.plexus.context.ContextException; +import org.codehaus.plexus.logging.AbstractLogEnabled; +import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; + +/** + * DiscovererConsumerFactory - factory for consumers. + * + * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> + * @version $Id$ + * @plexus.component role="org.apache.maven.archiva.common.consumers.ConsumerFactory" + */ +public class ConsumerFactory + extends AbstractLogEnabled + implements Contextualizable +{ + public static final String ROLE = ConsumerFactory.class.getName(); + + private PlexusContainer container; + + public Consumer createConsumer( String name ) + throws ConsumerException + { + getLogger().info( "Attempting to create consumer [" + name + "]" ); + + Consumer consumer; + try + { + consumer = (Consumer) container.lookup( Consumer.ROLE, container.getLookupRealm() ); + } + catch ( Throwable t ) + { + String emsg = "Unable to create consumer [" + name + "]: " + t.getMessage(); + getLogger().warn( t.getMessage(), t ); + throw new ConsumerException( null, emsg, t ); + } + + getLogger().info( "Created consumer [" + name + "|" + consumer.getName() + "]" ); + return consumer; + } + + public void contextualize( Context context ) + throws ContextException + { + container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericArtifactConsumer.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericArtifactConsumer.java new file mode 100644 index 000000000..c9e5437b7 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericArtifactConsumer.java @@ -0,0 +1,130 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.archiva.common.artifact.builder.BuilderException; +import org.apache.maven.archiva.common.artifact.builder.DefaultLayoutArtifactBuilder; +import org.apache.maven.archiva.common.artifact.builder.LayoutArtifactBuilder; +import org.apache.maven.archiva.common.artifact.builder.LegacyLayoutArtifactBuilder; +import org.apache.maven.archiva.common.utils.BaseFile; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.artifact.repository.layout.LegacyRepositoryLayout; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * DefaultArtifactConsumer + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public abstract class GenericArtifactConsumer + extends AbstractConsumer + implements Consumer +{ + public abstract void processArtifact( Artifact artifact, BaseFile file ); + + private Map artifactBuilders = new HashMap(); + + private static final List includePatterns; + + static + { + includePatterns = new ArrayList(); + includePatterns.add( "**/*.pom" ); + includePatterns.add( "**/*.jar" ); + includePatterns.add( "**/*.war" ); + includePatterns.add( "**/*.ear" ); + includePatterns.add( "**/*.sar" ); + includePatterns.add( "**/*.zip" ); + includePatterns.add( "**/*.gz" ); + includePatterns.add( "**/*.bz2" ); + } + + private String layoutId = "default"; + + public boolean init( ArtifactRepository repository ) + { + this.artifactBuilders.clear(); + this.artifactBuilders.put( "default", new DefaultLayoutArtifactBuilder( artifactFactory ) ); + this.artifactBuilders.put( "legacy", new LegacyLayoutArtifactBuilder( artifactFactory ) ); + + if ( repository.getLayout() instanceof LegacyRepositoryLayout ) + { + this.layoutId = "legacy"; + } + + return super.init( repository ); + } + + public List getIncludePatterns() + { + return includePatterns; + } + + public boolean isEnabled() + { + ArtifactRepositoryLayout layout = repository.getLayout(); + return ( layout instanceof DefaultRepositoryLayout ) || ( layout instanceof LegacyRepositoryLayout ); + } + + public void processFile( BaseFile file ) + throws ConsumerException + { + if ( file.length() <= 0 ) + { + processFileProblem( file, "File is empty." ); + } + + if ( !file.canRead() ) + { + processFileProblem( file, "Not allowed to read file due to permission settings on file." ); + } + + try + { + Artifact artifact = buildArtifact( file ); + + processArtifact( artifact, file ); + } + catch ( BuilderException e ) + { + throw new ConsumerException( file, e.getMessage(), e ); + } + } + + private Artifact buildArtifact( BaseFile file ) + throws BuilderException + { + LayoutArtifactBuilder builder = (LayoutArtifactBuilder) artifactBuilders.get( layoutId ); + + Artifact artifact = builder.build( file.getRelativePath() ); + artifact.setRepository( repository ); + artifact.setFile( file ); + + return artifact; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericModelConsumer.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericModelConsumer.java new file mode 100644 index 000000000..efcd7af64 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericModelConsumer.java @@ -0,0 +1,98 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.archiva.common.utils.BaseFile; +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +/** + * GenericModelConsumer - consumer for pom files. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public abstract class GenericModelConsumer + extends AbstractConsumer + implements Consumer +{ + public abstract void processModel( Model model, BaseFile file ); + + private static final List includePatterns; + + static + { + includePatterns = new ArrayList(); + includePatterns.add( "**/*.pom" ); + } + + public List getIncludePatterns() + { + return includePatterns; + } + + public boolean isEnabled() + { + return true; + } + + public void processFile( BaseFile file ) + throws ConsumerException + { + Model model = buildModel( file ); + processModel( model, file ); + } + + private Model buildModel( BaseFile file ) + throws ConsumerException + { + Model model; + Reader reader = null; + try + { + reader = new FileReader( file ); + MavenXpp3Reader modelReader = new MavenXpp3Reader(); + + model = modelReader.read( reader ); + } + catch ( XmlPullParserException e ) + { + throw new ConsumerException( file, "Error parsing metadata file: " + e.getMessage(), e ); + } + catch ( IOException e ) + { + throw new ConsumerException( file, "Error reading metadata file: " + e.getMessage(), e ); + } + finally + { + IOUtil.close( reader ); + } + + return model; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericRepositoryMetadataConsumer.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericRepositoryMetadataConsumer.java new file mode 100644 index 000000000..1f4433c49 --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/consumers/GenericRepositoryMetadataConsumer.java @@ -0,0 +1,231 @@ +package org.apache.maven.archiva.common.consumers; + +/* + * 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.lang.StringUtils; +import org.apache.maven.archiva.common.utils.BaseFile; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata; +import org.apache.maven.artifact.repository.metadata.GroupRepositoryMetadata; +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.RepositoryMetadata; +import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +/** + * GenericRepositoryMetadataConsumer - Consume any maven-metadata.xml files as {@link RepositoryMetadata} objects. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public abstract class GenericRepositoryMetadataConsumer + extends AbstractConsumer + implements Consumer +{ + public abstract void processRepositoryMetadata( RepositoryMetadata metadata, BaseFile file ); + + private static final List includePatterns; + + static + { + includePatterns = new ArrayList(); + includePatterns.add( "**/maven-metadata.xml" ); + } + + public List getIncludePatterns() + { + return includePatterns; + } + + public boolean isEnabled() + { + // the RepositoryMetadata objects only exist in 'default' layout repositories. + ArtifactRepositoryLayout layout = repository.getLayout(); + return ( layout instanceof DefaultRepositoryLayout ); + } + + public void processFile( BaseFile file ) + throws ConsumerException + { + if ( file.length() <= 0 ) + { + throw new ConsumerException( file, "File is empty." ); + } + + if ( !file.canRead() ) + { + throw new ConsumerException( file, "Not allowed to read file due to permission settings on file." ); + } + + RepositoryMetadata metadata = buildMetadata( file ); + processRepositoryMetadata( metadata, file ); + } + + private RepositoryMetadata buildMetadata( BaseFile metadataFile ) + throws ConsumerException + { + Metadata m; + Reader reader = null; + try + { + reader = new FileReader( metadataFile ); + MetadataXpp3Reader metadataReader = new MetadataXpp3Reader(); + + m = metadataReader.read( reader ); + } + catch ( XmlPullParserException e ) + { + throw new ConsumerException( metadataFile, "Error parsing metadata file: " + e.getMessage(), e ); + } + catch ( IOException e ) + { + throw new ConsumerException( metadataFile, "Error reading metadata file: " + e.getMessage(), e ); + } + finally + { + IOUtil.close( reader ); + } + + RepositoryMetadata repositoryMetadata = buildMetadata( m, metadataFile ); + + if ( repositoryMetadata == null ) + { + throw new ConsumerException( metadataFile, "Unable to build a repository metadata from path." ); + } + + return repositoryMetadata; + } + + /** + * Builds a RepositoryMetadata object from a Metadata object and its path. + * + * @param m Metadata + * @param metadataFile file information + * @return RepositoryMetadata if the parameters represent one; null if not + * @throws ConsumerException + */ + private RepositoryMetadata buildMetadata( Metadata m, BaseFile metadataFile ) + throws ConsumerException + { + if ( artifactFactory == null ) + { + throw new IllegalStateException( "Unable to build metadata with a null artifactFactory." ); + } + + String metaGroupId = m.getGroupId(); + String metaArtifactId = m.getArtifactId(); + String metaVersion = m.getVersion(); + + // check if the groupId, artifactId and version is in the + // metadataPath + // parse the path, in reverse order + List pathParts = new ArrayList(); + StringTokenizer st = new StringTokenizer( metadataFile.getRelativePath(), "/\\" ); + while ( st.hasMoreTokens() ) + { + pathParts.add( st.nextToken() ); + } + + Collections.reverse( pathParts ); + // remove the metadata file + pathParts.remove( 0 ); + Iterator it = pathParts.iterator(); + String tmpDir = (String) it.next(); + + Artifact artifact = null; + if ( StringUtils.isNotEmpty( metaVersion ) ) + { + artifact = artifactFactory.createProjectArtifact( metaGroupId, metaArtifactId, metaVersion ); + } + + // snapshotMetadata + RepositoryMetadata metadata = null; + if ( tmpDir != null && tmpDir.equals( metaVersion ) ) + { + if ( artifact != null ) + { + metadata = new SnapshotArtifactRepositoryMetadata( artifact ); + } + } + else if ( tmpDir != null && tmpDir.equals( metaArtifactId ) ) + { + // artifactMetadata + if ( artifact != null ) + { + metadata = new ArtifactRepositoryMetadata( artifact ); + } + else + { + artifact = artifactFactory.createProjectArtifact( metaGroupId, metaArtifactId, "1.0" ); + metadata = new ArtifactRepositoryMetadata( artifact ); + } + } + else + { + String groupDir = ""; + int ctr = 0; + for ( it = pathParts.iterator(); it.hasNext(); ) + { + String path = (String) it.next(); + if ( ctr == 0 ) + { + groupDir = path; + } + else + { + groupDir = path + "." + groupDir; + } + ctr++; + } + + // groupMetadata + if ( metaGroupId != null && metaGroupId.equals( groupDir ) ) + { + metadata = new GroupRepositoryMetadata( metaGroupId ); + } + else + { + /* If we reached this point, we have some bad metadata. + * We have a metadata file, with values for groupId / artifactId / version. + * But the information it is providing does not exist relative to the file location. + * + * See ${basedir}/src/test/repository/javax/maven-metadata.xml for example + */ + throw new ConsumerException( metadataFile, + "Contents of metadata are not appropriate for its location on disk." ); + } + } + + return metadata; + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/BaseFile.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/BaseFile.java new file mode 100644 index 000000000..a4b83db7e --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/BaseFile.java @@ -0,0 +1,105 @@ +package org.apache.maven.archiva.common.utils; + +/* + * 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.io.File; +import java.net.URI; + +/** + * BaseFile - convenient File object that tracks the Base Directory and can provide relative path values + * for the file object based on that Base Directory value. + * + * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> + * @version $Id$ + */ +public class BaseFile + extends File +{ + private File baseDir; + + public BaseFile( File pathFile ) + { + this( pathFile.getAbsolutePath() ); + } + + public BaseFile( File repoDir, File pathFile ) + { + this( repoDir, PathUtil.getRelative( repoDir.getAbsolutePath(), pathFile ) ); + } + + public BaseFile( File parent, String child ) + { + super( parent, child ); + this.baseDir = parent; + } + + public BaseFile( String pathname ) + { + super( pathname ); + + // Calculate the top level directory. + + File parent = this; + while ( parent.getParentFile() != null ) + { + parent = parent.getParentFile(); + } + + this.baseDir = parent; + } + + public BaseFile( String repoDir, File pathFile ) + { + this( new File( repoDir ), pathFile ); + } + + public BaseFile( String parent, String child ) + { + super( parent, child ); + this.baseDir = new File( parent ); + } + + public BaseFile( URI uri ) + { + super( uri ); // only to satisfy java compiler. + throw new IllegalStateException( "The " + BaseFile.class.getName() + + " object does not support URI construction." ); + } + + public File getBaseDir() + { + return baseDir; + } + + public String getRelativePath() + { + return PathUtil.getRelative( this.baseDir.getAbsolutePath(), this ); + } + + public void setBaseDir( File baseDir ) + { + this.baseDir = baseDir; + } + + public void setBaseDir( String repoDir ) + { + setBaseDir( new File( repoDir ) ); + } +} diff --git a/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/PathUtil.java b/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/PathUtil.java new file mode 100644 index 000000000..25df4254a --- /dev/null +++ b/archiva-common/src/main/java/org/apache/maven/archiva/common/utils/PathUtil.java @@ -0,0 +1,56 @@ +package org.apache.maven.archiva.common.utils; + +/* + * 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.io.File; + +/** + * PathUtil - simple utility methods for path manipulation. + * + * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a> + * @version $Id$ + */ +public class PathUtil +{ + public static String getRelative( String basedir, File file ) + { + return getRelative( basedir, file.getAbsolutePath() ); + } + + public static String getRelative( String basedir, String child ) + { + if ( child.startsWith( basedir ) ) + { + // simple solution. + return child.substring( basedir.length() + 1 ); + } + + String absoluteBasedir = new File( basedir ).getAbsolutePath(); + if ( child.startsWith( absoluteBasedir ) ) + { + // resolved basedir solution. + return child.substring( absoluteBasedir.length() + 1 ); + } + + // File is not within basedir. + throw new IllegalStateException( "Unable to obtain relative path of file " + child + + ", it is not within basedir " + basedir + "." ); + } +} |