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.xalan.internal.xsltc.dom;
23
24import com.sun.org.apache.xalan.internal.XalanConstants;
25import java.io.FileNotFoundException;
26
27import javax.xml.transform.stream.StreamSource;
28
29import com.sun.org.apache.xalan.internal.xsltc.DOM;
30import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
31import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
32import com.sun.org.apache.xalan.internal.xsltc.TransletException;
33import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
35import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
36import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
37import com.sun.org.apache.xml.internal.dtm.DTM;
38import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
39import com.sun.org.apache.xml.internal.dtm.DTMManager;
40import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
41import com.sun.org.apache.xml.internal.dtm.ref.EmptyIterator;
42import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
43
44import org.xml.sax.InputSource;
45import org.xml.sax.XMLReader;
46
47/**
48 * @author Morten Jorgensen
49 */
50public final class LoadDocument {
51
52    private static final String NAMESPACE_FEATURE =
53       "http://xml.org/sax/features/namespaces";
54
55    /**
56     * Interprets the arguments passed from the document() function (see
57     * com/sun/org/apache/xalan/internal/xsltc/compiler/DocumentCall.java) and returns an
58     * iterator containing the requested nodes. Builds a union-iterator if
59     * several documents are requested.
60     * 2 arguments arg1 and arg2.  document(Obj, node-set) call
61     */
62    public static DTMAxisIterator documentF(Object arg1, DTMAxisIterator arg2,
63                            String xslURI, AbstractTranslet translet, DOM dom)
64    throws TransletException {
65        String baseURI = null;
66        final int arg2FirstNode = arg2.next();
67        if (arg2FirstNode == DTMAxisIterator.END) {
68            //  the second argument node-set is empty
69            return EmptyIterator.getInstance();
70        } else {
71            //System.err.println("arg2FirstNode name: "
72            //                   + dom.getNodeName(arg2FirstNode )+"["
73            //                   +Integer.toHexString(arg2FirstNode )+"]");
74            baseURI = dom.getDocumentURI(arg2FirstNode);
75            if (!SystemIDResolver.isAbsoluteURI(baseURI))
76               baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
77        }
78
79        try {
80            if (arg1 instanceof String) {
81                if (((String)arg1).length() == 0) {
82                    return document(xslURI, "", translet, dom);
83                } else {
84                    return document((String)arg1, baseURI, translet, dom);
85                }
86            } else if (arg1 instanceof DTMAxisIterator) {
87                return document((DTMAxisIterator)arg1, baseURI, translet, dom);
88            } else {
89                final String err = "document("+arg1.toString()+")";
90                throw new IllegalArgumentException(err);
91            }
92        } catch (Exception e) {
93            throw new TransletException(e);
94        }
95    }
96    /**
97     * Interprets the arguments passed from the document() function (see
98     * com/sun/org/apache/xalan/internal/xsltc/compiler/DocumentCall.java) and returns an
99     * iterator containing the requested nodes. Builds a union-iterator if
100     * several documents are requested.
101     * 1 arguments arg.  document(Obj) call
102     */
103    public static DTMAxisIterator documentF(Object arg, String xslURI,
104                    AbstractTranslet translet, DOM dom)
105    throws TransletException {
106        try {
107            if (arg instanceof String) {
108                if (xslURI == null )
109                    xslURI = "";
110
111                String baseURI = xslURI;
112                if (!SystemIDResolver.isAbsoluteURI(xslURI))
113                   baseURI = SystemIDResolver.getAbsoluteURIFromRelative(xslURI);
114
115                String href = (String)arg;
116                if (href.length() == 0) {
117                    href = "";
118                    // %OPT% Optimization to cache the stylesheet DOM.
119                    // The stylesheet DOM is built once and cached
120                    // in the Templates object.
121                    TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
122                    DOM sdom = null;
123                    if (templates != null) {
124                        sdom = templates.getStylesheetDOM();
125                    }
126
127                    // If the cached dom exists, we need to migrate it
128                    // to the new DTMManager and create a DTMAxisIterator
129                    // for the document.
130                    if (sdom != null) {
131                        return document(sdom, translet, dom);
132                    }
133                    else {
134                        return document(href, baseURI, translet, dom, true);
135                    }
136                }
137                else {
138                    return document(href, baseURI, translet, dom);
139                }
140            } else if (arg instanceof DTMAxisIterator) {
141                return document((DTMAxisIterator)arg, null, translet, dom);
142            } else {
143                final String err = "document("+arg.toString()+")";
144                throw new IllegalArgumentException(err);
145            }
146        } catch (Exception e) {
147            throw new TransletException(e);
148        }
149    }
150
151    private static DTMAxisIterator document(String uri, String base,
152                    AbstractTranslet translet, DOM dom)
153        throws Exception
154    {
155        return document(uri, base, translet, dom, false);
156    }
157
158    private static DTMAxisIterator document(String uri, String base,
159                    AbstractTranslet translet, DOM dom,
160                    boolean cacheDOM)
161    throws Exception
162    {
163        try {
164        final String originalUri = uri;
165        MultiDOM multiplexer = (MultiDOM)dom;
166
167        // Prepend URI base to URI (from context)
168        if (base != null && !base.equals("")) {
169            uri = SystemIDResolver.getAbsoluteURI(uri, base);
170        }
171
172        // Return an empty iterator if the URI is clearly invalid
173        // (to prevent some unncessary MalformedURL exceptions).
174        if (uri == null || uri.equals("")) {
175            return(EmptyIterator.getInstance());
176        }
177
178        // Check if this DOM has already been added to the multiplexer
179        int mask = multiplexer.getDocumentMask(uri);
180        if (mask != -1) {
181            DOM newDom = ((DOMAdapter)multiplexer.getDOMAdapter(uri))
182                                       .getDOMImpl();
183            if (newDom instanceof DOMEnhancedForDTM) {
184                return new SingletonIterator(((DOMEnhancedForDTM)newDom)
185                                                               .getDocument(),
186                                             true);
187            }
188        }
189
190        // Check if we can get the DOM from a DOMCache
191        DOMCache cache = translet.getDOMCache();
192        DOM newdom;
193
194        mask = multiplexer.nextMask(); // peek
195
196        if (cache != null) {
197            newdom = cache.retrieveDocument(base, originalUri, translet);
198            if (newdom == null) {
199                final Exception e = new FileNotFoundException(originalUri);
200                throw new TransletException(e);
201            }
202        } else {
203            String accessError = SecuritySupport.checkAccess(uri, translet.getAllowedProtocols(), XalanConstants.ACCESS_EXTERNAL_ALL);
204            if (accessError != null) {
205                ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
206                        SecuritySupport.sanitizePath(uri), accessError);
207                throw new Exception(msg.toString());
208            }
209
210            // Parse the input document and construct DOM object
211            // Trust the DTMManager to pick the right parser and
212            // set up the DOM correctly.
213            XSLTCDTMManager dtmManager = (XSLTCDTMManager)multiplexer
214                                                              .getDTMManager();
215            DOMEnhancedForDTM enhancedDOM =
216                    (DOMEnhancedForDTM) dtmManager.getDTM(new StreamSource(uri),
217                                            false, null, true, false,
218                                            translet.hasIdCall(), cacheDOM);
219            newdom = enhancedDOM;
220
221            // Cache the stylesheet DOM in the Templates object
222            if (cacheDOM) {
223                TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
224                if (templates != null) {
225                    templates.setStylesheetDOM(enhancedDOM);
226                }
227            }
228
229            translet.prepassDocument(enhancedDOM);
230            enhancedDOM.setDocumentURI(uri);
231        }
232
233        // Wrap the DOM object in a DOM adapter and add to multiplexer
234        final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
235        multiplexer.addDOMAdapter(domAdapter);
236
237        // Create index for any key elements
238        translet.buildKeys(domAdapter, null, null, newdom.getDocument());
239
240        // Return a singleton iterator containing the root node
241        return new SingletonIterator(newdom.getDocument(), true);
242        } catch (Exception e) {
243            throw e;
244        }
245    }
246
247
248    private static DTMAxisIterator document(DTMAxisIterator arg1,
249                                            String baseURI,
250                                            AbstractTranslet translet, DOM dom)
251    throws Exception
252    {
253        UnionIterator union = new UnionIterator(dom);
254        int node = DTM.NULL;
255
256        while ((node = arg1.next()) != DTM.NULL) {
257            String uri = dom.getStringValueX(node);
258            //document(node-set) if true;  document(node-set,node-set) if false
259            if (baseURI  == null) {
260               baseURI = dom.getDocumentURI(node);
261               if (!SystemIDResolver.isAbsoluteURI(baseURI))
262                    baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
263            }
264            union.addIterator(document(uri, baseURI, translet, dom));
265        }
266        return(union);
267    }
268
269    /**
270     * Create a DTMAxisIterator for the newdom. This is currently only
271     * used to create an iterator for the cached stylesheet DOM.
272     *
273     * @param newdom the cached stylesheet DOM
274     * @param translet the translet
275     * @param the main dom (should be a MultiDOM)
276     * @return a DTMAxisIterator from the document root
277     */
278    private static DTMAxisIterator document(DOM newdom,
279                                            AbstractTranslet translet,
280                                            DOM dom)
281        throws Exception
282    {
283        DTMManager dtmManager = ((MultiDOM)dom).getDTMManager();
284        // Need to migrate the cached DTM to the new DTMManager
285        if (dtmManager != null && newdom instanceof DTM) {
286            ((DTM)newdom).migrateTo(dtmManager);
287        }
288
289        translet.prepassDocument(newdom);
290
291        // Wrap the DOM object in a DOM adapter and add to multiplexer
292        final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
293        ((MultiDOM)dom).addDOMAdapter(domAdapter);
294
295        // Create index for any key elements
296        translet.buildKeys(domAdapter, null, null,
297                           newdom.getDocument());
298
299        // Return a singleton iterator containing the root node
300        return new SingletonIterator(newdom.getDocument(), true);
301    }
302
303}
304