
thredds.catalog.query.DqcFactory Maven / Gradle / Ivy
// $Id: DqcFactory.java 48 2006-07-12 16:15:40Z caron $
/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.catalog.query;
import thredds.catalog.XMLEntityResolver;
import ucar.nc2.constants.CDM;
import ucar.nc2.util.IO;
import org.jdom2.input.SAXBuilder;
import org.jdom2.*;
import java.io.*;
import java.net.*;
import java.util.*;
import ucar.nc2.util.DiskCache2;
/**
* Reads an XML document and constructs an QueryCapability object.
*
* Example of normal use:
*
*
* DqcFactory fac = new DqcFactory(true);
* QueryCapability dqc = fac.readXML(url);
* System.out.println(" dqc hasFatalError= "+dqc.hasFatalError());
* System.out.println(" dqc messages= \n"+dqc.getErrorMessages());
* fac.writeXML(dqc, System.out);
*
*
* Implementation details: Uses JAXP to load an XML Parser and construct a DOM tree.
* Uses a pluggable "converter" to transform the DOM to the thredds.catalog.query objects.
*
* @author John Caron
*/
public class DqcFactory {
public static boolean debugVersion = false;
public static boolean showParsedXML = false;
static private DiskCache2 diskCache = null;
static private int buffer_size = 64000;
static public void setPersistenceCache(DiskCache2 dc) {
diskCache = dc;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
private SAXBuilder builder; // JAXP parser
private DqcConvertIF defaultConverter;
private HashMap versionToNamespaceHash = new HashMap<>(10);
private HashMap namespaceToDqcConverterHash = new HashMap<>(10);
private StringBuilder warnMessages, errMessages, fatalMessages;
/**
* Constructor.
* Can use this to read as many catalogs as you want, but should only
* use in single thread.
*
* @param validate : do XML validation or not.
*/
public DqcFactory(boolean validate) {
XMLEntityResolver jaxp = new XMLEntityResolver(validate);
builder = jaxp.getSAXBuilder();
warnMessages = jaxp.getWarningMessages();
errMessages = jaxp.getErrorMessages();
fatalMessages = jaxp.getFatalMessages();
setDefaults();
}
private void setDefaults() {
try {
/* Class fac2 = Class.forName("thredds.catalog.parser.jdom.DqcConvert2");
Object fac2o = fac2.newInstance();
registerConverter( "0.2", XMLEntityResolver.DQC_NAMESPACE_02, (DqcConvertIF) fac2o);
Class fac3 = Class.forName("thredds.catalog.parser.jdom.DqcConvert3");
Object fac3o = fac3.newInstance();
registerConverter( "0.3", XMLEntityResolver.DQC_NAMESPACE_03, (DqcConvertIF) fac3o); */
Class fac4 = Class.forName("thredds.catalog.parser.jdom.DqcConvert4");
Object fac4o = fac4.newInstance();
defaultConverter = (DqcConvertIF) fac4o;
registerConverter( "0.4", XMLEntityResolver.DQC_NAMESPACE_04, (DqcConvertIF) fac4o);
} catch (ClassNotFoundException e) {
throw new RuntimeException("DqcFactory: no implementing class found: " + e.getMessage());
} catch (InstantiationException e) {
throw new RuntimeException("DqcFactory: instantiation failed: " + e.getMessage());
} catch (IllegalAccessException e) {
throw new RuntimeException("DqcFactory: access failed: " + e.getMessage());
}
}
private void registerConverter(String version, String namespace, DqcConvertIF converter) {
namespaceToDqcConverterHash.put(namespace, converter);
versionToNamespaceHash.put(version, namespace);
// converter.setCatalogFactory( this);
}
public void appendErr(String err) {
errMessages.append(err);
}
public void appendFatalErr(String err) {
fatalMessages.append(err);
}
public void appendWarning(String err) {
warnMessages.append(err);
}
public QueryCapability readXML( String docAsString, URI uri ) throws IOException
{
// get ready for XML parsing
warnMessages.setLength( 0 );
errMessages.setLength( 0 );
fatalMessages.setLength( 0 );
Document doc = null;
try
{
doc = builder.build( new StringReader( docAsString ) );
}
catch ( JDOMException e )
{
fatalMessages.append( e.getMessage() ); // makes it invalid
}
return readXML( doc, uri );
}
/**
* Create an QueryCapability from an XML document at a named URL.
* check dqc.isValid, dqc.getErrorMessages() to see if ok.
* If Disk caching is set, cache the dqc and check IfModifiedSince.
*
* @param uriString : the URI name that the XML doc is at.
* @return an QueryCapability object
* @throws IOException on failure
*/
public QueryCapability readXML(String uriString) throws IOException {
// get URI
URI uri;
try {
uri = new URI(uriString);
} catch (URISyntaxException e) {
throw new MalformedURLException(e.getMessage());
}
// check if its cached
if (diskCache != null) {
File file = diskCache.getCacheFile(uriString);
if (file != null) {
HttpURLConnection conn = null;
try {
URL url = uri.toURL();
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setIfModifiedSince(file.lastModified());
int code = conn.getResponseCode();
if (code == HttpURLConnection.HTTP_OK) {
java.io.InputStream is = conn.getInputStream();
if (is != null) {
try (FileOutputStream fout = new FileOutputStream(file)) {
IO.copyB(is, fout, buffer_size); // cache it
}
try (InputStream fin = new BufferedInputStream( new FileInputStream(file), 50000)) {
return readXML(fin, uri);
}
}
} else {
// use file
try (FileInputStream fin = new FileInputStream(file)) {
return readXML(fin, uri);
}
}
} finally {
if (conn != null)
conn.disconnect();
}
} // has file
// no file - read and cache
IO.readURLtoFileWithExceptions(uriString, file, buffer_size);
try (InputStream fin = new BufferedInputStream(
new FileInputStream(file), 50000)) {
return readXML(fin, uri);
}
} // has diskCache
// otherwise just open the URL
warnMessages.setLength(0);
errMessages.setLength(0);
fatalMessages.setLength(0);
Document doc = null;
try {
doc = builder.build(uriString);
} catch (JDOMException e) {
fatalMessages.append(e.getMessage()); // makes it invalid
}
return readXML(doc, uri);
}
/**
* Create an QueryCapability from an InputStream.
* check dqc.isValid, dqc.getErrorMessages() to see if ok.
*
* @param docIs : the InputStream to read from
* @param uri : the URI of the document, used for resolving reletive references.
* @return an QueryCapability object
* @throws IOException on failure
*/
public QueryCapability readXML(InputStream docIs, URI uri) throws IOException {
// get ready for XML parsing
warnMessages.setLength(0);
errMessages.setLength(0);
fatalMessages.setLength(0);
Document doc = null;
try {
doc = builder.build(docIs);
} catch (JDOMException e) {
fatalMessages.append(e.getMessage()); // makes it invalid
}
return readXML(doc, uri);
}
/**
* Create an InvCatalog from an a JDOM document.
* check dqc.isValid, dqc.getErrorMessages() to see if ok.
*
* @param doc parse this document
* @param uri : the URI of the document, used for resolving reletive references.
* @return an InvCatalogImpl object
* @throws IOException on failure
*/
private QueryCapability readXML(org.jdom2.Document doc, URI uri) throws IOException {
if (doc == null) { // parse failed
QueryCapability dqc = new QueryCapability();
if (fatalMessages.length() > 0)
dqc.appendErrorMessage(fatalMessages.toString(), true); // makes it invalid
if (errMessages.length() > 0)
dqc.appendErrorMessage(errMessages.toString(), false); // doesnt make it invalid
if (errMessages.length() > 0)
dqc.appendErrorMessage(warnMessages.toString(), false); // doesnt make it invalid
return dqc;
}
// decide on converter based on namespace
Element root = doc.getRootElement();
String namespace = root.getNamespaceURI();
DqcConvertIF fac = namespaceToDqcConverterHash.get(namespace);
if (fac == null) {
fac = defaultConverter; // LOOK
if (debugVersion)
System.out.println("use default converter " + fac.getClass().getName() + "; no namespace " + namespace);
} else if (debugVersion)
System.out.println("use converter " + fac.getClass().getName() + " based on namespace " + namespace);
// convert to object model
QueryCapability dqc = fac.parseXML(this, doc, uri);
if (fatalMessages.length() > 0)
dqc.appendErrorMessage(fatalMessages.toString(), true); // makes it invalid
if (errMessages.length() > 0)
dqc.appendErrorMessage(errMessages.toString(), false); // doesnt make it invalid
if (errMessages.length() > 0)
dqc.appendErrorMessage(warnMessages.toString(), false); // doesnt make it invalid
return dqc;
}
/**
* Write the catalog as an XML document to a String.
*
* @param dqc : write this QueryCapability to an XML representation.
* @return string containing XML representation
* @throws IOException on failure
*/
public String writeXML(QueryCapability dqc) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(10000);
writeXML(dqc, os);
return os.toString(CDM.utf8Charset.name());
}
/**
* Write the catalog as an XML document to the specified stream.
*
* @param dqc : write this QueryCapability to an XML representation.
* @param os write to this OutputStream
* @throws IOException on an error.
*/
public void writeXML(QueryCapability dqc, OutputStream os) throws IOException {
String ns = versionToNamespaceHash.get( dqc.getVersion() );
DqcConvertIF fac = namespaceToDqcConverterHash.get( ns );
if ( fac == null )
fac = defaultConverter;
fac.writeXML( dqc, os );
}
/**
* Write the catalog as an XML document to the specified filename.
*
* @param dqc : write this QueryCapability to an XML representation.
* @param filename write to this filename
* @return true if success
*/
public boolean writeXML(QueryCapability dqc, String filename) {
try {
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(filename));
writeXML(dqc, os);
os.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/************************************************************************/
/**
* testing
*/
private static void doOne(DqcFactory fac, String url) {
System.out.println("***read " + url);
try {
QueryCapability dqc = fac.readXML(url);
System.out.println(" dqc hasFatalError= " + dqc.hasFatalError());
System.out.println(" dqc messages= \n" + dqc.getErrorMessages());
fac.writeXML(dqc, System.out);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
DqcFactory fac = new DqcFactory(true);
doOne(fac, "file:///C:/data/dqc/metarDQC.xml");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy