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