001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.maven.plugin.jbi;
018:
019: import java.io.File;
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.net.URLClassLoader;
023: import java.util.Collections;
024: import java.util.HashMap;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.Set;
030: import java.util.regex.Matcher;
031: import java.util.regex.Pattern;
032:
033: import org.apache.maven.artifact.Artifact;
034: import org.apache.maven.artifact.factory.ArtifactFactory;
035: import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
036: import org.apache.maven.artifact.repository.ArtifactRepository;
037: import org.apache.maven.artifact.resolver.ArtifactCollector;
038: import org.apache.maven.artifact.resolver.ArtifactResolutionException;
039: import org.apache.maven.artifact.resolver.ArtifactResolver;
040: import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
041: import org.apache.maven.artifact.versioning.VersionRange;
042: import org.apache.maven.model.Dependency;
043: import org.apache.maven.model.DependencyManagement;
044: import org.apache.maven.plugin.AbstractMojo;
045: import org.apache.maven.plugin.MojoExecutionException;
046: import org.apache.maven.project.MavenProject;
047: import org.apache.maven.project.MavenProjectBuilder;
048: import org.apache.maven.project.MavenProjectHelper;
049: import org.apache.maven.project.ProjectBuildingException;
050: import org.apache.servicemix.maven.plugin.jbi.JbiResolutionListener.Node;
051: import org.codehaus.plexus.archiver.jar.Manifest;
052: import org.codehaus.plexus.archiver.jar.ManifestException;
053:
054: public abstract class AbstractJbiMojo extends AbstractMojo {
055:
056: public static final String META_INF = "META-INF";
057:
058: public static final String JBI_DESCRIPTOR = "jbi.xml";
059:
060: public static final String LIB_DIRECTORY = "lib";
061:
062: private static final Pattern VERSION_PATTERN = Pattern
063: .compile("^(\\d+(\\.\\d+(\\.\\d+)?)?)-");
064:
065: private static final String[] VERSION_COMPLETERS = new String[] {
066: ".0.0", ".0" };
067:
068: /**
069: * Maven ProjectHelper
070: *
071: * @component
072: */
073: protected MavenProjectHelper projectHelper;
074:
075: /**
076: * The maven project.
077: *
078: * @parameter expression="${project}"
079: * @required
080: * @readonly
081: */
082: protected MavenProject project;
083:
084: /**
085: * Directory that resources are copied to during the build.
086: *
087: * @parameter expression="${project.build.directory}/${project.artifactId}-${project.version}-installer"
088: * @required
089: */
090: protected File workDirectory;
091:
092: /**
093: * @component
094: */
095: protected MavenProjectBuilder projectBuilder;
096:
097: /**
098: * @parameter default-value="${localRepository}"
099: */
100: protected ArtifactRepository localRepo;
101:
102: /**
103: * @parameter default-value="${project.remoteArtifactRepositories}"
104: */
105: protected List remoteRepos;
106:
107: /**
108: * @component
109: */
110: protected ArtifactMetadataSource artifactMetadataSource;
111:
112: /**
113: * @component
114: */
115: protected ArtifactResolver resolver;
116:
117: protected ArtifactCollector collector = new GraphArtifactCollector();
118:
119: /**
120: * @component
121: */
122: protected ArtifactFactory factory;
123:
124: protected MavenProject getProject() {
125: return project;
126: }
127:
128: protected File getWorkDirectory() {
129: return workDirectory;
130: }
131:
132: public MavenProjectHelper getProjectHelper() {
133: return projectHelper;
134: }
135:
136: protected void removeBranch(JbiResolutionListener listener,
137: Artifact artifact) {
138: Node n = listener.getNode(artifact);
139: if (n != null) {
140: for (Iterator it = n.getParents().iterator(); it.hasNext();) {
141: Node parent = (Node) it.next();
142: parent.getChildren().remove(n);
143: }
144: }
145: }
146:
147: protected void removeChildren(JbiResolutionListener listener,
148: Artifact artifact) {
149: Node n = listener.getNode(artifact);
150: n.getChildren().clear();
151: }
152:
153: protected Set getArtifacts(Node n, Set s) {
154: if (!s.contains(n.getArtifact())) {
155: s.add(n.getArtifact());
156: for (Iterator iter = n.getChildren().iterator(); iter
157: .hasNext();) {
158: Node c = (Node) iter.next();
159: getArtifacts(c, s);
160: }
161: }
162: return s;
163: }
164:
165: protected void excludeBranch(Node n, Set excludes) {
166: excludes.add(n);
167: for (Iterator iter = n.getChildren().iterator(); iter.hasNext();) {
168: Node c = (Node) iter.next();
169: excludeBranch(c, excludes);
170: }
171: }
172:
173: protected void print(Node rootNode) {
174: for (Iterator iter = getArtifacts(rootNode, new HashSet())
175: .iterator(); iter.hasNext();) {
176: Artifact a = (Artifact) iter.next();
177: getLog().info(" " + a);
178: }
179: }
180:
181: protected Set retainArtifacts(Set includes,
182: JbiResolutionListener listener) {
183: Set finalIncludes = new HashSet();
184: Set filteredArtifacts = getArtifacts(listener.getRootNode(),
185: new HashSet());
186: for (Iterator iter = includes.iterator(); iter.hasNext();) {
187: Artifact artifact = (Artifact) iter.next();
188: for (Iterator iter2 = filteredArtifacts.iterator(); iter2
189: .hasNext();) {
190: Artifact filteredArtifact = (Artifact) iter2.next();
191: if (filteredArtifact.getArtifactId().equals(
192: artifact.getArtifactId())
193: && filteredArtifact.getType().equals(
194: artifact.getType())
195: && filteredArtifact.getGroupId().equals(
196: artifact.getGroupId())) {
197: if (!filteredArtifact.getVersion().equals(
198: artifact.getVersion())) {
199: getLog()
200: .warn(
201: "Resolved artifact "
202: + artifact
203: + " has a different version from that in dependency management "
204: + filteredArtifact
205: + ", overriding dependency management");
206: }
207: finalIncludes.add(artifact);
208: }
209: }
210:
211: }
212:
213: return finalIncludes;
214: }
215:
216: protected JbiResolutionListener resolveProject() {
217: Map managedVersions = null;
218: try {
219: managedVersions = createManagedVersionMap(project.getId(),
220: project.getDependencyManagement());
221: } catch (ProjectBuildingException e) {
222: getLog()
223: .error(
224: "An error occurred while resolving project dependencies.",
225: e);
226: }
227: JbiResolutionListener listener = new JbiResolutionListener();
228: listener.setLog(getLog());
229: try {
230: collector.collect(project.getDependencyArtifacts(), project
231: .getArtifact(), managedVersions, localRepo,
232: remoteRepos, artifactMetadataSource, null,
233: Collections.singletonList(listener));
234: } catch (ArtifactResolutionException e) {
235: getLog()
236: .error(
237: "An error occurred while resolving project dependencies.",
238: e);
239: }
240: if (getLog().isDebugEnabled()) {
241: getLog().debug("Dependency graph");
242: getLog().debug("================");
243: print(listener.getRootNode());
244: getLog().debug("================");
245: }
246: return listener;
247: }
248:
249: protected Map createManagedVersionMap(String projectId,
250: DependencyManagement dependencyManagement)
251: throws ProjectBuildingException {
252: Map map;
253: if (dependencyManagement != null
254: && dependencyManagement.getDependencies() != null) {
255: map = new HashMap();
256: for (Iterator i = dependencyManagement.getDependencies()
257: .iterator(); i.hasNext();) {
258: Dependency d = (Dependency) i.next();
259:
260: try {
261: VersionRange versionRange = VersionRange
262: .createFromVersionSpec(d.getVersion());
263: Artifact artifact = factory
264: .createDependencyArtifact(d.getGroupId(), d
265: .getArtifactId(), versionRange, d
266: .getType(), d.getClassifier(), d
267: .getScope());
268: map.put(d.getManagementKey(), artifact);
269: } catch (InvalidVersionSpecificationException e) {
270: throw new ProjectBuildingException(projectId,
271: "Unable to parse version '"
272: + d.getVersion()
273: + "' for dependency '"
274: + d.getManagementKey() + "': "
275: + e.getMessage(), e);
276: }
277: }
278: } else {
279: map = Collections.EMPTY_MAP;
280: }
281: return map;
282: }
283:
284: /**
285: * Set up a classloader for the execution of the main class.
286: *
287: * @return
288: * @throws MojoExecutionException
289: */
290: protected URLClassLoader getClassLoader()
291: throws MojoExecutionException {
292: try {
293: Set urls = new HashSet();
294:
295: URL mainClasses = new File(project.getBuild()
296: .getOutputDirectory()).toURL();
297: getLog().debug("Adding to classpath : " + mainClasses);
298: urls.add(mainClasses);
299:
300: URL testClasses = new File(project.getBuild()
301: .getTestOutputDirectory()).toURL();
302: getLog().debug("Adding to classpath : " + testClasses);
303: urls.add(testClasses);
304:
305: Set dependencies = project.getArtifacts();
306: Iterator iter = dependencies.iterator();
307: while (iter.hasNext()) {
308: Artifact classPathElement = (Artifact) iter.next();
309: getLog().debug(
310: "Adding artifact: "
311: + classPathElement.getFile()
312: + " to classpath");
313: urls.add(classPathElement.getFile().toURL());
314: }
315: URLClassLoader appClassloader = new URLClassLoader(
316: (URL[]) urls.toArray(new URL[urls.size()]), this
317: .getClass().getClassLoader());
318: return appClassloader;
319: } catch (MalformedURLException e) {
320: throw new MojoExecutionException(
321: "Error during setting up classpath", e);
322: }
323: }
324:
325: protected Manifest createManifest() throws ManifestException {
326: Manifest manifest = new Manifest();
327: //manifest.getMainSection().addConfiguredAttribute(new Manifest.Attribute("Bundle-Name", project.getName()));
328: //manifest.getMainSection().addConfiguredAttribute(new Manifest.Attribute("Bundle-SymbolicName", project.getArtifactId()));
329: //manifest.getMainSection().addConfiguredAttribute(new Manifest.Attribute("Bundle-Version", fixBundleVersion(project.getVersion())));
330: return manifest;
331: }
332:
333: private static String fixBundleVersion(String version) {
334: // Maven uses a '-' to separate the version qualifier, while
335: // OSGi uses a '.', so we need to convert the first '-' to a
336: // '.' and fill in any missing minor or micro version
337: // components if necessary.
338: final Matcher matcher = VERSION_PATTERN.matcher(version);
339: if (!matcher.lookingAt()) {
340: return version;
341: }
342: // Leave extra space for worst-case additional insertion:
343: final StringBuffer sb = new StringBuffer(version.length() + 4);
344: sb.append(matcher.group(1));
345: if (null == matcher.group(3)) {
346: final int count = null != matcher.group(2) ? 2 : 1;
347: sb.append(VERSION_COMPLETERS[count - 1]);
348: }
349: sb.append('.');
350: sb.append(version.substring(matcher.end(), version.length()));
351: return sb.toString();
352: }
353:
354: }
|