package org.spaceroots.util;

import java.util.HashMap;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
 * This class implements a resolver for external entities that are
 * cached locally in the same jar file as the application.
 * @version $Id: EmbeddedCatalogResolver.java,v 1.1 2002/08/13 16:54:17 luc Exp $
 * @author L. Maisonobe
 */
public class EmbeddedCatalogResolver
  extends DefaultHandler {

  /** Simple constructor.
   * Build an empty resolver.
   * @param catalog catalog path (inside the jar)
   * @param factory parser factory to use for building the catalog parser
   */
  public EmbeddedCatalogResolver(String catalog, SAXParserFactory factory) {

    int index = catalog.lastIndexOf('/');
    if (index < 0) {
      base = "";
      catalogName = catalog;
    } else {
      base = catalog.substring(0, index + 1);
      catalogName = catalog.substring(index + 1);
    }

    this.factory = factory;

    map = new HashMap();

  }

  /** Get the resource associated with a public identifier
   * @param id public identifier
   * @return the resource name or null if the identifier is unknown
   * @exception SAXException if parsing the catalog throws one
   */
  private String getResourceName(String id)
    throws SAXException {

    try {

      if (id.equals("-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN")) {
        // special case, this should be handled BEFORE trying to
        // parse the catalog, because it is needed during this parsing
        // (this is a chicken and egg problem)
        return base + "catalog.dtd";
      }

      if (map.isEmpty()) {
        // read the catalog containing the entities mapping
        InputStream is = getClass().getResourceAsStream(base + catalogName);
        if (is == null) {
          return null;
        }
        factory.newSAXParser().parse(is, this);
      }

      // return the mapping we have for this entity, or null
      return (String) map.get(id);

    } catch (ParserConfigurationException pce) {
      throw new SAXException(pce.getMessage());
    } catch (IOException ioe) {
      throw new SAXException(ioe.getMessage());
    }

  }

  public InputSource resolveEntity (String publicId, String systemId)
    throws SAXException {

    String dtdResource = getResourceName(publicId);

    if (dtdResource != null) {
      // the DTD is cached locally in the jar
      InputStream is = getClass().getResourceAsStream(dtdResource);
      return (is != null) ? new InputSource(is) : null;
    } else {
      // we did not find the DTD, we let the parser use the default behaviour
      return null;
    }

  }

  public void startElement(String namespaceURI,
                           String localName, String qName,
                           Attributes attrs)
    throws SAXException {

    String eltName = localName.equals("") ? qName : localName;

    if (eltName.equals("public")) {
      // the current element is a public entry of the catalog

      String publicId = attrs.getValue("publicId");
      String uri = attrs.getValue("uri");
      if ((publicId != null) && (uri != null)) {

        // store the publicId/uri mapping
        // (adding the base prefix if uri is relative)
        map.put(publicId, uri.startsWith("/") ? uri : (base + uri));

      }
    }

  }

  /** Base directory (inside the jar file). */
  String base;

  /** Catalog name (in the base directory). */
  String catalogName;

  /** Parser factory to use. */
  SAXParserFactory factory;

  /** Map for public identifiers. */
  HashMap map;

}

 

Ads help maintain this website.