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: */
018: package org.apache.ivy.plugins.parser.m2;
019:
020: import java.text.ParseException;
021: import java.util.Date;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Map.Entry;
026:
027: import org.apache.ivy.Ivy;
028: import org.apache.ivy.core.module.descriptor.Configuration;
029: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
030: import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor;
031: import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
032: import org.apache.ivy.core.module.descriptor.DefaultExcludeRule;
033: import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
034: import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
035: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
036: import org.apache.ivy.core.module.descriptor.Configuration.Visibility;
037: import org.apache.ivy.core.module.id.ArtifactId;
038: import org.apache.ivy.core.module.id.ModuleId;
039: import org.apache.ivy.core.module.id.ModuleRevisionId;
040: import org.apache.ivy.plugins.matcher.ExactPatternMatcher;
041: import org.apache.ivy.plugins.matcher.PatternMatcher;
042: import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
043: import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyData;
044: import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyMgt;
045: import org.apache.ivy.plugins.repository.Resource;
046:
047: /**
048: * Build a module descriptor. This class handle the complexity of the structure of an ivy
049: * ModuleDescriptor and isolate the PomModuleDescriptorParser from it.
050: */
051: public class PomModuleDescriptorBuilder {
052:
053: public static final Configuration[] MAVEN2_CONFIGURATIONS = new Configuration[] {
054: new Configuration(
055: "default",
056: Visibility.PUBLIC,
057: "runtime dependencies and master artifact can be used with this conf",
058: new String[] { "runtime", "master" }, true, null),
059: new Configuration("master", Visibility.PUBLIC,
060: "contains only the artifact published by this module itself, "
061: + "with no transitive dependencies",
062: new String[0], true, null),
063: new Configuration(
064: "compile",
065: Visibility.PUBLIC,
066: "this is the default scope, used if none is specified. "
067: + "Compile dependencies are available in all classpaths.",
068: new String[0], true, null),
069: new Configuration(
070: "provided",
071: Visibility.PUBLIC,
072: "this is much like compile, but indicates you expect the JDK or a container "
073: + "to provide it. "
074: + "It is only available on the compilation classpath, and is not transitive.",
075: new String[0], true, null),
076: new Configuration(
077: "runtime",
078: Visibility.PUBLIC,
079: "this scope indicates that the dependency is not required for compilation, "
080: + "but is for execution. It is in the runtime and test classpaths, "
081: + "but not the compile classpath.",
082: new String[] { "compile" }, true, null),
083: new Configuration(
084: "test",
085: Visibility.PRIVATE,
086: "this scope indicates that the dependency is not required for normal use of "
087: + "the application, and is only available for the test compilation and "
088: + "execution phases.",
089: new String[] { "runtime" }, true, null),
090: new Configuration(
091: "system",
092: Visibility.PUBLIC,
093: "this scope is similar to provided except that you have to provide the JAR "
094: + "which contains it explicitly. The artifact is always available and is not "
095: + "looked up in a repository.",
096: new String[0], true, null),
097: new Configuration("optional", Visibility.PUBLIC,
098: "contains all optional dependencies",
099: new String[0], true, null) };
100:
101: static final Map MAVEN2_CONF_MAPPING = new HashMap();
102:
103: private static final String DEPENDENCY_MANAGEMENT = "m:dependency.management";
104: private static final String PROPERTIES = "m:properties";
105: private static final String EXTRA_INFO_DELIMITER = "__";
106:
107: static interface ConfMapper {
108: public void addMappingConfs(DefaultDependencyDescriptor dd,
109: boolean isOptional);
110: }
111:
112: static {
113: MAVEN2_CONF_MAPPING.put("compile", new ConfMapper() {
114: public void addMappingConfs(DefaultDependencyDescriptor dd,
115: boolean isOptional) {
116: if (isOptional) {
117: dd.addDependencyConfiguration("optional",
118: "compile(*)");
119: //dd.addDependencyConfiguration("optional", "provided(*)");
120: dd.addDependencyConfiguration("optional",
121: "master(*)");
122:
123: } else {
124: dd.addDependencyConfiguration("compile",
125: "compile(*)");
126: //dd.addDependencyConfiguration("compile", "provided(*)");
127: dd.addDependencyConfiguration("compile",
128: "master(*)");
129: dd.addDependencyConfiguration("runtime",
130: "runtime(*)");
131: }
132: }
133: });
134: MAVEN2_CONF_MAPPING.put("provided", new ConfMapper() {
135: public void addMappingConfs(DefaultDependencyDescriptor dd,
136: boolean isOptional) {
137: if (isOptional) {
138: dd.addDependencyConfiguration("optional",
139: "compile(*)");
140: dd.addDependencyConfiguration("optional",
141: "provided(*)");
142: dd.addDependencyConfiguration("optional",
143: "runtime(*)");
144: dd.addDependencyConfiguration("optional",
145: "master(*)");
146: } else {
147: dd.addDependencyConfiguration("provided",
148: "compile(*)");
149: dd.addDependencyConfiguration("provided",
150: "provided(*)");
151: dd.addDependencyConfiguration("provided",
152: "runtime(*)");
153: dd.addDependencyConfiguration("provided",
154: "master(*)");
155: }
156: }
157: });
158: MAVEN2_CONF_MAPPING.put("runtime", new ConfMapper() {
159: public void addMappingConfs(DefaultDependencyDescriptor dd,
160: boolean isOptional) {
161: if (isOptional) {
162: dd.addDependencyConfiguration("optional",
163: "compile(*)");
164: dd.addDependencyConfiguration("optional",
165: "provided(*)");
166: dd.addDependencyConfiguration("optional",
167: "master(*)");
168:
169: } else {
170: dd.addDependencyConfiguration("runtime",
171: "compile(*)");
172: dd.addDependencyConfiguration("runtime",
173: "runtime(*)");
174: dd.addDependencyConfiguration("runtime",
175: "master(*)");
176: }
177: }
178: });
179: MAVEN2_CONF_MAPPING.put("test", new ConfMapper() {
180: public void addMappingConfs(DefaultDependencyDescriptor dd,
181: boolean isOptional) {
182: //optional doesn't make sense in the test scope
183: dd.addDependencyConfiguration("test", "runtime(*)");
184: dd.addDependencyConfiguration("test", "master(*)");
185: }
186: });
187: MAVEN2_CONF_MAPPING.put("system", new ConfMapper() {
188: public void addMappingConfs(DefaultDependencyDescriptor dd,
189: boolean isOptional) {
190: //optional doesn't make sense in the system scope
191: dd.addDependencyConfiguration("system", "master(*)");
192: }
193: });
194: }
195:
196: private final DefaultModuleDescriptor ivyModuleDescriptor;
197:
198: private ModuleRevisionId mrid;
199:
200: public PomModuleDescriptorBuilder(ModuleDescriptorParser parser,
201: Resource res) {
202: ivyModuleDescriptor = new DefaultModuleDescriptor(parser, res);
203: ivyModuleDescriptor.setResolvedPublicationDate(new Date(res
204: .getLastModified()));
205: for (int i = 0; i < MAVEN2_CONFIGURATIONS.length; i++) {
206: ivyModuleDescriptor
207: .addConfiguration(MAVEN2_CONFIGURATIONS[i]);
208: }
209: ivyModuleDescriptor.setMappingOverride(true);
210: ivyModuleDescriptor.addExtraAttributeNamespace("m", Ivy
211: .getIvyHomeURL()
212: + "maven");
213: }
214:
215: public ModuleDescriptor getModuleDescriptor() {
216: return ivyModuleDescriptor;
217: }
218:
219: public void setModuleRevId(String groupId, String artifactId,
220: String version) {
221: mrid = ModuleRevisionId.newInstance(groupId, artifactId,
222: version);
223: ivyModuleDescriptor.setModuleRevisionId(mrid);
224: }
225:
226: public void addArtifact(String artifactId, String packaging) {
227: ivyModuleDescriptor.addArtifact("master", new DefaultArtifact(
228: mrid, new Date(), artifactId, packaging, packaging));
229: }
230:
231: public void addDependency(Resource res, PomDependencyData dep)
232: throws ParseException {
233: if (!MAVEN2_CONF_MAPPING.containsKey(dep.getScope())) {
234: String msg = "Unknown scope "
235: + dep.getScope()
236: + " for dependency "
237: + ModuleId.newInstance(dep.getGroupId(), dep
238: .getArtifaceId()) + " in " + res.getName();
239: throw new ParseException(msg, 0);
240: }
241:
242: String version = dep.getVersion();
243: version = (version == null || version.length() == 0) ? getDefaultVersion(dep)
244: : version;
245: ModuleRevisionId moduleRevId = ModuleRevisionId.newInstance(dep
246: .getGroupId(), dep.getArtifaceId(), version);
247: DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(
248: ivyModuleDescriptor, moduleRevId, true, false, true);
249: ConfMapper mapping = (ConfMapper) MAVEN2_CONF_MAPPING.get(dep
250: .getScope());
251: mapping.addMappingConfs(dd, dep.isOptional());
252: Map extraAtt = new HashMap();
253: if (dep.getClassifier() != null) {
254: // we deal with classifiers by setting an extra attribute and forcing the
255: // dependency to assume such an artifact is published
256: extraAtt.put("m:classifier", dep.getClassifier());
257: DefaultDependencyArtifactDescriptor depArtifact = new DefaultDependencyArtifactDescriptor(
258: dd.getDependencyId().getName(), "jar", "jar", null,
259: extraAtt);
260: // here we have to assume a type and ext for the artifact, so this is a limitation
261: // compared to how m2 behave with classifiers
262: String optionalizedScope = dep.isOptional() ? "optional"
263: : dep.getScope();
264: dd.addDependencyArtifact(optionalizedScope, depArtifact);
265: }
266:
267: for (Iterator itExcl = dep.getExcludedModules().iterator(); itExcl
268: .hasNext();) {
269: ModuleId excludedModule = (ModuleId) itExcl.next();
270: String[] confs = dd.getModuleConfigurations();
271: for (int k = 0; k < confs.length; k++) {
272: dd.addExcludeRule(confs[k], new DefaultExcludeRule(
273: new ArtifactId(excludedModule,
274: PatternMatcher.ANY_EXPRESSION,
275: PatternMatcher.ANY_EXPRESSION,
276: PatternMatcher.ANY_EXPRESSION),
277: ExactPatternMatcher.INSTANCE, null));
278: }
279: }
280:
281: ivyModuleDescriptor.addDependency(dd);
282: }
283:
284: public void addDependency(DependencyDescriptor descriptor) {
285: ivyModuleDescriptor.addDependency(descriptor);
286: }
287:
288: public void addDependencyMgt(PomDependencyMgt dep) {
289: String key = getDependencyMgtExtraInfoKey(dep.getGroupId(), dep
290: .getArtifaceId());
291: ivyModuleDescriptor.addExtraInfo(key, dep.getVersion());
292: }
293:
294: private String getDefaultVersion(PomDependencyData dep) {
295: String key = getDependencyMgtExtraInfoKey(dep.getGroupId(), dep
296: .getArtifaceId());
297: return (String) ivyModuleDescriptor.getExtraInfo().get(key);
298: }
299:
300: private static String getDependencyMgtExtraInfoKey(String groupId,
301: String artifaceId) {
302: return DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + groupId
303: + EXTRA_INFO_DELIMITER + artifaceId;
304: }
305:
306: private static String getPropertyExtraInfoKey(String propertyName) {
307: return PROPERTIES + EXTRA_INFO_DELIMITER + propertyName;
308: }
309:
310: public void addExtraInfos(Map extraAttributes) {
311: for (Iterator it = extraAttributes.entrySet().iterator(); it
312: .hasNext();) {
313: Map.Entry entry = (Entry) it.next();
314: String key = (String) entry.getKey();
315: String value = (String) entry.getValue();
316: addExtraInfo(key, value);
317: }
318: }
319:
320: private void addExtraInfo(String key, String value) {
321: if (!ivyModuleDescriptor.getExtraInfo().containsKey(key)) {
322: ivyModuleDescriptor.addExtraInfo(key, value);
323: }
324: }
325:
326: public static Map extractPomProperties(Map extraInfo) {
327: Map r = new HashMap();
328: for (Iterator it = extraInfo.entrySet().iterator(); it
329: .hasNext();) {
330: Map.Entry extraInfoEntry = (Map.Entry) it.next();
331: if (((String) extraInfoEntry.getKey())
332: .startsWith(PROPERTIES)) {
333: String prop = ((String) extraInfoEntry.getKey())
334: .substring(PROPERTIES.length()
335: + EXTRA_INFO_DELIMITER.length());
336: r.put(prop, extraInfoEntry.getValue());
337: }
338: }
339: return r;
340: }
341:
342: public void addProperty(String propertyName, String value) {
343: addExtraInfo(getPropertyExtraInfoKey(propertyName), value);
344: }
345:
346: }
|