content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package mf.org.apache.xerces.impl.xs;
  
  import mf.org.apache.xerces.impl.xs.util.XSGrammarPool;
  import mf.org.apache.xerces.xni.grammars.Grammar;
  import mf.org.apache.xerces.xni.grammars.XMLGrammarDescription;
  import mf.org.apache.xerces.xni.grammars.XSGrammar;
  import mf.org.apache.xerces.xni.parser.XMLInputSource;
  import mf.org.apache.xerces.xs.LSInputList;
  import mf.org.apache.xerces.xs.StringList;
  import mf.org.apache.xerces.xs.XSConstants;
  import mf.org.apache.xerces.xs.XSLoader;
  import mf.org.apache.xerces.xs.XSModel;
  import mf.org.apache.xerces.xs.XSNamedMap;
  import mf.org.apache.xerces.xs.XSObjectList;
  import mf.org.apache.xerces.xs.XSTypeDefinition;
  import mf.org.w3c.dom.DOMConfiguration;
  import mf.org.w3c.dom.DOMException;
  import mf.org.w3c.dom.DOMStringList;
  import mf.org.w3c.dom.ls.LSInput;
  
  
  /**
   * <p>An implementation of XSLoader which wraps XMLSchemaLoader.</p>
   *
   * @author Michael Glavassevich, IBM
   * @version $Id: XSLoaderImpl.java 699892 2008-09-28 21:08:27Z mrglavas $
   * @xerces.internal
   */
  public final class XSLoaderImpl implements XSLoader, DOMConfiguration {
  
      /**
       * Grammar pool. Need this to prevent us from
       * getting two grammars from the same namespace.
       */
      private final XSGrammarPool fGrammarPool = new XSGrammarMerger();
  
      /**
       * Schema loader.
       **/
      private final XMLSchemaLoader fSchemaLoader = new XMLSchemaLoader();
  
      /**
       * No-args constructor.
       */
      public XSLoaderImpl() {
          fSchemaLoader.setProperty(XMLSchemaLoader.XMLGRAMMAR_POOL, fGrammarPool);
      }
  
      /**
       * The configuration of a document. It maintains a table of recognized
       * parameters. Using the configuration, it is possible to change the
       * behavior of the load methods. The configuration may support the
       * setting of and the retrieval of the following non-boolean parameters
       * defined on the <code>DOMConfiguration</code> interface:
       * <code>error-handler</code> (<code>DOMErrorHandler</code>) and
       * <code>resource-resolver</code> (<code>LSResourceResolver</code>).
       * <br> The following list of boolean parameters is defined:
       * <dl>
       * <dt>
       * <code>"validate"</code></dt>
       * <dd>
       * <dl>
       * <dt><code>true</code></dt>
       * <dd>[required] (default) Validate an XML
       * Schema during loading. If validation errors are found, the error
       * handler is notified. </dd>
       * <dt><code>false</code></dt>
       * <dd>[optional] Do not
       * report errors during the loading of an XML Schema document. </dd>
       * </dl></dd>
       * </dl>
       */
      @Override
      public DOMConfiguration getConfig() {
          return this;
      }
  
      /**
       * Parses the content of XML Schema documents specified as the list of URI
       * references. If the URI contains a fragment identifier, the behavior
       * is not defined by this specification.
       *
       * @param uriList The list of URI locations.
       * @return An XSModel representing the schema documents.
       */
      @Override
      public XSModel loadURIList(StringList uriList) {
          int length = uriList.getLength();
          try {
              fGrammarPool.clear();
              for (int i = 0; i < length; ++i) {
                  fSchemaLoader.loadGrammar(new XMLInputSource(null, uriList.item(i), null));
              }
              return fGrammarPool.toXSModel();
          } catch (Exception e) {
              fSchemaLoader.reportDOMFatalError(e);
              return null;
          }
      }
  
      /**
       * Parses the content of XML Schema documents specified as a list of
       * <code>LSInput</code>s.
       *
       * @param is The list of <code>LSInput</code>s from which the XML
       *           Schema documents are to be read.
       * @return An XSModel representing the schema documents.
       */
      @Override
      public XSModel loadInputList(LSInputList is) {
          final int length = is.getLength();
          try {
              fGrammarPool.clear();
              for (int i = 0; i < length; ++i) {
                  fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is.item(i)));
              }
              return fGrammarPool.toXSModel();
          } catch (Exception e) {
              fSchemaLoader.reportDOMFatalError(e);
              return null;
          }
      }
  
      /**
       * Parse an XML Schema document from a location identified by a URI
       * reference. If the URI contains a fragment identifier, the behavior is
       * not defined by this specification.
       *
       * @param uri The location of the XML Schema document to be read.
       * @return An XSModel representing this schema.
       */
      @Override
      public XSModel loadURI(String uri) {
          try {
              fGrammarPool.clear();
              return ((XSGrammar) fSchemaLoader.loadGrammar(new XMLInputSource(null, uri, null))).toXSModel();
          } catch (Exception e) {
              fSchemaLoader.reportDOMFatalError(e);
              return null;
          }
      }
  
      /**
       * Parse an XML Schema document from a resource identified by a
       * <code>LSInput</code> .
       *
       * @param is The <code>LSInput</code> from which the source
       *           document is to be read.
       * @return An XSModel representing this schema.
       */
      @Override
      public XSModel load(LSInput is) {
          try {
              fGrammarPool.clear();
              return ((XSGrammar) fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is))).toXSModel();
          } catch (Exception e) {
              fSchemaLoader.reportDOMFatalError(e);
              return null;
          }
      }
  
      /* (non-Javadoc)
       * @see org.apache.xerces.dom3.DOMConfiguration#setParameter(java.lang.String, java.lang.Object)
       */
      @Override
      public void setParameter(String name, Object value) throws DOMException {
          fSchemaLoader.setParameter(name, value);
      }
  
      /* (non-Javadoc)
       * @see org.apache.xerces.dom3.DOMConfiguration#getParameter(java.lang.String)
       */
      @Override
      public Object getParameter(String name) throws DOMException {
          return fSchemaLoader.getParameter(name);
      }
  
      /* (non-Javadoc)
       * @see org.apache.xerces.dom3.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object)
       */
      @Override
      public boolean canSetParameter(String name, Object value) {
          return fSchemaLoader.canSetParameter(name, value);
      }
  
      /* (non-Javadoc)
       * @see org.apache.xerces.dom3.DOMConfiguration#getParameterNames()
       */
      @Override
      public DOMStringList getParameterNames() {
          return fSchemaLoader.getParameterNames();
      }
  
      /**
       * Grammar pool which merges grammars from the same namespace into one. This eliminates
       * duplicate named components. It doesn't ensure that the grammar is consistent, however
       * this no worse than than the behaviour of XMLSchemaLoader alone when used as an XSLoader.
       */
      private static final class XSGrammarMerger extends XSGrammarPool {
  
          public XSGrammarMerger() {
          }
  
          @Override
          public void putGrammar(Grammar grammar) {
              SchemaGrammar cachedGrammar =
                      toSchemaGrammar(super.getGrammar(grammar.getGrammarDescription()));
              if (cachedGrammar != null) {
                  SchemaGrammar newGrammar = toSchemaGrammar(grammar);
                  if (newGrammar != null) {
                      mergeSchemaGrammars(cachedGrammar, newGrammar);
                  }
              } else {
                  super.putGrammar(grammar);
              }
          }
  
          private SchemaGrammar toSchemaGrammar(Grammar grammar) {
              return (grammar instanceof SchemaGrammar) ? (SchemaGrammar) grammar : null;
          }
  
          private void mergeSchemaGrammars(SchemaGrammar cachedGrammar, SchemaGrammar newGrammar) {
  
              /** Add new top-level element declarations. **/
              XSNamedMap map = newGrammar.getComponents(XSConstants.ELEMENT_DECLARATION);
              int length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSElementDecl decl = (XSElementDecl) map.item(i);
                  if (cachedGrammar.getGlobalElementDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalElementDecl(decl);
                  }
              }
  
              /** Add new top-level attribute declarations. **/
              map = newGrammar.getComponents(XSConstants.ATTRIBUTE_DECLARATION);
              length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSAttributeDecl decl = (XSAttributeDecl) map.item(i);
                  if (cachedGrammar.getGlobalAttributeDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalAttributeDecl(decl);
                  }
              }
  
              /** Add new top-level type definitions. **/
              map = newGrammar.getComponents(XSConstants.TYPE_DEFINITION);
              length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSTypeDefinition decl = (XSTypeDefinition) map.item(i);
                  if (cachedGrammar.getGlobalTypeDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalTypeDecl(decl);
                  }
              }
  
              /** Add new top-level attribute group definitions. **/
              map = newGrammar.getComponents(XSConstants.ATTRIBUTE_GROUP);
              length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSAttributeGroupDecl decl = (XSAttributeGroupDecl) map.item(i);
                  if (cachedGrammar.getGlobalAttributeGroupDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalAttributeGroupDecl(decl);
                  }
              }
  
              /** Add new top-level model group definitions. **/
              map = newGrammar.getComponents(XSConstants.MODEL_GROUP);
              length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSGroupDecl decl = (XSGroupDecl) map.item(i);
                  if (cachedGrammar.getGlobalGroupDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalGroupDecl(decl);
                  }
              }
  
              /** Add new top-level notation declarations. **/
              map = newGrammar.getComponents(XSConstants.NOTATION_DECLARATION);
              length = map.getLength();
              for (int i = 0; i < length; ++i) {
                  XSNotationDecl decl = (XSNotationDecl) map.item(i);
                  if (cachedGrammar.getGlobalNotationDecl(decl.getName()) == null) {
                      cachedGrammar.addGlobalNotationDecl(decl);
                  }
              }
  
              /**
               * Add all annotations. Since these components are not named it's
               * possible we'll add duplicate components. There isn't much we can
               * do. It's no worse than XMLSchemaLoader when used as an XSLoader.
               */
              XSObjectList annotations = newGrammar.getAnnotations();
              length = annotations.getLength();
              for (int i = 0; i < length; ++i) {
                  cachedGrammar.addAnnotation((XSAnnotationImpl) annotations.item(i));
              }
  
          }
  
          @Override
          public boolean containsGrammar(XMLGrammarDescription desc) {
              return false;
          }
  
          @Override
          public Grammar getGrammar(XMLGrammarDescription desc) {
              return null;
          }
  
          @Override
          public Grammar retrieveGrammar(XMLGrammarDescription desc) {
              return null;
          }
  
          @Override
          public Grammar[] retrieveInitialGrammarSet(String grammarType) {
              return new Grammar[0];
          }
      }
  }
  