1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl.xs;
23
24import com.sun.org.apache.xerces.internal.impl.xs.util.XSGrammarPool;
25import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
26import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
27import com.sun.org.apache.xerces.internal.xni.grammars.XSGrammar;
28import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
29import com.sun.org.apache.xerces.internal.xs.LSInputList;
30import com.sun.org.apache.xerces.internal.xs.StringList;
31import com.sun.org.apache.xerces.internal.xs.XSConstants;
32import com.sun.org.apache.xerces.internal.xs.XSLoader;
33import com.sun.org.apache.xerces.internal.xs.XSModel;
34import com.sun.org.apache.xerces.internal.xs.XSNamedMap;
35import com.sun.org.apache.xerces.internal.xs.XSObjectList;
36import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
37import org.w3c.dom.DOMConfiguration;
38import org.w3c.dom.DOMException;
39import org.w3c.dom.DOMStringList;
40import org.w3c.dom.ls.LSInput;
41
42/**
43 * <p>An implementation of XSLoader which wraps XMLSchemaLoader.</p>
44 *
45 * @xerces.internal
46 *
47 * @author Michael Glavassevich, IBM
48 *
49 */
50public final class XSLoaderImpl implements XSLoader, DOMConfiguration {
51
52    /**
53     * Grammar pool. Need this to prevent us from
54     * getting two grammars from the same namespace.
55     */
56    private final XSGrammarPool fGrammarPool = new XSGrammarMerger();
57
58    /** Schema loader. **/
59    private final XMLSchemaLoader fSchemaLoader = new XMLSchemaLoader();
60
61    /**
62     * No-args constructor.
63     */
64    public XSLoaderImpl() {
65        fSchemaLoader.setProperty(XMLSchemaLoader.XMLGRAMMAR_POOL, fGrammarPool);
66    }
67
68    /**
69     *  The configuration of a document. It maintains a table of recognized
70     * parameters. Using the configuration, it is possible to change the
71     * behavior of the load methods. The configuration may support the
72     * setting of and the retrieval of the following non-boolean parameters
73     * defined on the <code>DOMConfiguration</code> interface:
74     * <code>error-handler</code> (<code>DOMErrorHandler</code>) and
75     * <code>resource-resolver</code> (<code>LSResourceResolver</code>).
76     * <br> The following list of boolean parameters is defined:
77     * <dl>
78     * <dt>
79     * <code>"validate"</code></dt>
80     * <dd>
81     * <dl>
82     * <dt><code>true</code></dt>
83     * <dd>[required] (default) Validate an XML
84     * Schema during loading. If validation errors are found, the error
85     * handler is notified. </dd>
86     * <dt><code>false</code></dt>
87     * <dd>[optional] Do not
88     * report errors during the loading of an XML Schema document. </dd>
89     * </dl></dd>
90     * </dl>
91     */
92    public DOMConfiguration getConfig() {
93        return this;
94    }
95
96    /**
97     * Parses the content of XML Schema documents specified as the list of URI
98     * references. If the URI contains a fragment identifier, the behavior
99     * is not defined by this specification.
100     * @param uriList The list of URI locations.
101     * @return An XSModel representing the schema documents.
102     */
103    public XSModel loadURIList(StringList uriList) {
104        int length = uriList.getLength();
105        try {
106            fGrammarPool.clear();
107            for (int i = 0; i < length; ++i) {
108                fSchemaLoader.loadGrammar(new XMLInputSource(null, uriList.item(i), null, false));
109            }
110            return fGrammarPool.toXSModel();
111        }
112        catch (Exception e) {
113            fSchemaLoader.reportDOMFatalError(e);
114            return null;
115        }
116    }
117
118    /**
119     *  Parses the content of XML Schema documents specified as a list of
120     * <code>LSInput</code>s.
121     * @param is  The list of <code>LSInput</code>s from which the XML
122     *   Schema documents are to be read.
123     * @return An XSModel representing the schema documents.
124     */
125    public XSModel loadInputList(LSInputList is) {
126        final int length = is.getLength();
127        try {
128            fGrammarPool.clear();
129            for (int i = 0; i < length; ++i) {
130                fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is.item(i)));
131            }
132            return fGrammarPool.toXSModel();
133        }
134        catch (Exception e) {
135            fSchemaLoader.reportDOMFatalError(e);
136            return null;
137        }
138    }
139
140    /**
141     * Parse an XML Schema document from a location identified by a URI
142     * reference. If the URI contains a fragment identifier, the behavior is
143     * not defined by this specification.
144     * @param uri The location of the XML Schema document to be read.
145     * @return An XSModel representing this schema.
146     */
147    public XSModel loadURI(String uri) {
148        try {
149            fGrammarPool.clear();
150            return ((XSGrammar) fSchemaLoader.loadGrammar(new XMLInputSource(null, uri, null, false))).toXSModel();
151        }
152        catch (Exception e){
153            fSchemaLoader.reportDOMFatalError(e);
154            return null;
155        }
156    }
157
158    /**
159     *  Parse an XML Schema document from a resource identified by a
160     * <code>LSInput</code> .
161     * @param is  The <code>LSInput</code> from which the source
162     *   document is to be read.
163     * @return An XSModel representing this schema.
164     */
165    public XSModel load(LSInput is) {
166        try {
167            fGrammarPool.clear();
168            return ((XSGrammar) fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is))).toXSModel();
169        }
170        catch (Exception e) {
171            fSchemaLoader.reportDOMFatalError(e);
172            return null;
173        }
174    }
175
176    /* (non-Javadoc)
177     * @see com.sun.org.apache.xerces.internal.dom3.DOMConfiguration#setParameter(java.lang.String, java.lang.Object)
178     */
179    public void setParameter(String name, Object value) throws DOMException {
180        fSchemaLoader.setParameter(name, value);
181    }
182
183    /* (non-Javadoc)
184     * @see com.sun.org.apache.xerces.internal.dom3.DOMConfiguration#getParameter(java.lang.String)
185     */
186    public Object getParameter(String name) throws DOMException {
187        return fSchemaLoader.getParameter(name);
188    }
189
190    /* (non-Javadoc)
191     * @see com.sun.org.apache.xerces.internal.dom3.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object)
192     */
193    public boolean canSetParameter(String name, Object value) {
194        return fSchemaLoader.canSetParameter(name, value);
195    }
196
197    /* (non-Javadoc)
198     * @see com.sun.org.apache.xerces.internal.dom3.DOMConfiguration#getParameterNames()
199     */
200    public DOMStringList getParameterNames() {
201        return fSchemaLoader.getParameterNames();
202    }
203
204    /**
205     * Grammar pool which merges grammars from the same namespace into one. This eliminates
206     * duplicate named components. It doesn't ensure that the grammar is consistent, however
207     * this no worse than than the behaviour of XMLSchemaLoader alone when used as an XSLoader.
208     */
209    private static final class XSGrammarMerger extends XSGrammarPool {
210
211        public XSGrammarMerger () {}
212
213        public void putGrammar(Grammar grammar) {
214            SchemaGrammar cachedGrammar =
215                toSchemaGrammar(super.getGrammar(grammar.getGrammarDescription()));
216            if (cachedGrammar != null) {
217                SchemaGrammar newGrammar = toSchemaGrammar(grammar);
218                if (newGrammar != null) {
219                    mergeSchemaGrammars(cachedGrammar, newGrammar);
220                }
221            }
222            else {
223                super.putGrammar(grammar);
224            }
225        }
226
227        private SchemaGrammar toSchemaGrammar (Grammar grammar) {
228            return (grammar instanceof SchemaGrammar) ? (SchemaGrammar) grammar : null;
229        }
230
231        private void mergeSchemaGrammars(SchemaGrammar cachedGrammar, SchemaGrammar newGrammar) {
232
233            /** Add new top-level element declarations. **/
234            XSNamedMap map = newGrammar.getComponents(XSConstants.ELEMENT_DECLARATION);
235            int length = map.getLength();
236            for (int i = 0; i < length; ++i) {
237                XSElementDecl decl = (XSElementDecl) map.item(i);
238                if (cachedGrammar.getGlobalElementDecl(decl.getName()) == null) {
239                    cachedGrammar.addGlobalElementDecl(decl);
240                }
241            }
242
243            /** Add new top-level attribute declarations. **/
244            map = newGrammar.getComponents(XSConstants.ATTRIBUTE_DECLARATION);
245            length = map.getLength();
246            for (int i = 0; i < length; ++i) {
247                XSAttributeDecl decl = (XSAttributeDecl) map.item(i);
248                if (cachedGrammar.getGlobalAttributeDecl(decl.getName()) == null) {
249                    cachedGrammar.addGlobalAttributeDecl(decl);
250                }
251            }
252
253            /** Add new top-level type definitions. **/
254            map = newGrammar.getComponents(XSConstants.TYPE_DEFINITION);
255            length = map.getLength();
256            for (int i = 0; i < length; ++i) {
257                XSTypeDefinition decl = (XSTypeDefinition) map.item(i);
258                if (cachedGrammar.getGlobalTypeDecl(decl.getName()) == null) {
259                    cachedGrammar.addGlobalTypeDecl(decl);
260                }
261            }
262
263            /** Add new top-level attribute group definitions. **/
264            map = newGrammar.getComponents(XSConstants.ATTRIBUTE_GROUP);
265            length = map.getLength();
266            for (int i = 0; i < length; ++i) {
267                XSAttributeGroupDecl decl = (XSAttributeGroupDecl) map.item(i);
268                if (cachedGrammar.getGlobalAttributeGroupDecl(decl.getName()) == null) {
269                    cachedGrammar.addGlobalAttributeGroupDecl(decl);
270                }
271            }
272
273            /** Add new top-level model group definitions. **/
274            map = newGrammar.getComponents(XSConstants.MODEL_GROUP);
275            length = map.getLength();
276            for (int i = 0; i < length; ++i) {
277                XSGroupDecl decl = (XSGroupDecl) map.item(i);
278                if (cachedGrammar.getGlobalGroupDecl(decl.getName()) == null) {
279                    cachedGrammar.addGlobalGroupDecl(decl);
280                }
281            }
282
283            /** Add new top-level notation declarations. **/
284            map = newGrammar.getComponents(XSConstants.NOTATION_DECLARATION);
285            length = map.getLength();
286            for (int i = 0; i < length; ++i) {
287                XSNotationDecl decl = (XSNotationDecl) map.item(i);
288                if (cachedGrammar.getGlobalNotationDecl(decl.getName()) == null) {
289                    cachedGrammar.addGlobalNotationDecl(decl);
290                }
291            }
292
293            /**
294             * Add all annotations. Since these components are not named it's
295             * possible we'll add duplicate components. There isn't much we can
296             * do. It's no worse than XMLSchemaLoader when used as an XSLoader.
297             */
298            XSObjectList annotations = newGrammar.getAnnotations();
299            length = annotations.getLength();
300            for (int i = 0; i < length; ++i) {
301                cachedGrammar.addAnnotation((XSAnnotationImpl) annotations.item(i));
302            }
303
304        }
305
306        public boolean containsGrammar(XMLGrammarDescription desc) {
307            return false;
308        }
309
310        public Grammar getGrammar(XMLGrammarDescription desc) {
311            return null;
312        }
313
314        public Grammar retrieveGrammar(XMLGrammarDescription desc) {
315            return null;
316        }
317
318        public Grammar [] retrieveInitialGrammarSet (String grammarType) {
319            return new Grammar[0];
320        }
321    }
322}
323