001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.repository.util;
007:
008: import java.util.HashMap;
009: import java.util.Map;
010:
011: import org.openrdf.OpenRDFUtil;
012: import org.openrdf.model.BNode;
013: import org.openrdf.model.Resource;
014: import org.openrdf.model.Statement;
015: import org.openrdf.model.URI;
016: import org.openrdf.model.Value;
017: import org.openrdf.repository.RepositoryConnection;
018: import org.openrdf.repository.RepositoryException;
019: import org.openrdf.rio.RDFHandlerException;
020: import org.openrdf.rio.helpers.RDFHandlerBase;
021:
022: /**
023: * An RDFHandler that adds RDF data to a repository.
024: *
025: * @author jeen
026: */
027: public class RDFInserter extends RDFHandlerBase {
028:
029: /*-----------*
030: * Variables *
031: *-----------*/
032:
033: /**
034: * The connection to use for the add operations.
035: */
036: private RepositoryConnection con;
037:
038: /**
039: * The contexts to add the statements to. If this variable is a non-empty
040: * array, statements will be added to the corresponding contexts.
041: */
042: private Resource[] contexts = new Resource[0];
043:
044: /**
045: * Flag indicating whether blank node IDs should be preserved.
046: */
047: private boolean preserveBNodeIDs;
048:
049: /**
050: * Map that stores namespaces that are reported during the evaluation of the
051: * query. Key is the namespace prefix, value is the namespace name.
052: */
053: private Map<String, String> namespaceMap;
054:
055: /**
056: * Map used to keep track of which blank node IDs have been mapped to which
057: * BNode object in case preserveBNodeIDs is false.
058: */
059: private Map<String, BNode> bNodesMap;
060:
061: /*--------------*
062: * Constructors *
063: *--------------*/
064:
065: /**
066: * Creates a new RDFInserter object that preserves bnode IDs and that does
067: * not enforce any context upon statements that are reported to it.
068: *
069: * @param con
070: * The connection to use for the add operations.
071: */
072: public RDFInserter(RepositoryConnection con) {
073: this .con = con;
074: preserveBNodeIDs = true;
075: namespaceMap = new HashMap<String, String>();
076: bNodesMap = new HashMap<String, BNode>();
077: }
078:
079: /*---------*
080: * Methods *
081: *---------*/
082:
083: /**
084: * Sets whether this RDFInserter should preserve blank node IDs.
085: *
086: * @param preserveBNodeIDs
087: * The new value for this flag.
088: */
089: public void setPreserveBNodeIDs(boolean preserveBNodeIDs) {
090: this .preserveBNodeIDs = preserveBNodeIDs;
091: }
092:
093: /**
094: * Checks whether this RDFInserter preserves blank node IDs.
095: */
096: public boolean preservesBNodeIDs() {
097: return preserveBNodeIDs;
098: }
099:
100: /**
101: * Enforces the supplied contexts upon all statements that are reported to
102: * this RDFInserter.
103: *
104: * @param contexts
105: * the contexts to use. Use an empty array (not null!) to indicate no
106: * context(s) should be enforced.
107: */
108: public void enforceContext(Resource... contexts) {
109: OpenRDFUtil.verifyContextNotNull(contexts);
110: this .contexts = contexts;
111: }
112:
113: /**
114: * Checks whether this RDFInserter enforces its contexts upon all statements
115: * that are reported to it.
116: *
117: * @return <tt>true</tt> if it enforces its contexts, <tt>false</tt>
118: * otherwise.
119: */
120: public boolean enforcesContext() {
121: return contexts.length != 0;
122: }
123:
124: /**
125: * Gets the contexts that this RDFInserter enforces upon all statements that
126: * are reported to it (in case <tt>enforcesContext()</tt> returns
127: * <tt>true</tt>).
128: *
129: * @return A Resource[] identifying the contexts, or <tt>null</tt> if no
130: * contexts is enforced.
131: */
132: public Resource[] getContexts() {
133: return contexts;
134: }
135:
136: @Override
137: public void endRDF() throws RDFHandlerException {
138: for (Map.Entry<String, String> entry : namespaceMap.entrySet()) {
139: String prefix = entry.getKey();
140: String name = entry.getValue();
141:
142: try {
143: if (con.getNamespace(prefix) == null) {
144: con.setNamespace(prefix, name);
145: }
146: } catch (RepositoryException e) {
147: throw new RDFHandlerException(e);
148: }
149: }
150:
151: namespaceMap.clear();
152: bNodesMap.clear();
153: }
154:
155: @Override
156: public void handleNamespace(String prefix, String name) {
157: // FIXME: set namespaces directly when they are properly handled wrt
158: // rollback
159: // don't replace earlier declarations
160: if (prefix != null && prefix.trim().length() > 0
161: && !namespaceMap.containsKey(prefix)) {
162: namespaceMap.put(prefix, name);
163: }
164: }
165:
166: @Override
167: public void handleStatement(Statement st)
168: throws RDFHandlerException {
169: Resource subj = st.getSubject();
170: URI pred = st.getPredicate();
171: Value obj = st.getObject();
172: Resource ctxt = st.getContext();
173:
174: if (!preserveBNodeIDs) {
175: if (subj instanceof BNode) {
176: subj = mapBNode((BNode) subj);
177: }
178:
179: if (obj instanceof BNode) {
180: obj = mapBNode((BNode) obj);
181: }
182:
183: if (!enforcesContext() && ctxt instanceof BNode) {
184: ctxt = mapBNode((BNode) ctxt);
185: }
186: }
187:
188: try {
189: if (enforcesContext()) {
190: con.add(subj, pred, obj, contexts);
191: } else {
192: con.add(subj, pred, obj, ctxt);
193: }
194: } catch (RepositoryException e) {
195: throw new RDFHandlerException(e);
196: }
197: }
198:
199: /**
200: * Maps the supplied BNode, which comes from the data, to a new BNode object.
201: * Consecutive calls with equal BNode objects returns the same object
202: * everytime.
203: *
204: * @throws RepositoryException
205: */
206: private BNode mapBNode(BNode bNode) {
207: BNode result = bNodesMap.get(bNode.getID());
208:
209: if (result == null) {
210: result = con.getRepository().getValueFactory()
211: .createBNode();
212: bNodesMap.put(bNode.getID(), result);
213: }
214:
215: return result;
216: }
217: }
|