001 /* 002 * Copyright 2001,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.apache.commons.jjar; 018 019 import java.util.Properties; 020 import java.util.StringTokenizer; 021 import java.util.ArrayList; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Stack; 025 import java.util.Map; 026 import java.util.HashMap; 027 028 import java.io.StringWriter; 029 import java.io.Writer; 030 import java.io.InputStream; 031 import java.io.InputStreamReader; 032 import java.io.BufferedInputStream; 033 import java.io.IOException; 034 035 import java.net.URL; 036 import java.net.URLConnection; 037 038 import org.xml.sax.*; 039 import uk.co.wilson.xml.MinML2; 040 041 /** 042 * Repository implementation that supports XML repository 043 * definitions. Uses a great small little lightweight SAX 044 * parser - but it's not clear what it doesn't support, so 045 * be careful 046 * 047 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> 048 * @version $Id: RepositoryXML.java 155454 2005-02-26 13:23:34Z dirkv $ 049 */ 050 public class RepositoryXML extends MinML2 implements Repository 051 { 052 /** list of packages */ 053 private HashMap packageMap = new HashMap(); 054 int packageCount = 0; 055 056 /** handles package dependency generation */ 057 private static DependencyEngine de = new DependencyEngine(); 058 059 /** root of our document tree */ 060 private Node root = null; 061 062 /** stack used for SAX parsing */ 063 private Stack stack = new Stack(); 064 065 /** user for SAX parsing to avoid character events */ 066 private StringWriter saxWriter = null; 067 068 /** string constants for use in data structure */ 069 private static String PACKAGENAME = "packagename"; 070 private static String DEFAULTVERSION = "defaultversion"; 071 private static String NODE = "node"; 072 private static String DESCRIPTION = "description"; 073 private static String HREF = "href"; 074 private static String VERSION = "version"; 075 private static String VERSION_INFO = "version_info"; 076 private static String VERSION_JAR = "version_jar"; 077 private static String DEP_PACKAGE = "dep_package"; 078 private static String DEP_VERSION = "dep_version"; 079 private static String VERSION_DEPS = "version_deps"; 080 private static String VERSION_ARRAY = "version_array"; 081 082 /** 083 * loads the object with the XML data from the 084 * passed in URL. Invokes the SAX parser. 085 * 086 * @param url location of the repository.xml 087 */ 088 public void load( URL url ) 089 { 090 load( url, packageMap ); 091 } 092 093 public void load( URL url, Map pkgMap ) 094 { 095 try 096 { 097 URLConnection conn = url.openConnection(); 098 InputStream is = conn.getInputStream(); 099 100 parse(new InputStreamReader(new BufferedInputStream( is))); 101 process( pkgMap ); 102 } 103 catch ( IOException e) 104 { 105 System.out.println("IOException: " + e); 106 e.printStackTrace(); 107 } 108 catch ( SAXException e) 109 { 110 System.out.println("SAXException: " + e); 111 e.printStackTrace(); 112 } 113 catch ( Throwable e) 114 { 115 System.out.println("Other Exception: " + e); 116 e.printStackTrace(); 117 } 118 } 119 120 /** 121 * returns a list of dependencies for 122 * a given package. The list contains 123 * Maps, with 'package' and 'version' 124 * as the keys for the necessary info. 125 * 126 * @param pkg package to get dep list for 127 * @return List of Maps 128 */ 129 public List getDependencyList( String pkg, String version ) 130 { 131 if( isPackage( pkg )) 132 return de.getDependencies( pkg + ":" + version ); 133 134 return new ArrayList(); 135 } 136 137 /** 138 * returns an iterator over the 139 * list of package names 140 */ 141 public Iterator getPackageListIter() 142 { 143 return packageMap.keySet().iterator(); 144 } 145 146 /** 147 * returns the number of packages known to 148 * the repository 149 */ 150 public int getPackageCount() 151 { 152 return packageMap.size(); 153 } 154 155 /** 156 * returns the default version of the package to the caller 157 */ 158 public String getPackageDefaultVersion( String pkg ) 159 { 160 if (isPackage( pkg ) ) 161 { 162 HashMap hpack = (HashMap) packageMap.get( pkg ); 163 return (String) hpack.get( DEFAULTVERSION); 164 } 165 166 return null; 167 } 168 169 /** 170 * returns the info/desc string to the caller 171 */ 172 public String getPackageDescription( String pkg ) 173 { 174 if (isPackage( pkg ) ) 175 { 176 HashMap hpack = (HashMap) packageMap.get( pkg ); 177 return (String) hpack.get( DESCRIPTION); 178 } 179 180 return ""; 181 } 182 183 /** 184 * returns the 'fetch' target (jarname) for the 185 * given package : version 186 */ 187 public String getFetchTarget( String pkg, String version ) 188 { 189 190 /* 191 * first see if we know about this package. 192 */ 193 194 if (!isPackage( pkg )) 195 return null; 196 197 /* 198 * next, get the package info and see if we have this version 199 */ 200 201 Map hp = (HashMap) packageMap.get( pkg ); 202 Iterator i =((ArrayList) hp.get( VERSION_ARRAY )).iterator(); 203 204 while( i.hasNext() ) 205 { 206 HashMap vi = (HashMap) i.next(); 207 String ver = (String) vi.get( VERSION ); 208 209 if (ver != null) 210 { 211 if (version.equals( ver ) ) 212 { 213 String out = (String) vi.get(VERSION_JAR); 214 return out; 215 } 216 } 217 } 218 219 return null; 220 } 221 222 /** 223 * determines if something is a known package 224 */ 225 public boolean isPackage( String pkg ) 226 { 227 Object o = packageMap.get( pkg ); 228 229 if( o != null) 230 return true; 231 232 return false; 233 } 234 235 /** 236 * returns a given property 237 * not implemented 238 */ 239 public String getProp( String s ) 240 { 241 return s; 242 } 243 244 /** 245 * returns a list of the know versions available 246 * for this package 247 */ 248 public List getPackageVersionList( String pkg ) 249 { 250 if(!isPackage( pkg )) 251 return null; 252 253 Map hp = (HashMap) packageMap.get( pkg ); 254 255 ArrayList verlist = new ArrayList(); 256 257 Iterator i =((ArrayList) hp.get( VERSION_ARRAY )).iterator(); 258 259 while( i.hasNext() ) 260 { 261 verlist.add( ( (HashMap)i.next() ).get( VERSION ) ); 262 } 263 264 return verlist; 265 } 266 267 private List makeList( String thing ) 268 { 269 StringTokenizer st = new StringTokenizer( thing, ", "); 270 271 List list = new ArrayList(); 272 273 while(st.hasMoreTokens() ) 274 { 275 list.add( st.nextToken().trim() ); 276 } 277 278 return list; 279 } 280 281 /** 282 * takes the intermediary form of input data, and loads the 283 * internal data structures for use later. This needs to be 284 * called right after parsing, and before use. 285 */ 286 private void process( Map pkgMap ) 287 { 288 /* 289 * need to build a package list. Get the package groups. 290 */ 291 292 List packagegroup = getDocNodeList( root, "packagegroup"); 293 294 if (packagegroup == null) 295 System.out.println("Packagegroup == null"); 296 297 //System.out.println("packagegroup has " + packagegroup.size() + "elements"); 298 299 Iterator i = packagegroup.iterator(); 300 301 while( i.hasNext() ) 302 { 303 Node pkggrp = (Node) i.next(); 304 305 //System.out.println("Processing packagegroup : " + pkggrp.getAttribute("name") ); 306 307 List packages = getDocNodeList( pkggrp, "package"); 308 309 /* 310 * for each package... 311 */ 312 313 Iterator ii = packages.iterator(); 314 315 while( ii.hasNext() ) 316 { 317 processPackageNode( (Node) ii.next(), pkgMap ); 318 } 319 } 320 } 321 322 private void processPackageNode( Node pkg, Map pkgMap ) 323 { 324 HashMap pkginfo = new HashMap(); 325 326 /* 327 * start with the basics 328 */ 329 330 pkginfo.put( PACKAGENAME, pkg.getAttribute("name") ); 331 pkginfo.put( DEFAULTVERSION, pkg.getAttribute("default")); 332 pkginfo.put( NODE, pkg ); 333 334 /* 335 * does this have a definition here or remote? 336 */ 337 338 Node def = getDocNode( pkg, "definition"); 339 340 if (def != null) 341 { 342 /* 343 * now get the information node 344 */ 345 346 Node info = getDocNode( def, "info/desc"); 347 348 if( info != null) 349 pkginfo.put( DESCRIPTION, info.getValue()); 350 351 info = getDocNode( def, "info/href"); 352 353 if( info != null) 354 pkginfo.put( HREF, info.getValue()); 355 356 /* 357 * process version info 358 */ 359 360 List versionlist = getDocNodeList( def, "versionset/version"); 361 ArrayList versionArray = new ArrayList(); 362 363 Iterator v = versionlist.iterator(); 364 365 while( v.hasNext() ) 366 { 367 Node n = (Node) v.next(); 368 369 HashMap vi = new HashMap(); 370 371 vi.put( VERSION, n.getAttribute("version") ); 372 373 Node nn = getDocNode( n, "note"); 374 vi.put( VERSION_INFO, nn.getValue() ); 375 376 nn = getDocNode( n, "jar"); 377 vi.put( VERSION_JAR, nn.getValue() ); 378 379 /* the dependencies */ 380 381 ArrayList deplist = new ArrayList(); 382 383 List deps = getDocNodeList( n, "dependencies/dep"); 384 385 if (deps != null) 386 { 387 Iterator ii = deps.iterator(); 388 389 while( ii.hasNext() ) 390 { 391 HashMap h = new HashMap(); 392 Node ndep = (Node) ii.next(); 393 394 h.put( DEP_PACKAGE, ndep.getAttribute("package") ); 395 h.put( DEP_VERSION, ndep.getAttribute("version") ); 396 397 deplist.add( h ); 398 } 399 400 vi.put( VERSION_DEPS, deplist ); 401 } 402 403 versionArray.add( vi ); 404 405 /* 406 * add the package:version to the dependency engine 407 */ 408 409 String token = pkginfo.get( PACKAGENAME ) + ":" + (String) vi.get( VERSION ); 410 411 // System.out.println("Adding " + token + " to dependency engine."); 412 413 ArrayList depar = new ArrayList(); 414 415 Iterator depiter = deplist.iterator(); 416 417 while( depiter.hasNext() ) 418 { 419 HashMap h = (HashMap) depiter.next(); 420 421 String deptoken = (String) h.get(DEP_PACKAGE) + ":" + (String) h.get(DEP_VERSION); 422 depar.add( deptoken ); 423 } 424 425 try 426 { 427 de.addProject( token, depar, token ); 428 } 429 catch( Exception e ) 430 {} 431 432 } 433 434 pkginfo.put( VERSION_ARRAY, versionArray ); 435 436 /* 437 * add the info to the packageMap 438 */ 439 440 pkgMap.put( pkginfo.get( PACKAGENAME ), pkginfo ); 441 442 // dumpPackageInfo( pkginfo ); 443 } 444 else 445 { 446 /* 447 * is this a remote repository? 448 */ 449 450 Node remote = getDocNode( pkg, "remotedefinition"); 451 452 if (remote != null) 453 { 454 System.out.println( "Note package '" + ( (String) pkginfo.get( PACKAGENAME ) ) 455 + "' defining repository is remote, coming from " + remote.getValue() ); 456 457 /* 458 * now recursively get the info 459 */ 460 461 try 462 { 463 RepositoryXML rep = new RepositoryXML(); 464 rep.load( new URL( remote.getValue() ), pkgMap ); 465 } 466 catch( Exception ee ) 467 {} 468 } 469 else 470 { 471 System.out.println("Malformed repository : neither <definition> or <remotedefinition>"); 472 } 473 474 475 } 476 } 477 478 /** 479 * simple dumper for debugging 480 */ 481 private void dumpPackageInfo( Map h ) 482 { 483 System.out.println("Package : " + h.get( PACKAGENAME ) ); 484 System.out.println(" default version : " + h.get(DEFAULTVERSION )); 485 System.out.println(" description : " + h.get(DESCRIPTION )); 486 System.out.println(" href : " + h.get(HREF )); 487 488 System.out.println(" version info -> " ); 489 490 ArrayList vl = (ArrayList) h.get( VERSION_ARRAY ); 491 Iterator i = vl.iterator(); 492 493 while( i.hasNext() ) 494 { 495 HashMap vi = (HashMap) i.next(); 496 497 System.out.println(" ver : " + vi.get( VERSION ) ); 498 System.out.println(" info : " + vi.get( VERSION_INFO ) ); 499 System.out.println(" jar : " + vi.get( VERSION_JAR ) ); 500 } 501 } 502 503 504 /** 505 * Returns a given node from the document tree. 506 * if a multivalued node, will return the first 507 * 508 * @param root node to start seaching on 509 * @param path node path, a la "foo/bar/woogie" 510 * @return node or null 511 */ 512 private Node getDocNode( Node root, String path ) 513 { 514 List ar = getDocNodeList(root, path ); 515 516 if (ar == null || ar.size() == 0) 517 return null; 518 519 return (Node) ar.get(0); 520 } 521 522 /** 523 * returns the node list for a given path relative to the 524 * passed in node 525 * 526 * @param root node to start from 527 * @param path note path 528 * @return List of nodes that match 529 */ 530 private List getDocNodeList( Node root, String path) 531 { 532 StringTokenizer st = new StringTokenizer( path, "/"); 533 534 Node n = root; 535 ArrayList ar = null; 536 537 while( st.hasMoreTokens() ) 538 { 539 String token = st.nextToken(); 540 541 ar = n.getChildren(token); 542 543 if (ar == null || ar.size() == 0) 544 return null; 545 546 n = (Node) ar.get(0); 547 } 548 549 return ar; 550 } 551 552 /** 553 * start element event handler for SAX. 554 */ 555 public Writer startElement( String namespaceURI, String localName, String qName, Attributes atts, Writer writer) 556 throws SAXException 557 { 558 /* 559 * get the top element on the list 560 */ 561 562 Node parent = null; 563 Node element = new Node( qName ); 564 565 if( root == null) 566 { 567 root = element; 568 } 569 else 570 { 571 /* 572 * get parent node 573 */ 574 575 try 576 { 577 parent = (Node) stack.peek(); 578 } 579 catch(Exception e) 580 {} 581 } 582 583 /* 584 * everything is a list 585 */ 586 587 if (parent != null) 588 { 589 parent.addChildNode( element); 590 } 591 592 /* 593 * now add our attributes 594 */ 595 596 for (int i = 0; i < atts.getLength(); i++) 597 { 598 element.setAttribute( atts.getQName(i), atts.getValue(i) ); 599 } 600 601 /* 602 * now put this element on the stack for later 603 */ 604 605 stack.push(element); 606 607 saxWriter = new StringWriter(); 608 return saxWriter; 609 } 610 611 612 /** 613 * end element event handler for SAX parsing 614 */ 615 public void endElement( String namespaceURI, String localName, String qName) 616 throws SAXException 617 { 618 try 619 { 620 Node element = (Node) stack.pop(); 621 622 String s = saxWriter.toString(); 623 624 if ( s.length() > 0) 625 element.setValue( s ); 626 } 627 catch( Exception e ) 628 { 629 System.out.println("endElement : " + e ); 630 } 631 } 632 633 public void fatalError (SAXParseException e) 634 throws SAXException 635 { 636 System.out.println("RepositoryXML.fatalError(): " + e); 637 throw e; 638 } 639 640 /** 641 * used for debugging 642 */ 643 public static void main ( String[] args) 644 { 645 RepositoryXML rep = new RepositoryXML(); 646 647 try 648 { 649 rep.load( new URL("file://" + args[0] )); 650 } 651 catch( Exception e ) 652 { System.out.println(e );} 653 654 655 List al = rep.getDependencyList( "ant", "1.3"); 656 657 Iterator i = al.iterator(); 658 659 System.out.println("dep for ant 1.3 "); 660 661 while( i.hasNext() ) 662 { 663 System.out.println(" " + (String) i.next() ); 664 } 665 666 } 667 /** 668 * meethod for debugging parsing 669 */ 670 private static void show( String indent, Map map ) 671 { 672 System.out.println(""); 673 674 Iterator i = map.keySet().iterator(); 675 676 while(i.hasNext() ) 677 { 678 String s = (String) i.next(); 679 Object o = map.get( s ); 680 System.out.print( indent + "<" + s + ">"); 681 682 if ( o instanceof Map ) 683 { 684 show( indent + " ", (Map) o); 685 } 686 else if ( o instanceof List ) 687 { 688 Iterator j = ((List) o).iterator(); 689 690 while( j.hasNext() ) 691 { 692 Object oo = j.next(); 693 694 if (oo instanceof Map) 695 show( indent + " ", (Map) oo); 696 else 697 System.out.println("woo!" + oo.getClass()); 698 } 699 } 700 else 701 { 702 System.out.println( map.get( s )); 703 } 704 705 } 706 } 707 708 /** 709 * small class to hold our node information for 710 * XML processing 711 */ 712 class Node 713 { 714 String name = null; 715 String value = ""; 716 717 HashMap attributes = new HashMap(); 718 HashMap children = new HashMap(); 719 720 Node( String name ) 721 { 722 this.name = name; 723 } 724 725 void setValue( String val ) 726 { 727 value = val; 728 } 729 730 String getValue() 731 { 732 return value; 733 } 734 735 void setAttribute( String key, String val ) 736 { 737 attributes.put( key, val ); 738 } 739 740 String getAttribute( String key ) 741 { 742 return (String) attributes.get( key ); 743 } 744 745 void addChildNode( Node node ) 746 { 747 ArrayList ar = (ArrayList) children.get( node.name ); 748 749 if (ar == null) 750 ar = new ArrayList(); 751 752 ar.add( node ); 753 754 children.put( node.name, ar ); 755 } 756 757 ArrayList getChildren( String name ) 758 { 759 return (ArrayList) children.get( name ); 760 } 761 762 } 763 764 } 765 766 767 768 769