1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 // Resolver.java - Represents an extension of OASIS Open Catalog files.
   6 
   7 /*
   8  * Copyright 2001-2004 The Apache Software Foundation or its licensors,
   9  * as applicable.
  10  *
  11  * Licensed under the Apache License, Version 2.0 (the "License");
  12  * you may not use this file except in compliance with the License.
  13  * You may obtain a copy of the License at
  14  *
  15  *      http://www.apache.org/licenses/LICENSE-2.0
  16  *
  17  * Unless required by applicable law or agreed to in writing, software
  18  * distributed under the License is distributed on an "AS IS" BASIS,
  19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20  * See the License for the specific language governing permissions and
  21  * limitations under the License.
  22  */
  23 
  24 package com.sun.org.apache.xml.internal.resolver;
  25 
  26 import java.io.IOException;
  27 import java.io.InputStream;
  28 import java.io.FileNotFoundException;
  29 import java.util.Enumeration;
  30 import java.util.Vector;
  31 import java.net.URL;
  32 import java.net.URLConnection;
  33 import java.net.MalformedURLException;
  34 import javax.xml.parsers.SAXParserFactory;
  35 import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
  36 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
  37 import com.sun.org.apache.xml.internal.resolver.readers.SAXCatalogReader;
  38 import com.sun.org.apache.xml.internal.resolver.readers.OASISXMLCatalogReader;
  39 import com.sun.org.apache.xml.internal.resolver.readers.TR9401CatalogReader;
  40 
  41 /**
  42  * An extension to OASIS Open Catalog files, this class supports
  43  * suffix-based matching and an external RFC2483 resolver.
  44  *
  45  * @see Catalog
  46  *
  47  * @author Norman Walsh
  48  * <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
  49  *
  50  * @version 1.0
  51  */
  52 public class Resolver extends Catalog {
  53   /**
  54    * The URISUFFIX Catalog Entry type.
  55    *
  56    * <p>URI suffix entries match URIs that end in a specified suffix.</p>
  57    */
  58   public static final int URISUFFIX = CatalogEntry.addEntryType("URISUFFIX", 2);
  59 
  60   /**
  61    * The SYSTEMSUFFIX Catalog Entry type.
  62    *
  63    * <p>System suffix entries match system identifiers that end in a
  64    * specified suffix.</p>
  65    */
  66   public static final int SYSTEMSUFFIX = CatalogEntry.addEntryType("SYSTEMSUFFIX", 2);
  67 
  68   /**
  69    * The RESOLVER Catalog Entry type.
  70    *
  71    * <p>A hook for providing support for web-based backup resolvers.</p>
  72    */
  73   public static final int RESOLVER = CatalogEntry.addEntryType("RESOLVER", 1);
  74 
  75   /**
  76    * The SYSTEMREVERSE Catalog Entry type.
  77    *
  78    * <p>This is a bit of a hack. There's no actual SYSTEMREVERSE entry,
  79    * but this entry type is used to indicate that a reverse lookup is
  80    * being performed. (This allows the Resolver to implement
  81    * RFC2483 I2N and I2NS.)
  82    */
  83   public static final int SYSTEMREVERSE
  84     = CatalogEntry.addEntryType("SYSTEMREVERSE", 1);
  85 
  86   /**
  87    * Setup readers.
  88    */
  89   public void setupReaders() {
  90     SAXParserFactory spf = catalogManager.useServicesMechanism() ?
  91                     SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
  92     spf.setNamespaceAware(true);
  93     spf.setValidating(false);
  94 
  95     SAXCatalogReader saxReader = new SAXCatalogReader(spf);
  96 
  97     saxReader.setCatalogParser(null, "XMLCatalog",
  98                                "com.sun.org.apache.xml.internal.resolver.readers.XCatalogReader");
  99 
 100     saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName,
 101                                "catalog",
 102                                "com.sun.org.apache.xml.internal.resolver.readers.ExtendedXMLCatalogReader");
 103 
 104     addReader("application/xml", saxReader);
 105 
 106     TR9401CatalogReader textReader = new TR9401CatalogReader();
 107     addReader("text/plain", textReader);
 108   }
 109 
 110   /**
 111    * Cleanup and process a Catalog entry.
 112    *
 113    * <p>This method processes each Catalog entry, changing mapped
 114    * relative system identifiers into absolute ones (based on the current
 115    * base URI), and maintaining other information about the current
 116    * catalog.</p>
 117    *
 118    * @param entry The CatalogEntry to process.
 119    */
 120   public void addEntry(CatalogEntry entry) {
 121     int type = entry.getEntryType();
 122 
 123     if (type == URISUFFIX) {
 124       String suffix = normalizeURI(entry.getEntryArg(0));
 125       String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
 126 
 127       entry.setEntryArg(1, fsi);
 128 
 129       catalogManager.debug.message(4, "URISUFFIX", suffix, fsi);
 130     } else if (type == SYSTEMSUFFIX) {
 131       String suffix = normalizeURI(entry.getEntryArg(0));
 132       String fsi = makeAbsolute(normalizeURI(entry.getEntryArg(1)));
 133 
 134       entry.setEntryArg(1, fsi);
 135 
 136       catalogManager.debug.message(4, "SYSTEMSUFFIX", suffix, fsi);
 137     }
 138 
 139     super.addEntry(entry);
 140   }
 141 
 142   /**
 143    * Return the applicable URI.
 144    *
 145    * <p>If a URI entry exists in the Catalog
 146    * for the URI specified, return the mapped value.</p>
 147    *
 148    * <p>In the Resolver (as opposed to the Catalog) class, if the
 149    * URI isn't found by the usual algorithm, URISUFFIX entries are
 150    * considered.</p>
 151    *
 152    * <p>URI comparison is case sensitive.</p>
 153    *
 154    * @param uri The URI to locate in the catalog.
 155    *
 156    * @return The resolved URI.
 157    *
 158    * @throws MalformedURLException The system identifier of a
 159    * subordinate catalog cannot be turned into a valid URL.
 160    * @throws IOException Error reading subordinate catalog file.
 161    */
 162   public String resolveURI(String uri)
 163     throws MalformedURLException, IOException {
 164 
 165     String resolved = super.resolveURI(uri);
 166     if (resolved != null) {
 167       return resolved;
 168     }
 169 
 170     Enumeration en = catalogEntries.elements();
 171     while (en.hasMoreElements()) {
 172       CatalogEntry e = (CatalogEntry) en.nextElement();
 173       if (e.getEntryType() == RESOLVER) {
 174         resolved = resolveExternalSystem(uri, e.getEntryArg(0));
 175         if (resolved != null) {
 176           return resolved;
 177         }
 178       } else if (e.getEntryType() == URISUFFIX) {
 179         String suffix = e.getEntryArg(0);
 180         String result = e.getEntryArg(1);
 181 
 182         if (suffix.length() <= uri.length()
 183             && uri.substring(uri.length()-suffix.length()).equals(suffix)) {
 184           return result;
 185         }
 186       }
 187     }
 188 
 189     // Otherwise, look in the subordinate catalogs
 190     return resolveSubordinateCatalogs(Catalog.URI,
 191                                       null,
 192                                       null,
 193                                       uri);
 194   }
 195 
 196   /**
 197    * Return the applicable SYSTEM system identifier, resorting
 198    * to external RESOLVERs if necessary.
 199    *
 200    * <p>If a SYSTEM entry exists in the Catalog
 201    * for the system ID specified, return the mapped value.</p>
 202    *
 203    * <p>In the Resolver (as opposed to the Catalog) class, if the
 204    * URI isn't found by the usual algorithm, SYSTEMSUFFIX entries are
 205    * considered.</p>
 206    *
 207    * <p>On Windows-based operating systems, the comparison between
 208    * the system identifier provided and the SYSTEM entries in the
 209    * Catalog is case-insensitive.</p>
 210    *
 211    * @param systemId The system ID to locate in the catalog.
 212    *
 213    * @return The system identifier to use for systemId.
 214    *
 215    * @throws MalformedURLException The formal system identifier of a
 216    * subordinate catalog cannot be turned into a valid URL.
 217    * @throws IOException Error reading subordinate catalog file.
 218    */
 219   public String resolveSystem(String systemId)
 220     throws MalformedURLException, IOException {
 221 
 222     String resolved = super.resolveSystem(systemId);
 223     if (resolved != null) {
 224       return resolved;
 225     }
 226 
 227     Enumeration en = catalogEntries.elements();
 228     while (en.hasMoreElements()) {
 229       CatalogEntry e = (CatalogEntry) en.nextElement();
 230       if (e.getEntryType() == RESOLVER) {
 231         resolved = resolveExternalSystem(systemId, e.getEntryArg(0));
 232         if (resolved != null) {
 233           return resolved;
 234         }
 235       } else if (e.getEntryType() == SYSTEMSUFFIX) {
 236         String suffix = e.getEntryArg(0);
 237         String result = e.getEntryArg(1);
 238 
 239         if (suffix.length() <= systemId.length()
 240             && systemId.substring(systemId.length()-suffix.length()).equals(suffix)) {
 241           return result;
 242         }
 243       }
 244     }
 245 
 246     return resolveSubordinateCatalogs(Catalog.SYSTEM,
 247                                       null,
 248                                       null,
 249                                       systemId);
 250   }
 251 
 252   /**
 253    * Return the applicable PUBLIC or SYSTEM identifier, resorting
 254    * to external resolvers if necessary.
 255    *
 256    * <p>This method searches the Catalog and returns the system
 257    * identifier specified for the given system or
 258    * public identifiers. If
 259    * no appropriate PUBLIC or SYSTEM entry is found in the Catalog,
 260    * null is returned.</p>
 261    *
 262    * <p>Note that a system or public identifier in the current catalog
 263    * (or subordinate catalogs) will be used in preference to an
 264    * external resolver. Further, if a systemId is present, the external
 265    * resolver(s) will be queried for that before the publicId.</p>
 266    *
 267    * @param publicId The public identifier to locate in the catalog.
 268    * Public identifiers are normalized before comparison.
 269    * @param systemId The nominal system identifier for the entity
 270    * in question (as provided in the source document).
 271    *
 272    * @throws MalformedURLException The formal system identifier of a
 273    * subordinate catalog cannot be turned into a valid URL.
 274    * @throws IOException Error reading subordinate catalog file.
 275    *
 276    * @return The system identifier to use.
 277    * Note that the nominal system identifier is not returned if a
 278    * match is not found in the catalog, instead null is returned
 279    * to indicate that no match was found.
 280    */
 281   public String resolvePublic(String publicId, String systemId)
 282     throws MalformedURLException, IOException {
 283 
 284     String resolved = super.resolvePublic(publicId, systemId);
 285     if (resolved != null) {
 286       return resolved;
 287     }
 288 
 289     Enumeration en = catalogEntries.elements();
 290     while (en.hasMoreElements()) {
 291       CatalogEntry e = (CatalogEntry) en.nextElement();
 292       if (e.getEntryType() == RESOLVER) {
 293         if (systemId != null) {
 294           resolved = resolveExternalSystem(systemId,
 295                                            e.getEntryArg(0));
 296           if (resolved != null) {
 297             return resolved;
 298           }
 299         }
 300         resolved = resolveExternalPublic(publicId, e.getEntryArg(0));
 301         if (resolved != null) {
 302           return resolved;
 303         }
 304       }
 305     }
 306 
 307     return resolveSubordinateCatalogs(Catalog.PUBLIC,
 308                                       null,
 309                                       publicId,
 310                                       systemId);
 311   }
 312 
 313     /**
 314      * Query an external RFC2483 resolver for a system identifier.
 315      *
 316      * @param systemId The system ID to locate.
 317      * @param resolver The name of the resolver to use.
 318      *
 319      * @return The system identifier to use for the systemId.
 320      */
 321     protected String resolveExternalSystem(String systemId, String resolver)
 322         throws MalformedURLException, IOException {
 323         Resolver r = queryResolver(resolver, "i2l", systemId, null);
 324         if (r != null) {
 325             return r.resolveSystem(systemId);
 326         } else {
 327             return null;
 328         }
 329     }
 330 
 331     /**
 332      * Query an external RFC2483 resolver for a public identifier.
 333      *
 334      * @param publicId The system ID to locate.
 335      * @param resolver The name of the resolver to use.
 336      *
 337      * @return The system identifier to use for the systemId.
 338      */
 339     protected String resolveExternalPublic(String publicId, String resolver)
 340         throws MalformedURLException, IOException {
 341         Resolver r = queryResolver(resolver, "fpi2l", publicId, null);
 342         if (r != null) {
 343             return r.resolvePublic(publicId, null);
 344         } else {
 345             return null;
 346         }
 347     }
 348 
 349     /**
 350      * Query an external RFC2483 resolver.
 351      *
 352      * @param resolver The URL of the RFC2483 resolver.
 353      * @param command The command to send the resolver.
 354      * @param arg1 The first argument to the resolver.
 355      * @param arg2 The second argument to the resolver, usually null.
 356      *
 357      * @return The Resolver constructed.
 358      */
 359     protected Resolver queryResolver(String resolver,
 360                                      String command,
 361                                      String arg1,
 362                                      String arg2) {
 363         InputStream iStream = null;
 364         String RFC2483 = resolver + "?command=" + command
 365             + "&format=tr9401&uri=" + arg1
 366             + "&uri2=" + arg2;
 367         String line = null;
 368 
 369         try {
 370             URL url = new URL(RFC2483);
 371 
 372             URLConnection urlCon = url.openConnection();
 373 
 374             urlCon.setUseCaches(false);
 375 
 376             Resolver r = (Resolver) newCatalog();
 377 
 378             String cType = urlCon.getContentType();
 379 
 380             // I don't care about the character set or subtype
 381             if (cType.indexOf(";") > 0) {
 382                 cType = cType.substring(0, cType.indexOf(";"));
 383             }
 384 
 385             r.parseCatalog(cType, urlCon.getInputStream());
 386 
 387             return r;
 388         } catch (CatalogException cex) {
 389           if (cex.getExceptionType() == CatalogException.UNPARSEABLE) {
 390             catalogManager.debug.message(1, "Unparseable catalog: " + RFC2483);
 391           } else if (cex.getExceptionType()
 392                      == CatalogException.UNKNOWN_FORMAT) {
 393             catalogManager.debug.message(1, "Unknown catalog format: " + RFC2483);
 394           }
 395           return null;
 396         } catch (MalformedURLException mue) {
 397             catalogManager.debug.message(1, "Malformed resolver URL: " + RFC2483);
 398             return null;
 399         } catch (IOException ie) {
 400             catalogManager.debug.message(1, "I/O Exception opening resolver: " + RFC2483);
 401             return null;
 402         }
 403     }
 404 
 405     /**
 406      * Append two vectors, returning the result.
 407      *
 408      * @param vec The first vector
 409      * @param appvec The vector to be appended
 410      * @return The vector vec, with appvec's elements appended to it
 411      */
 412     private Vector appendVector(Vector vec, Vector appvec) {
 413         if (appvec != null) {
 414             for (int count = 0; count < appvec.size(); count++) {
 415                 vec.addElement(appvec.elementAt(count));
 416             }
 417         }
 418         return vec;
 419     }
 420 
 421     /**
 422      * Find the URNs for a given system identifier in all catalogs.
 423      *
 424      * @param systemId The system ID to locate.
 425      *
 426      * @return A vector of URNs that map to the systemId.
 427      */
 428     public Vector resolveAllSystemReverse(String systemId)
 429         throws MalformedURLException, IOException {
 430         Vector resolved = new Vector();
 431 
 432         // If there's a SYSTEM entry in this catalog, use it
 433         if (systemId != null) {
 434             Vector localResolved = resolveLocalSystemReverse(systemId);
 435             resolved = appendVector(resolved, localResolved);
 436         }
 437 
 438         // Otherwise, look in the subordinate catalogs
 439         Vector subResolved = resolveAllSubordinateCatalogs(SYSTEMREVERSE,
 440                                                            null,
 441                                                            null,
 442                                                            systemId);
 443 
 444         return appendVector(resolved, subResolved);
 445     }
 446 
 447     /**
 448      * Find the URN for a given system identifier.
 449      *
 450      * @param systemId The system ID to locate.
 451      *
 452      * @return A (single) URN that maps to the systemId.
 453      */
 454     public String resolveSystemReverse(String systemId)
 455         throws MalformedURLException, IOException {
 456         Vector resolved = resolveAllSystemReverse(systemId);
 457         if (resolved != null && resolved.size() > 0) {
 458             return (String) resolved.elementAt(0);
 459         } else {
 460             return null;
 461         }
 462     }
 463 
 464     /**
 465      * Return the applicable SYSTEM system identifiers.
 466      *
 467      * <p>If one or more SYSTEM entries exists in the Catalog
 468      * for the system ID specified, return the mapped values.</p>
 469      *
 470      * <p>The caller is responsible for doing any necessary
 471      * normalization of the system identifier before calling
 472      * this method. For example, a relative system identifier in
 473      * a document might be converted to an absolute system identifier
 474      * before attempting to resolve it.</p>
 475      *
 476      * <p>Note that this function will force all subordinate catalogs
 477      * to be loaded.</p>
 478      *
 479      * <p>On Windows-based operating systems, the comparison between
 480      * the system identifier provided and the SYSTEM entries in the
 481      * Catalog is case-insensitive.</p>
 482      *
 483      * @param systemId The system ID to locate in the catalog.
 484      *
 485      * @return The system identifier to use for the notation.
 486      *
 487      * @throws MalformedURLException The formal system identifier of a
 488      * subordinate catalog cannot be turned into a valid URL.
 489      * @throws IOException Error reading subordinate catalog file.
 490      */
 491     public Vector resolveAllSystem(String systemId)
 492         throws MalformedURLException, IOException {
 493         Vector resolutions = new Vector();
 494 
 495         // If there are SYSTEM entries in this catalog, start with them
 496         if (systemId != null) {
 497             Vector localResolutions = resolveAllLocalSystem(systemId);
 498             resolutions = appendVector(resolutions, localResolutions);
 499         }
 500 
 501         // Then look in the subordinate catalogs
 502         Vector subResolutions = resolveAllSubordinateCatalogs(SYSTEM,
 503                                                               null,
 504                                                               null,
 505                                                               systemId);
 506         resolutions = appendVector(resolutions, subResolutions);
 507 
 508         if (resolutions.size() > 0) {
 509             return resolutions;
 510         } else {
 511             return null;
 512         }
 513     }
 514 
 515     /**
 516      * Return all applicable SYSTEM system identifiers in this
 517      * catalog.
 518      *
 519      * <p>If one or more SYSTEM entries exists in the catalog file
 520      * for the system ID specified, return the mapped values.</p>
 521      *
 522      * @param systemId The system ID to locate in the catalog
 523      *
 524      * @return A vector of the mapped system identifiers or null
 525      */
 526     private Vector resolveAllLocalSystem(String systemId) {
 527         Vector map = new Vector();
 528         String osname = SecuritySupport.getSystemProperty("os.name");
 529         boolean windows = (osname.indexOf("Windows") >= 0);
 530         Enumeration en = catalogEntries.elements();
 531         while (en.hasMoreElements()) {
 532             CatalogEntry e = (CatalogEntry) en.nextElement();
 533             if (e.getEntryType() == SYSTEM
 534                 && (e.getEntryArg(0).equals(systemId)
 535                     || (windows
 536                         && e.getEntryArg(0).equalsIgnoreCase(systemId)))) {
 537                 map.addElement(e.getEntryArg(1));
 538             }
 539         }
 540         if (map.size() == 0) {
 541             return null;
 542         } else {
 543             return map;
 544         }
 545     }
 546 
 547     /**
 548      * Find the URNs for a given system identifier in the current catalog.
 549      *
 550      * @param systemId The system ID to locate.
 551      *
 552      * @return A vector of URNs that map to the systemId.
 553      */
 554     private Vector resolveLocalSystemReverse(String systemId) {
 555         Vector map = new Vector();
 556         String osname = SecuritySupport.getSystemProperty("os.name");
 557         boolean windows = (osname.indexOf("Windows") >= 0);
 558         Enumeration en = catalogEntries.elements();
 559         while (en.hasMoreElements()) {
 560             CatalogEntry e = (CatalogEntry) en.nextElement();
 561             if (e.getEntryType() == SYSTEM
 562                 && (e.getEntryArg(1).equals(systemId)
 563                     || (windows
 564                         && e.getEntryArg(1).equalsIgnoreCase(systemId)))) {
 565                 map.addElement(e.getEntryArg(0));
 566             }
 567         }
 568         if (map.size() == 0) {
 569             return null;
 570         } else {
 571             return map;
 572         }
 573     }
 574 
 575     /**
 576      * Search the subordinate catalogs, in order, looking for all
 577      * match.
 578      *
 579      * <p>This method searches the Catalog and returns all of the system
 580      * identifiers specified for the given entity type with the given
 581      * name, public, and system identifiers. In some contexts, these
 582      * may be null.</p>
 583      *
 584      * @param entityType The CatalogEntry type for which this query is
 585      * being conducted. This is necessary in order to do the approprate
 586      * query on a subordinate catalog.
 587      * @param entityName The name of the entity being searched for, if
 588      * appropriate.
 589      * @param publicId The public identifier of the entity in question
 590      * (as provided in the source document).
 591      * @param systemId The nominal system identifier for the entity
 592      * in question (as provided in the source document).
 593      *
 594      * @throws MalformedURLException The formal system identifier of a
 595      * delegated catalog cannot be turned into a valid URL.
 596      * @throws IOException Error reading delegated catalog file.
 597      *
 598      * @return The system identifier to use.
 599      * Note that the nominal system identifier is not returned if a
 600      * match is not found in the catalog, instead null is returned
 601      * to indicate that no match was found.
 602      */
 603     private synchronized Vector resolveAllSubordinateCatalogs(int entityType,
 604                                               String entityName,
 605                                               String publicId,
 606                                               String systemId)
 607         throws MalformedURLException, IOException {
 608 
 609         Vector resolutions = new Vector();
 610 
 611         for (int catPos = 0; catPos < catalogs.size(); catPos++) {
 612             Resolver c = null;
 613 
 614             try {
 615                 c = (Resolver) catalogs.elementAt(catPos);
 616             } catch (ClassCastException e) {
 617                 String catfile = (String) catalogs.elementAt(catPos);
 618                 c = (Resolver) newCatalog();
 619 
 620                 try {
 621                     c.parseCatalog(catfile);
 622                 } catch (MalformedURLException mue) {
 623                     catalogManager.debug.message(1, "Malformed Catalog URL", catfile);
 624                 } catch (FileNotFoundException fnfe) {
 625                     catalogManager.debug.message(1, "Failed to load catalog, file not found",
 626                           catfile);
 627                 } catch (IOException ioe) {
 628                     catalogManager.debug.message(1, "Failed to load catalog, I/O error", catfile);
 629                 }
 630 
 631                 catalogs.setElementAt(c, catPos);
 632             }
 633 
 634             String resolved = null;
 635 
 636             // Ok, now what are we supposed to call here?
 637             if (entityType == DOCTYPE) {
 638                 resolved = c.resolveDoctype(entityName,
 639                                             publicId,
 640                                             systemId);
 641                 if (resolved != null) {
 642                     // Only find one DOCTYPE resolution
 643                     resolutions.addElement(resolved);
 644                     return resolutions;
 645                 }
 646             } else if (entityType == DOCUMENT) {
 647                 resolved = c.resolveDocument();
 648                 if (resolved != null) {
 649                     // Only find one DOCUMENT resolution
 650                     resolutions.addElement(resolved);
 651                     return resolutions;
 652                 }
 653             } else if (entityType == ENTITY) {
 654                 resolved = c.resolveEntity(entityName,
 655                                            publicId,
 656                                            systemId);
 657                 if (resolved != null) {
 658                     // Only find one ENTITY resolution
 659                     resolutions.addElement(resolved);
 660                     return resolutions;
 661                 }
 662             } else if (entityType == NOTATION) {
 663                 resolved = c.resolveNotation(entityName,
 664                                              publicId,
 665                                              systemId);
 666                 if (resolved != null) {
 667                     // Only find one NOTATION resolution
 668                     resolutions.addElement(resolved);
 669                     return resolutions;
 670                 }
 671             } else if (entityType == PUBLIC) {
 672                 resolved = c.resolvePublic(publicId, systemId);
 673                 if (resolved != null) {
 674                     // Only find one PUBLIC resolution
 675                     resolutions.addElement(resolved);
 676                     return resolutions;
 677                 }
 678             } else if (entityType == SYSTEM) {
 679                 Vector localResolutions = c.resolveAllSystem(systemId);
 680                 resolutions = appendVector(resolutions, localResolutions);
 681                 break;
 682             } else if (entityType == SYSTEMREVERSE) {
 683                 Vector localResolutions = c.resolveAllSystemReverse(systemId);
 684                 resolutions = appendVector(resolutions, localResolutions);
 685             }
 686         }
 687 
 688         if (resolutions != null) {
 689             return resolutions;
 690         } else {
 691             return null;
 692         }
 693     }
 694 }