Improve content edition and validation
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / acr / TypesManager.java
index f9077f0a6da9414b016caa25d0a6142c461cb376..d3617e128729dd3678b09058e9cd12027ae9d299 100644 (file)
@@ -5,11 +5,11 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -22,6 +22,7 @@ import javax.xml.validation.Validator;
 
 import org.apache.xerces.impl.xs.XSImplementationImpl;
 import org.apache.xerces.impl.xs.util.StringListImpl;
+import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl;
 import org.apache.xerces.xs.StringList;
 import org.apache.xerces.xs.XSAttributeDeclaration;
 import org.apache.xerces.xs.XSAttributeUse;
@@ -40,6 +41,8 @@ import org.apache.xerces.xs.XSSimpleTypeDefinition;
 import org.apache.xerces.xs.XSTerm;
 import org.apache.xerces.xs.XSTypeDefinition;
 import org.argeo.api.acr.CrAttributeType;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.RuntimeNamespaceContext;
 import org.argeo.api.cms.CmsLog;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.SAXException;
@@ -48,7 +51,7 @@ import org.xml.sax.SAXParseException;
 /** Register content types. */
 class TypesManager {
        private final static CmsLog log = CmsLog.getLog(TypesManager.class);
-       private Map<String, String> prefixes = new TreeMap<>();
+//     private Map<String, String> prefixes = new TreeMap<>();
 
        // immutable factories
        private SchemaFactory schemaFactory;
@@ -58,52 +61,46 @@ class TypesManager {
 
        // cached
        private Schema schema;
-       DocumentBuilderFactory documentBuilderFactory;
+       private DocumentBuilderFactory documentBuilderFactory;
        private XSModel xsModel;
        private SortedMap<QName, Map<QName, CrAttributeType>> types;
 
        private boolean validating = true;
 
+       private final static boolean limited = false;
+
        public TypesManager() {
-               schemaFactory = SchemaFactory.newDefaultInstance();
+               schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
 
                // types
-               types = new TreeMap<>((qn1, qn2) -> {
-                       if (Objects.equals(qn1.getNamespaceURI(), qn2.getNamespaceURI())) {// same namespace
-                               return qn1.getLocalPart().compareTo(qn2.getLocalPart());
-                       } else {
-                               return qn1.getNamespaceURI().compareTo(qn2.getNamespaceURI());
-                       }
-               });
+               types = new TreeMap<>(NamespaceUtils.QNAME_COMPARATOR);
 
        }
 
-       public synchronized void init() {
-//             prefixes.put(CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI);
-//             prefixes.put("basic", CrName.CR_NAMESPACE_URI);
-//             prefixes.put("owner", CrName.CR_NAMESPACE_URI);
-//             prefixes.put("posix", CrName.CR_NAMESPACE_URI);
-
+       public void init() {
                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());
+                       if (cs.getResource() != null) {
+                               StreamSource source = new StreamSource(cs.getResource().toExternalForm());
+                               sources.add(source);
+                       }
+                       RuntimeNamespaceContext.register(cs.getNamespace(), cs.getDefaultPrefix());
                }
 
                reload();
        }
 
-       public synchronized void registerTypes(String defaultPrefix, String namespace, String xsdSystemId) {
-               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));
-               reload();
+       public void registerTypes(String defaultPrefix, String namespace, String xsdSystemId) {
+//             if (prefixes.containsKey(defaultPrefix))
+//                     throw new IllegalStateException(
+//                                     "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix));
+//             prefixes.put(defaultPrefix, namespace);
+               RuntimeNamespaceContext.register(namespace, defaultPrefix);
+
+               if (xsdSystemId != null) {
+                       sources.add(new StreamSource(xsdSystemId));
+                       reload();
+                       log.debug(() -> "Registered types " + namespace + " from " + xsdSystemId);
+               }
        }
 
        public Set<QName> listTypes() {
@@ -122,11 +119,14 @@ class TypesManager {
                        schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()]));
 
                        // document builder factory
-                       documentBuilderFactory = DocumentBuilderFactory.newInstance();
+                       // we force usage of Xerces for predictability
+                       documentBuilderFactory = limited ? DocumentBuilderFactory.newInstance() : new DocumentBuilderFactoryImpl();
                        documentBuilderFactory.setNamespaceAware(true);
-                       documentBuilderFactory.setXIncludeAware(true);
-                       documentBuilderFactory.setSchema(getSchema());
-                       documentBuilderFactory.setValidating(validating);
+                       if (!limited) {
+                               documentBuilderFactory.setXIncludeAware(true);
+                               documentBuilderFactory.setSchema(getSchema());
+                               documentBuilderFactory.setValidating(validating);
+                       }
 
                        // XS model
                        // TODO use JVM implementation?
@@ -150,7 +150,7 @@ class TypesManager {
 //                     }
                        collectTypes();
                } catch (XSException | SAXException e) {
-                       throw new IllegalStateException("Cannot relaod types");
+                       throw new IllegalStateException("Cannot reload types", e);
                }
        }
 
@@ -453,13 +453,14 @@ class TypesManager {
                try {
                        validator.validate(source);
                } catch (SAXException e) {
-                       throw new IllegalArgumentException("Provided source is not valid", e);
+                       log.error(source + " is not valid " + e);
+                       // throw new IllegalArgumentException("Provided source is not valid", e);
                }
        }
 
-       public Map<String, String> getPrefixes() {
-               return prefixes;
-       }
+//     public Map<String, String> getPrefixes() {
+//             return prefixes;
+//     }
 
        public List<Source> getSources() {
                return sources;