lu.softec.maven.mavenizer.mavenfile.internal.DefaultMavenFileFactory.java Source code

Java tutorial

Introduction

Here is the source code for lu.softec.maven.mavenizer.mavenfile.internal.DefaultMavenFileFactory.java

Source

/*
 * Copyright 2010 SOFTEC sa. All rights reserved.
 *
 * 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 lu.softec.maven.mavenizer.mavenfile.internal;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Model;
import org.apache.maven.project.validation.ModelValidationResult;
import org.apache.maven.project.validation.ModelValidator;
import org.apache.maven.shared.jar.JarAnalyzer;
import org.apache.maven.shared.jar.identification.JarIdentification;
import org.apache.maven.shared.jar.identification.JarIdentificationAnalysis;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;

import lu.softec.maven.mavenizer.analyzer.dependency.FileDependencySet;
import lu.softec.maven.mavenizer.mavenfile.FileMavenInfo;
import lu.softec.maven.mavenizer.mavenfile.InvalidMavenCoordinatesException;
import lu.softec.maven.mavenizer.mavenfile.MavenFile;
import lu.softec.maven.mavenizer.mavenfile.MavenFileFactory;
import lu.softec.maven.mavenizer.mavenfile.MavenFileSet;

/**
 * Default implementation of the {@link MavenFileFactory} interface.
 *
 * This implementation is a singleton and keep hard references to all created instances of {@link MavenFile}. It ensure
 * only one {@link MavenFile} instance is created for a given {@link File}, and that any subsequent request matches the
 * initially created instance.
 */
public class DefaultMavenFileFactory implements MavenFileFactory {
    /**
     * Artifact Factory populated by Plexus
     */
    private ArtifactFactory artifactFactory;

    /**
     * Artifact Resolver populated by Plexus
     */
    private ArtifactResolver artifactResolver;

    /**
     * ModelValidator populated by Plexus
     */
    private ModelValidator modelValidator;

    /**
     * JarIdentificationAnalysis populated by Plexus
     */
    private JarIdentificationAnalysis jarIdentificationAnalysis;

    /**
     * Hints for creating new instances
     */
    private final Map fileMavenInfo = new HashMap();

    /**
     * Map of all existing instances of {@link MavenFile} constructed by this factory
     */
    private static final Map mavenFiles = new HashMap();

    public void addMavenInfo(FileMavenInfo info) {
        fileMavenInfo.put(info.getName(), info);
    }

    public FileMavenInfo getMavenInfo(String name) {
        return (FileMavenInfo) fileMavenInfo.get(name);
    }

    public MavenFileSet getMavenFileSet(FileDependencySet fileSet) throws IOException,
            InvalidMavenCoordinatesException, ArtifactResolutionException, ArtifactNotFoundException {
        InternalMavenFileSet mavenFiles = new InternalMavenFileSet();

        for (Iterator it = fileSet.iterator(); it.hasNext();) {
            FileDependencySet.FilePair pair = (FileDependencySet.FilePair) it.next();

            InternalMavenFile from = (InternalMavenFile) getMavenFile(pair.getFromFile());
            mavenFiles.add(from);

            if (pair.getToFile() != null) {
                MavenFile to = getMavenFile(pair.getToFile());
                from.addDependency(to);
            }
        }

        return mavenFiles;
    }

    public MavenFile getMavenFile(File file) throws IOException, InvalidMavenCoordinatesException,
            ArtifactResolutionException, ArtifactNotFoundException {
        if (mavenFiles.containsKey(file)) {
            return (MavenFile) mavenFiles.get(file);
        }

        JarIdentification id = getJarIdentification(file);
        FileMavenInfo info = getFileMavenInfo(file, id.getArtifactId());

        return getMavenFile(file,
                (info.getGroupId() != null) ? info.getGroupId()
                        : getCommonPrefix(id.getGroupId(), id.getPotentialGroupIds()),
                (info.getArtifactId() != null) ? info.getArtifactId() : id.getArtifactId(),
                (info.getVersion() != null) ? info.getVersion() : id.getVersion(),
                (info.getClassifier() != null) ? info.getClassifier() : null, null, null, null);
    }

    public MavenFile getMavenFile(File libfile, String groupId, String artifactId, String version,
            String classifier, MavenFileSet deps, ArtifactRepository repository, List remoteRepositories)
            throws InvalidMavenCoordinatesException, ArtifactResolutionException, ArtifactNotFoundException {
        File file = libfile;

        // If no local file is provided, try to resolve missing artifact from local or remote repositories
        if (file == null) {
            if (repository == null) {
                return null;
            }
            Artifact artifact = artifactFactory.createArtifactWithClassifier(groupId, artifactId, version, "jar",
                    classifier);

            if (!artifact.isResolved() && remoteRepositories != null) {
                artifactResolver.resolve(artifact, remoteRepositories, repository);
            }
            file = artifact.getFile();

            if (file == null) {
                // Should never happen
                throw new ArtifactNotFoundException("No file available after artifact resolution", artifact);
            }
        }

        // If maven file already exists, than check it for consistencies and return the existing one
        if (mavenFiles.containsKey(file)) {
            InternalMavenFile mvnFile = (InternalMavenFile) mavenFiles.get(file);
            if (!StringUtils.equals(mvnFile.getGroupId(), groupId)
                    || !StringUtils.equals(mvnFile.getArtifactId(), artifactId)
                    || !StringUtils.equals(mvnFile.getVersion(), version)
                    || !StringUtils.equals(mvnFile.getClassifier(), classifier) || (deps != null
                            && mvnFile.getDependencies().size() != 0 && !deps.equals(mvnFile.getDependencies()))) {
                throw new IllegalArgumentException(
                        "The instance requested mismatch with a previously existing instance for file "
                                + file.getAbsolutePath());
            }

            if (deps != null && mvnFile.getDependencies().size() == 0) {
                mvnFile.setDependencies(deps);
            }

            return mvnFile;
        }

        // Create a new maven file instance
        MavenFile mvnFile = new InternalMavenFile(file, groupId, artifactId, version, classifier, deps);

        // If the file has been provided, ensure proper maven coordinates has been used
        if (libfile != null) {
            validateArtifactInformation(mvnFile);
        }

        // Remember this new instance for future request
        mavenFiles.put(file, mvnFile);
        return mvnFile;
    }

    /**
     * Validate coordinates of a {@link MavenFile} using the {@link ModelValidator}
     *
     * @param file {@link MavenFile} to be validated
     * @throws InvalidMavenCoordinatesException when validation fails
     */
    private void validateArtifactInformation(MavenFile file) throws InvalidMavenCoordinatesException {
        Model model = file.getMinimalModel();

        ModelValidationResult result = modelValidator.validate(model);

        if (result.getMessageCount() > 0) {
            throw new InvalidMavenCoordinatesException(
                    "Coordinates are incomplete or not valid:\n" + result.render("  "));
        }
    }

    public JarIdentification getJarIdentification(File file) throws IOException {
        JarAnalyzer jar = new JarAnalyzer(file);
        return (jarIdentificationAnalysis.analyze(jar));
    }

    public FileMavenInfo getFileMavenInfo(File file, String artifactId) {
        // Get file specific info
        FileMavenInfo info = (FileMavenInfo) fileMavenInfo.get(FileUtils.removeExtension(file.getName()));
        // Get artefact specific info
        if (info == null && artifactId != null) {
            info = (FileMavenInfo) fileMavenInfo.get(artifactId);
        }
        // Get default info
        if (info == null) {
            info = (FileMavenInfo) fileMavenInfo.get(null);
        }
        // Get empty info
        if (info == null) {
            info = FileMavenInfo.NOINFO;
        }
        return info;
    }

    private static String getCommonPrefix(String initialPrefix, List strings) {
        if (strings == null) {
            return initialPrefix;
        }

        String prefix = initialPrefix;
        Iterator it = strings.iterator();
        if (isIgnored(prefix)) {
            prefix = findNextPotentialId(it);
        }

        while (it.hasNext()) {
            int pl = getCommonPrefixLength(prefix, findNextPotentialId(it));
            if (pl != -1) {
                if (pl == 0 || pl < prefix.length()) {
                    int p = prefix.lastIndexOf('.', pl);
                    if (p == -1) {
                        if (isIgnored(initialPrefix)) {
                            return prefix;
                        } else {
                            return initialPrefix;
                        }
                    }
                    prefix = prefix.substring(0, p);
                }
            }
        }

        if (prefix == null || prefix.length() == 0) {
            return initialPrefix;
        }

        return prefix;
    }

    private static boolean isIgnored(String s) {
        return (s == null || s.startsWith("java.") || s.startsWith("javax.") || s.startsWith("com.sun.")
                || s.startsWith("org.xml.sax.") || s.startsWith("org.omg.") || s.startsWith("org.w3c.dom.")
                || s.indexOf("log4j") != -1);
    }

    private static String findNextPotentialId(Iterator it) {
        while (it.hasNext()) {
            String s = (String) it.next();
            if (!isIgnored(s)) {
                return s;
            }
        }
        return null;
    }

    private static int getCommonPrefixLength(String s, String t) {
        if (s == null || t == null || s.length() == 0 || t.length() == 0) {
            return -1;
        }

        int m = Math.min(s.length(), t.length());
        for (int k = 0; k < m; ++k) {
            if (s.charAt(k) != t.charAt(k)) {
                return k;
            }
        }
        return m;
    }
}