001    package org.apache.archiva.repository.content.legacy;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.archiva.configuration.ArchivaConfiguration;
023    import org.apache.archiva.configuration.LegacyArtifactPath;
024    import org.apache.archiva.model.ArtifactReference;
025    import org.apache.archiva.repository.content.ArtifactClassifierMapping;
026    import org.apache.archiva.repository.content.PathParser;
027    import org.apache.archiva.repository.content.maven2.ArtifactExtensionMapping;
028    import org.apache.archiva.repository.content.maven2.FilenameParser;
029    import org.apache.archiva.repository.layout.LayoutException;
030    import org.apache.commons.lang.StringUtils;
031    
032    import java.util.Collection;
033    
034    /**
035     * LegacyPathParser is a parser for maven 1 (legacy layout) paths to
036     * ArtifactReference.
037     *
038     *
039     */
040    public class LegacyPathParser
041        implements PathParser
042    {
043        private static final String INVALID_ARTIFACT_PATH = "Invalid path to Artifact: ";
044    
045        protected ArchivaConfiguration configuration;
046    
047        public LegacyPathParser( ArchivaConfiguration configuration )
048        {
049            this.configuration = configuration;
050        }
051    
052    
053        /**
054         * {@inheritDoc}
055         *
056         * @see org.apache.archiva.repository.content.PathParser#toArtifactReference(String)
057         */
058        public ArtifactReference toArtifactReference( String path )
059            throws LayoutException
060        {
061            ArtifactReference artifact = new ArtifactReference();
062    
063            // First, look if a custom resolution rule has been set for this artifact
064            Collection<LegacyArtifactPath> legacy = configuration.getConfiguration().getLegacyArtifactPaths();
065            for ( LegacyArtifactPath legacyPath : legacy )
066            {
067                if ( legacyPath.match( path ) )
068                {
069                    artifact.setGroupId( legacyPath.getGroupId() );
070                    artifact.setArtifactId( legacyPath.getArtifactId() );
071                    artifact.setClassifier( legacyPath.getClassifier() );
072                    artifact.setVersion( legacyPath.getVersion() );
073                    artifact.setType( legacyPath.getType() );
074                    return artifact;
075                }
076            }
077    
078            String normalizedPath = StringUtils.replace( path, "\\", "/" );
079    
080            String pathParts[] = StringUtils.split( normalizedPath, '/' );
081    
082            /* Always 3 parts. (Never more or less)
083             * 
084             *   path = "commons-lang/jars/commons-lang-2.1.jar"
085             *   path[0] = "commons-lang";          // The Group ID
086             *   path[1] = "jars";                  // The Directory Type
087             *   path[2] = "commons-lang-2.1.jar";  // The Filename.
088             */
089    
090            if ( pathParts.length != 3 )
091            {
092                // Illegal Path Parts Length.
093                throw new LayoutException( INVALID_ARTIFACT_PATH
094                                               + "legacy paths should only have 3 parts [groupId]/[type]s/[artifactId]-[version].[type], found "
095                                               + pathParts.length + " instead." );
096            }
097    
098            // The Group ID.
099            artifact.setGroupId( pathParts[0] );
100    
101            // The Expected Type.
102            String expectedType = pathParts[1];
103    
104            // Sanity Check: expectedType should end in "s".
105            if ( !expectedType.endsWith( "s" ) )
106            {
107                throw new LayoutException( INVALID_ARTIFACT_PATH
108                                               + "legacy paths should have an expected type ending in [s] in the second part of the path." );
109            }
110    
111            // The Filename.
112            String filename = pathParts[2];
113    
114            FilenameParser parser = new FilenameParser( filename );
115    
116            artifact.setArtifactId( parser.nextNonVersion() );
117    
118            // Sanity Check: does it have an artifact id?
119            if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
120            {
121                // Special Case: The filename might start with a version id (like "test-arch-1.0.jar").
122                int idx = filename.indexOf( '-' );
123                if ( idx > 0 )
124                {
125                    parser.reset();
126                    // Take the first section regardless of content.
127                    String artifactId = parser.next();
128    
129                    // Is there anything more that is considered not a version id?
130                    String moreArtifactId = parser.nextNonVersion();
131                    if ( StringUtils.isNotBlank( moreArtifactId ) )
132                    {
133                        artifact.setArtifactId( artifactId + "-" + moreArtifactId );
134                    }
135                    else
136                    {
137                        artifact.setArtifactId( artifactId );
138                    }
139                }
140    
141                // Sanity Check: still no artifact id?
142                if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
143                {
144                    throw new LayoutException( INVALID_ARTIFACT_PATH + "no artifact id present." );
145                }
146            }
147    
148            artifact.setVersion( parser.remaining() );
149    
150            // Sanity Check: does it have a version?
151            if ( StringUtils.isEmpty( artifact.getVersion() ) )
152            {
153                // Special Case: use last section of artifactId as version.
154                String artifactId = artifact.getArtifactId();
155                int idx = artifactId.lastIndexOf( '-' );
156                if ( idx > 0 )
157                {
158                    artifact.setVersion( artifactId.substring( idx + 1 ) );
159                    artifact.setArtifactId( artifactId.substring( 0, idx ) );
160                }
161                else
162                {
163                    throw new LayoutException( INVALID_ARTIFACT_PATH + "no version found." );
164                }
165            }
166    
167            String classifier = ArtifactClassifierMapping.getClassifier( expectedType );
168            if ( classifier != null )
169            {
170                String version = artifact.getVersion();
171                if ( !version.endsWith( "-" + classifier ) )
172                {
173                    throw new LayoutException(
174                        INVALID_ARTIFACT_PATH + expectedType + " artifacts must use the classifier " + classifier );
175                }
176                version = version.substring( 0, version.length() - classifier.length() - 1 );
177                artifact.setVersion( version );
178                artifact.setClassifier( classifier );
179            }
180    
181            String extension = parser.getExtension();
182    
183            // Set Type
184            String defaultExtension = expectedType.substring( 0, expectedType.length() - 1 );
185            artifact.setType(
186                ArtifactExtensionMapping.mapExtensionAndClassifierToType( classifier, extension, defaultExtension ) );
187    
188            // Sanity Check: does it have an extension?
189            if ( StringUtils.isEmpty( artifact.getType() ) )
190            {
191                throw new LayoutException( INVALID_ARTIFACT_PATH + "no extension found." );
192            }
193    
194            // Special Case with Maven Plugins
195            if ( StringUtils.equals( "jar", extension ) && StringUtils.equals( "plugins", expectedType ) )
196            {
197                artifact.setType( ArtifactExtensionMapping.MAVEN_ONE_PLUGIN );
198            }
199            else
200            {
201                // Sanity Check: does extension match pathType on path?
202                String expectedExtension = ArtifactExtensionMapping.getExtension( artifact.getType() );
203    
204                if ( !expectedExtension.equals( extension ) )
205                {
206                    throw new LayoutException(
207                        INVALID_ARTIFACT_PATH + "mismatch on extension [" + extension + "] and layout specified type ["
208                            + artifact.getType() + "] (which maps to extension: [" + expectedExtension + "]) on path ["
209                            + path + "]" );
210                }
211            }
212    
213            return artifact;
214        }
215    }