1 6 package fr.jayasoft.ivy.xml; 7 8 import java.io.File ; 9 import java.io.IOException ; 10 import java.io.InputStream ; 11 import java.net.MalformedURLException ; 12 import java.net.URL ; 13 import java.text.ParseException ; 14 import java.util.Arrays ; 15 import java.util.Collections ; 16 import java.util.List ; 17 18 import javax.xml.parsers.ParserConfigurationException ; 19 20 import org.xml.sax.Attributes ; 21 import org.xml.sax.SAXException ; 22 23 import fr.jayasoft.ivy.ArtifactId; 24 import fr.jayasoft.ivy.Configuration; 25 import fr.jayasoft.ivy.ConflictManager; 26 import fr.jayasoft.ivy.DefaultDependencyArtifactDescriptor; 27 import fr.jayasoft.ivy.DefaultDependencyDescriptor; 28 import fr.jayasoft.ivy.DefaultModuleDescriptor; 29 import fr.jayasoft.ivy.Ivy; 30 import fr.jayasoft.ivy.License; 31 import fr.jayasoft.ivy.MDArtifact; 32 import fr.jayasoft.ivy.ModuleDescriptor; 33 import fr.jayasoft.ivy.ModuleId; 34 import fr.jayasoft.ivy.ModuleRevisionId; 35 import fr.jayasoft.ivy.conflict.FixedConflictManager; 36 import fr.jayasoft.ivy.extendable.ExtendableItemHelper; 37 import fr.jayasoft.ivy.matcher.PatternMatcher; 38 import fr.jayasoft.ivy.namespace.Namespace; 39 import fr.jayasoft.ivy.parser.AbstractModuleDescriptorParser; 40 import fr.jayasoft.ivy.parser.ModuleDescriptorParser; 41 import fr.jayasoft.ivy.repository.Resource; 42 import fr.jayasoft.ivy.repository.url.URLResource; 43 import fr.jayasoft.ivy.util.Message; 44 import fr.jayasoft.ivy.util.XMLHelper; 45 46 55 public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { 56 private static XmlModuleDescriptorParser INSTANCE = new XmlModuleDescriptorParser(); 57 58 public static XmlModuleDescriptorParser getInstance() { 59 return INSTANCE; 60 } 61 62 private XmlModuleDescriptorParser() { 63 64 } 65 66 76 public ModuleDescriptor parseDescriptor(Ivy ivy, URL xmlURL, Resource res, boolean validate) throws ParseException , IOException { 77 Parser parser = new Parser(this, ivy, validate); 78 parser.parse(xmlURL, res, validate); 79 return parser.getModuleDescriptor(); 80 } 81 82 public boolean accept(Resource res) { 83 return true; } 85 86 public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws IOException , ParseException { 87 try { 88 Namespace ns = null; 89 if (md instanceof DefaultModuleDescriptor) { 90 DefaultModuleDescriptor dmd = (DefaultModuleDescriptor)md; 91 ns = dmd.getNamespace(); 92 } 93 XmlModuleDescriptorUpdater.update( 94 null, 95 is, 96 destFile, 97 Collections.EMPTY_MAP, 98 md.getStatus(), 99 md.getResolvedModuleRevisionId().getRevision(), 100 md.getResolvedPublicationDate(), 101 ns, 102 false); 103 } catch (SAXException e) { 104 ParseException ex = new ParseException ("exception occured while parsing "+res, 0); 105 ex.initCause(e); 106 throw ex; 107 } finally { 108 if (is != null) { 109 is.close(); 110 } 111 } 112 } 113 114 private static class Parser extends AbstractParser { 115 116 private static final List ALLOWED_VERSIONS = Arrays.asList(new String [] {"1.0", "1.1", "1.2", "1.3", "1.4"}); 117 118 private DefaultDependencyDescriptor _dd; 119 private DefaultDependencyArtifactDescriptor _dad; 120 private MDArtifact _artifact; 121 private String _conf; 122 private boolean _validate = true; 123 private Ivy _ivy; 124 private boolean _artifactsDeclared = false; 125 private PatternMatcher _defaultMatcher; 126 127 private static final int NONE = 0; 128 private static final int INFO = 1; 129 private static final int CONF = 2; 130 private static final int PUB = 3; 131 private static final int DEP = 4; 132 private static final int ARTIFACT_INCLUDE = 5; 133 private static final int ARTIFACT_EXCLUDE = 6; 134 private static final int CONFLICT = 7; 135 private int _state = NONE; 136 137 public Parser(ModuleDescriptorParser parser, Ivy ivy, boolean validate) { 138 super(parser); 139 _ivy = ivy; 140 _validate = validate; 141 } 142 143 private void parse(URL xmlURL, Resource res, boolean validate) throws ParseException , IOException { 144 try { 145 setResource(res); 146 URL schemaURL = validate?getClass().getResource("ivy.xsd"):null; 147 XMLHelper.parse(xmlURL, schemaURL, this); 148 checkConfigurations(); 149 replaceConfigurationWildcards(); 150 if (!_artifactsDeclared) { 151 String [] confs = _md.getConfigurationsNames(); 152 for (int i = 0; i < confs.length; i++) { 153 _md.addArtifact(confs[i], new MDArtifact(_md, _md.getModuleRevisionId().getName(), "jar", "jar")); 154 } 155 } 156 _md.check(); 157 } catch (ParserConfigurationException ex) { 158 IllegalStateException ise = new IllegalStateException (ex.getMessage()+" in "+xmlURL); 159 ise.initCause(ex); 160 throw ise; 161 } catch (Exception ex) { 162 checkErrors(); 163 ParseException pe = new ParseException (ex.getMessage()+" in "+xmlURL, 0); 164 pe.initCause(ex); 165 throw pe; 166 } 167 } 168 169 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 170 try { 171 if ("ivy-module".equals(qName)) { 172 String version = attributes.getValue("version"); 173 int versionIndex = ALLOWED_VERSIONS.indexOf(version); 174 if (versionIndex == -1) { 175 addError("invalid version "+version); 176 throw new SAXException ("invalid version "+version); 177 } 178 if (versionIndex >= ALLOWED_VERSIONS.indexOf("1.3")) { 179 Message.debug("post 1.3 ivy file: using "+PatternMatcher.EXACT+" as default matcher"); 180 _defaultMatcher = _ivy.getMatcher(PatternMatcher.EXACT); 181 } else { 182 Message.debug("pre 1.3 ivy file: using "+PatternMatcher.EXACT_OR_REGEXP+" as default matcher"); 183 _defaultMatcher = _ivy.getMatcher(PatternMatcher.EXACT_OR_REGEXP); 184 } 185 } else if ("info".equals(qName)) { 186 _state = INFO; 187 String org = _ivy.substitute(attributes.getValue("organisation")); 188 String module = _ivy.substitute(attributes.getValue("module")); 189 String revision = _ivy.substitute(attributes.getValue("revision")); 190 String branch = _ivy.substitute(attributes.getValue("branch")); 191 _md.setModuleRevisionId(ModuleRevisionId.newInstance(org, module, branch, revision, ExtendableItemHelper.getExtraAttributes(attributes, new String [] {"organisation", "module", "revision", "status", "publication", "namespace", "default", "resolver"}))); 192 193 String namespace = _ivy.substitute(attributes.getValue("namespace")); 194 if (namespace != null) { 195 Namespace ns = _ivy.getNamespace(namespace); 196 if (ns == null) { 197 Message.warn("namespace not found for "+_md.getModuleRevisionId()+": "+namespace); 198 } else { 199 _md.setNamespace(ns); 200 } 201 } 202 203 String status = _ivy.substitute(attributes.getValue("status")); 204 _md.setStatus(status == null ? _ivy.getStatusManager().getDefaultStatus() : status); 205 _md.setDefault(Boolean.valueOf(_ivy.substitute(attributes.getValue("default"))).booleanValue()); 206 String pubDate = _ivy.substitute(attributes.getValue("publication")); 207 if (pubDate != null && pubDate.length() > 0) { 208 try { 209 _md.setPublicationDate(Ivy.DATE_FORMAT.parse(pubDate)); 210 } catch (ParseException e) { 211 addError("invalid publication date format: "+pubDate); 212 _md.setPublicationDate(getDefaultPubDate()); 213 } 214 } else { 215 _md.setPublicationDate(getDefaultPubDate()); 216 } 217 218 } else if ("license".equals(qName)) { 219 _md.addLicense(new License(_ivy.substitute(attributes.getValue("name")), _ivy.substitute(attributes.getValue("url")))); 220 } else if ("description".equals(qName)) { 221 _md.setHomePage(_ivy.substitute(attributes.getValue("homepage"))); 222 } else if ("configurations".equals(qName)) { 223 _state = CONF; 224 setDefaultConfMapping(_ivy.substitute(attributes.getValue("defaultconfmapping"))); 225 _md.setMappingOverride(Boolean.valueOf(_ivy.substitute(attributes.getValue("confmappingoverride"))).booleanValue()); 226 } else if ("publications".equals(qName)) { 227 _state = PUB; 228 _artifactsDeclared = true; 229 checkConfigurations(); 230 } else if ("dependencies".equals(qName)) { 231 _state = DEP; 232 String defaultConf = _ivy.substitute(attributes.getValue("defaultconf")); 233 if (defaultConf != null) { 234 setDefaultConf(defaultConf); 235 } 236 defaultConf = _ivy.substitute(attributes.getValue("defaultconfmapping")); 237 if (defaultConf != null) { 238 setDefaultConfMapping(defaultConf); 239 } 240 String confMappingOverride = _ivy.substitute(attributes.getValue("confmappingoverride")); 241 if (confMappingOverride != null) { 242 _md.setMappingOverride(Boolean.valueOf(confMappingOverride).booleanValue()); 243 } 244 checkConfigurations(); 245 } else if ("conflicts".equals(qName)) { 246 _state = CONFLICT; 247 checkConfigurations(); 248 } else if ("artifact".equals(qName)) { 249 if (_state == PUB) { 250 String artName = _ivy.substitute(attributes.getValue("name")); 252 artName = artName == null ? _md.getModuleRevisionId().getName() : artName; 253 String type = _ivy.substitute(attributes.getValue("type")); 254 type = type == null ? "jar" : type; 255 String ext = _ivy.substitute(attributes.getValue("ext")); 256 ext = ext != null ? ext : type; 257 String url = _ivy.substitute(attributes.getValue("url")); 258 _artifact = new MDArtifact(_md, artName, type, ext, url == null ? null : new URL (url), ExtendableItemHelper.getExtraAttributes(attributes, new String [] {"ext", "type", "name", "conf"})); 259 String confs = _ivy.substitute(attributes.getValue("conf")); 260 if (confs != null && confs.length() > 0) { 263 String [] conf; 264 if ("*".equals(confs)) { 265 conf = _md.getConfigurationsNames(); 266 } else { 267 conf = confs.split(","); 268 } 269 for (int i = 0; i < conf.length; i++) { 270 _artifact.addConfiguration(conf[i].trim()); 271 _md.addArtifact(conf[i].trim(), _artifact); 272 } 273 } 274 } else if (_state == DEP) { 275 addDependencyArtifacts(qName, attributes); 277 } else if (_validate) { 278 addError("artifact tag found in invalid tag: "+_state); 279 } 280 } else if ("include".equals(qName) && _state == DEP) { 281 addDependencyArtifactsIncludes(qName, attributes); 282 } else if ("exclude".equals(qName)) { 283 addDependencyArtifactsExcludes(qName, attributes); 284 } else if ("dependency".equals(qName)) { 285 String org = _ivy.substitute(attributes.getValue("org")); 286 if (org == null) { 287 org = _md.getModuleRevisionId().getOrganisation(); 288 } 289 boolean force = Boolean.valueOf(_ivy.substitute(attributes.getValue("force"))).booleanValue(); 290 boolean changing = Boolean.valueOf(_ivy.substitute(attributes.getValue("changing"))).booleanValue(); 291 292 String transitiveValue = _ivy.substitute(attributes.getValue("transitive")); 293 boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf(attributes.getValue("transitive")).booleanValue(); 294 295 String name = _ivy.substitute(attributes.getValue("name")); 296 String branch = _ivy.substitute(attributes.getValue("branch")); 297 String rev = _ivy.substitute(attributes.getValue("rev")); 298 _dd = new DefaultDependencyDescriptor(_md, ModuleRevisionId.newInstance(org, name, branch, rev, ExtendableItemHelper.getExtraAttributes(attributes, new String [] {"org", "name", "rev", "force", "transitive", "changing", "conf"})), force, changing, transitive); 299 _md.addDependency(_dd); 300 String confs = _ivy.substitute(attributes.getValue("conf")); 301 if (confs != null && confs.length() > 0) { 302 parseDepsConfs(confs, _dd); 303 } 304 } else if ("conf".equals(qName)) { 305 String conf = _ivy.substitute(attributes.getValue("name")); 306 switch (_state) { 307 case CONF: 308 String visibility = _ivy.substitute(attributes.getValue("visibility")); 309 String ext = _ivy.substitute(attributes.getValue("extends")); 310 String transitiveValue = attributes.getValue("transitive"); 311 boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf(attributes.getValue("transitive")).booleanValue(); 312 Configuration configuration = new Configuration( 313 conf, 314 Configuration.Visibility.getVisibility(visibility == null ? "public":visibility), 315 _ivy.substitute(attributes.getValue("description")), 316 ext==null?null:ext.split(","), 317 transitive); 318 ExtendableItemHelper.fillExtraAttributes(configuration, attributes, new String [] {"name", "visibility", "extends", "transitive", "description"}); 319 _md.addConfiguration(configuration); 320 break; 321 case PUB: 322 if ("*".equals(conf)) { 323 String [] confs = _md.getConfigurationsNames(); 324 for (int i = 0; i < confs.length; i++) { 325 _artifact.addConfiguration(confs[i]); 326 _md.addArtifact(confs[i], _artifact); 327 } 328 } else { 329 _artifact.addConfiguration(conf); 330 _md.addArtifact(conf, _artifact); 331 } 332 break; 333 case DEP: 334 _conf = conf; 335 String mappeds = _ivy.substitute(attributes.getValue("mapped")); 336 if (mappeds != null) { 337 String [] mapped = mappeds.split(","); 338 for (int i = 0; i < mapped.length; i++) { 339 _dd.addDependencyConfiguration(_conf, mapped[i].trim()); 340 } 341 } 342 break; 343 case ARTIFACT_INCLUDE: 344 case ARTIFACT_EXCLUDE: 345 _dad.addConfiguration(conf); 346 break; 347 default: 348 if (_validate) { 349 addError("conf tag found in invalid tag: "+_state); 350 } 351 break; 352 } 353 } else if ("mapped".equals(qName)) { 354 _dd.addDependencyConfiguration(_conf, _ivy.substitute(attributes.getValue("name"))); 355 } else if ("manager".equals(qName) && _state == CONFLICT) { 356 String org = _ivy.substitute(attributes.getValue("org")); 357 org = org == null ? PatternMatcher.ANY_EXPRESSION : org; 358 String mod = _ivy.substitute(attributes.getValue("module")); 359 mod = mod == null ? PatternMatcher.ANY_EXPRESSION : mod; 360 ConflictManager cm; 361 String name = _ivy.substitute(attributes.getValue("name")); 362 String rev = _ivy.substitute(attributes.getValue("rev")); 363 if (rev != null) { 364 String [] revs = rev.split(","); 365 for (int i = 0; i < revs.length; i++) { 366 revs[i] = revs[i].trim(); 367 } 368 cm = new FixedConflictManager(revs); 369 } else if (name != null) { 370 cm = _ivy.getConflictManager(name); 371 if (cm == null) { 372 addError("unknown conflict manager: "+name); 373 return; 374 } 375 } else { 376 addError("bad conflict manager: no name nor rev"); 377 return; 378 } 379 String matcherName = _ivy.substitute(attributes.getValue("matcher")); 380 PatternMatcher matcher = matcherName == null ? _defaultMatcher : _ivy.getMatcher(matcherName); 381 if (matcher == null) { 382 addError("unknown matcher: "+matcherName); 383 return; 384 } 385 _md.addConflictManager(new ModuleId(org, mod), matcher, cm); 386 } else if ("include".equals(qName) && _state == CONF) { 387 URL url; 388 String fileName = _ivy.substitute(attributes.getValue("file")); 389 if (fileName == null) { 390 String urlStr = _ivy.substitute(attributes.getValue("url")); 391 url = new URL (urlStr); 392 } else { 393 url = new File (fileName).toURL(); 394 } 395 396 Parser parser = new Parser(getModuleDescriptorParser(), _ivy, false); 399 parser._md = new DefaultModuleDescriptor(getModuleDescriptorParser(), new URLResource(url)); 400 XMLHelper.parse(url, null, parser); 401 402 Configuration[] configs = parser.getModuleDescriptor().getConfigurations(); 404 for (int i = 0; i < configs.length; i++) { 405 _md.addConfiguration(configs[i]); 406 } 407 if (parser.getDefaultConfMapping() != null) { 408 Message.debug("setting default conf from imported configurations file: "+parser.getDefaultConfMapping()); 409 setDefaultConfMapping(parser.getDefaultConfMapping()); 410 } 411 if (parser._md.isMappingOverride()) { 412 Message.debug("enabling mapping-override from imported configurations file"); 413 _md.setMappingOverride(true); 414 } 415 } else if (_validate && _state != INFO) { 416 addError("unknwon tag "+qName); 417 } 418 } catch (Exception ex) { 419 if (ex instanceof SAXException ) { 420 throw (SAXException )ex; 421 } 422 throw new SAXException ("problem occured while parsing ivy file. message: "+ex.getMessage(), ex); 423 } 424 } 425 426 private void addDependencyArtifacts(String tag, Attributes attributes) throws MalformedURLException { 427 _state = ARTIFACT_INCLUDE; 428 addDependencyArtifact(tag, attributes, true); 429 } 430 431 private void addDependencyArtifactsIncludes(String tag, Attributes attributes) throws MalformedURLException { 432 _state = ARTIFACT_INCLUDE; 433 addDependencyArtifact(tag, attributes, true); 434 } 435 436 private void addDependencyArtifactsExcludes(String tag, Attributes attributes) throws MalformedURLException { 437 _state = ARTIFACT_EXCLUDE; 438 addDependencyArtifact(tag, attributes, false); 439 } 440 441 private void addDependencyArtifact(String tag, Attributes attributes, boolean includes) throws MalformedURLException { 442 String name = _ivy.substitute(attributes.getValue("name")); 443 if (name == null) { 444 name = "artifact".equals(tag)?_dd.getDependencyId().getName() : PatternMatcher.ANY_EXPRESSION; 445 } 446 String type = _ivy.substitute(attributes.getValue("type")); 447 if (type == null) { 448 type = "artifact".equals(tag)?"jar" : PatternMatcher.ANY_EXPRESSION; 449 } 450 String ext = _ivy.substitute(attributes.getValue("ext")); 451 ext = ext != null?ext:type; 452 String matcherName = _ivy.substitute(attributes.getValue("matcher")); 453 PatternMatcher matcher = matcherName == null ? _defaultMatcher : _ivy.getMatcher(matcherName); 454 if (matcher == null) { 455 addError("unknown matcher "+matcherName); 456 return; 457 } 458 if (includes) { 459 String url = _ivy.substitute(attributes.getValue("url")); 460 _dad = new DefaultDependencyArtifactDescriptor(_dd, name, type, ext, url==null?null:new URL (url), includes, matcher); 461 } else { 462 String org = _ivy.substitute(attributes.getValue("org")); 463 org = org == null ? PatternMatcher.ANY_EXPRESSION : org; 464 String module = _ivy.substitute(attributes.getValue("module")); 465 module = module == null ? PatternMatcher.ANY_EXPRESSION : module; 466 ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext); 467 _dad = new DefaultDependencyArtifactDescriptor(_dd, aid, includes, matcher); 468 } 469 String confs = _ivy.substitute(attributes.getValue("conf")); 470 if (confs != null && confs.length() > 0) { 473 String [] conf; 474 if ("*".equals(confs)) { 475 conf = _md.getConfigurationsNames(); 476 } else { 477 conf = confs.split(","); 478 } 479 for (int i = 0; i < conf.length; i++) { 480 _dad.addConfiguration(conf[i].trim()); 481 } 482 } 483 } 484 485 public void endElement(String uri, String localName, String qName) throws SAXException { 486 if (_state == PUB && "artifact".equals(qName) && _artifact.getConfigurations().length == 0) { 487 String [] confs = _md.getConfigurationsNames(); 488 for (int i = 0; i < confs.length; i++) { 489 _artifact.addConfiguration(confs[i]); 490 _md.addArtifact(confs[i], _artifact); 491 } 492 } else if ("configurations".equals(qName)) { 493 checkConfigurations(); 494 } else if ((_state == ARTIFACT_INCLUDE && ("artifact".equals(qName) || "include".equals(qName))) 495 || (_state == ARTIFACT_EXCLUDE && "exclude".equals(qName))){ 496 _state = DEP; 497 if (_dad.getConfigurations().length == 0) { 498 String [] confs = _md.getConfigurationsNames(); 499 for (int i = 0; i < confs.length; i++) { 500 _dad.addConfiguration(confs[i]); 501 } 502 } 503 } else if ("dependency".equals(qName) && _dd.getModuleConfigurations().length == 0) { 504 parseDepsConfs(getDefaultConf(), _dd); 505 } 506 } 507 508 private void checkConfigurations() { 509 if (_md.getConfigurations().length == 0) { 510 _md.addConfiguration(new Configuration("default")); 511 } 512 } 513 514 private void replaceConfigurationWildcards() { 515 Configuration[] configs = _md.getConfigurations(); 516 for (int i = 0; i < configs.length; i++) { 517 configs[i].replaceWildcards(_md); 518 } 519 } 520 521 522 } 523 524 public String toString() { 525 return "ivy parser"; 526 } 527 528 public static void main(String [] args) throws Exception { 529 System.out.println(getInstance().parseDescriptor(new Ivy(), new File ("test/xml/module1/module1.ivy.xml").toURL(), true)); 530 } 531 } 532 | Popular Tags |