blob: f41caf1f7e04ed2a454059b75f232ddb6e498ced [file] [log] [blame]
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.xml.catalog;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.xml.catalog.BaseEntry.CatalogEntryType;
import javax.xml.parsers.SAXParser;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* CatalogReader handles SAX events while parsing through a catalog file to
* create a catalog object.
*
* @since 9
*/
class CatalogReader extends DefaultHandler implements EntityResolver, URIResolver {
/** URI of the W3C XML Schema for OASIS XML Catalog files. */
public static final String xmlCatalogXSD = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.xsd";
/** Public identifier for OASIS XML Catalog files. */
public static final String xmlCatalogPubId = "-//OASIS//DTD XML Catalogs V1.0//EN";
/**
* The namespace name defined by the OASIS Standard
*/
public static final String NAMESPACE_OASIS = "urn:oasis:names:tc:entity:xmlns:xml:catalog";
//Indicate whether the root element has been found
boolean seenRoot;
//Indicate that the parser is in a group entry
boolean inGroup;
//The Catalog instance
CatalogImpl catalog;
//The parser for reading the catalog
SAXParser parser;
//The current catalog entry
CatalogEntry catalogEntry;
//The current group
GroupEntry group;
//The current entry
BaseEntry entry;
//remove this variable once 8136778 is committed
boolean ignoreTheCatalog = false;
/**
* Constructs an instance with a Catalog object and parser.
*
* @param catalog The Catalog object that represents a catalog
*/
@SuppressWarnings("unchecked")
public CatalogReader(Catalog catalog, SAXParser parser) {
this.catalog = (CatalogImpl) catalog;
this.parser = parser;
}
/**
* Returns when the specified path is valid.
* @param path a path
* @return true if the path is valid, false otherwise
*/
boolean isValidPath(String path) {
boolean valid = true;
try {
Path p = Paths.get(new URI(path));
if (!p.toFile().exists()) {
valid = false;
}
} catch (URISyntaxException ex) {
valid = false;
}
return valid;
}
@Override
public void startElement(String namespaceURI,
String localName,
String qName,
Attributes atts)
throws SAXException {
//ignore the catalog if it's not compliant. See section 8, item 3 of the spec.
if (ignoreTheCatalog) return;
if (!NAMESPACE_OASIS.equals(namespaceURI)) {
//wait till 8136778 is committed
// parser.stop();
ignoreTheCatalog = true;
return;
}
CatalogEntryType type = CatalogEntryType.getType(localName);
if (type == null) {
CatalogMessages.reportError(CatalogMessages.ERR_INVALID_ENTRY_TYPE,
new Object[]{localName});
}
if (type != CatalogEntryType.CATALOGENTRY) {
if (!seenRoot) {
CatalogMessages.reportError(CatalogMessages.ERR_INVALID_CATALOG);
}
}
String base = atts.getValue("xml:base");
if (base == null) {
if (inGroup) {
base = group.getBaseURI().toString();
} else {
if (type == CatalogEntryType.CATALOGENTRY) {
base = catalog.getBaseURI().toString();
} else {
base = catalogEntry.getBaseURI().toString();
}
}
} else {
base = Normalizer.normalizeURI(base);
}
//parse the catalog and group entries
if (type == CatalogEntryType.CATALOGENTRY
|| type == CatalogEntryType.GROUP) {
String prefer = atts.getValue("prefer");
if (prefer == null) {
if (type == CatalogEntryType.CATALOGENTRY) {
//use the general setting
prefer = catalog.isPreferPublic() ?
CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM;
} else {
//Group inherit from the catalog entry
prefer = catalogEntry.isPreferPublic() ?
CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM;
}
}
if (type == CatalogEntryType.CATALOGENTRY) {
seenRoot = true;
if (catalog.isTop()) {
String defer = atts.getValue("defer");
String resolve = atts.getValue("resolve");
if (defer == null) {
defer = catalog.isDeferred() ?
CatalogFeatures.DEFER_TRUE : CatalogFeatures.DEFER_FALSE;
}
if (resolve == null) {
resolve = catalog.getResolve().literal;
}
catalog.setResolve(resolve);
catalogEntry = new CatalogEntry(base, prefer, defer, resolve);
} else {
catalogEntry = new CatalogEntry(base, prefer);
}
return;
} else {
inGroup = true;
group = new GroupEntry(catalog, base, prefer);
catalog.addEntry(group);
return;
}
}
//parse entries other than the catalog and group entries
switch (type) {
case PUBLIC:
entry = new PublicEntry(base, atts.getValue("publicId"), atts.getValue("uri"));
break;
case SYSTEM:
entry = new SystemEntry(base, atts.getValue("systemId"), atts.getValue("uri"));
break;
case REWRITESYSTEM:
entry = new RewriteSystem(base, atts.getValue("systemIdStartString"), atts.getValue("rewritePrefix"));
break;
case SYSTEMSUFFIX:
entry = new SystemSuffix(base, atts.getValue("systemIdSuffix"), atts.getValue("uri"));
break;
case DELEGATEPUBLIC:
entry = new DelegatePublic(base, atts.getValue("publicIdStartString"), atts.getValue("catalog"));
break;
case DELEGATESYSTEM:
entry = new DelegateSystem(base, atts.getValue("systemIdStartString"), atts.getValue("catalog"));
break;
case URI:
entry = new UriEntry(base, atts.getValue("name"), atts.getValue("uri"));
break;
case REWRITEURI:
entry = new RewriteUri(base, atts.getValue("uriStartString"), atts.getValue("rewritePrefix"));
break;
case URISUFFIX:
entry = new UriSuffix(base, atts.getValue("uriSuffix"), atts.getValue("uri"));
break;
case DELEGATEURI:
entry = new DelegateUri(base, atts.getValue("uriStartString"), atts.getValue("catalog"));
break;
case NEXTCATALOG:
entry = new NextCatalog(base, atts.getValue("catalog"));
break;
}
if (type == CatalogEntryType.NEXTCATALOG) {
catalog.addNextCatalog((NextCatalog) entry);
} else if (inGroup) {
group.addEntry(entry);
} else {
catalog.addEntry(entry);
}
}
/**
* Handles endElement event
*/
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (ignoreTheCatalog) return;
CatalogEntryType type = CatalogEntryType.getType(localName);
if (type == CatalogEntryType.GROUP) {
inGroup = false;
} else if (type == CatalogEntryType.CATALOGENTRY) {
/*
Done reading the catalog file.
Load delegate and alternative catalogs if defer is false.
*/
if (!catalog.isDeferred()) {
catalog.loadDelegateCatalogs();
catalog.loadNextCatalogs();
}
}
}
/**
* Skips external DTD since resolving external DTD is not required
* by the specification.
*/
@Override
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
/**
* Skips external references since resolution is not required
* by the specification.
*/
@Override
public Source resolve(String href, String base)
throws TransformerException {
return new SAXSource(new InputSource(new StringReader("")));
}
}