~ubuntu-branches/ubuntu/trusty/ivy/trusty

« back to all changes in this revision

Viewing changes to src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2009-03-06 22:04:56 UTC
  • Revision ID: james.westby@ubuntu.com-20090306220456-5v37luqiuqda8ewp
Tags: upstream-2.0.0
ImportĀ upstreamĀ versionĀ 2.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 *  contributor license agreements.  See the NOTICE file distributed with
 
4
 *  this work for additional information regarding copyright ownership.
 
5
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 *  (the "License"); you may not use this file except in compliance with
 
7
 *  the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 *  Unless required by applicable law or agreed to in writing, software
 
12
 *  distributed under the License is distributed on an "AS IS" BASIS,
 
13
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 *  See the License for the specific language governing permissions and
 
15
 *  limitations under the License.
 
16
 *
 
17
 */
 
18
package org.apache.ivy.plugins.parser.xml;
 
19
 
 
20
import java.io.File;
 
21
import java.io.IOException;
 
22
import java.io.InputStream;
 
23
import java.net.MalformedURLException;
 
24
import java.net.URL;
 
25
import java.text.ParseException;
 
26
import java.util.Arrays;
 
27
import java.util.List;
 
28
import java.util.Map;
 
29
 
 
30
import javax.xml.parsers.ParserConfigurationException;
 
31
 
 
32
import org.apache.ivy.Ivy;
 
33
import org.apache.ivy.core.IvyContext;
 
34
import org.apache.ivy.core.module.descriptor.Configuration;
 
35
import org.apache.ivy.core.module.descriptor.ConfigurationAware;
 
36
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
 
37
import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor;
 
38
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
 
39
import org.apache.ivy.core.module.descriptor.DefaultExcludeRule;
 
40
import org.apache.ivy.core.module.descriptor.DefaultIncludeRule;
 
41
import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
 
42
import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor;
 
43
import org.apache.ivy.core.module.descriptor.ExcludeRule;
 
44
import org.apache.ivy.core.module.descriptor.IncludeRule;
 
45
import org.apache.ivy.core.module.descriptor.License;
 
46
import org.apache.ivy.core.module.descriptor.MDArtifact;
 
47
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
 
48
import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator;
 
49
import org.apache.ivy.core.module.id.ArtifactId;
 
50
import org.apache.ivy.core.module.id.ModuleId;
 
51
import org.apache.ivy.core.module.id.ModuleRevisionId;
 
52
import org.apache.ivy.plugins.conflict.ConflictManager;
 
53
import org.apache.ivy.plugins.conflict.FixedConflictManager;
 
54
import org.apache.ivy.plugins.matcher.PatternMatcher;
 
55
import org.apache.ivy.plugins.namespace.Namespace;
 
56
import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParser;
 
57
import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
 
58
import org.apache.ivy.plugins.parser.ParserSettings;
 
59
import org.apache.ivy.plugins.repository.Resource;
 
60
import org.apache.ivy.plugins.repository.url.URLResource;
 
61
import org.apache.ivy.util.Message;
 
62
import org.apache.ivy.util.XMLHelper;
 
63
import org.apache.ivy.util.extendable.ExtendableItemHelper;
 
64
import org.xml.sax.Attributes;
 
65
import org.xml.sax.SAXException;
 
66
 
 
67
/**
 
68
 * Parses an xml ivy file and output a ModuleDescriptor. For dependency and performance reasons, it
 
69
 * uses only the SAX API, which makes the parsing code harder to understand.
 
70
 */
 
71
public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser {
 
72
    static final String[] DEPENDENCY_REGULAR_ATTRIBUTES = new String[] {"org", "name", "branch",
 
73
            "branchConstraint", "rev", "revConstraint", "force", "transitive", "changing", "conf"};
 
74
 
 
75
    private static final XmlModuleDescriptorParser INSTANCE = new XmlModuleDescriptorParser();
 
76
 
 
77
    public static XmlModuleDescriptorParser getInstance() {
 
78
        return INSTANCE;
 
79
    }
 
80
 
 
81
    protected XmlModuleDescriptorParser() {
 
82
    }
 
83
 
 
84
    /**
 
85
     * @param settings
 
86
     * @param xmlURL
 
87
     *            the url pointing to the file to parse
 
88
     * @param res
 
89
     *            the real resource to parse, used for log only
 
90
     * @param validate
 
91
     * @return
 
92
     * @throws ParseException
 
93
     * @throws IOException
 
94
     */
 
95
    public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL xmlURL, Resource res,
 
96
            boolean validate) throws ParseException, IOException {
 
97
        Parser parser = newParser(ivySettings);
 
98
        parser.setValidate(validate);
 
99
        parser.setResource(res);
 
100
        parser.setInput(xmlURL);
 
101
        parser.parse();
 
102
        return parser.getModuleDescriptor();
 
103
    }
 
104
 
 
105
    /** Used for test purpose */
 
106
    ModuleDescriptor parseDescriptor(ParserSettings ivySettings, InputStream descriptor,
 
107
            Resource res, boolean validate) throws ParseException, IOException {
 
108
        Parser parser = newParser(ivySettings);
 
109
        parser.setValidate(validate);
 
110
        parser.setResource(res);
 
111
        parser.setInput(descriptor);
 
112
        parser.parse();
 
113
        return parser.getModuleDescriptor();
 
114
    }
 
115
 
 
116
    /**
 
117
     * Instantiates a Parser instance responsible for actual parsing of Ivy files.
 
118
     * <p>
 
119
     * Override this method if you want to use a custom Parser.
 
120
     * </p>
 
121
     * 
 
122
     * @param ivySettings
 
123
     *            the settings to use during parsing
 
124
     * @return the Parser instance used for parsing Ivy files
 
125
     */
 
126
    protected Parser newParser(ParserSettings ivySettings) {
 
127
        return new Parser(this, ivySettings);
 
128
    }
 
129
 
 
130
    public boolean accept(Resource res) {
 
131
        return true; // this the default parser, it thus accepts all resources
 
132
    }
 
133
 
 
134
    public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md)
 
135
            throws IOException, ParseException {
 
136
        try {
 
137
            Namespace ns = null;
 
138
            if (md instanceof DefaultModuleDescriptor) {
 
139
                DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md;
 
140
                ns = dmd.getNamespace();
 
141
            }
 
142
            XmlModuleDescriptorUpdater.update(is, res, destFile, 
 
143
                    new UpdateOptions()
 
144
                        .setSettings(IvyContext.getContext().getSettings())
 
145
                        .setStatus(md.getStatus()) 
 
146
                        .setRevision(md.getResolvedModuleRevisionId().getRevision()) 
 
147
                        .setPubdate(md.getResolvedPublicationDate())
 
148
                        .setUpdateBranch(false)
 
149
                        .setNamespace(ns));
 
150
        } catch (SAXException e) {
 
151
            ParseException ex = new ParseException("exception occured while parsing " + res, 0);
 
152
            ex.initCause(e);
 
153
            throw ex;
 
154
        } finally {
 
155
            if (is != null) {
 
156
                is.close();
 
157
            }
 
158
        }
 
159
    }
 
160
 
 
161
    public static class Parser extends AbstractParser {
 
162
        public static final class State {
 
163
            public static final int NONE = 0;
 
164
 
 
165
            public static final int INFO = 1;
 
166
 
 
167
            public static final int CONF = 2;
 
168
 
 
169
            public static final int PUB = 3;
 
170
 
 
171
            public static final int DEP = 4;
 
172
 
 
173
            public static final int DEP_ARTIFACT = 5;
 
174
 
 
175
            public static final int ARTIFACT_INCLUDE = 6;
 
176
 
 
177
            public static final int ARTIFACT_EXCLUDE = 7;
 
178
 
 
179
            public static final int CONFLICT = 8;
 
180
 
 
181
            public static final int EXCLUDE = 9;
 
182
 
 
183
            public static final int DEPS = 10;
 
184
        
 
185
            public static final int DESCRIPTION = 11;
 
186
 
 
187
            public static final int EXTRA_INFO = 12;
 
188
            
 
189
            private State() {
 
190
            }
 
191
        }
 
192
 
 
193
        protected static final List ALLOWED_VERSIONS = Arrays.asList(
 
194
            new String[] {"1.0", "1.1", "1.2", "1.3", "1.4", "2.0"});
 
195
 
 
196
        /* how and what do we have to parse */
 
197
        private ParserSettings settings;
 
198
        private boolean validate = true;
 
199
        private URL descriptorURL;
 
200
        private InputStream descriptorInput;
 
201
 
 
202
 
 
203
        /* Parsing state */
 
204
        private int state = State.NONE;
 
205
        private PatternMatcher defaultMatcher;
 
206
        private DefaultDependencyDescriptor dd;
 
207
        private ConfigurationAware confAware;
 
208
        private MDArtifact artifact;
 
209
        private String conf;
 
210
        private boolean artifactsDeclared = false;
 
211
        private StringBuffer buffer;
 
212
        private String descriptorVersion;
 
213
        private String[] publicationsDefaultConf;
 
214
        
 
215
        public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) {
 
216
            super(parser);
 
217
            settings = ivySettings;
 
218
        }
 
219
 
 
220
        public void setInput(InputStream descriptorInput) {
 
221
            this.descriptorInput = descriptorInput;
 
222
        }
 
223
 
 
224
        public void setInput(URL descriptorURL) {
 
225
            this.descriptorURL = descriptorURL;
 
226
        }
 
227
 
 
228
        public void setValidate(boolean validate) {
 
229
            this.validate = validate;
 
230
        }
 
231
 
 
232
        public void parse() throws ParseException,
 
233
                IOException {
 
234
            try {
 
235
                URL schemaURL = validate ? getSchemaURL() : null;
 
236
                if (descriptorURL != null) {
 
237
                    XMLHelper.parse(descriptorURL, schemaURL, this);
 
238
                } else {
 
239
                    XMLHelper.parse(descriptorInput, schemaURL, this, null);
 
240
                }
 
241
                checkConfigurations();
 
242
                replaceConfigurationWildcards();
 
243
                getMd().setModuleArtifact(
 
244
                    DefaultArtifact.newIvyArtifact(
 
245
                        getMd().getResolvedModuleRevisionId(), getMd().getPublicationDate()));
 
246
                if (!artifactsDeclared) {
 
247
                    String[] confs = getMd().getConfigurationsNames();
 
248
                    for (int i = 0; i < confs.length; i++) {
 
249
                        getMd().addArtifact(confs[i], 
 
250
                            new MDArtifact(getMd(), getMd().getModuleRevisionId().getName(), 
 
251
                                "jar", "jar"));
 
252
                    }
 
253
                }
 
254
                getMd().check();
 
255
            } catch (ParserConfigurationException ex) {
 
256
                IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in "
 
257
                        + descriptorURL);
 
258
                ise.initCause(ex);
 
259
                throw ise;
 
260
            } catch (Exception ex) {
 
261
                checkErrors();
 
262
                ParseException pe = new ParseException(ex.getMessage() + " in " + descriptorURL, 0);
 
263
                pe.initCause(ex);
 
264
                throw pe;
 
265
            }
 
266
        }
 
267
 
 
268
        public void startElement(String uri, String localName, String qName, Attributes attributes)
 
269
                throws SAXException {
 
270
            try {
 
271
                if (state == State.DESCRIPTION) {
 
272
                    //make sure we don't interpret any tag while in description tag 
 
273
                    buffer.append("<" + qName + ">");
 
274
                    return;
 
275
                } else if ("ivy-module".equals(qName)) {
 
276
                    ivyModuleStarted(attributes);
 
277
                } else if ("info".equals(qName)) {
 
278
                    infoStarted(attributes);
 
279
                } else if (state == State.INFO && "license".equals(qName)) {
 
280
                    getMd().addLicense(new License(settings.substitute(attributes.getValue("name")),
 
281
                                        settings.substitute(attributes.getValue("url"))));
 
282
                } else if (state == State.INFO && "description".equals(qName)) {
 
283
                    getMd().setHomePage(settings.substitute(attributes.getValue("homepage")));
 
284
                    state = State.DESCRIPTION;
 
285
                    buffer = new StringBuffer();
 
286
                } else if (state == State.INFO && "ivyauthor".equals(qName)) {
 
287
                    // nothing to do, we don't store this
 
288
                } else if (state == State.INFO && "repository".equals(qName)) {
 
289
                    // nothing to do, we don't store this
 
290
                } else if (state == State.INFO && isOtherNamespace(qName)) {
 
291
                    buffer = new StringBuffer();
 
292
                    state = State.EXTRA_INFO;
 
293
                } else if ("configurations".equals(qName)) {
 
294
                    configurationStarted(attributes);
 
295
                } else if ("publications".equals(qName)) {
 
296
                    publicationsStarted(attributes);
 
297
                } else if ("dependencies".equals(qName)) {
 
298
                    dependenciesStarted(attributes);
 
299
                } else if ("conflicts".equals(qName)) {
 
300
                    if (!descriptorVersion.startsWith("1.")) {
 
301
                        Message.deprecated("using conflicts section is deprecated: "
 
302
                            + "please use hints section instead. Ivy file URL: " + descriptorURL);
 
303
                    }
 
304
                    state = State.CONFLICT;
 
305
                    checkConfigurations();
 
306
                } else if ("artifact".equals(qName)) {
 
307
                    artifactStarted(qName, attributes);
 
308
                } else if ("include".equals(qName) && state == State.DEP) {
 
309
                    addIncludeRule(qName, attributes);
 
310
                } else if ("exclude".equals(qName) && state == State.DEP) {
 
311
                    addExcludeRule(qName, attributes);
 
312
                } else if ("exclude".equals(qName) && state == State.DEPS) {
 
313
                    state = State.EXCLUDE;
 
314
                    parseRule(qName, attributes);
 
315
                    getMd().addExcludeRule((ExcludeRule) confAware);
 
316
                } else if ("dependency".equals(qName)) {
 
317
                    dependencyStarted(attributes);
 
318
                } else if ("conf".equals(qName)) {
 
319
                    confStarted(attributes);
 
320
                } else if ("mapped".equals(qName)) {
 
321
                    dd.addDependencyConfiguration(conf, settings.substitute(attributes
 
322
                            .getValue("name")));
 
323
                } else if (("conflict".equals(qName) && state == State.DEPS)
 
324
                        || "manager".equals(qName) && state == State.CONFLICT) {
 
325
                    managerStarted(attributes, state == State.CONFLICT ? "name" : "manager");
 
326
                } else if ("override".equals(qName) && state == State.DEPS) {
 
327
                    mediationOverrideStarted(attributes);
 
328
                } else if ("include".equals(qName) && state == State.CONF) {
 
329
                    includeConfStarted(attributes);
 
330
                } else if (validate && state != State.EXTRA_INFO && state != State.DESCRIPTION) {
 
331
                    addError("unknown tag " + qName);
 
332
                }
 
333
            } catch (Exception ex) {
 
334
                if (ex instanceof SAXException) {
 
335
                    throw (SAXException) ex;
 
336
                }
 
337
                SAXException sax = new SAXException("Problem occured while parsing ivy file: "
 
338
                        + ex.getMessage(), ex);
 
339
                sax.initCause(ex);
 
340
                throw sax;
 
341
            }
 
342
        }
 
343
 
 
344
        protected void publicationsStarted(Attributes attributes) {
 
345
            state = State.PUB;
 
346
            artifactsDeclared = true;
 
347
            checkConfigurations();
 
348
            String defaultConf = settings.substitute(attributes.getValue("defaultconf"));
 
349
            if (defaultConf != null) {
 
350
                setPublicationsDefaultConf(defaultConf);
 
351
            }
 
352
        }
 
353
 
 
354
        protected void setPublicationsDefaultConf(String defaultConf) {
 
355
            this.publicationsDefaultConf = defaultConf == null ? null : defaultConf.split(",");
 
356
        }
 
357
 
 
358
        protected boolean isOtherNamespace(String qName) {
 
359
            return qName.indexOf(':') != -1;
 
360
        }
 
361
 
 
362
        protected void managerStarted(Attributes attributes, String managerAtt) {
 
363
            String org = settings.substitute(attributes.getValue("org"));
 
364
            org = org == null ? PatternMatcher.ANY_EXPRESSION : org;
 
365
            String mod = settings.substitute(attributes.getValue("module"));
 
366
            mod = mod == null ? PatternMatcher.ANY_EXPRESSION : mod;
 
367
            ConflictManager cm;
 
368
            String name = settings.substitute(attributes.getValue(managerAtt));
 
369
            String rev = settings.substitute(attributes.getValue("rev"));
 
370
            if (rev != null) {
 
371
                String[] revs = rev.split(",");
 
372
                for (int i = 0; i < revs.length; i++) {
 
373
                    revs[i] = revs[i].trim();
 
374
                }
 
375
                cm = new FixedConflictManager(revs);
 
376
            } else if (name != null) {
 
377
                cm = settings.getConflictManager(name);
 
378
                if (cm == null) {
 
379
                    addError("unknown conflict manager: " + name);
 
380
                    return;
 
381
                }
 
382
            } else {
 
383
                addError("bad conflict manager: no manager nor rev");
 
384
                return;
 
385
            }
 
386
            String matcherName = settings.substitute(attributes.getValue("matcher"));
 
387
            PatternMatcher matcher = matcherName == null ? defaultMatcher : settings
 
388
                    .getMatcher(matcherName);
 
389
            if (matcher == null) {
 
390
                addError("unknown matcher: " + matcherName);
 
391
                return;
 
392
            }
 
393
            getMd().addConflictManager(new ModuleId(org, mod), matcher, cm);
 
394
        }
 
395
 
 
396
        protected void mediationOverrideStarted(Attributes attributes) {
 
397
            String org = settings.substitute(attributes.getValue("org"));
 
398
            org = org == null ? PatternMatcher.ANY_EXPRESSION : org;
 
399
            String mod = settings.substitute(attributes.getValue("module"));
 
400
            mod = mod == null ? PatternMatcher.ANY_EXPRESSION : mod;
 
401
            String rev = settings.substitute(attributes.getValue("rev"));
 
402
            String branch = settings.substitute(attributes.getValue("branch"));
 
403
            String matcherName = settings.substitute(attributes.getValue("matcher"));
 
404
            PatternMatcher matcher = matcherName == null ? defaultMatcher : settings
 
405
                    .getMatcher(matcherName);
 
406
            if (matcher == null) {
 
407
                addError("unknown matcher: " + matcherName);
 
408
                return;
 
409
            }
 
410
            getMd().addDependencyDescriptorMediator(
 
411
                new ModuleId(org, mod), matcher, 
 
412
                new OverrideDependencyDescriptorMediator(branch, rev));
 
413
        }
 
414
 
 
415
        protected void includeConfStarted(Attributes attributes) 
 
416
                throws SAXException, IOException, ParserConfigurationException, ParseException {
 
417
            URL url = settings.getRelativeUrlResolver().getURL(descriptorURL,
 
418
                    settings.substitute(attributes.getValue("file")),
 
419
                    settings.substitute(attributes.getValue("url")));
 
420
            
 
421
            if (url == null) {
 
422
                throw new SAXException("include tag must have a file or an url attribute");
 
423
            }
 
424
            
 
425
            // create a new temporary parser to read the configurations from
 
426
            // the specified file.
 
427
            Parser parser = new Parser(getModuleDescriptorParser(), settings);
 
428
            parser.setInput(url);
 
429
            parser.setMd(new DefaultModuleDescriptor(getModuleDescriptorParser(),
 
430
                    new URLResource(url)));
 
431
            XMLHelper.parse(url , null, parser);
 
432
 
 
433
            // add the configurations from this temporary parser to this module descriptor
 
434
            Configuration[] configs = parser.getModuleDescriptor().getConfigurations();
 
435
            for (int i = 0; i < configs.length; i++) {
 
436
                getMd().addConfiguration(configs[i]);
 
437
            }
 
438
            if (parser.getDefaultConfMapping() != null) {
 
439
                Message.debug("setting default conf from imported configurations file: "
 
440
                        + parser.getDefaultConfMapping());
 
441
                setDefaultConfMapping(parser.getDefaultConfMapping());
 
442
            }
 
443
            if (parser.getMd().isMappingOverride()) {
 
444
                Message.debug("enabling mapping-override from imported configurations" 
 
445
                        + " file");
 
446
                getMd().setMappingOverride(true);
 
447
            }
 
448
        }
 
449
 
 
450
        protected void confStarted(Attributes attributes) {
 
451
            String conf = settings.substitute(attributes.getValue("name"));
 
452
            switch (state) {
 
453
                case State.CONF:
 
454
                    String visibility = settings.substitute(attributes.getValue("visibility"));
 
455
                    String ext = settings.substitute(attributes.getValue("extends"));
 
456
                    String transitiveValue = attributes.getValue("transitive");
 
457
                    boolean transitive = (transitiveValue == null) ? true : Boolean
 
458
                            .valueOf(attributes.getValue("transitive")).booleanValue();
 
459
                    String deprecated = attributes.getValue("deprecated");
 
460
                    Configuration configuration = new Configuration(conf,
 
461
                            Configuration.Visibility
 
462
                                    .getVisibility(visibility == null ? "public"
 
463
                                            : visibility), settings.substitute(attributes
 
464
                                    .getValue("description")), ext == null ? null : ext
 
465
                                    .split(","), transitive, deprecated);
 
466
                    ExtendableItemHelper.fillExtraAttributes(settings, configuration, attributes,
 
467
                        new String[] {"name", "visibility", "extends", "transitive",
 
468
                                "description", "deprecated"});
 
469
                    getMd().addConfiguration(configuration);
 
470
                    break;
 
471
                case State.PUB:
 
472
                    if ("*".equals(conf)) {
 
473
                        String[] confs = getMd().getConfigurationsNames();
 
474
                        for (int i = 0; i < confs.length; i++) {
 
475
                            artifact.addConfiguration(confs[i]);
 
476
                            getMd().addArtifact(confs[i], artifact);
 
477
                        }
 
478
                    } else {
 
479
                        artifact.addConfiguration(conf);
 
480
                        getMd().addArtifact(conf, artifact);
 
481
                    }
 
482
                    break;
 
483
                case State.DEP:
 
484
                    this.conf = conf;
 
485
                    String mappeds = settings.substitute(attributes.getValue("mapped"));
 
486
                    if (mappeds != null) {
 
487
                        String[] mapped = mappeds.split(",");
 
488
                        for (int i = 0; i < mapped.length; i++) {
 
489
                            dd.addDependencyConfiguration(conf, mapped[i].trim());
 
490
                        }
 
491
                    }
 
492
                    break;
 
493
                case State.DEP_ARTIFACT:
 
494
                case State.ARTIFACT_INCLUDE:
 
495
                case State.ARTIFACT_EXCLUDE:
 
496
                    addConfiguration(conf);
 
497
                    break;
 
498
                default:
 
499
                    if (validate) {
 
500
                        addError("conf tag found in invalid tag: " + state);
 
501
                    }
 
502
                    break;
 
503
            }
 
504
        }
 
505
 
 
506
        protected void dependencyStarted(Attributes attributes) {
 
507
            state = State.DEP;
 
508
            String org = settings.substitute(attributes.getValue("org"));
 
509
            if (org == null) {
 
510
                org = getMd().getModuleRevisionId().getOrganisation();
 
511
            }
 
512
            boolean force = Boolean.valueOf(settings.substitute(attributes.getValue("force")))
 
513
                    .booleanValue();
 
514
            boolean changing = Boolean.valueOf(
 
515
                settings.substitute(attributes.getValue("changing"))).booleanValue();
 
516
 
 
517
            String transitiveValue = settings.substitute(attributes.getValue("transitive"));
 
518
            boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf(
 
519
                attributes.getValue("transitive")).booleanValue();
 
520
 
 
521
            String name = settings.substitute(attributes.getValue("name"));
 
522
            String branch = settings.substitute(attributes.getValue("branch"));
 
523
            String branchConstraint = settings.substitute(attributes.getValue("branchConstraint"));
 
524
            String rev = settings.substitute(attributes.getValue("rev"));
 
525
            String revConstraint = settings.substitute(attributes.getValue("revConstraint"));
 
526
            revConstraint = revConstraint == null ? rev : revConstraint;
 
527
            Map extraAttributes = ExtendableItemHelper.getExtraAttributes(
 
528
                settings, attributes, DEPENDENCY_REGULAR_ATTRIBUTES);
 
529
            dd = new DefaultDependencyDescriptor(
 
530
                getMd(), 
 
531
                ModuleRevisionId.newInstance(org, name, branch, rev, extraAttributes), 
 
532
                ModuleRevisionId.newInstance(
 
533
                    org, name, branchConstraint, revConstraint, extraAttributes), 
 
534
                force, changing, transitive);
 
535
            getMd().addDependency(dd);
 
536
            String confs = settings.substitute(attributes.getValue("conf"));
 
537
            if (confs != null && confs.length() > 0) {
 
538
                parseDepsConfs(confs, dd);
 
539
            }
 
540
        }
 
541
 
 
542
        protected void artifactStarted(String qName, Attributes attributes) 
 
543
                throws MalformedURLException {
 
544
            if (state == State.PUB) {
 
545
                // this is a published artifact
 
546
                String artName = settings.substitute(attributes.getValue("name"));
 
547
                artName = artName == null ? getMd().getModuleRevisionId().getName() : artName;
 
548
                String type = settings.substitute(attributes.getValue("type"));
 
549
                type = type == null ? "jar" : type;
 
550
                String ext = settings.substitute(attributes.getValue("ext"));
 
551
                ext = ext != null ? ext : type;
 
552
                String url = settings.substitute(attributes.getValue("url"));
 
553
                artifact = new MDArtifact(getMd(), artName, type, ext, url == null ? null
 
554
                        : new URL(url), ExtendableItemHelper.getExtraAttributes(
 
555
                            settings, attributes, new String[] {"ext", "type", "name", "conf"}));
 
556
                String confs = settings.substitute(attributes.getValue("conf"));
 
557
                // only add confs if they are specified. if they aren't, endElement will
 
558
                // handle this
 
559
                // only if there are no conf defined in sub elements
 
560
                if (confs != null && confs.length() > 0) {
 
561
                    String[] conf;
 
562
                    if ("*".equals(confs)) {
 
563
                        conf = getMd().getConfigurationsNames();
 
564
                    } else {
 
565
                        conf = confs.split(",");
 
566
                    }
 
567
                    for (int i = 0; i < conf.length; i++) {
 
568
                        artifact.addConfiguration(conf[i].trim());
 
569
                        getMd().addArtifact(conf[i].trim(), artifact);
 
570
                    }
 
571
                }
 
572
            } else if (state == State.DEP) {
 
573
                // this is an artifact asked for a particular dependency
 
574
                addDependencyArtifacts(qName, attributes);
 
575
            } else if (validate) {
 
576
                addError("artifact tag found in invalid tag: " + state);
 
577
            }
 
578
        }
 
579
 
 
580
        protected void dependenciesStarted(Attributes attributes) {
 
581
            state = State.DEPS;
 
582
            String defaultConf = settings.substitute(attributes.getValue("defaultconf"));
 
583
            if (defaultConf != null) {
 
584
                setDefaultConf(defaultConf);
 
585
            }
 
586
            defaultConf = settings.substitute(attributes.getValue("defaultconfmapping"));
 
587
            if (defaultConf != null) {
 
588
                setDefaultConfMapping(defaultConf);
 
589
            }
 
590
            String confMappingOverride = settings.substitute(attributes
 
591
                    .getValue("confmappingoverride"));
 
592
            if (confMappingOverride != null) {
 
593
                getMd().setMappingOverride(Boolean.valueOf(confMappingOverride).booleanValue());
 
594
            }
 
595
            checkConfigurations();
 
596
        }
 
597
 
 
598
        protected void configurationStarted(Attributes attributes) {
 
599
            state = State.CONF;
 
600
            setDefaultConfMapping(settings
 
601
                    .substitute(attributes.getValue("defaultconfmapping")));
 
602
            getMd()
 
603
                    .setMappingOverride(Boolean.valueOf(
 
604
                        settings.substitute(attributes.getValue("confmappingoverride")))
 
605
                            .booleanValue());
 
606
        }
 
607
 
 
608
        protected void infoStarted(Attributes attributes) {
 
609
            state = State.INFO;
 
610
            String org = settings.substitute(attributes.getValue("organisation"));
 
611
            String module = settings.substitute(attributes.getValue("module"));
 
612
            String revision = settings.substitute(attributes.getValue("revision"));
 
613
            String branch = settings.substitute(attributes.getValue("branch"));
 
614
            getMd().setModuleRevisionId(ModuleRevisionId.newInstance(org, module, branch,
 
615
                revision, ExtendableItemHelper.getExtraAttributes(settings, attributes, 
 
616
                    new String[] {
 
617
                        "organisation", "module", "revision", "status", "publication",
 
618
                        "branch", "namespace", "default", "resolver"})));
 
619
 
 
620
            String namespace = settings.substitute(attributes.getValue("namespace"));
 
621
            if (namespace != null) {
 
622
                Namespace ns = settings.getNamespace(namespace);
 
623
                if (ns == null) {
 
624
                    Message.warn("namespace not found for " + getMd().getModuleRevisionId()
 
625
                            + ": " + namespace);
 
626
                } else {
 
627
                    getMd().setNamespace(ns);
 
628
                }
 
629
            }
 
630
 
 
631
            String status = settings.substitute(attributes.getValue("status"));
 
632
            getMd().setStatus(status == null ? settings.getStatusManager().getDefaultStatus()
 
633
                    : status);
 
634
            getMd().setDefault(Boolean.valueOf(settings.substitute(attributes.getValue("default")))
 
635
                    .booleanValue());
 
636
            String pubDate = settings.substitute(attributes.getValue("publication"));
 
637
            if (pubDate != null && pubDate.length() > 0) {
 
638
                try {
 
639
                    getMd().setPublicationDate(Ivy.DATE_FORMAT.parse(pubDate));
 
640
                } catch (ParseException e) {
 
641
                    addError("invalid publication date format: " + pubDate);
 
642
                    getMd().setPublicationDate(getDefaultPubDate());
 
643
                }
 
644
            } else {
 
645
                getMd().setPublicationDate(getDefaultPubDate());
 
646
            }
 
647
        }
 
648
 
 
649
        protected void ivyModuleStarted(Attributes attributes) throws SAXException {
 
650
            descriptorVersion = attributes.getValue("version");
 
651
            int versionIndex = ALLOWED_VERSIONS.indexOf(descriptorVersion);
 
652
            if (versionIndex == -1) {
 
653
                addError("invalid version " + descriptorVersion);
 
654
                throw new SAXException("invalid version " + descriptorVersion);
 
655
            }
 
656
            if (versionIndex >= ALLOWED_VERSIONS.indexOf("1.3")) {
 
657
                Message.debug("post 1.3 ivy file: using " + PatternMatcher.EXACT
 
658
                        + " as default matcher");
 
659
                defaultMatcher = settings.getMatcher(PatternMatcher.EXACT);
 
660
            } else {
 
661
                Message.debug("pre 1.3 ivy file: using " + PatternMatcher.EXACT_OR_REGEXP
 
662
                        + " as default matcher");
 
663
                defaultMatcher = settings.getMatcher(PatternMatcher.EXACT_OR_REGEXP);
 
664
            }
 
665
            
 
666
            for (int i = 0; i < attributes.getLength(); i++) {
 
667
                if (attributes.getQName(i).startsWith("xmlns:")) {
 
668
                    getMd().addExtraAttributeNamespace(
 
669
                        attributes.getQName(i).substring("xmlns:".length()), 
 
670
                        attributes.getValue(i));
 
671
                }
 
672
            }
 
673
        }
 
674
 
 
675
        protected void addDependencyArtifacts(String tag, Attributes attributes)
 
676
                throws MalformedURLException {
 
677
            state = State.DEP_ARTIFACT;
 
678
            parseRule(tag, attributes);
 
679
        }
 
680
 
 
681
        protected void addIncludeRule(String tag, Attributes attributes) 
 
682
                throws MalformedURLException {
 
683
            state = State.ARTIFACT_INCLUDE;
 
684
            parseRule(tag, attributes);
 
685
        }
 
686
 
 
687
        protected void addExcludeRule(String tag, Attributes attributes) 
 
688
                throws MalformedURLException {
 
689
            state = State.ARTIFACT_EXCLUDE;
 
690
            parseRule(tag, attributes);
 
691
        }
 
692
 
 
693
        protected void parseRule(String tag, Attributes attributes) throws MalformedURLException {
 
694
            String name = settings.substitute(attributes.getValue("name"));
 
695
            if (name == null) {
 
696
                name = settings.substitute(attributes.getValue("artifact"));
 
697
                if (name == null) {
 
698
                    name = "artifact".equals(tag) ? dd.getDependencyId().getName()
 
699
                            : PatternMatcher.ANY_EXPRESSION;
 
700
                }
 
701
            }
 
702
            String type = settings.substitute(attributes.getValue("type"));
 
703
            if (type == null) {
 
704
                type = "artifact".equals(tag) ? "jar" : PatternMatcher.ANY_EXPRESSION;
 
705
            }
 
706
            String ext = settings.substitute(attributes.getValue("ext"));
 
707
            ext = ext != null ? ext : type;
 
708
            if (state == State.DEP_ARTIFACT) {
 
709
                String url = settings.substitute(attributes.getValue("url"));
 
710
                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
 
711
                    new String[] {"name", "type", "ext", "url", "conf"});
 
712
                confAware = new DefaultDependencyArtifactDescriptor(dd, name, type, ext,
 
713
                        url == null ? null : new URL(url), extraAtt);
 
714
            } else if (state == State.ARTIFACT_INCLUDE) {
 
715
                PatternMatcher matcher = getPatternMatcher(attributes.getValue("matcher"));
 
716
                String org = settings.substitute(attributes.getValue("org"));
 
717
                org = org == null ? PatternMatcher.ANY_EXPRESSION : org;
 
718
                String module = settings.substitute(attributes.getValue("module"));
 
719
                module = module == null ? PatternMatcher.ANY_EXPRESSION : module;
 
720
                ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext);
 
721
                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
 
722
                    new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"});
 
723
                confAware = new DefaultIncludeRule(aid, matcher, extraAtt);
 
724
            } else { // _state == ARTIFACT_EXCLUDE || EXCLUDE
 
725
                PatternMatcher matcher = getPatternMatcher(attributes.getValue("matcher"));
 
726
                String org = settings.substitute(attributes.getValue("org"));
 
727
                org = org == null ? PatternMatcher.ANY_EXPRESSION : org;
 
728
                String module = settings.substitute(attributes.getValue("module"));
 
729
                module = module == null ? PatternMatcher.ANY_EXPRESSION : module;
 
730
                ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext);
 
731
                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
 
732
                    new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"});
 
733
                confAware = new DefaultExcludeRule(aid, matcher, extraAtt);
 
734
            }
 
735
            String confs = settings.substitute(attributes.getValue("conf"));
 
736
            // only add confs if they are specified. if they aren't, endElement will handle this
 
737
            // only if there are no conf defined in sub elements
 
738
            if (confs != null && confs.length() > 0) {
 
739
                String[] conf;
 
740
                if ("*".equals(confs)) {
 
741
                    conf = getMd().getConfigurationsNames();
 
742
                } else {
 
743
                    conf = confs.split(",");
 
744
                }
 
745
                for (int i = 0; i < conf.length; i++) {
 
746
                    addConfiguration(conf[i].trim());
 
747
                }
 
748
            }
 
749
        }
 
750
 
 
751
        protected void addConfiguration(String c) {
 
752
            confAware.addConfiguration(c);
 
753
            if (state == State.EXCLUDE) {
 
754
                // we are adding a configuration to a module wide exclude rule
 
755
                // we have nothing special to do here, the rule has already been added to the module
 
756
                // descriptor
 
757
            } else {
 
758
                // we are currently adding a configuration to either an include, exclude or artifact
 
759
                // element
 
760
                // of a dependency. This means that we have to add this element to the corresponding
 
761
                // conf
 
762
                // of the current dependency descriptor
 
763
                if (confAware instanceof DependencyArtifactDescriptor) {
 
764
                    dd.addDependencyArtifact(c, (DependencyArtifactDescriptor) confAware);
 
765
                } else if (confAware instanceof IncludeRule) {
 
766
                    dd.addIncludeRule(c, (IncludeRule) confAware);
 
767
                } else if (confAware instanceof ExcludeRule) {
 
768
                    dd.addExcludeRule(c, (ExcludeRule) confAware);
 
769
                }
 
770
            }
 
771
        }
 
772
 
 
773
        protected PatternMatcher getPatternMatcher(String m) {
 
774
            String matcherName = settings.substitute(m);
 
775
            PatternMatcher matcher = matcherName == null ? defaultMatcher : settings
 
776
                    .getMatcher(matcherName);
 
777
            if (matcher == null) {
 
778
                throw new IllegalArgumentException("unknown matcher " + matcherName);
 
779
            }
 
780
            return matcher;
 
781
        }
 
782
 
 
783
        
 
784
        public void characters(char[] ch, int start, int length) throws SAXException {
 
785
            if (buffer != null) {
 
786
                buffer.append(ch, start, length);
 
787
            }            
 
788
        }
 
789
 
 
790
        
 
791
        public void endElement(String uri, String localName, String qName) throws SAXException {
 
792
            if (state == State.PUB && "artifact".equals(qName)
 
793
                    && artifact.getConfigurations().length == 0) {
 
794
                String[] confs = publicationsDefaultConf == null 
 
795
                    ? getMd().getConfigurationsNames()
 
796
                    : publicationsDefaultConf;
 
797
                for (int i = 0; i < confs.length; i++) {
 
798
                    artifact.addConfiguration(confs[i].trim());
 
799
                    getMd().addArtifact(confs[i].trim(), artifact);
 
800
                }
 
801
            } else if ("configurations".equals(qName)) {
 
802
                checkConfigurations();
 
803
            } else if ((state == State.DEP_ARTIFACT && "artifact".equals(qName))
 
804
                    || (state == State.ARTIFACT_INCLUDE && "include".equals(qName))
 
805
                    || (state == State.ARTIFACT_EXCLUDE && "exclude".equals(qName))) {
 
806
                state = State.DEP;
 
807
                if (confAware.getConfigurations().length == 0) {
 
808
                    String[] confs = getMd().getConfigurationsNames();
 
809
                    for (int i = 0; i < confs.length; i++) {
 
810
                        addConfiguration(confs[i]);
 
811
                    }
 
812
                }
 
813
                confAware = null;
 
814
            } else if ("exclude".equals(qName) && state == State.EXCLUDE) {
 
815
                if (confAware.getConfigurations().length == 0) {
 
816
                    String[] confs = getMd().getConfigurationsNames();
 
817
                    for (int i = 0; i < confs.length; i++) {
 
818
                        addConfiguration(confs[i]);
 
819
                    }
 
820
                }
 
821
                confAware = null;
 
822
                state = State.DEPS;
 
823
            } else if ("dependency".equals(qName) && state == State.DEP) {
 
824
                if (dd.getModuleConfigurations().length == 0) {
 
825
                    parseDepsConfs(getDefaultConf(), dd);
 
826
                }
 
827
                state = State.DEPS;
 
828
            } else if ("dependencies".equals(qName) && state == State.DEPS) {
 
829
                state = State.NONE;
 
830
            } else if (state == State.INFO && "info".equals(qName)) {
 
831
                state = State.NONE;
 
832
            } else if (state == State.DESCRIPTION && "description".equals(qName)) {
 
833
                getMd().setDescription(buffer == null ? "" : buffer.toString().trim());
 
834
                buffer = null;
 
835
                state = State.INFO;
 
836
            } else if (state == State.EXTRA_INFO) {
 
837
                getMd().addExtraInfo(qName, buffer == null ? "" : buffer.toString());
 
838
                buffer = null;
 
839
                state = State.INFO;
 
840
            } else if (state == State.DESCRIPTION) {
 
841
                if (buffer.toString().endsWith("<" + qName + ">")) {
 
842
                    buffer.deleteCharAt(buffer.length() - 1);
 
843
                    buffer.append("/>");
 
844
                } else {
 
845
                    buffer.append("</" + qName + ">");
 
846
                }
 
847
            }
 
848
        }
 
849
 
 
850
        protected void checkConfigurations() {
 
851
            if (getMd().getConfigurations().length == 0) {
 
852
                getMd().addConfiguration(new Configuration("default"));
 
853
            }
 
854
        }
 
855
 
 
856
        protected void replaceConfigurationWildcards() {
 
857
            Configuration[] configs = getMd().getConfigurations();
 
858
            for (int i = 0; i < configs.length; i++) {
 
859
                configs[i].replaceWildcards(getMd());
 
860
            }
 
861
        }
 
862
 
 
863
        /* getters and setters available for extension only */
 
864
        protected ParserSettings getSettings() {
 
865
            return settings;
 
866
        }
 
867
 
 
868
        protected URL getDescriptorURL() {
 
869
            return descriptorURL;
 
870
        }
 
871
 
 
872
        protected InputStream getDescriptorInput() {
 
873
            return descriptorInput;
 
874
        }
 
875
 
 
876
        protected int getState() {
 
877
            return state;
 
878
        }
 
879
 
 
880
        protected void setState(int state) {
 
881
            this.state = state;
 
882
        }
 
883
 
 
884
        protected PatternMatcher getDefaultMatcher() {
 
885
            return defaultMatcher;
 
886
        }
 
887
 
 
888
        protected DefaultDependencyDescriptor getDd() {
 
889
            return dd;
 
890
        }
 
891
 
 
892
        protected void setDd(DefaultDependencyDescriptor dd) {
 
893
            this.dd = dd;
 
894
        }
 
895
 
 
896
        protected ConfigurationAware getConfAware() {
 
897
            return confAware;
 
898
        }
 
899
 
 
900
        protected void setConfAware(ConfigurationAware confAware) {
 
901
            this.confAware = confAware;
 
902
        }
 
903
 
 
904
        protected MDArtifact getArtifact() {
 
905
            return artifact;
 
906
        }
 
907
 
 
908
        protected void setArtifact(MDArtifact artifact) {
 
909
            this.artifact = artifact;
 
910
        }
 
911
 
 
912
        protected String getConf() {
 
913
            return conf;
 
914
        }
 
915
 
 
916
        protected void setConf(String conf) {
 
917
            this.conf = conf;
 
918
        }
 
919
 
 
920
        protected boolean isArtifactsDeclared() {
 
921
            return artifactsDeclared;
 
922
        }
 
923
 
 
924
        protected void setArtifactsDeclared(boolean artifactsDeclared) {
 
925
            this.artifactsDeclared = artifactsDeclared;
 
926
        }
 
927
 
 
928
        protected StringBuffer getBuffer() {
 
929
            return buffer;
 
930
        }
 
931
 
 
932
        protected void setBuffer(StringBuffer buffer) {
 
933
            this.buffer = buffer;
 
934
        }
 
935
 
 
936
        protected String getDescriptorVersion() {
 
937
            return descriptorVersion;
 
938
        }
 
939
 
 
940
        protected void setDescriptorVersion(String descriptorVersion) {
 
941
            this.descriptorVersion = descriptorVersion;
 
942
        }
 
943
 
 
944
        protected String[] getPublicationsDefaultConf() {
 
945
            return publicationsDefaultConf;
 
946
        }
 
947
 
 
948
        protected void setPublicationsDefaultConf(String[] publicationsDefaultConf) {
 
949
            this.publicationsDefaultConf = publicationsDefaultConf;
 
950
        }
 
951
 
 
952
        protected boolean isValidate() {
 
953
            return validate;
 
954
        }
 
955
 
 
956
        protected URL getSchemaURL() {
 
957
            return getClass().getResource("ivy.xsd");
 
958
        }
 
959
    }
 
960
 
 
961
    public String toString() {
 
962
        return "ivy parser";
 
963
    }
 
964
}