X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2FContentTypesManager.java;h=48093bee034b9bdedf2f5f1f633f0419e60ce90f;hb=e3db2eba9a7f8380a6f76d7b0e6cd4825e91893e;hp=23f2d90018beb9668e0be2e8ade946fd55429314;hpb=ceb6d574e9ea49fcac490d0923d23f259f271f8d;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/acr/ContentTypesManager.java b/org.argeo.cms/src/org/argeo/cms/acr/ContentTypesManager.java index 23f2d9001..48093bee0 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/ContentTypesManager.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/ContentTypesManager.java @@ -1,14 +1,24 @@ package org.argeo.cms.acr; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.NavigableSet; +import java.util.Objects; +import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; import org.apache.xerces.impl.xs.XSImplementationImpl; import org.apache.xerces.impl.xs.util.StringListImpl; @@ -24,20 +34,40 @@ import org.apache.xerces.xs.XSNamedMap; import org.apache.xerces.xs.XSTypeDefinition; import org.argeo.api.acr.CrName; import org.argeo.api.cms.CmsLog; +import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; public class ContentTypesManager { private final static CmsLog log = CmsLog.getLog(ContentTypesManager.class); private Map prefixes = new TreeMap<>(); + // immutable factories + private SchemaFactory schemaFactory; + + /** Schema sources. */ private List sources = new ArrayList<>(); - private SchemaFactory schemaFactory; + // cached private Schema schema; + DocumentBuilderFactory documentBuilderFactory; + private XSModel xsModel; + private NavigableSet types; + + private boolean validating = true; public ContentTypesManager() { schemaFactory = SchemaFactory.newDefaultInstance(); + // types + types = new TreeSet<>((qn1, qn2) -> { + if (Objects.equals(qn1.getNamespaceURI(), qn2.getNamespaceURI())) {// same namespace + return qn1.getLocalPart().compareTo(qn2.getLocalPart()); + } else { + return qn1.getNamespaceURI().compareTo(qn2.getNamespaceURI()); + } + }); + } public synchronized void init() { @@ -46,53 +76,98 @@ public class ContentTypesManager { prefixes.put("owner", CrName.CR_NAMESPACE_URI); prefixes.put("posix", CrName.CR_NAMESPACE_URI); - try { - for (CmsContentTypes cs : CmsContentTypes.values()) { - StreamSource source = new StreamSource(cs.getResource().toExternalForm()); - sources.add(source); - if (prefixes.containsKey(cs.getDefaultPrefix())) - throw new IllegalStateException("Prefix " + cs.getDefaultPrefix() + " is already mapped with " - + prefixes.get(cs.getDefaultPrefix())); - prefixes.put(cs.getDefaultPrefix(), cs.getNamespace()); - } - - schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()])); - } catch (SAXException e) { - throw new IllegalStateException("Cannot initialise types", e); + for (CmsContentTypes cs : CmsContentTypes.values()) { + StreamSource source = new StreamSource(cs.getResource().toExternalForm()); + sources.add(source); + if (prefixes.containsKey(cs.getDefaultPrefix())) + throw new IllegalStateException("Prefix " + cs.getDefaultPrefix() + " is already mapped with " + + prefixes.get(cs.getDefaultPrefix())); + prefixes.put(cs.getDefaultPrefix(), cs.getNamespace()); } + reload(); } public synchronized void registerTypes(String defaultPrefix, String namespace, String xsdSystemId) { - try { - if (prefixes.containsKey(defaultPrefix)) - throw new IllegalStateException( - "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix)); - prefixes.put(defaultPrefix, namespace); + if (prefixes.containsKey(defaultPrefix)) + throw new IllegalStateException( + "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix)); + prefixes.put(defaultPrefix, namespace); - sources.add(new StreamSource(xsdSystemId)); - schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()])); - } catch (SAXException e) { - throw new IllegalStateException("Cannot initialise types " + namespace + " based on " + xsdSystemId, e); - } + sources.add(new StreamSource(xsdSystemId)); + reload(); + } + public Set listTypes() { +// TODO cache it? + return types; } - public void listTypes() { + private synchronized void reload() { try { - // Find an XMLSchema loader instance + // schema + schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()])); + + // document builder factory + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setXIncludeAware(true); + documentBuilderFactory.setSchema(getSchema()); + documentBuilderFactory.setValidating(validating); + + // XS model + // TODO use JVM implementation? // DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance(); // XSImplementation implementation = (XSImplementation) registry.getDOMImplementation("XS-Loader"); - XSImplementation implementation = new XSImplementationImpl(); - XSLoader loader = implementation.createXSLoader(null); - - // Load the XML Schema + XSImplementation xsImplementation = new XSImplementationImpl(); + XSLoader xsLoader = xsImplementation.createXSLoader(null); List systemIds = new ArrayList<>(); for (Source source : sources) { systemIds.add(source.getSystemId()); } StringList sl = new StringListImpl(systemIds.toArray(new String[systemIds.size()]), systemIds.size()); - XSModel xsModel = loader.loadURIList(sl); + xsModel = xsLoader.loadURIList(sl); + + // types + XSNamedMap map = xsModel.getComponents(XSConstants.ELEMENT_DECLARATION); + for (int i = 0; i < map.getLength(); i++) { + XSElementDeclaration eDec = (XSElementDeclaration) map.item(i); + QName type = new QName(eDec.getNamespace(), eDec.getName()); + types.add(type); + } + } catch (XSException | SAXException e) { + throw new IllegalStateException("Cannot relaod types"); + } + } + + public DocumentBuilder newDocumentBuilder() { + try { + DocumentBuilder dBuilder = documentBuilderFactory.newDocumentBuilder(); + dBuilder.setErrorHandler(new ErrorHandler() { + + @Override + public void warning(SAXParseException exception) throws SAXException { + log.warn(exception); + } + + @Override + public void fatalError(SAXParseException exception) throws SAXException { + log.error(exception); + } + + @Override + public void error(SAXParseException exception) throws SAXException { + log.error(exception); + } + }); + return dBuilder; + } catch (ParserConfigurationException e) { + throw new IllegalStateException("Cannot create document builder", e); + } + } + + public void printTypes() { + try { // Convert top level complex type definitions to node types log.debug("\n## TYPES"); @@ -123,6 +198,20 @@ public class ContentTypesManager { } + public void validate(Source source) throws IOException { + if (!validating) + return; + Validator validator; + synchronized (this) { + validator = schema.newValidator(); + } + try { + validator.validate(source); + } catch (SAXException e) { + throw new IllegalArgumentException("Provided source is not valid", e); + } + } + public Map getPrefixes() { return prefixes; }