Java tutorial
package org.ops4j.pax.construct.util; /* * Copyright 2007 Stuart McCulloch, Alin Dreghiciu * * 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. */ import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.OverConstrainedVersionException; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.model.Dependency; import org.apache.maven.model.Repository; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; /** * Provide API {@link Pom} and factory for editing Maven project files */ public final class PomUtils { /** * Hide constructor for utility class */ private PomUtils() { /* * nothing to do */ } /** * API for editing Maven project files */ public interface Pom { /** * @return unique project identifier */ String getId(); /** * @return parents' unique project identifier */ String getParentId(); /** * @return project group id */ String getGroupId(); /** * @return project artifact id */ String getArtifactId(); /** * @return project version */ String getVersion(); /** * @return project packaging */ String getPackaging(); /** * @return names of modules contained in this project */ List getModuleNames(); /** * @return the physical parent project */ Pom getContainingPom(); /** * @param module name of a module in this project * @return the module POM, null if it doesn't exist */ Pom getModulePom(String module); /** * @return the underlying Maven POM file */ File getFile(); /** * @return the directory containing this Maven project */ File getBasedir(); /** * @return true if this is an OSGi bundle project, otherwise false */ boolean isBundleProject(); /** * @return the symbolic name for this project, null if it doesn't define one */ String getBundleSymbolicName(); /** * @param pom the new logical parent project * @param relativePath the relative path from this POM to its new parent * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @throws ExistingElementException */ void setParent(Pom pom, String relativePath, boolean overwrite) throws ExistingElementException; /** * @param project the new logical parent project * @param relativePath the relative path from this POM to the parent * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @throws ExistingElementException */ void setParent(MavenProject project, String relativePath, boolean overwrite) throws ExistingElementException; /** * @param newGroupId the new project group id */ void setGroupId(String newGroupId); /** * @param newVersion the new project version */ void setVersion(String newVersion); /** * @param repository a Maven repository * @param snapshots enable snapshots for this repository * @param releases enable releases for this repository * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @param pluginRepo treat as plugin repository if true, otherwise assume normal repository * @throws ExistingElementException */ void addRepository(Repository repository, boolean snapshots, boolean releases, boolean overwrite, boolean pluginRepo) throws ExistingElementException; /** * @param module module name * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @throws ExistingElementException */ void addModule(String module, boolean overwrite) throws ExistingElementException; /** * @param module module name * @return true if module was removed from the project, otherwise false */ boolean removeModule(String module); /** * @param dependency project dependency * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @throws ExistingElementException */ void addDependency(Dependency dependency, boolean overwrite) throws ExistingElementException; /** * @param dependency project dependency * @param newGroupId updated dependency group id * @return true if the dependency was updated */ boolean updateDependencyGroup(Dependency dependency, String newGroupId); /** * @param dependency project dependency * @return true if dependency was removed from the project, otherwise false */ boolean removeDependency(Dependency dependency); /** * @param groupId dependency exclusion group id * @param artifactId dependency exclusion artifact id * @param overwrite overwrite element if true, otherwise throw {@link ExistingElementException} * @throws ExistingElementException */ void addExclusion(String groupId, String artifactId, boolean overwrite) throws ExistingElementException; /** * @param groupId dependency exclusion group id * @param artifactId dependency exclusion artifact id * @return true if dependency exclusion was removed from the project, otherwise false */ boolean removeExclusion(String groupId, String artifactId); /** * @return properties defined by the current project */ Properties getProperties(); /** * @param key property key * @param value property value */ void setProperty(String key, String value); /** * @param groupId plugin group id * @param artifactId plugin artifact id * @param newVersion new plugin version * @return true if the plugin was updated */ boolean updatePluginVersion(String groupId, String artifactId, String newVersion); /** * Merge a section of XML from another Maven project POM * * @param pom another Maven project * @param fromSection path to XML section to merge from * @param toSection path to XML section to merge into * @param append when true, append instead of merging */ void mergeSection(Pom pom, String fromSection, String toSection, boolean append); /** * Overlay POM template with detail from another Maven project POM * * @param pom another Maven project */ void overlayDetails(Pom pom); /** * @throws IOException */ void write() throws IOException; } /** * Thrown when a POM element already exists and can't be overwritten {@link Pom} */ public static class ExistingElementException extends RuntimeException { private static final long serialVersionUID = 1L; /** * @param element name of the existing POM element */ public ExistingElementException(String element) { super("Project already has a <" + element + "> which matches, use -Doverwrite or -o to replace it"); } /** * {@inheritDoc} */ public synchronized Throwable fillInStackTrace() { return this; } /** * {@inheritDoc} */ public String toString() { return "[INFO] not available"; } } /** * Factory method that provides an editor for an existing Maven project file * * @param here a Maven POM, or a directory containing a file named 'pom.xml' * @return simple Maven project editor * @throws IOException */ public static Pom readPom(File here) throws IOException { File candidate = here; if (null == here) { throw new IOException("null location"); } else if (here.isDirectory()) { candidate = new File(here, "pom.xml"); } return new XppPom(candidate); } /** * Factory method that provides an editor for a new Maven project file * * @param here the file, or directory for the new Maven project * @param groupId project group id * @param artifactId project artifact id * @return simple Maven project editor * @throws IOException */ public static Pom createModulePom(File here, String groupId, String artifactId) throws IOException { File candidate = here; if (null == here) { throw new IOException("null location"); } else if (here.isDirectory()) { candidate = new File(here, "pom.xml"); } return new XppPom(candidate, groupId, artifactId); } /** * @param project Maven project * @return true if this is an OSGi bundle project, otherwise false */ public static boolean isBundleProject(MavenProject project) { return isBundleProject(project, null, null, null, false); } /** * @param project Maven project * @param resolver artifact resolver * @param remoteRepos sequence of remote repositories * @param localRepo local Maven repository * @param testMetadata check jar manifest for OSGi attributes if true * @return true if this is an OSGi bundle project, otherwise false */ public static boolean isBundleProject(MavenProject project, ArtifactResolver resolver, List remoteRepos, ArtifactRepository localRepo, boolean testMetadata) { String packaging = project.getPackaging(); if (packaging != null && packaging.indexOf("bundle") >= 0) { return true; } return isBundleArtifact(project.getArtifact(), resolver, remoteRepos, localRepo, testMetadata); } /** * @param artifact Maven artifact * @param resolver artifact resolver * @param remoteRepos sequence of remote repositories * @param localRepo local Maven repository * @param testMetadata check jar manifest for OSGi attributes if true * @return true if this is an OSGi bundle artifact, otherwise false */ public static boolean isBundleArtifact(Artifact artifact, ArtifactResolver resolver, List remoteRepos, ArtifactRepository localRepo, boolean testMetadata) { if (null == artifact) { return false; } String type = artifact.getType(); if (null != type && type.indexOf("bundle") >= 0) { return true; } else if (!testMetadata || !downloadFile(artifact, resolver, remoteRepos, localRepo)) { return false; } try { return isBundleArtifact(new JarFile(artifact.getFile()).getManifest()); } catch (IOException e) { return false; } } /** * @param manifest jar manifest, possibly null * @return true if this is an OSGi bundle artifact, otherwise false */ private static boolean isBundleArtifact(Manifest manifest) { if (null == manifest) { return false; } Attributes mainAttributes = manifest.getMainAttributes(); return mainAttributes.getValue("Bundle-SymbolicName") != null || mainAttributes.getValue("Bundle-Name") != null; } /** * Look for the artifact in local Maven repository * * @param artifact Maven artifact * @param resolver artifact resolver * @param localRepo local Maven repository * @return true if the artifact is available, otherwise false */ public static boolean getFile(Artifact artifact, ArtifactResolver resolver, ArtifactRepository localRepo) { return downloadFile(artifact, resolver, Collections.EMPTY_LIST, localRepo); } /** * Look for the artifact in local and remote Maven repositories * * @param artifact Maven artifact * @param resolver artifact resolver * @param remoteRepos sequence of remote repositories * @param localRepo local Maven repository * @return true if the artifact is available, otherwise false */ public static boolean downloadFile(Artifact artifact, ArtifactResolver resolver, List remoteRepos, ArtifactRepository localRepo) { if (artifact.getFile() == null || !artifact.getFile().exists()) { try { resolver.resolve(artifact, remoteRepos, localRepo); } catch (AbstractArtifactResolutionException e) { return false; } catch (NullPointerException e) { return false; } } return true; } /** * Try to combine overlapping group and artifact identifiers to remove duplicate elements * * @param groupId project group id * @param artifactId project artifact id * @return the combined group and artifact sequence */ public static String getCompoundId(String groupId, String artifactId) { // treat any dashes like dots String lhs = groupId.replace('-', '.'); String rhs = artifactId.replace('-', '.'); // simple common prefix check if (rhs.equals(lhs) || rhs.startsWith(lhs + '.')) { return artifactId; } rhs = '.' + rhs; // optimization when testing for overlap // check for overlapping segments by repeated chopping of artifactId for (int i = rhs.length(); i > 0; i = rhs.lastIndexOf('.', i - 1)) { if (lhs.endsWith(rhs.substring(0, i))) { if (rhs.length() == i) { return groupId; } return groupId + '.' + artifactId.substring(i); } } // no common segments, so append return groupId + '.' + artifactId; } /** * Find the symbolic (meta) Maven version, such as 1.0-SNAPSHOT * * @param artifact Maven artifact * @return meta version for the artifact */ public static String getMetaVersion(Artifact artifact) { if (artifact.isSnapshot()) { try { return artifact.getSelectedVersion().toString(); } catch (OverConstrainedVersionException e) { return artifact.getVersion(); } catch (NullPointerException e) { return artifact.getVersion(); } } return artifact.getVersion(); } /** * @param version project version * @return true if we need to resolve this version */ public static boolean needReleaseVersion(String version) { return isEmpty(version) || "RELEASE".equals(version) || "LATEST".equals(version); } /** * @param artifact Maven artifact * @param source metadata source * @param remoteRepos sequence of remote repositories * @param localRepo local Maven repository * @param range acceptable versions * @return the release version if available, otherwise throws {@link MojoExecutionException} * @throws MojoExecutionException */ public static String getReleaseVersion(Artifact artifact, ArtifactMetadataSource source, List remoteRepos, ArtifactRepository localRepo, VersionRange range) throws MojoExecutionException { try { List versions = source.retrieveAvailableVersions(artifact, localRepo, remoteRepos); ArtifactVersion releaseVersion = getLatestReleaseInRange(versions, range); if (null == releaseVersion) { throw new MojoExecutionException("Unable to find release version for " + artifact); } return releaseVersion.toString(); } catch (ArtifactMetadataRetrievalException e) { throw new MojoExecutionException("Unable to find artifact " + artifact); } } /** * @param versions list of available versions * @param range acceptable range of versions * @return latest acceptable release, otherwise null */ private static ArtifactVersion getLatestReleaseInRange(List versions, VersionRange range) { final ArtifactVersion baseline = new DefaultArtifactVersion("0"); ArtifactVersion releaseVersion = baseline; for (Iterator i = versions.iterator(); i.hasNext();) { ArtifactVersion v = (ArtifactVersion) i.next(); if (isCompatible(range, v) && releaseVersion.compareTo(v) <= 0) { releaseVersion = v; } } // no compatible version found if (baseline == releaseVersion) { return null; } return releaseVersion; } /** * @param range compatible range * @param version candidate version * @return true if this version is compatible, otherwise false */ private static boolean isCompatible(VersionRange range, ArtifactVersion version) { if (version.getMajorVersion() > 10000000 || ArtifactUtils.isSnapshot(version.toString())) { return false; // ignore snapshots and possible timestamped releases } else if (range != null && !range.containsVersion(version)) { return false; // ignore this version as it's not compatible } return true; } /** * @param param Maven plugin parameter * @return true if parameter is empty, otherwise false */ public static boolean isEmpty(String param) { return null == param || param.trim().length() == 0; } /** * @param param Maven plugin parameter * @return false if parameter is empty, otherwise true */ public static boolean isNotEmpty(String param) { return null != param && param.trim().length() > 0; } }