/*
* Copyright 2007 Alin Dreghiciu.
* Copyright 2010,2011 Toni Menzel.
*
* Licensed 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.
*/
package org.apache.karaf.util.maven;
import java.net.MalformedURLException;
import java.util.Map;
/**
* Parser for mvn: protocol.
*
* @author Alin Dreghiciu
* @author Toni Menzel
*
* @since August 10, 2007
*/
public class Parser
{
/**
* Default version if none present in the url.
*/
public static final String VERSION_LATEST = "LATEST";
/**
* Syntax for the url; to be shown on exception messages.
*/
private static final String SYNTAX = "mvn:[repository_url!]groupId/artifactId[/[version]/[type]]";
/**
* Separator between repository and artifact definition.
*/
private static final String REPOSITORY_SEPARATOR = "!";
/**
* Artifact definition segments separator.
*/
private static final String ARTIFACT_SEPARATOR = "/";
/**
* Snapshot version
*/
private static final String VERSION_SNAPSHOT = "SNAPSHOT";
/**
* Default type if not present in the url.
*/
private static final String TYPE_JAR = "jar";
/**
* Final artifact path separator.
*/
public static final String FILE_SEPARATOR = "/";
/**
* Group id path separator.
*/
private static final String GROUP_SEPARATOR = "\\.";
/**
* Separator used to constructs the artifact file name.
*/
private static final String VERSION_SEPARATOR = "-";
/**
* Artifact extension(type) separator.
*/
private static final String TYPE_SEPARATOR = ".";
/**
* Separator used to separate classifier in artifact name.
*/
private static final String CLASSIFIER_SEPARATOR = "-";
/**
* Maven metadata file.
*/
private static final String METADATA_FILE = "maven-metadata.xml";
/**
* Maven local metadata file.
*/
private static final String METADATA_FILE_LOCAL = "maven-metadata-local.xml";
/**
* Repository URL. Null if not present.
*/
private String m_repositoryURL;
/**
* Artifact group id.
*/
private String m_group;
/**
* Artifact id.
*/
private String m_artifact;
/**
* Artifact version.
*/
private String m_version;
/**
* Artifact type.
*/
private String m_type;
/**
* Artifact classifier.
*/
private String m_classifier;
/**
* Artifact classifier to use to build artifact name.
*/
private String m_fullClassifier;
/**
* Creates a new protocol parser.
*
* @param path the path part of the url (without starting mvn:)
* @throws MalformedURLException if provided path does not comply to expected syntax or an malformed repository URL
*/
public Parser( final String path )
throws MalformedURLException
{
if( path == null )
{
throw new MalformedURLException( "Path cannot be null. Syntax " + SYNTAX );
}
if( path.startsWith( REPOSITORY_SEPARATOR ) || path.endsWith( REPOSITORY_SEPARATOR ) )
{
throw new MalformedURLException(
"Path cannot start or end with " + REPOSITORY_SEPARATOR + ". Syntax " + SYNTAX
);
}
if( path.contains( REPOSITORY_SEPARATOR ) )
{
int pos = path.lastIndexOf( REPOSITORY_SEPARATOR );
parseArtifactPart( path.substring( pos + 1 ) );
m_repositoryURL = path.substring( 0, pos ) + "@snapshots";
}
else
{
parseArtifactPart( path );
}
}
/**
* Return the artifact path from the given maven uri.
* @param uri the Maven URI.
* @return the artifact actual path.
* @throws MalformedURLException in case of "bad" provided URL/URI.
*/
public static String pathFromMaven(String uri) throws MalformedURLException {
return pathFromMaven(uri, null);
}
public static String pathFromMaven(String uri, String resolved) throws MalformedURLException {
if (!uri.startsWith("mvn:")) {
return uri;
}
Parser parser = new Parser(uri.substring("mvn:".length()));
if (resolved != null) {
String grp = FILE_SEPARATOR
+ parser.getGroup().replaceAll(GROUP_SEPARATOR, FILE_SEPARATOR)
+ FILE_SEPARATOR
+ parser.getArtifact()
+ FILE_SEPARATOR;
int idx = resolved.indexOf(grp);
if (idx >= 0) {
String version = resolved.substring(idx + grp.length(), resolved.indexOf('/', idx + grp.length()));
return parser.getArtifactPath(version);
}
}
return parser.getArtifactPath();
}
public static String pathToMaven(String location, Map parts) {
String[] p = location.split("/");
if (p.length >= 4 && p[p.length-1].startsWith(p[p.length-3] + "-" + p[p.length-2])) {
String artifactId = p[p.length-3];
String version = p[p.length-2];
String classifier;
String type;
String artifactIdVersion = artifactId + "-" + version;
StringBuilder sb = new StringBuilder();
if (p[p.length-1].charAt(artifactIdVersion.length()) == '-') {
classifier = p[p.length-1].substring(artifactIdVersion.length() + 1, p[p.length-1].lastIndexOf('.'));
} else {
classifier = null;
}
type = p[p.length-1].substring(p[p.length-1].lastIndexOf('.') + 1);
sb.append("mvn:");
if (parts != null) {
parts.put("artifactId", artifactId);
parts.put("version", version);
parts.put("classifier", classifier);
parts.put("type", type);
}
for (int j = 0; j < p.length - 3; j++) {
if (j > 0) {
sb.append('.');
}
sb.append(p[j]);
}
sb.append('/').append(artifactId).append('/').append(version);
if (!"jar".equals(type) || classifier != null) {
sb.append('/');
if (!"jar".equals(type)) {
sb.append(type);
}
if (classifier != null) {
sb.append('/').append(classifier);
}
}
return sb.toString();
}
return location;
}
public static String pathToMaven(String location) {
return pathToMaven(location, null);
}
/**
* Parse the artifact part of the url (without the repository).
*
* @param part url part without protocol and repository.
* @throws MalformedURLException if provided path does not comply to syntax.
*/
private void parseArtifactPart( final String part )
throws MalformedURLException
{
String[] segments = part.split( ARTIFACT_SEPARATOR );
if( segments.length < 2 )
{
throw new MalformedURLException( "Invalid path. Syntax " + SYNTAX );
}
// we must have a valid group
m_group = segments[ 0 ];
if( m_group.trim().length() == 0 )
{
throw new MalformedURLException( "Invalid groupId. Syntax " + SYNTAX );
}
// valid artifact
m_artifact = segments[ 1 ];
if( m_artifact.trim().length() == 0 )
{
throw new MalformedURLException( "Invalid artifactId. Syntax " + SYNTAX );
}
// version is optional but we have a default value
m_version = VERSION_LATEST;
if( segments.length >= 3 && segments[ 2 ].trim().length() > 0 )
{
m_version = segments[ 2 ];
}
// type is optional but we have a default value
m_type = TYPE_JAR;
if( segments.length >= 4 && segments[ 3 ].trim().length() > 0 )
{
m_type = segments[ 3 ];
}
// classifier is optional (if not present or empty we will have a null classifier
m_fullClassifier = "";
if( segments.length >= 5 && segments[ 4 ].trim().length() > 0 )
{
m_classifier = segments[ 4 ];
m_fullClassifier = CLASSIFIER_SEPARATOR + m_classifier;
}
}
/**
* Return the repository URL if present, null otherwise.
*
* @return repository URL.
*/
public String getRepositoryURL()
{
return m_repositoryURL;
}
/**
* Return the group id of the artifact.
*
* @return group ID.
*/
public String getGroup()
{
return m_group;
}
/**
* Return the artifact id.
*
* @return artifact id.
*/
public String getArtifact()
{
return m_artifact;
}
/**
* Return the artifact version.
*
* @return version.
*/
public String getVersion()
{
return m_version;
}
/**
* Return the artifact type.
*
* @return type.
*/
public String getType()
{
return m_type;
}
/**
* Return the artifact classifier.
*
* @return classifier.
*/
public String getClassifier()
{
return m_classifier;
}
/**
* Return the complete path to artifact as stated by Maven 2 repository layout.
*
* @return artifact path.
*/
public String getArtifactPath()
{
return getArtifactPath( m_version );
}
/**
* Return the complete path to artifact as stated by Maven 2 repository layout.
*
* @param version The version of the artifact.
* @return artifact path.
*/
public String getArtifactPath( final String version )
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( version )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( VERSION_SEPARATOR )
.append( version )
.append( m_fullClassifier )
.append( TYPE_SEPARATOR )
.append( m_type )
.toString();
}
/**
* Return the version for an artifact for a snapshot version.
*
* @param version The version of the snapshot.
* @param timestamp The timestamp of the snapshot.
* @param buildnumber The buildnumber of the snapshot.
* @return artifact path.
*/
public String getSnapshotVersion( final String version, final String timestamp, final String buildnumber )
{
return version.replace( VERSION_SNAPSHOT, timestamp ) + VERSION_SEPARATOR + buildnumber;
}
/**
* Return the complete path to artifact for a snapshot file.
*
* @param version The version of the snapshot.
* @param timestamp The timestamp of the snapshot.
* @param buildnumber The buildnumber of the snapshot.
* @return artifact path.
*/
public String getSnapshotPath( final String version, final String timestamp, final String buildnumber )
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( version )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( VERSION_SEPARATOR )
.append( getSnapshotVersion( version, timestamp, buildnumber ) )
.append( m_fullClassifier )
.append( TYPE_SEPARATOR )
.append( m_type )
.toString();
}
/**
* Return the path to metadata file corresponding to this artifact version.
*
* @param version The version of the the metadata.
* @return metadata file path.
*/
public String getVersionMetadataPath( final String version )
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( version )
.append( FILE_SEPARATOR )
.append( METADATA_FILE )
.toString();
}
/**
* Return the path to local metadata file corresponding to this artifact version.
*
* @param version The version of the the metadata.
* @return metadata file path.
*/
public String getVersionLocalMetadataPath( final String version )
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( version )
.append( FILE_SEPARATOR )
.append( METADATA_FILE_LOCAL )
.toString();
}
/**
* Return the complete path to artifact local metadata file.
*
* @return artifact path.
*/
public String getArtifactLocalMetdataPath()
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( METADATA_FILE_LOCAL )
.toString();
}
/**
* Return the complete path to artifact metadata file.
*
* @return artifact path.
*/
public String getArtifactMetdataPath()
{
return new StringBuilder()
.append( m_group.replaceAll( GROUP_SEPARATOR, FILE_SEPARATOR ) )
.append( FILE_SEPARATOR )
.append( m_artifact )
.append( FILE_SEPARATOR )
.append( METADATA_FILE )
.toString();
}
}