001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.io;
025    
026    import java.io.IOException;
027    import java.io.InputStream;
028    import java.net.URI;
029    import org.jboss.dna.common.text.TextDecoder;
030    import org.jboss.dna.common.util.CheckArg;
031    import org.jboss.dna.graph.ExecutionContext;
032    import org.jboss.dna.graph.Graph;
033    import org.jboss.dna.graph.JcrLexicon;
034    import org.jboss.dna.graph.JcrNtLexicon;
035    import org.jboss.dna.graph.Location;
036    import org.jboss.dna.graph.connector.RepositorySource;
037    import org.jboss.dna.graph.connector.RepositorySourceException;
038    import org.jboss.dna.graph.property.Name;
039    import org.jboss.dna.graph.property.NamespaceRegistry;
040    import org.jboss.dna.graph.property.Path;
041    import org.jboss.dna.graph.xml.XmlHandler;
042    import org.xml.sax.InputSource;
043    import org.xml.sax.SAXException;
044    import org.xml.sax.XMLReader;
045    import org.xml.sax.helpers.XMLReaderFactory;
046    
047    /**
048     * @author Randall Hauch
049     * @author John Verhaeg
050     */
051    public class GraphImporter {
052    
053        private final Graph graph;
054    
055        public GraphImporter( Graph graph ) {
056            CheckArg.isNotNull(graph, "graph");
057            this.graph = graph;
058        }
059    
060        /**
061         * Get the context in which the importer will be executed.
062         * 
063         * @return the execution context; never null
064         */
065        public ExecutionContext getContext() {
066            return this.graph.getContext();
067        }
068    
069        /**
070         * The graph that this importer uses.
071         * 
072         * @return the graph; never null
073         */
074        public Graph getGraph() {
075            return graph;
076        }
077    
078        /**
079         * Read the content from the supplied URI and import into the repository at the supplied location.
080         * 
081         * @param uri the URI where the importer can read the content that is to be imported
082         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
083         *        be null
084         * @return the batch of requests for creating the graph content that represents the imported content
085         * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
086         * @throws IOException if there is a problem reading the content
087         * @throws SAXException if there is a problem with the SAX Parser
088         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
089         *         source}
090         */
091        public Graph.Batch importXml( URI uri,
092                                      Location location ) throws IOException, SAXException, RepositorySourceException {
093            return importXml(uri, location, false);
094        }
095    
096        /**
097         * Read the content from the supplied URI and import into the repository at the supplied location.
098         * 
099         * @param uri the URI where the importer can read the content that is to be imported
100         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
101         *        be null
102         * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
103         * @return the batch of requests for creating the graph content that represents the imported content
104         * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
105         * @throws IOException if there is a problem reading the content
106         * @throws SAXException if there is a problem with the SAX Parser
107         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
108         *         source}
109         */
110        public Graph.Batch importXml( URI uri,
111                                      Location location,
112                                      boolean skip ) throws IOException, SAXException, RepositorySourceException {
113            CheckArg.isNotNull(uri, "uri");
114            CheckArg.isNotNull(location, "location");
115            CheckArg.isNotNull(location.getPath(), "location.getPath()");
116            InputStream stream = null;
117            try {
118                stream = uri.toURL().openStream();
119                return importXml(stream, location, skip);
120            } finally {
121                if (stream != null) stream.close();
122            }
123        }
124    
125        /**
126         * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
127         * close the stream.
128         * 
129         * @param stream the stream containing the content to be imported
130         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
131         *        be null
132         * @return the batch of requests for creating the graph content that represents the imported content
133         * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
134         * @throws IOException if there is a problem reading the content
135         * @throws SAXException if there is a problem with the SAX Parser
136         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
137         *         source}
138         */
139        public Graph.Batch importXml( InputStream stream,
140                                      Location location ) throws IOException, SAXException, RepositorySourceException {
141            return importXml(stream, location, false);
142        }
143    
144        /**
145         * Read the content from the supplied URI and import into the repository at the supplied location. This method does <i>not</i>
146         * close the stream.
147         * 
148         * @param stream the stream containing the content to be imported
149         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
150         *        be null
151         * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
152         * @return the batch of requests for creating the graph content that represents the imported content
153         * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
154         * @throws IOException if there is a problem reading the content
155         * @throws SAXException if there is a problem with the SAX Parser
156         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
157         *         source}
158         */
159        public Graph.Batch importXml( InputStream stream,
160                                      Location location,
161                                      boolean skip ) throws IOException, SAXException, RepositorySourceException {
162            CheckArg.isNotNull(stream, "uri");
163            CheckArg.isNotNull(location, "location");
164            CheckArg.isNotNull(location.getPath(), "location.getPath()");
165    
166            // Create the destination for the XmlHandler ...
167            Graph.Batch batch = graph.batch();
168            Destination destination = new GraphBatchDestination(batch, true);
169    
170            // Determine where the content is to be placed ...
171            Path parentPath = location.getPath();
172            Name nameAttribute = JcrLexicon.NAME;
173            Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
174            Name typeAttributeValue = null;
175            NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
176            if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
177                typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
178            }
179    
180            TextDecoder decoder = null;
181            XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
182            XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
183                                                typeAttributeValue, scoping);
184            XMLReader reader = XMLReaderFactory.createXMLReader();
185            reader.setContentHandler(handler);
186            reader.setErrorHandler(handler);
187            reader.parse(new InputSource(stream));
188            if (stream != null) stream.close();
189            return batch;
190        }
191    
192        /**
193         * Return an {@link XmlHandler} that can be used to import content directly into the supplied location. The operations
194         * resulting from the {@link XmlHandler} operations are batched until the {@link XmlHandler#endDocument()} is called, at which
195         * point all enqueued operations are submitted to the graph.
196         * 
197         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
198         *        be null
199         * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
200         * @return the {@link XmlHandler} that can be used to import content
201         * @throws IllegalArgumentException if the <code>stream</code> or destination path are null
202         */
203        public XmlHandler getHandlerForImportingXml( Location location,
204                                                     boolean skip ) {
205            CheckArg.isNotNull(location, "location");
206            CheckArg.isNotNull(location.getPath(), "location.getPath()");
207    
208            // Create the destination for the XmlHandler ...
209            Graph.Batch batch = graph.batch();
210            Destination destination = new GraphBatchDestination(batch, false);
211    
212            // Determine where the content is to be placed ...
213            Path parentPath = location.getPath();
214            Name nameAttribute = JcrLexicon.NAME;
215            Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
216            Name typeAttributeValue = null;
217            NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
218            if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
219                typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
220            }
221    
222            TextDecoder decoder = null;
223            XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
224            XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
225                                                typeAttributeValue, scoping);
226            return handler;
227        }
228    
229    }