// $Id: XMLEntityResolver.java,v 1.3 2004/12/15 23:08:40 edavis Exp $
/*
 * Copyright 1997-2004 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@unidata.ucar.edu.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package ucar.nc2.dataset;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.jdom.input.SAXBuilder;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;

import javax.xml.parsers.*;

import java.io.*;
import java.util.*;
import java.net.URL;

public class XMLEntityResolver implements org.xml.sax.EntityResolver {
  static private boolean debugEntityResolution = true;
  static private HashMap entityHash = new HashMap();

  // schema
  static private final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
  static public final String W3C_XML_NAMESPACE = "http://www.w3.org/2001/XMLSchema";
  static private final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";

  // catalog namespaces
  static public final String CATALOG_NAMESPACE_06 = "http://www.unidata.ucar.edu/thredds";
  static public final String CATALOG_NAMESPACE_10 = "http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.0";
  // dqc namespaces
  static public final String DQC_NAMESPACE_02 = "http://www.unidata.ucar.edu/schemas/thredds/queryCapability";
  static public final String DQC_NAMESPACE_03 = "http://www.unidata.ucar.edu/namespaces/thredds/queryCapability/v0.3";

  // nj22 namespaces
  static public final String NJ22_NAMESPACE = "http://www.unidata.ucar.edu/namespaces/netcdf/ncml-2.2";

  // other namespaces
  static public final String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink";

  static {
    /* set up entity resolution - see MyEntityResolver class
    // catalog 0.6 dtd
    initEntity( "http://www.unidata.ucar.edu/projects/THREDDS/xml/InvCatalog.0.6.dtd",
                "/resources/xml/InvCatalog.0.6.dtd",
                "http://www.unidata.ucar.edu/projects/THREDDS/xml/InvCatalog.0.6.dtd");

    // catalog 1.0 schema
    initEntity( CATALOG_NAMESPACE_10,
                "/resources/xml/InvCatalog.1.0.xsd",
                "http://www.unidata.ucar.edu/schemas/thredds/InvCatalog.1.0.xsd");

    // catalog 0.6 schema
    initEntity( CATALOG_NAMESPACE_06,
                "/resources/xml/InvCatalog.0.6.xsd",
                "http://www.unidata.ucar.edu/schemas/thredds/InvCatalog.0.6.xsd");

    // DQC schema 0.2
    initEntity( DQC_NAMESPACE_02,
                "/resources/xml/queryCapability.0.2.xsd",
                "http://www.unidata.ucar.edu/schemas/thredds/queryCapability.0.2.xsd");

    // DQC schema 0.3
    initEntity( DQC_NAMESPACE_03,
                "/resources/xml/queryCapability.0.3.xsd",
                "http://www.unidata.ucar.edu/schemas/thredds/queryCapability.0.3.xsd"); */

    // nj22 schema
    initEntity( NJ22_NAMESPACE,
                "/resources/xml/ncml-2.2.xsd",
                "http://www.unidata.ucar.edu/schemas/netcdf/ncml-2.2.xsd");

    /* XLink schema
    initEntity( XLINK_NAMESPACE,
                "/resources/xml/xlink.xsd",
                "http://www.unidata.ucar.edu/schemas/other/xlink.xsd"); */

  }

  static private void initEntity( String entityName, String resourceName, String urlName) {
    String entity = null;

    try { // try to read from local file resource, eg from catalog.jar
      ByteArrayOutputStream sbuff = new ByteArrayOutputStream(3000);
      InputStream is = thredds.util.Resource.getFileResource( resourceName);
      if (is != null) {
        thredds.util.IO.copy(is, sbuff);
        entity = sbuff.toString();
        if (debugEntityResolution) System.out.println(" *** entity "+entityName+" mapped to local resource at "+resourceName);

      } else if (urlName != null) { // otherwise, get from network
        entity = thredds.util.IO.readURLcontentsWithException(urlName);
        if (debugEntityResolution) System.out.println(" *** entity "+entityName+" mapped to remote URL at "+urlName);
      }

    } catch (IOException e) {
      System.out.println(" *** FAILED to map entity "+entityName+" locally at "+resourceName+" or remotely at "+urlName);
      // e.printStackTrace();
    }

    entityHash.put( entityName, entity);
    entityHash.put( urlName, entity); // also map it to the remote URL
  }

  public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
    if (debugEntityResolution) System.out.print("  publicId="+publicId+" systemId="+systemId);
    String entity = (String) entityHash.get( systemId);
    if (entity != null) {
      if (debugEntityResolution) System.out.println(" *** resolved  with local copy");
      return new MyInputSource(entity);
    }

    if (systemId.indexOf("InvCatalog.0.6.dtd") >= 0) {
      entity = (String) entityHash.get( "http://www.unidata.ucar.edu/projects/THREDDS/xml/InvCatalog.0.6.dtd");
      if (entity != null) {
        if (debugEntityResolution) System.out.println(" *** resolved2 with local copy");
        return new MyInputSource(entity);
      }
    }

    if (debugEntityResolution) System.out.println(" *** not resolved");
    return null;
  }

  private class MyInputSource extends org.xml.sax.InputSource {
    MyInputSource( String entity) {
      setCharacterStream(new StringReader(entity));
    }
  }

  private static class MyErrorHandler implements org.xml.sax.ErrorHandler {

    public void warning(SAXParseException e) throws SAXException {
      System.out.println("*** XML parser warning="+e.getMessage()+"\n");
    }

    public void error(SAXParseException e) throws SAXException {
      System.out.println("*** XML parser error="+e.getMessage()+"\n");
    }

    public void fatalError(SAXParseException e) throws SAXException {
      System.out.println("*** XML parser fatalError="+e.getMessage()+"\n");
    }
  }

  /************************************************************************/
   /** testing */
  public static void main (String[] args) throws Exception {
    String urlString = "file:C:/dev/netcdf-java-2.2/test/data/dataset/xml/readMetadata.xml";
    SAXBuilder builder = new SAXBuilder( true);
    builder.setEntityResolver( new XMLEntityResolver());

    URL url = new URL(urlString);
    Document doc = builder.build( url);

    XMLOutputter xmlOut = new XMLOutputter();
    System.out.println ("*** XMLEntityResolver = \n"+xmlOut.outputString(doc)+"\n*******");

    javax.xml.parsers.DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    docBuilderFactory.setNamespaceAware(true);

    // try to get schema validation
    docBuilderFactory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_NAMESPACE);
    docBuilderFactory.setAttribute(JAXP_SCHEMA_SOURCE, new String[] { NJ22_NAMESPACE } );
    docBuilderFactory.setValidating(true);
    javax.xml.parsers.DocumentBuilder  b = docBuilderFactory.newDocumentBuilder();
    b.setEntityResolver(new XMLEntityResolver());
    b.setErrorHandler(new MyErrorHandler());

    b.parse( urlString);
  }

}

/* Change History:
   $Log: XMLEntityResolver.java,v $
   Revision 1.3  2004/12/15 23:08:40  edavis
   Update NJ22_NAMESPACE value.

   Revision 1.2  2004/11/07 03:00:49  caron
   *** empty log message ***

   Revision 1.1  2004/11/05 21:43:29  caron
   no message

   Revision 1.5  2004/10/06 19:03:39  caron
   clean up javadoc
   change useV3 -> useRecordsAsStructure
   remove id, title, from NetcdfFile constructors
   add "in memory" NetcdfFile

   Revision 1.4  2004/09/28 21:39:09  caron
   *** empty log message ***

   Revision 1.3  2004/09/24 03:26:27  caron
   merge nj22

   Revision 1.2  2004/06/04 00:51:54  caron
   release 2.0b

   Revision 1.1  2004/05/11 23:30:28  caron
   release 2.0a


 */