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;
019:
020: import java.io.IOException;
021: import java.net.URL;
022: import java.text.ParseException;
023: import java.util.ArrayList;
024: import java.util.Date;
025: import java.util.HashSet;
026: import java.util.List;
027: import java.util.Set;
028:
029: import org.apache.ivy.core.module.descriptor.Artifact;
030: import org.apache.ivy.core.module.descriptor.Configuration;
031: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
032: import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
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.id.ModuleRevisionId;
037: import org.apache.ivy.plugins.repository.Resource;
038: import org.apache.ivy.plugins.repository.ResourceHelper;
039: import org.apache.ivy.plugins.repository.url.URLResource;
040: import org.apache.ivy.util.Message;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.SAXParseException;
043: import org.xml.sax.helpers.DefaultHandler;
044:
045: public abstract class AbstractModuleDescriptorParser implements
046: ModuleDescriptorParser {
047: public ModuleDescriptor parseDescriptor(ParserSettings ivySettings,
048: URL descriptorURL, boolean validate) throws ParseException,
049: IOException {
050: return parseDescriptor(ivySettings, descriptorURL,
051: new URLResource(descriptorURL), validate);
052: }
053:
054: public String getType() {
055: return "ivy";
056: }
057:
058: public Artifact getMetadataArtifact(ModuleRevisionId mrid,
059: Resource res) {
060: return DefaultArtifact.newIvyArtifact(mrid, new Date(res
061: .getLastModified()));
062: }
063:
064: protected abstract static class AbstractParser extends
065: DefaultHandler {
066: private static final String DEFAULT_CONF_MAPPING = "*->*";
067:
068: private String defaultConf; // used only as defaultconf, not used for
069:
070: // guesssing right side part of a mapping
071: private String defaultConfMapping; // same as default conf but is used
072:
073: // for guesssing right side part of a mapping
074: private DefaultDependencyDescriptor defaultConfMappingDescriptor;
075:
076: private Resource res;
077:
078: private List errors = new ArrayList();
079:
080: protected DefaultModuleDescriptor md;
081:
082: private ModuleDescriptorParser parser;
083:
084: protected AbstractParser(ModuleDescriptorParser parser) {
085: this .parser = parser;
086: }
087:
088: public ModuleDescriptorParser getModuleDescriptorParser() {
089: return parser;
090: }
091:
092: protected void checkErrors() throws ParseException {
093: if (!errors.isEmpty()) {
094: throw new ParseException(errors.toString(), 0);
095: }
096: }
097:
098: protected void setResource(Resource res) {
099: this .res = res; // used for log and date only
100: md = new DefaultModuleDescriptor(parser, res);
101: md.setLastModified(ResourceHelper
102: .getLastModifiedOrDefault(res));
103: }
104:
105: protected Resource getResource() {
106: return res;
107: }
108:
109: protected String getDefaultConfMapping() {
110: return defaultConfMapping;
111: }
112:
113: protected void setDefaultConfMapping(String defaultConf) {
114: defaultConfMapping = defaultConf;
115: }
116:
117: protected void parseDepsConfs(String confs,
118: DefaultDependencyDescriptor dd) {
119: parseDepsConfs(confs, dd, defaultConfMapping != null);
120: }
121:
122: protected void parseDepsConfs(String confs,
123: DefaultDependencyDescriptor dd,
124: boolean useDefaultMappingToGuessRightOperande) {
125: parseDepsConfs(confs, dd,
126: useDefaultMappingToGuessRightOperande, true);
127: }
128:
129: protected void parseDepsConfs(String confs,
130: DefaultDependencyDescriptor dd,
131: boolean useDefaultMappingToGuessRightOperande,
132: boolean evaluateConditions) {
133: if (confs == null) {
134: return;
135: }
136:
137: String[] conf = confs.split(";");
138: parseDepsConfs(conf, dd,
139: useDefaultMappingToGuessRightOperande,
140: evaluateConditions);
141: }
142:
143: protected void parseDepsConfs(String[] conf,
144: DefaultDependencyDescriptor dd,
145: boolean useDefaultMappingToGuessRightOperande) {
146: parseDepsConfs(conf, dd,
147: useDefaultMappingToGuessRightOperande, true);
148: }
149:
150: protected void parseDepsConfs(String[] conf,
151: DefaultDependencyDescriptor dd,
152: boolean useDefaultMappingToGuessRightOperande,
153: boolean evaluateConditions) {
154: replaceConfigurationWildcards(md);
155: for (int i = 0; i < conf.length; i++) {
156: String[] ops = conf[i].split("->");
157: if (ops.length == 1) {
158: String[] modConfs = ops[0].split(",");
159: if (!useDefaultMappingToGuessRightOperande) {
160: for (int j = 0; j < modConfs.length; j++) {
161: dd.addDependencyConfiguration(modConfs[j]
162: .trim(), modConfs[j].trim());
163: }
164: } else {
165: for (int j = 0; j < modConfs.length; j++) {
166: String[] depConfs = getDefaultConfMappingDescriptor()
167: .getDependencyConfigurations(
168: modConfs[j]);
169: if (depConfs.length > 0) {
170: for (int k = 0; k < depConfs.length; k++) {
171: String mappedDependency = evaluateConditions ? evaluateCondition(
172: depConfs[k].trim(), dd)
173: : depConfs[k].trim();
174: if (mappedDependency != null) {
175: dd.addDependencyConfiguration(
176: modConfs[j].trim(),
177: mappedDependency);
178: }
179: }
180: } else {
181: // no default mapping found for this configuration, map
182: // configuration to itself
183: dd.addDependencyConfiguration(
184: modConfs[j].trim(), modConfs[j]
185: .trim());
186: }
187: }
188: }
189: } else if (ops.length == 2) {
190: String[] modConfs = ops[0].split(",");
191: String[] depConfs = ops[1].split(",");
192: for (int j = 0; j < modConfs.length; j++) {
193: for (int k = 0; k < depConfs.length; k++) {
194: String mappedDependency = evaluateConditions ? evaluateCondition(
195: depConfs[k].trim(), dd)
196: : depConfs[k].trim();
197: if (mappedDependency != null) {
198: dd.addDependencyConfiguration(
199: modConfs[j].trim(),
200: mappedDependency);
201: }
202: }
203: }
204: } else {
205: addError("invalid conf " + conf[i] + " for "
206: + dd.getDependencyRevisionId());
207: }
208: }
209:
210: if (md.isMappingOverride()) {
211: addExtendingConfigurations(conf, dd,
212: useDefaultMappingToGuessRightOperande);
213: }
214: }
215:
216: /**
217: * Evaluate the optional condition in the given configuration, like "[org=MYORG]confX". If
218: * the condition evaluates to true, the configuration is returned, if the condition
219: * evaluatate to false, null is returned. If there are no conditions, the configuration
220: * itself is returned.
221: *
222: * @param conf
223: * the configuration to evaluate
224: * @param dd
225: * the dependencydescriptor to which the configuration will be added
226: * @return the evaluated condition
227: */
228: private String evaluateCondition(String conf,
229: DefaultDependencyDescriptor dd) {
230: if (conf.charAt(0) != '[') {
231: return conf;
232: }
233:
234: int endConditionIndex = conf.indexOf(']');
235: if (endConditionIndex == -1) {
236: addError("invalid conf " + conf + " for "
237: + dd.getDependencyRevisionId());
238: return null;
239: }
240:
241: String condition = conf.substring(1, endConditionIndex);
242:
243: int notEqualIndex = condition.indexOf("!=");
244: if (notEqualIndex == -1) {
245: int equalIndex = condition.indexOf('=');
246: if (equalIndex == -1) {
247: addError("invalid conf " + conf + " for "
248: + dd.getDependencyRevisionId());
249: return null;
250: }
251:
252: String leftOp = condition.substring(0, equalIndex)
253: .trim();
254: String rightOp = condition.substring(equalIndex + 1)
255: .trim();
256:
257: // allow organisation synonyms, like 'org' or 'organization'
258: if (leftOp.equals("org")
259: || leftOp.equals("organization")) {
260: leftOp = "organisation";
261: }
262:
263: String attrValue = dd.getAttribute(leftOp);
264: if (!rightOp.equals(attrValue)) {
265: return null;
266: }
267: } else {
268: String leftOp = condition.substring(0, notEqualIndex)
269: .trim();
270: String rightOp = condition.substring(notEqualIndex + 2)
271: .trim();
272:
273: // allow organisation synonyms, like 'org' or 'organization'
274: if (leftOp.equals("org")
275: || leftOp.equals("organization")) {
276: leftOp = "organisation";
277: }
278:
279: String attrValue = dd.getAttribute(leftOp);
280: if (rightOp.equals(attrValue)) {
281: return null;
282: }
283: }
284:
285: return conf.substring(endConditionIndex + 1);
286: }
287:
288: private void addExtendingConfigurations(String[] confs,
289: DefaultDependencyDescriptor dd,
290: boolean useDefaultMappingToGuessRightOperande) {
291: for (int i = 0; i < confs.length; i++) {
292: addExtendingConfigurations(confs[i], dd,
293: useDefaultMappingToGuessRightOperande);
294: }
295: }
296:
297: private void addExtendingConfigurations(String conf,
298: DefaultDependencyDescriptor dd,
299: boolean useDefaultMappingToGuessRightOperande) {
300: Set configsToAdd = new HashSet();
301: Configuration[] configs = md.getConfigurations();
302: for (int i = 0; i < configs.length; i++) {
303: String[] ext = configs[i].getExtends();
304: for (int j = 0; j < ext.length; j++) {
305: if (conf.equals(ext[j])) {
306: String configName = configs[i].getName();
307: configsToAdd.add(configName);
308: addExtendingConfigurations(configName, dd,
309: useDefaultMappingToGuessRightOperande);
310: }
311: }
312: }
313:
314: String[] confs = (String[]) configsToAdd
315: .toArray(new String[configsToAdd.size()]);
316: parseDepsConfs(confs, dd,
317: useDefaultMappingToGuessRightOperande);
318: }
319:
320: protected DependencyDescriptor getDefaultConfMappingDescriptor() {
321: if (defaultConfMappingDescriptor == null) {
322: defaultConfMappingDescriptor = new DefaultDependencyDescriptor(
323: ModuleRevisionId.newInstance("", "", ""), false);
324: parseDepsConfs(defaultConfMapping,
325: defaultConfMappingDescriptor, false, false);
326: }
327: return defaultConfMappingDescriptor;
328: }
329:
330: protected void addError(String msg) {
331: if (res != null) {
332: errors.add(msg + " in " + res + "\n");
333: } else {
334: errors.add(msg + "\n");
335: }
336: }
337:
338: public void warning(SAXParseException ex) {
339: Message.warn("xml parsing: " + getLocationString(ex) + ": "
340: + ex.getMessage());
341: }
342:
343: public void error(SAXParseException ex) {
344: addError("xml parsing: " + getLocationString(ex) + ": "
345: + ex.getMessage());
346: }
347:
348: public void fatalError(SAXParseException ex)
349: throws SAXException {
350: addError("[Fatal Error] " + getLocationString(ex) + ": "
351: + ex.getMessage());
352: }
353:
354: /** Returns a string of the location. */
355: private String getLocationString(SAXParseException ex) {
356: StringBuffer str = new StringBuffer();
357:
358: String systemId = ex.getSystemId();
359: if (systemId != null) {
360: int index = systemId.lastIndexOf('/');
361: if (index != -1) {
362: systemId = systemId.substring(index + 1);
363: }
364: str.append(systemId);
365: } else if (getResource() != null) {
366: str.append(getResource().toString());
367: }
368: str.append(':');
369: str.append(ex.getLineNumber());
370: str.append(':');
371: str.append(ex.getColumnNumber());
372:
373: return str.toString();
374:
375: } // getLocationString(SAXParseException):String
376:
377: protected String getDefaultConf() {
378: return defaultConfMapping != null ? defaultConfMapping
379: : (defaultConf != null ? defaultConf
380: : DEFAULT_CONF_MAPPING);
381: }
382:
383: protected void setDefaultConf(String defaultConf) {
384: this .defaultConf = defaultConf;
385: }
386:
387: public ModuleDescriptor getModuleDescriptor()
388: throws ParseException {
389: checkErrors();
390: return md;
391: }
392:
393: protected Date getDefaultPubDate() {
394: return new Date(md.getLastModified());
395: }
396:
397: private void replaceConfigurationWildcards(ModuleDescriptor md) {
398: Configuration[] configs = md.getConfigurations();
399: for (int i = 0; i < configs.length; i++) {
400: configs[i].replaceWildcards(md);
401: }
402: }
403: }
404:
405: }
|