001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: LoadDocument.java 1225369 2011-12-28 22:54:01Z mrglavas $
020     */
021    
022    package org.apache.xalan.xsltc.dom;
023    
024    import java.io.FileNotFoundException;
025    
026    import javax.xml.transform.stream.StreamSource;
027    
028    import org.apache.xalan.xsltc.DOM;
029    import org.apache.xalan.xsltc.DOMCache;
030    import org.apache.xalan.xsltc.DOMEnhancedForDTM;
031    import org.apache.xalan.xsltc.TransletException;
032    import org.apache.xalan.xsltc.runtime.AbstractTranslet;
033    import org.apache.xalan.xsltc.trax.TemplatesImpl;
034    import org.apache.xml.dtm.DTM;
035    import org.apache.xml.dtm.DTMAxisIterator;
036    import org.apache.xml.dtm.DTMManager;
037    import org.apache.xml.dtm.ref.EmptyIterator;
038    import org.apache.xml.utils.SystemIDResolver;
039    
040    /**
041     * @author Morten Jorgensen
042     */
043    public final class LoadDocument {
044    
045        private static final String NAMESPACE_FEATURE =
046           "http://xml.org/sax/features/namespaces";
047    
048        /**
049         * Interprets the arguments passed from the document() function (see
050         * org/apache/xalan/xsltc/compiler/DocumentCall.java) and returns an
051         * iterator containing the requested nodes. Builds a union-iterator if
052         * several documents are requested.
053         * 2 arguments arg1 and arg2.  document(Obj, node-set) call 
054         */
055        public static DTMAxisIterator documentF(Object arg1, DTMAxisIterator arg2,
056                                String xslURI, AbstractTranslet translet, DOM dom)
057        throws TransletException {
058            String baseURI = null;
059            final int arg2FirstNode = arg2.next();
060            if (arg2FirstNode == DTMAxisIterator.END) {
061                //  the second argument node-set is empty
062                return EmptyIterator.getInstance();
063            } else {
064                //System.err.println("arg2FirstNode name: "
065                //                   + dom.getNodeName(arg2FirstNode )+"["
066                //                   +Integer.toHexString(arg2FirstNode )+"]");
067                baseURI = dom.getDocumentURI(arg2FirstNode);
068                if (!SystemIDResolver.isAbsoluteURI(baseURI))
069                   baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
070            }
071          
072            try {
073                if (arg1 instanceof String) {
074                    if (((String)arg1).length() == 0) {
075                        return document(xslURI, "", translet, dom);
076                    } else {
077                        return document((String)arg1, baseURI, translet, dom);
078                    }
079                } else if (arg1 instanceof DTMAxisIterator) {
080                    return document((DTMAxisIterator)arg1, baseURI, translet, dom);
081                } else {
082                    final String err = "document("+arg1.toString()+")";
083                    throw new IllegalArgumentException(err);
084                }      
085            } catch (Exception e) {
086                throw new TransletException(e);
087            }
088        }
089        /**
090         * Interprets the arguments passed from the document() function (see
091         * org/apache/xalan/xsltc/compiler/DocumentCall.java) and returns an
092         * iterator containing the requested nodes. Builds a union-iterator if
093         * several documents are requested.
094         * 1 arguments arg.  document(Obj) call
095         */
096        public static DTMAxisIterator documentF(Object arg, String xslURI,
097                        AbstractTranslet translet, DOM dom)
098        throws TransletException {
099            try {
100                if (arg instanceof String) {
101                    if (xslURI == null )
102                        xslURI = "";
103    
104                    String baseURI = xslURI;
105                    if (!SystemIDResolver.isAbsoluteURI(xslURI))
106                       baseURI = SystemIDResolver.getAbsoluteURIFromRelative(xslURI);
107                    
108                    String href = (String)arg;
109                    if (href.length() == 0) {
110                        href = "";
111                        // %OPT% Optimization to cache the stylesheet DOM.
112                        // The stylesheet DOM is built once and cached
113                        // in the Templates object.
114                        TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
115                        DOM sdom = null;
116                        if (templates != null) {
117                            sdom = templates.getStylesheetDOM();
118                        }
119                        
120                        // If the cached dom exists, we need to migrate it
121                        // to the new DTMManager and create a DTMAxisIterator
122                        // for the document.
123                        if (sdom != null) {
124                            return document(sdom, translet, dom);
125                        }
126                        else {
127                            return document(href, baseURI, translet, dom, true);
128                        } 
129                    }
130                    else {
131                        return document(href, baseURI, translet, dom);
132                    }
133                } else if (arg instanceof DTMAxisIterator) {
134                    return document((DTMAxisIterator)arg, null, translet, dom);
135                } else {
136                    final String err = "document("+arg.toString()+")";
137                    throw new IllegalArgumentException(err);
138                }      
139            } catch (Exception e) {
140                throw new TransletException(e);
141            }
142        }
143     
144        private static DTMAxisIterator document(String uri, String base,
145                        AbstractTranslet translet, DOM dom)
146            throws Exception
147        {
148            return document(uri, base, translet, dom, false);
149        }
150     
151        private static DTMAxisIterator document(String uri, String base,
152                        AbstractTranslet translet, DOM dom,
153                        boolean cacheDOM)
154        throws Exception 
155        {
156            try {
157            final String originalUri = uri;
158            MultiDOM multiplexer = (MultiDOM)dom;
159    
160            // Prepend URI base to URI (from context)
161            if (base != null && base.length() != 0) {
162                uri = SystemIDResolver.getAbsoluteURI(uri, base);
163            }
164    
165            // Return an empty iterator if the URI is clearly invalid
166            // (to prevent some unncessary MalformedURL exceptions).
167            if (uri == null || uri.length() == 0) {
168                return(EmptyIterator.getInstance());
169            }
170            
171            // Check if this DOM has already been added to the multiplexer
172            int mask = multiplexer.getDocumentMask(uri);
173            if (mask != -1) {
174                DOM newDom = ((DOMAdapter)multiplexer.getDOMAdapter(uri))
175                                           .getDOMImpl();
176                if (newDom instanceof DOMEnhancedForDTM) {
177                    return new SingletonIterator(((DOMEnhancedForDTM)newDom)
178                                                                   .getDocument(),
179                                                 true);
180                } 
181            }
182    
183            // Check if we can get the DOM from a DOMCache
184            DOMCache cache = translet.getDOMCache();
185            DOM newdom;
186    
187            mask = multiplexer.nextMask(); // peek
188    
189            if (cache != null) {
190                newdom = cache.retrieveDocument(base, originalUri, translet);
191                if (newdom == null) {
192                    final Exception e = new FileNotFoundException(originalUri);
193                    throw new TransletException(e);
194                }
195            } else {
196                // Parse the input document and construct DOM object
197                // Trust the DTMManager to pick the right parser and
198                // set up the DOM correctly.
199                XSLTCDTMManager dtmManager = (XSLTCDTMManager)multiplexer
200                                                                  .getDTMManager();
201                DOMEnhancedForDTM enhancedDOM =
202                        (DOMEnhancedForDTM) dtmManager.getDTM(new StreamSource(uri),
203                                                false, null, true, false,
204                                                translet.hasIdCall(), cacheDOM);
205                newdom = enhancedDOM;
206    
207                // Cache the stylesheet DOM in the Templates object
208                if (cacheDOM) {
209                    TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
210                    if (templates != null) {
211                        templates.setStylesheetDOM(enhancedDOM);
212                    }
213                }
214                
215                translet.prepassDocument(enhancedDOM);
216                enhancedDOM.setDocumentURI(uri);
217            }
218    
219            // Wrap the DOM object in a DOM adapter and add to multiplexer
220            final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
221            multiplexer.addDOMAdapter(domAdapter);
222    
223            // Create index for any key elements
224            translet.buildKeys(domAdapter, null, null, newdom.getDocument());
225    
226            // Return a singleton iterator containing the root node
227            return new SingletonIterator(newdom.getDocument(), true);
228            } catch (Exception e) {
229                throw e;
230            }
231        }
232    
233    
234        private static DTMAxisIterator document(DTMAxisIterator arg1,
235                                                String baseURI,
236                                                AbstractTranslet translet, DOM dom)
237        throws Exception
238        {
239            UnionIterator union = new UnionIterator(dom);
240            int node = DTM.NULL;
241    
242            while ((node = arg1.next()) != DTM.NULL) {
243                String uri = dom.getStringValueX(node);
244                //document(node-set) if true;  document(node-set,node-set) if false
245                if (baseURI  == null) {
246                   baseURI = dom.getDocumentURI(node);
247                   if (!SystemIDResolver.isAbsoluteURI(baseURI))
248                        baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
249                }
250                union.addIterator(document(uri, baseURI, translet, dom));
251            }
252            return(union);
253        }
254    
255        /**
256         * Create a DTMAxisIterator for the newdom. This is currently only
257         * used to create an iterator for the cached stylesheet DOM.
258         * 
259         * @param newdom the cached stylesheet DOM
260         * @param translet the translet
261         * @param the main dom (should be a MultiDOM)
262         * @return a DTMAxisIterator from the document root
263         */
264        private static DTMAxisIterator document(DOM newdom, 
265                                                AbstractTranslet translet,
266                                                DOM dom)
267            throws Exception
268        {
269            DTMManager dtmManager = ((MultiDOM)dom).getDTMManager();
270            // Need to migrate the cached DTM to the new DTMManager
271            if (dtmManager != null && newdom instanceof DTM) {
272                ((DTM)newdom).migrateTo(dtmManager);
273            }
274            
275            translet.prepassDocument(newdom);
276            
277            // Wrap the DOM object in a DOM adapter and add to multiplexer
278            final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
279            ((MultiDOM)dom).addDOMAdapter(domAdapter);
280    
281            // Create index for any key elements
282            translet.buildKeys(domAdapter, null, null,
283                               newdom.getDocument());
284    
285            // Return a singleton iterator containing the root node
286            return new SingletonIterator(newdom.getDocument(), true);
287        }
288     
289    }