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.core.settings;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.net.URL;
024: import java.text.ParseException;
025: import java.util.Arrays;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030:
031: import javax.xml.parsers.SAXParserFactory;
032:
033: import org.apache.ivy.core.IvyPatternHelper;
034: import org.apache.ivy.core.cache.RepositoryCacheManager;
035: import org.apache.ivy.core.module.status.StatusManager;
036: import org.apache.ivy.plugins.circular.CircularDependencyStrategy;
037: import org.apache.ivy.plugins.conflict.ConflictManager;
038: import org.apache.ivy.plugins.latest.LatestStrategy;
039: import org.apache.ivy.plugins.lock.LockStrategy;
040: import org.apache.ivy.plugins.matcher.PatternMatcher;
041: import org.apache.ivy.util.Configurator;
042: import org.apache.ivy.util.Message;
043: import org.apache.ivy.util.url.URLHandlerRegistry;
044: import org.xml.sax.Attributes;
045: import org.xml.sax.SAXException;
046: import org.xml.sax.helpers.DefaultHandler;
047:
048: /**
049: */
050: public class XmlSettingsParser extends DefaultHandler {
051: private Configurator configurator;
052:
053: private List configuratorTags = Arrays.asList(new String[] {
054: "resolvers", "namespaces", "parsers", "latest-strategies",
055: "conflict-managers", "outputters", "version-matchers",
056: "statuses", "circular-dependency-strategies", "triggers",
057: "lock-strategies", "caches" });
058:
059: private IvySettings ivy;
060:
061: private String defaultResolver;
062:
063: private String defaultCM;
064:
065: private String defaultLatest;
066:
067: private String defaultCacheManager;
068:
069: private String defaultCircular;
070:
071: private String defaultLock;
072:
073: private String currentConfiguratorTag;
074:
075: private URL settings;
076:
077: private boolean deprecatedMessagePrinted = false;
078:
079: public XmlSettingsParser(IvySettings ivy) {
080: this .ivy = ivy;
081: }
082:
083: public void parse(URL settings) throws ParseException, IOException {
084: configurator = new Configurator();
085: // put every type definition from ivy to configurator
086: Map typeDefs = ivy.getTypeDefs();
087: for (Iterator iter = typeDefs.keySet().iterator(); iter
088: .hasNext();) {
089: String name = (String) iter.next();
090: configurator.typeDef(name, (Class) typeDefs.get(name));
091: }
092:
093: doParse(settings);
094: }
095:
096: private void doParse(URL settingsUrl) throws IOException,
097: ParseException {
098: this .settings = settingsUrl;
099: InputStream stream = null;
100: try {
101: stream = URLHandlerRegistry.getDefault().openStream(
102: settingsUrl);
103: SAXParserFactory.newInstance().newSAXParser().parse(stream,
104: this );
105: } catch (IOException e) {
106: throw e;
107: } catch (Exception e) {
108: ParseException pe = new ParseException(
109: "failed to load settings from " + settingsUrl
110: + ": " + e.getMessage(), 0);
111: pe.initCause(e);
112: throw pe;
113: } finally {
114: if (stream != null) {
115: try {
116: stream.close();
117: } catch (IOException e) {
118: }
119: }
120: }
121: }
122:
123: private void parse(Configurator configurator, URL configuration)
124: throws IOException, ParseException {
125: this .configurator = configurator;
126: doParse(configuration);
127: }
128:
129: public void startElement(String uri, String localName,
130: String qName, Attributes att) throws SAXException {
131: // we first copy attributes in a Map to be able to modify them
132: Map attributes = new HashMap();
133: for (int i = 0; i < att.getLength(); i++) {
134: attributes.put(att.getQName(i), ivy.substitute(att
135: .getValue(i)));
136: }
137:
138: try {
139: if ("ivyconf".equals(qName)) {
140: deprecatedMessagePrinted = true;
141: Message
142: .deprecated("'ivyconf' element is deprecated, use 'ivysettings' instead ("
143: + settings + ")");
144: }
145: if (configurator.getCurrent() != null) {
146: if ("macrodef".equals(currentConfiguratorTag)
147: && configurator.getTypeDef(qName) != null) {
148: String name = (String) attributes.get("name");
149: if (name == null) {
150: attributes.put("name", "@{name}");
151: } else if (configurator.isTopLevelMacroRecord()
152: && name.indexOf("@{name}") != -1) {
153: attributes.put("name", name);
154: } else {
155: attributes.put("name", "@{name}-" + name);
156: }
157: }
158: if (attributes.get("ref") != null) {
159: if (attributes.size() != 1) {
160: throw new IllegalArgumentException(
161: "ref attribute should be the only one ! found "
162: + attributes.size() + " in "
163: + qName);
164: }
165: String name = (String) attributes.get("ref");
166: Object child = null;
167: if ("resolvers".equals(currentConfiguratorTag)) {
168: child = ivy.getResolver(name);
169: if (child == null) {
170: throw new IllegalArgumentException(
171: "unknown resolver "
172: + name
173: + ": resolver should be defined before being referenced");
174: }
175: } else if ("latest-strategies"
176: .equals(currentConfiguratorTag)) {
177: child = ivy.getLatestStrategy(name);
178: if (child == null) {
179: throw new IllegalArgumentException(
180: "unknown latest strategy "
181: + name
182: + ": latest strategy should be defined before being referenced");
183: }
184: } else if ("conflict-managers"
185: .equals(currentConfiguratorTag)) {
186: child = ivy.getConflictManager(name);
187: if (child == null) {
188: throw new IllegalArgumentException(
189: "unknown conflict manager "
190: + name
191: + ": conflict manager should be defined before being referenced");
192: }
193: }
194: if (child == null) {
195: throw new IllegalArgumentException(
196: "bad reference " + name);
197: }
198: configurator.addChild(qName, child);
199: } else {
200: configurator.startCreateChild(qName);
201: for (Iterator iter = attributes.keySet().iterator(); iter
202: .hasNext();) {
203: String attName = (String) iter.next();
204: configurator.setAttribute(attName,
205: (String) attributes.get(attName));
206: }
207: }
208: } else if ("classpath".equals(qName)) {
209: String urlStr = (String) attributes.get("url");
210: URL url = null;
211: if (urlStr == null) {
212: String file = (String) attributes.get("file");
213: if (file == null) {
214: throw new IllegalArgumentException(
215: "either url or file should be given for classpath element");
216: } else {
217: url = new File(file).toURL();
218: }
219: } else {
220: url = new URL(urlStr);
221: }
222: ivy.addClasspathURL(url);
223: } else if ("typedef".equals(qName)) {
224: String name = (String) attributes.get("name");
225: String className = (String) attributes.get("classname");
226: Class clazz = ivy.typeDef(name, className);
227: configurator.typeDef(name, clazz);
228: } else if ("property".equals(qName)) {
229: String name = (String) attributes.get("name");
230: String value = (String) attributes.get("value");
231: String override = (String) attributes.get("override");
232: if (name == null) {
233: throw new IllegalArgumentException(
234: "missing attribute name on property tag");
235: }
236: if (value == null) {
237: throw new IllegalArgumentException(
238: "missing attribute value on property tag");
239: }
240: ivy.setVariable(name, value, override == null ? true
241: : Boolean.valueOf(override).booleanValue());
242: } else if ("properties".equals(qName)) {
243: String propFilePath = (String) attributes.get("file");
244: String environmentPrefix = (String) attributes
245: .get("environment");
246: if (propFilePath != null) {
247: String override = (String) attributes
248: .get("override");
249: try {
250: Message.verbose("loading properties: "
251: + propFilePath);
252: ivy.loadProperties(new File(propFilePath),
253: override == null ? true : Boolean
254: .valueOf(override)
255: .booleanValue());
256: } catch (Exception fileEx) {
257: Message
258: .verbose("failed to load properties as file: trying as url: "
259: + propFilePath);
260: try {
261: ivy.loadProperties(new URL(propFilePath),
262: override == null ? true : Boolean
263: .valueOf(override)
264: .booleanValue());
265: } catch (Exception urlEx) {
266: throw new IllegalArgumentException(
267: "unable to load properties from "
268: + propFilePath
269: + ". Tried both as an url and a file, with no success. File exception: "
270: + fileEx
271: + ". URL exception: "
272: + urlEx);
273: }
274: }
275: } else if (environmentPrefix != null) {
276: ivy.getVariableContainer().setEnvironmentPrefix(
277: environmentPrefix);
278: } else {
279: throw new IllegalArgumentException(
280: "Didn't find a 'file' or 'environment' attribute "
281: + "on the 'properties' element");
282: }
283: } else if ("include".equals(qName)) {
284: IvyVariableContainer variables = (IvyVariableContainer) ivy
285: .getVariableContainer().clone();
286: try {
287: String propFilePath = (String) attributes
288: .get("file");
289: URL settingsURL = null;
290: if (propFilePath == null) {
291: propFilePath = (String) attributes.get("url");
292: if (propFilePath == null) {
293: Message
294: .error("bad include tag: specify file or url to include");
295: return;
296: } else {
297: Message.verbose("including url: "
298: + propFilePath);
299: settingsURL = new URL(propFilePath);
300: ivy.setSettingsVariables(settingsURL);
301: }
302: } else {
303: File incFile = new File(propFilePath);
304: if (!incFile.exists()) {
305: Message
306: .error("impossible to include "
307: + incFile
308: + ": file does not exist");
309: return;
310: } else {
311: Message.verbose("including file: "
312: + propFilePath);
313: ivy.setSettingsVariables(incFile);
314: settingsURL = incFile.toURL();
315: }
316: }
317: new XmlSettingsParser(ivy).parse(configurator,
318: settingsURL);
319: } finally {
320: ivy.setVariableContainer(variables);
321: }
322: } else if ("settings".equals(qName) || "conf".equals(qName)) {
323: if ("conf".equals(qName) && !deprecatedMessagePrinted) {
324: Message
325: .deprecated("'conf' is deprecated, use 'settings' instead ("
326: + settings + ")");
327: }
328: String cache = (String) attributes.get("defaultCache");
329: if (cache != null) {
330: Message
331: .deprecated("'defaultCache' is deprecated, "
332: + "use 'caches[@defaultCacheDir]' instead ("
333: + settings + ")");
334: ivy.setDefaultCache(new File(cache));
335: }
336: String defaultBranch = (String) attributes
337: .get("defaultBranch");
338: if (defaultBranch != null) {
339: ivy.setDefaultBranch(defaultBranch);
340: }
341: String validate = (String) attributes.get("validate");
342: if (validate != null) {
343: ivy.setValidate(Boolean.valueOf(validate)
344: .booleanValue());
345: }
346: String up2d = (String) attributes.get("checkUpToDate");
347: if (up2d != null) {
348: Message
349: .deprecated("'checkUpToDate' is deprecated, "
350: + "use 'caches[@checkUpToDate]' instead ("
351: + settings + ")");
352: ivy.setCheckUpToDate(Boolean.valueOf(up2d)
353: .booleanValue());
354: }
355: String useRemoteConfig = (String) attributes
356: .get("useRemoteConfig");
357: if (useRemoteConfig != null) {
358: ivy.setUseRemoteConfig(Boolean.valueOf(
359: useRemoteConfig).booleanValue());
360: }
361: String cacheIvyPattern = (String) attributes
362: .get("cacheIvyPattern");
363: if (cacheIvyPattern != null) {
364: Message
365: .deprecated("'cacheIvyPattern' is deprecated, use 'caches[@ivyPattern]' instead"
366: + " (" + settings + ")");
367: ivy.setDefaultCacheIvyPattern(cacheIvyPattern);
368: }
369: String cacheArtPattern = (String) attributes
370: .get("cacheArtifactPattern");
371: if (cacheArtPattern != null) {
372: Message
373: .deprecated("'cacheArtifactPattern' is deprecated, "
374: + "use 'caches[@artifactPattern]' instead ("
375: + settings + ")");
376: ivy.setDefaultCacheArtifactPattern(cacheArtPattern);
377: }
378:
379: // we do not set following defaults here since no instances has been registered yet
380: defaultResolver = (String) attributes
381: .get("defaultResolver");
382: defaultCM = (String) attributes
383: .get("defaultConflictManager");
384: defaultLatest = (String) attributes
385: .get("defaultLatestStrategy");
386: defaultCircular = (String) attributes
387: .get("circularDependencyStrategy");
388:
389: } else if ("caches".equals(qName)) {
390: currentConfiguratorTag = qName;
391: configurator.setRoot(ivy);
392: defaultLock = (String) attributes.get("lockStrategy");
393: defaultCacheManager = (String) attributes
394: .get("default");
395:
396: String cache = (String) attributes
397: .get("defaultCacheDir");
398: if (cache != null) {
399: ivy.setDefaultCache(new File(cache));
400: }
401: String up2d = (String) attributes.get("checkUpToDate");
402: if (up2d != null) {
403: ivy.setCheckUpToDate(Boolean.valueOf(up2d)
404: .booleanValue());
405: }
406: String resolutionDir = (String) attributes
407: .get("resolutionCacheDir");
408: if (resolutionDir != null) {
409: ivy.setDefaultResolutionCacheBasedir(resolutionDir);
410: }
411: String useOrigin = (String) attributes.get("useOrigin");
412: if (useOrigin != null) {
413: ivy.setDefaultUseOrigin(Boolean.valueOf(useOrigin)
414: .booleanValue());
415: }
416: String cacheIvyPattern = (String) attributes
417: .get("ivyPattern");
418: if (cacheIvyPattern != null) {
419: ivy.setDefaultCacheIvyPattern(cacheIvyPattern);
420: }
421: String cacheArtPattern = (String) attributes
422: .get("artifactPattern");
423: if (cacheArtPattern != null) {
424: ivy.setDefaultCacheArtifactPattern(cacheArtPattern);
425: }
426: String repositoryDir = (String) attributes
427: .get("repositoryCacheDir");
428: if (repositoryDir != null) {
429: ivy.setDefaultRepositoryCacheBasedir(repositoryDir);
430: }
431: } else if ("version-matchers".equals(qName)) {
432: currentConfiguratorTag = qName;
433: configurator.setRoot(ivy);
434: if ("true".equals((String) attributes
435: .get("usedefaults"))) {
436: ivy.configureDefaultVersionMatcher();
437: }
438: } else if ("statuses".equals(qName)) {
439: currentConfiguratorTag = qName;
440: StatusManager m = new StatusManager();
441: String defaultStatus = (String) attributes
442: .get("default");
443: if (defaultStatus != null) {
444: m.setDefaultStatus(defaultStatus);
445: }
446: ivy.setStatusManager(m);
447: configurator.setRoot(m);
448: } else if (configuratorTags.contains(qName)) {
449: currentConfiguratorTag = qName;
450: configurator.setRoot(ivy);
451: } else if ("macrodef".equals(qName)) {
452: currentConfiguratorTag = qName;
453: Configurator.MacroDef macrodef = configurator
454: .startMacroDef((String) attributes.get("name"));
455: macrodef.addAttribute("name", null);
456: } else if ("module".equals(qName)) {
457: attributes.put(IvyPatternHelper.MODULE_KEY, attributes
458: .remove("name"));
459: String resolver = (String) attributes
460: .remove("resolver");
461: String branch = (String) attributes.remove("branch");
462: String cm = (String) attributes
463: .remove("conflict-manager");
464: String matcher = (String) attributes.remove("matcher");
465: matcher = matcher == null ? PatternMatcher.EXACT_OR_REGEXP
466: : matcher;
467: ivy.addModuleConfiguration(attributes, ivy
468: .getMatcher(matcher), resolver, branch, cm);
469: }
470: } catch (ParseException ex) {
471: throw new SAXException("problem in config file: "
472: + ex.getMessage(), ex);
473: } catch (IOException ex) {
474: throw new SAXException(
475: "io problem while parsing config file: "
476: + ex.getMessage(), ex);
477: }
478: }
479:
480: public void endElement(String uri, String localName, String qName)
481: throws SAXException {
482: if (configurator.getCurrent() != null) {
483: if (configuratorTags.contains(qName)
484: && configurator.getDepth() == 1) {
485: configurator.clear();
486: currentConfiguratorTag = null;
487: } else if ("macrodef".equals(qName)
488: && configurator.getDepth() == 1) {
489: configurator.endMacroDef();
490: currentConfiguratorTag = null;
491: } else {
492: configurator.endCreateChild();
493: }
494: }
495: }
496:
497: public void endDocument() throws SAXException {
498: if (defaultResolver != null) {
499: ivy.setDefaultResolver(ivy.substitute(defaultResolver));
500: }
501: if (defaultCM != null) {
502: ConflictManager conflictManager = ivy
503: .getConflictManager(defaultCM);
504: if (conflictManager == null) {
505: throw new IllegalArgumentException(
506: "unknown conflict manager "
507: + ivy.substitute(defaultCM));
508: }
509: ivy.setDefaultConflictManager(conflictManager);
510: }
511: if (defaultLatest != null) {
512: LatestStrategy latestStrategy = ivy.getLatestStrategy(ivy
513: .substitute(defaultLatest));
514: if (latestStrategy == null) {
515: throw new IllegalArgumentException(
516: "unknown latest strategy "
517: + ivy.substitute(defaultLatest));
518: }
519: ivy.setDefaultLatestStrategy(latestStrategy);
520: }
521: if (defaultCacheManager != null) {
522: RepositoryCacheManager cache = ivy
523: .getRepositoryCacheManager(ivy
524: .substitute(defaultCacheManager));
525: if (cache == null) {
526: throw new IllegalArgumentException(
527: "unknown cache manager "
528: + ivy.substitute(defaultCacheManager));
529: }
530: ivy.setDefaultRepositoryCacheManager(cache);
531: }
532: if (defaultCircular != null) {
533: CircularDependencyStrategy strategy = ivy
534: .getCircularDependencyStrategy(ivy
535: .substitute(defaultCircular));
536: if (strategy == null) {
537: throw new IllegalArgumentException(
538: "unknown circular dependency strategy "
539: + ivy.substitute(defaultCircular));
540: }
541: ivy.setCircularDependencyStrategy(strategy);
542: }
543: if (defaultLock != null) {
544: LockStrategy strategy = ivy.getLockStrategy(ivy
545: .substitute(defaultLock));
546: if (strategy == null) {
547: throw new IllegalArgumentException(
548: "unknown lock strategy "
549: + ivy.substitute(defaultLock));
550: }
551: ivy.setDefaultLockStrategy(strategy);
552: }
553: }
554: }
|