| /* |
| * 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. |
| */ |
| package org.apache.sling.maven.slingstart; |
| |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.maven.MavenExecutionException; |
| import org.apache.maven.artifact.Artifact; |
| import org.apache.maven.artifact.DefaultArtifact; |
| import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; |
| 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.artifact.versioning.VersionRange; |
| import org.apache.maven.execution.MavenSession; |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.sling.provisioning.model.ArtifactGroup; |
| import org.apache.sling.provisioning.model.Feature; |
| import org.apache.sling.provisioning.model.MergeUtility; |
| import org.apache.sling.provisioning.model.Model; |
| import org.apache.sling.provisioning.model.ModelConstants; |
| import org.apache.sling.provisioning.model.ModelResolveUtility; |
| import org.apache.sling.provisioning.model.ModelUtility; |
| import org.apache.sling.provisioning.model.ModelUtility.ResolverOptions; |
| import org.apache.sling.provisioning.model.RunMode; |
| import org.apache.sling.provisioning.model.Traceable; |
| import org.apache.sling.provisioning.model.io.ModelReader; |
| import org.codehaus.plexus.logging.Logger; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| |
| public class ModelPreprocessor { |
| |
| public static final class ProjectInfo { |
| |
| public MavenProject project; |
| public Plugin plugin; |
| public Model localModel; |
| public boolean done = false; |
| public Model model; |
| public boolean extendMavenClassPath = true; |
| public final Map<org.apache.sling.provisioning.model.Artifact, Model> includedModels = new HashMap<>(); |
| |
| } |
| |
| public static final class Environment { |
| public ArtifactHandlerManager artifactHandlerManager; |
| public ArtifactResolver resolver; |
| public MavenSession session; |
| public Logger logger; |
| public final Map<String, ProjectInfo> modelProjects = new HashMap<>(); |
| } |
| |
| /** |
| * Add dependencies for all projects. |
| * @param env The environment with all maven settings and projects |
| * @throws MavenExecutionException If anything goes wrong. |
| */ |
| public void addDependencies(final Environment env) throws MavenExecutionException { |
| for(final ProjectInfo info : env.modelProjects.values()) { |
| addDependencies(env, info); |
| } |
| } |
| |
| /** |
| * Add dependencies for a single project. |
| * @param env The environment with all maven settings and projects |
| * @param info The project to process. |
| * @throws MavenExecutionException If anything goes wrong. |
| */ |
| private Model addDependencies(final Environment env, final ProjectInfo info) |
| throws MavenExecutionException { |
| if ( info.done == true ) { |
| env.logger.debug("Return prepared model for " + info.project); |
| return info.model; |
| } |
| // prevent recursion and multiple processing |
| info.done = true; |
| env.logger.debug("Processing project " + info.project); |
| |
| // read local model |
| final String pattern = nodeValue(info.plugin, |
| "modelPattern", AbstractSlingStartMojo.DEFAULT_MODEL_PATTERN); |
| |
| final String inlinedModel = nodeValue(info.plugin, |
| "model", null); |
| |
| String scope = Artifact.SCOPE_PROVIDED; |
| try { |
| if (hasNodeValue(info.plugin, "modelDirectory")) { |
| final String directory = nodeValue(info.plugin, |
| "modelDirectory", null); |
| info.localModel = readLocalModel(info.project, inlinedModel, new File(directory), pattern, env.logger); |
| } else { |
| // use multiple fallbacks here only in case the default model directory is not explicitly set |
| File defaultModelDirectory = new File(info.project.getBasedir(), "src/main/provisioning"); |
| if (defaultModelDirectory.exists()) { |
| env.logger.debug("Try to extract model from default provisioning directory " + defaultModelDirectory.getAbsolutePath()); |
| info.localModel = readLocalModel(info.project, inlinedModel, defaultModelDirectory, pattern, env.logger); |
| } else { |
| File defaultModelDirectoryInTest = new File(info.project.getBasedir(), "src/test/provisioning"); |
| env.logger.debug("Try to extract model from default test provisioning directory " + defaultModelDirectoryInTest.getAbsolutePath()); |
| info.localModel = readLocalModel(info.project, inlinedModel, defaultModelDirectoryInTest, pattern, env.logger); |
| scope = Artifact.SCOPE_TEST; |
| } |
| } |
| } catch ( final IOException ioe) { |
| throw new MavenExecutionException(ioe.getMessage(), ioe); |
| } |
| |
| // process attachments |
| processAttachments(env, info); |
| |
| // is the maven classpath supposed to be extended? |
| info.extendMavenClassPath = !nodeBooleanValue(info.plugin, AbstractSlingStartMojo.CONFIGURATION_NAME_DISABLE_EXTENDING_CLASSPATH, false); |
| |
| // check for setting version |
| if ( nodeBooleanValue(info.plugin, "setFeatureVersions", false) ) { |
| for(final Feature f : info.localModel.getFeatures() ) { |
| if ( f.getVersion() == null ) { |
| f.setVersion(cleanupVersion(info.project.getVersion())); |
| } |
| } |
| } |
| |
| // prepare resolver options |
| ResolverOptions resolverOptions = new ResolverOptions(); |
| if (nodeBooleanValue(info.plugin, "usePomVariables", false)) { |
| resolverOptions.variableResolver(new PomVariableResolver(info.project)); |
| } |
| if (nodeBooleanValue(info.plugin, "usePomDependencies", false)) { |
| resolverOptions.artifactVersionResolver(new PomArtifactVersionResolver(info.project, |
| nodeBooleanValue(info.plugin, "allowUnresolvedPomDependencies", false))); |
| } |
| |
| final Model copyModel = new Model(); |
| this.mergeModels(copyModel, info.localModel); |
| |
| // we have to create an effective model to add the dependencies |
| final Model effectiveModel = ModelUtility.getEffectiveModel(copyModel, resolverOptions); |
| |
| final List<Model> dependencies = searchSlingstartDependencies(env, info, copyModel, effectiveModel, resolverOptions); |
| info.model = new Model(); |
| for(final Model d : dependencies) { |
| this.mergeModels(info.model, d); |
| } |
| this.mergeModels(info.model, copyModel); |
| info.model = ModelUtility.getEffectiveModel(info.model, resolverOptions); |
| |
| final Map<Traceable, String> errors = ModelUtility.validate(info.model); |
| if ( errors != null ) { |
| throw new MavenExecutionException("Unable to create model file for " + info.project + " : " + errors, (File)null); |
| } |
| |
| if (info.extendMavenClassPath) { |
| addDependenciesFromModel(env, info, scope); |
| env.logger.info("Extended Maven classpath (scope '" + scope + "') by the dependencies extracted from the Sling model."); |
| } else { |
| env.logger.debug("Do not enrich Maven classpath with Sling model!"); |
| } |
| |
| try { |
| ProjectHelper.storeProjectInfo(info); |
| } catch ( final IOException ioe) { |
| throw new MavenExecutionException(ioe.getMessage(), ioe); |
| } |
| return info.model; |
| } |
| |
| /** |
| * Add all dependencies from the model |
| * @param env The environment |
| * @param info The project info |
| * @param scope The scope which the new dependencies should have |
| * @throws MavenExecutionException |
| */ |
| private void addDependenciesFromModel( |
| final Environment env, |
| final ProjectInfo info, |
| final String scope) |
| throws MavenExecutionException { |
| if ( info.project.getPackaging().equals(BuildConstants.PACKAGING_SLINGSTART ) ) { |
| // add base artifact if defined in current model |
| final org.apache.sling.provisioning.model.Artifact baseArtifact = ModelUtils.findBaseArtifact(info.model); |
| |
| final String[] classifiers = new String[] {null, BuildConstants.CLASSIFIER_APP, BuildConstants.CLASSIFIER_WEBAPP}; |
| for(final String c : classifiers) { |
| final Dependency dep = new Dependency(); |
| dep.setGroupId(baseArtifact.getGroupId()); |
| dep.setArtifactId(baseArtifact.getArtifactId()); |
| dep.setVersion(baseArtifact.getVersion()); |
| dep.setType(baseArtifact.getType()); |
| dep.setClassifier(c); |
| if ( BuildConstants.CLASSIFIER_WEBAPP.equals(c) ) { |
| dep.setType(BuildConstants.TYPE_WAR); |
| } |
| dep.setScope(scope); |
| |
| info.project.getDependencies().add(dep); |
| env.logger.debug("- adding base dependency " + ModelUtils.toString(dep)); |
| } |
| } |
| |
| for(final Feature feature : info.model.getFeatures()) { |
| // skip launchpad feature |
| if ( feature.getName().equals(ModelConstants.FEATURE_LAUNCHPAD) ) { |
| continue; |
| } |
| for(final RunMode runMode : feature.getRunModes()) { |
| for(final ArtifactGroup group : runMode.getArtifactGroups()) { |
| for(final org.apache.sling.provisioning.model.Artifact a : group) { |
| if ( a.getGroupId().equals(info.project.getGroupId()) |
| && a.getArtifactId().equals(info.project.getArtifactId()) |
| && a.getVersion().equals(info.project.getVersion()) ) { |
| // skip artifact from the same project |
| env.logger.debug("- skipping dependency " + a.toMvnUrl()); |
| continue; |
| } |
| final Dependency dep = new Dependency(); |
| dep.setGroupId(a.getGroupId()); |
| dep.setArtifactId(a.getArtifactId()); |
| dep.setVersion(a.getVersion()); |
| dep.setType(a.getType()); |
| dep.setClassifier(a.getClassifier()); |
| |
| dep.setScope(scope); |
| |
| env.logger.debug("- adding dependency " + ModelUtils.toString(dep)); |
| info.project.getDependencies().add(dep); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Search for dependent slingstart/slingfeature artifacts and remove them from the effective model. |
| * @throws MavenExecutionException |
| */ |
| private List<Model> searchSlingstartDependencies( |
| final Environment env, |
| final ProjectInfo info, |
| final Model rawModel, |
| final Model effectiveModel, |
| final ResolverOptions resolverOptions) |
| throws MavenExecutionException { |
| // slingstart or slingfeature |
| final List<Model> dependencies = new ArrayList<>(); |
| |
| for(final Feature feature : effectiveModel.getFeatures()) { |
| for(final RunMode runMode : feature.getRunModes()) { |
| for(final ArtifactGroup group : runMode.getArtifactGroups()) { |
| final List<org.apache.sling.provisioning.model.Artifact> removeList = new ArrayList<>(); |
| for(final org.apache.sling.provisioning.model.Artifact a : group) { |
| if ( a.getType().equals(BuildConstants.PACKAGING_SLINGSTART) |
| || a.getType().equals(BuildConstants.PACKAGING_PARTIAL_SYSTEM)) { |
| |
| final Dependency dep = new Dependency(); |
| dep.setGroupId(a.getGroupId()); |
| dep.setArtifactId(a.getArtifactId()); |
| dep.setVersion(a.getVersion()); |
| dep.setType(BuildConstants.PACKAGING_PARTIAL_SYSTEM); |
| if ( a.getType().equals(BuildConstants.PACKAGING_SLINGSTART) ) { |
| dep.setClassifier(BuildConstants.PACKAGING_PARTIAL_SYSTEM); |
| } else { |
| dep.setClassifier(a.getClassifier()); |
| } |
| dep.setScope(Artifact.SCOPE_PROVIDED); |
| |
| env.logger.debug("- adding dependency " + ModelUtils.toString(dep)); |
| info.project.getDependencies().add(dep); |
| |
| // if it's a project from the current reactor build, we can't resolve it right now |
| final String key = a.getGroupId() + ":" + a.getArtifactId(); |
| final ProjectInfo depInfo = env.modelProjects.get(key); |
| if ( depInfo != null ) { |
| env.logger.debug("Found reactor " + a.getType() + " dependency : " + a); |
| final Model model = addDependencies(env, depInfo); |
| if ( model == null ) { |
| throw new MavenExecutionException("Recursive model dependency list including project " + info.project, (File)null); |
| } |
| dependencies.add(model); |
| info.includedModels.put(a, depInfo.localModel); |
| |
| } else { |
| env.logger.debug("Found external " + a.getType() + " dependency: " + a); |
| |
| // "external" dependency, we can already resolve it |
| final File modelFile = resolveSlingstartArtifact(env, info.project, dep); |
| FileReader r = null; |
| try { |
| r = new FileReader(modelFile); |
| final Model model = ModelReader.read(r, modelFile.getAbsolutePath()); |
| |
| info.includedModels.put(a, model); |
| |
| final Map<Traceable, String> errors = ModelUtility.validate(model); |
| if ( errors != null ) { |
| throw new MavenExecutionException("Unable to read model file from " + modelFile + " : " + errors, modelFile); |
| } |
| final Model fullModel = processSlingstartDependencies(env, info, dep, model, resolverOptions); |
| |
| dependencies.add(fullModel); |
| } catch ( final IOException ioe) { |
| throw new MavenExecutionException("Unable to read model file from " + modelFile, ioe); |
| } finally { |
| try { |
| if ( r != null ) { |
| r.close(); |
| } |
| } catch ( final IOException io) { |
| // ignore |
| } |
| } |
| } |
| |
| removeList.add(a); |
| } |
| } |
| for(final org.apache.sling.provisioning.model.Artifact r : removeList) { |
| group.remove(r); |
| final Feature localModelFeature = rawModel.getFeature(feature.getName()); |
| if ( localModelFeature != null ) { |
| final RunMode localRunMode = localModelFeature.getRunMode(runMode.getNames()); |
| if ( localRunMode != null ) { |
| final ArtifactGroup localAG = localRunMode.getArtifactGroup(group.getStartLevel()); |
| if ( localAG != null ) { |
| removeArtifact(localModelFeature, localAG, r, resolverOptions); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return dependencies; |
| } |
| |
| private static void removeArtifact(Feature feature, ArtifactGroup group, org.apache.sling.provisioning.model.Artifact toRemove, ResolverOptions resolverOptions) { |
| Iterator<org.apache.sling.provisioning.model.Artifact> it = group.iterator(); |
| while (it.hasNext()) { |
| org.apache.sling.provisioning.model.Artifact el = it.next(); |
| |
| String version = ModelResolveUtility.replace(feature, el.getVersion(), resolverOptions.getVariableResolver()); |
| org.apache.sling.provisioning.model.Artifact resolved; |
| if (el.getVersion().equals(version)) { |
| resolved = el; |
| } else { |
| resolved = new org.apache.sling.provisioning.model.Artifact(el.getGroupId(), el.getArtifactId(), version, el.getClassifier(), el.getType()); |
| } |
| if (resolved.equals(toRemove)) { |
| it.remove(); |
| } |
| } |
| } |
| |
| private Model processSlingstartDependencies(final Environment env, final ProjectInfo info, final Dependency dep, final Model rawModel, ResolverOptions resolverOptions) |
| throws MavenExecutionException { |
| env.logger.debug("Processing dependency " + dep); |
| |
| // we have to create an effective model to add the dependencies |
| final Model effectiveModel = ModelUtility.getEffectiveModel(rawModel, new ResolverOptions()); |
| |
| final List<Model> dependencies = searchSlingstartDependencies(env, info, rawModel, effectiveModel, resolverOptions); |
| Model mergingModel = new Model(); |
| for(final Model d : dependencies) { |
| this.mergeModels(mergingModel, d); |
| } |
| this.mergeModels(mergingModel, rawModel); |
| |
| final Map<Traceable, String> errors = ModelUtility.validate(ModelUtility.getEffectiveModel(mergingModel, new ResolverOptions())); |
| if ( errors != null ) { |
| throw new MavenExecutionException("Unable to create model file for " + dep + " : " + errors, (File)null); |
| } |
| |
| return mergingModel; |
| } |
| |
| /** |
| * Gets plugins configuration from POM (string parameter). |
| * @param plugin Plugin |
| * @param name Configuration parameter. |
| * @param defaultValue Default value that is returned if parameter is not set |
| * @return Parameter value or default value. |
| */ |
| private String nodeValue(final Plugin plugin, final String name, final String defaultValue) { |
| final Xpp3Dom config = plugin == null ? null : (Xpp3Dom)plugin.getConfiguration(); |
| return nodeValue(config, name, defaultValue); |
| } |
| |
| private String nodeValue(final Xpp3Dom config, final String name, final String defaultValue) { |
| final Xpp3Dom node = (config == null ? null : config.getChild(name)); |
| if (node != null) { |
| return node.getValue(); |
| } else { |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Checks if plugin configuration value is set in POM for a specific configuration parameter. |
| * @param plugin Plugin |
| * @param name Configuration parameter. |
| * @return {@code true} in case the configuration has been set in the pom, otherwise {@code false} |
| */ |
| private boolean hasNodeValue(final Plugin plugin, final String name) { |
| final Xpp3Dom config = plugin == null ? null : (Xpp3Dom)plugin.getConfiguration(); |
| final Xpp3Dom node = (config == null ? null : config.getChild(name)); |
| return (node != null); |
| } |
| |
| private void processAttachments(final Environment env, final ProjectInfo info) |
| throws MavenExecutionException { |
| final Xpp3Dom config = info.plugin == null ? null : (Xpp3Dom)info.plugin.getConfiguration(); |
| final Xpp3Dom[] nodes = (config == null ? null : config.getChildren("attach")); |
| if ( nodes != null ) { |
| for(final Xpp3Dom node : nodes) { |
| final String type = nodeValue(node, "type", null); |
| if ( type == null ) { |
| throw new MavenExecutionException("Attachment for provisioning model has no type.", (File)null); |
| } |
| final String classifier = nodeValue(node, "classifier", null); |
| final String featureName = nodeValue(node, "feature", null); |
| int startLevel = 0; |
| final String level = nodeValue(node, "startLevel", null); |
| if ( level != null ) { |
| startLevel = Integer.valueOf(level); |
| } |
| |
| final Feature f; |
| if ( featureName != null ) { |
| f = info.localModel.getFeature(featureName); |
| } else if ( info.localModel.getFeatures().isEmpty() ) { |
| f = null; |
| } else { |
| f = info.localModel.getFeatures().get(0); |
| } |
| if ( f == null ) { |
| if ( featureName == null ) { |
| throw new MavenExecutionException("No feature found in provisioning model for attachment.", (File)null); |
| } |
| throw new MavenExecutionException("Feature with name '" + featureName + "' not found in provisioning model for attachment.", (File)null); |
| } |
| final RunMode runMode = f.getOrCreateRunMode(null); |
| final ArtifactGroup group = runMode.getOrCreateArtifactGroup(startLevel); |
| |
| final org.apache.sling.provisioning.model.Artifact artifact = new org.apache.sling.provisioning.model.Artifact( |
| info.project.getGroupId(), |
| info.project.getArtifactId(), |
| info.project.getVersion(), |
| classifier, |
| type); |
| |
| env.logger.debug("Attaching " + artifact + " to feature " + f.getName()); |
| group.add(artifact); |
| } |
| } |
| } |
| |
| /** |
| * Gets plugins configuration from POM (boolean parameter). |
| * @param plugin Plugin |
| * @param name Configuration parameter. |
| * @param defaultValue Default value that is returned if parameter is not set |
| * @return Parameter value or default value. |
| */ |
| private boolean nodeBooleanValue(final Plugin plugin, final String name, final boolean defaultValue) { |
| String booleanValue = nodeValue(plugin, name, Boolean.toString(defaultValue)); |
| return "true".equals(booleanValue.toLowerCase()); |
| } |
| |
| private File resolveSlingstartArtifact(final Environment env, |
| final MavenProject project, |
| final Dependency d) |
| throws MavenExecutionException { |
| final Artifact prjArtifact = new DefaultArtifact(d.getGroupId(), |
| d.getArtifactId(), |
| VersionRange.createFromVersion(d.getVersion()), |
| Artifact.SCOPE_PROVIDED, |
| d.getType(), |
| d.getClassifier(), |
| env.artifactHandlerManager.getArtifactHandler(d.getType())); |
| try { |
| env.resolver.resolve(prjArtifact, project.getRemoteArtifactRepositories(), env.session.getLocalRepository()); |
| } catch (final ArtifactResolutionException e) { |
| throw new MavenExecutionException("Unable to get artifact for " + d, e); |
| } catch (final ArtifactNotFoundException e) { |
| throw new MavenExecutionException("Unable to get artifact for " + d, e); |
| } |
| return prjArtifact.getFile(); |
| } |
| |
| /** |
| * Read all model files from the directory in alphabetical order. |
| * Only files ending with .txt or .model are read. |
| * |
| * @param project The current maven project |
| * @param inlinedModel the inlined model to be merged with the models in modelDirectory (may be null) |
| * @param modelDirectory The directory to scan for models |
| * @param pattern Pattern used to find the textual models within the modelDirectory |
| * @param logger The logger |
| */ |
| protected Model readLocalModel( |
| final MavenProject project, |
| final String inlinedModel, |
| final File modelDirectory, |
| final String pattern, |
| final Logger logger) |
| throws MavenExecutionException, IOException { |
| final Pattern p = Pattern.compile(pattern); |
| final List<String> candidates = new ArrayList<>(); |
| if ( modelDirectory != null && modelDirectory.exists() ) { |
| for(final File f : modelDirectory.listFiles() ) { |
| if ( f.isFile() && !f.getName().startsWith(".") ) { |
| if ( p.matcher(f.getName()).matches() ) { |
| candidates.add(f.getName()); |
| } |
| } |
| } |
| Collections.sort(candidates); |
| } |
| if ( candidates.size() == 0 && (inlinedModel == null || inlinedModel.trim().length() == 0) ) { |
| throw new MavenExecutionException("No model files found in " + modelDirectory + ", and no model inlined in POM.", (File)null); |
| } |
| final Model result = new Model(); |
| if ( inlinedModel != null ) { |
| logger.debug("Reading inlined model from project " + project.getId()); |
| try { |
| final Reader reader = new StringReader(inlinedModel); |
| try { |
| final Model current = ModelReader.read(reader, "pom"); |
| final Map<Traceable, String> errors = ModelUtility.validate(current); |
| if (errors != null ) { |
| throw new MavenExecutionException("Invalid inlined model : " + errors, (File)null); |
| } |
| MergeUtility.merge(result, current, new MergeUtility.MergeOptions().setHandleRemoveRunMode(false)); |
| } finally { |
| IOUtils.closeQuietly(reader); |
| } |
| } catch ( final IOException io) { |
| throw new MavenExecutionException("Unable to read inlined model", io); |
| } |
| } |
| for(final String name : candidates) { |
| logger.debug("Reading model " + name + " in project " + project.getId()); |
| try { |
| final File f = new File(modelDirectory, name); |
| final FileReader reader = new FileReader(f); |
| try { |
| final Model current = ModelReader.read(reader, f.getAbsolutePath()); |
| final Map<Traceable, String> errors = ModelUtility.validate(current); |
| if (errors != null ) { |
| throw new MavenExecutionException("Invalid model at " + name + " : " + errors, (File)null); |
| } |
| MergeUtility.merge(result, current, new MergeUtility.MergeOptions().setHandleRemoveRunMode(false)); |
| } finally { |
| IOUtils.closeQuietly(reader); |
| } |
| } catch ( final IOException io) { |
| throw new MavenExecutionException("Unable to read model at " + name, io); |
| } |
| } |
| |
| final Map<Traceable, String> errors = ModelUtility.validate(result); |
| if (errors != null ) { |
| throw new MavenExecutionException("Invalid assembled model : " + errors, (File)null); |
| } |
| |
| return postProcessReadModel(result); |
| } |
| |
| /** |
| * Hook to post process the local model |
| * @param result The read model |
| * @return The post processed model |
| */ |
| protected Model postProcessReadModel(final Model result) throws MavenExecutionException { |
| return result; |
| } |
| |
| /** |
| * Hook to change the merge behavior |
| * @param base The base model |
| * @param additional The additional model |
| */ |
| protected void mergeModels(final Model base, final Model additional) throws MavenExecutionException { |
| MergeUtility.merge(base, additional); |
| } |
| |
| /** |
| * Pattern for converting Maven to OSGi version |
| * Based on the DefaultMaven2OsgiConverter from the Apache Maven Project. |
| */ |
| private static final Pattern FUZZY_VERSION = Pattern.compile( "(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?", |
| Pattern.DOTALL ); |
| |
| |
| private String cleanupVersion( final String version ) { |
| final StringBuilder result = new StringBuilder(); |
| final Matcher m = FUZZY_VERSION.matcher( version ); |
| if ( m.matches() ) { |
| final String major = m.group( 1 ); |
| final String minor = m.group( 3 ); |
| final String micro = m.group( 5 ); |
| final String qualifier = m.group( 7 ); |
| |
| if ( major != null ) { |
| result.append( major ); |
| if ( minor != null ) { |
| result.append( "." ); |
| result.append( minor ); |
| if ( micro != null ) { |
| result.append( "." ); |
| result.append( micro ); |
| if ( qualifier != null ) |
| { |
| result.append( "." ); |
| cleanupModifier( result, qualifier ); |
| } |
| } else if ( qualifier != null ) { |
| result.append( ".0." ); |
| cleanupModifier( result, qualifier ); |
| } else { |
| result.append( ".0" ); |
| } |
| } else if ( qualifier != null ) { |
| result.append( ".0.0." ); |
| cleanupModifier( result, qualifier ); |
| } else { |
| result.append( ".0.0" ); |
| } |
| } |
| } else { |
| result.append( "0.0.0." ); |
| cleanupModifier( result, version ); |
| } |
| return result.toString(); |
| } |
| |
| private static void cleanupModifier( final StringBuilder result, final String modifier ) { |
| for ( int i = 0; i < modifier.length(); i++ ) { |
| final char c = modifier.charAt( i ); |
| if ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' |
| || c == '-' ) { |
| result.append( c ); |
| } else { |
| result.append( '_' ); |
| } |
| } |
| } |
| } |