001    /*
002     * JBoss, Home of Professional Open Source.
003     * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004     * as indicated by the @author tags. See the copyright.txt file in the
005     * distribution for a full listing of individual contributors. 
006     *
007     * This is free software; you can redistribute it and/or modify it
008     * under the terms of the GNU Lesser General Public License as
009     * published by the Free Software Foundation; either version 2.1 of
010     * the License, or (at your option) any later version.
011     *
012     * This software is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * Lesser General Public License for more details.
016     *
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this software; if not, write to the Free
019     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021     */
022    package org.jboss.dna.graph;
023    
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.net.URI;
027    import java.util.List;
028    import net.jcip.annotations.NotThreadSafe;
029    import org.jboss.dna.common.text.TextDecoder;
030    import org.jboss.dna.common.util.CheckArg;
031    import org.jboss.dna.graph.connectors.RepositorySource;
032    import org.jboss.dna.graph.connectors.RepositorySourceException;
033    import org.jboss.dna.graph.properties.Name;
034    import org.jboss.dna.graph.properties.NamespaceRegistry;
035    import org.jboss.dna.graph.properties.Path;
036    import org.jboss.dna.graph.properties.Property;
037    import org.jboss.dna.graph.xml.XmlHandler;
038    import org.jboss.dna.graph.xml.XmlHandler.Destination;
039    import org.xml.sax.InputSource;
040    import org.xml.sax.SAXException;
041    import org.xml.sax.XMLReader;
042    import org.xml.sax.helpers.XMLReaderFactory;
043    
044    /**
045     * @author Randall Hauch
046     * @author John Verhaeg
047     */
048    public class GraphImporter {
049    
050        private final Graph graph;
051    
052        public GraphImporter( Graph graph ) {
053            CheckArg.isNotNull(graph, "graph");
054            this.graph = graph;
055        }
056    
057        /**
058         * Get the context in which the importer will be executed.
059         * 
060         * @return the execution context; never null
061         */
062        public ExecutionContext getContext() {
063            return this.graph.getContext();
064        }
065    
066        /**
067         * The graph that this importer uses.
068         * 
069         * @return the graph; never null
070         */
071        public Graph getGraph() {
072            return graph;
073        }
074    
075        /**
076         * Read the content from the supplied URI and import into the repository at the supplied location.
077         * 
078         * @param uri the URI where the importer can read the content that is to be imported
079         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
080         *        be null
081         * @return the batch of requests for creating the graph content that represents the imported content
082         * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
083         * @throws IOException if there is a problem reading the content
084         * @throws SAXException if there is a problem with the SAX Parser
085         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
086         *         source}
087         */
088        public Graph.Batch importXml( URI uri,
089                                      Location location ) throws IOException, SAXException, RepositorySourceException {
090            return importXml(uri, location, false);
091        }
092    
093        /**
094         * Read the content from the supplied URI and import into the repository at the supplied location.
095         * 
096         * @param uri the URI where the importer can read the content that is to be imported
097         * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
098         *        be null
099         * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
100         * @return the batch of requests for creating the graph content that represents the imported content
101         * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
102         * @throws IOException if there is a problem reading the content
103         * @throws SAXException if there is a problem with the SAX Parser
104         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
105         *         source}
106         */
107        public Graph.Batch importXml( URI uri,
108                                      Location location,
109                                      boolean skip ) throws IOException, SAXException, RepositorySourceException {
110            CheckArg.isNotNull(uri, "uri");
111            CheckArg.isNotNull(location, "location");
112            CheckArg.isNotNull(location.getPath(), "location.getPath()");
113    
114            // Create the destination for the XmlHandler ...
115            Graph.Batch batch = graph.batch();
116            XmlHandler.Destination destination = new CreateOnGraphInBatch(batch);
117    
118            // Determine where the content is to be placed ...
119            Path parentPath = location.getPath();
120            InputStream stream = null;
121            Name nameAttribute = JcrLexicon.NAME;
122            Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
123            Name typeAttributeValue = null;
124            NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
125            if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
126                typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
127            }
128    
129            TextDecoder decoder = null;
130            XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
131            XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
132                                                typeAttributeValue, scoping);
133            try {
134                stream = uri.toURL().openStream();
135                XMLReader reader = XMLReaderFactory.createXMLReader();
136                reader.setContentHandler(handler);
137                reader.setErrorHandler(handler);
138                reader.parse(new InputSource(stream));
139            } finally {
140                if (stream != null) stream.close();
141            }
142            return batch;
143        }
144    
145        @NotThreadSafe
146        protected final static class CreateOnGraphInBatch implements Destination {
147            private final Graph.Batch batch;
148    
149            protected CreateOnGraphInBatch( Graph.Batch batch ) {
150                assert batch != null;
151                this.batch = batch;
152            }
153    
154            public ExecutionContext getExecutionContext() {
155                return batch.getGraph().getContext();
156            }
157    
158            public void create( Path path,
159                                List<Property> properties ) {
160                assert properties != null;
161                if (properties.isEmpty()) {
162                    batch.create(path).and();
163                } else {
164                    batch.create(path, properties).and();
165                }
166            }
167    
168            public void create( Path path,
169                                Property firstProperty,
170                                Property... additionalProperties ) {
171                if (firstProperty == null) {
172                    batch.create(path).and();
173                } else {
174                    batch.create(path, firstProperty, additionalProperties);
175                }
176            }
177    
178            public void submit() {
179            }
180        }
181    
182    }