001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.sail.memory.model;
007:
008: import java.math.BigInteger;
009: import java.util.Collections;
010: import java.util.Set;
011:
012: import javax.xml.datatype.XMLGregorianCalendar;
013:
014: import org.openrdf.model.BNode;
015: import org.openrdf.model.Literal;
016: import org.openrdf.model.Resource;
017: import org.openrdf.model.Statement;
018: import org.openrdf.model.URI;
019: import org.openrdf.model.Value;
020: import org.openrdf.model.datatypes.XMLDatatypeUtil;
021: import org.openrdf.model.impl.BNodeImpl;
022: import org.openrdf.model.impl.ContextStatementImpl;
023: import org.openrdf.model.impl.LiteralImpl;
024: import org.openrdf.model.impl.StatementImpl;
025: import org.openrdf.model.impl.URIImpl;
026: import org.openrdf.model.impl.ValueFactoryBase;
027: import org.openrdf.model.util.URIUtil;
028: import org.openrdf.model.vocabulary.XMLSchema;
029:
030: /**
031: * A factory for MemValue objects that keeps track of created objects to prevent
032: * the creation of duplicate objects, minimizing memory usage as a result.
033: *
034: * @author Arjohn Kampman
035: * @author David Huynh
036: */
037: public class MemValueFactory extends ValueFactoryBase {
038:
039: /*-----------*
040: * Variables *
041: *-----------*/
042:
043: /**
044: * Registry containing the set of MemURI objects as used by a MemoryStore.
045: * This registry enables the reuse of objects, minimizing the number of
046: * objects in main memory.
047: */
048: private final WeakObjectRegistry<MemURI> uriRegistry = new WeakObjectRegistry<MemURI>();
049:
050: /**
051: * Registry containing the set of MemBNode objects as used by a MemoryStore.
052: * This registry enables the reuse of objects, minimizing the number of
053: * objects in main memory.
054: */
055: private final WeakObjectRegistry<MemBNode> bnodeRegistry = new WeakObjectRegistry<MemBNode>();
056:
057: /**
058: * Registry containing the set of MemLiteral objects as used by a
059: * MemoryStore. This registry enables the reuse of objects, minimizing the
060: * number of objects in main memory.
061: */
062: private final WeakObjectRegistry<MemLiteral> literalRegistry = new WeakObjectRegistry<MemLiteral>();
063:
064: /**
065: * Registry containing the set of namespce strings as used by MemURI objects
066: * in a MemoryStore. This registry enables the reuse of objects, minimizing
067: * the number of objects in main memory.
068: */
069: private final WeakObjectRegistry<String> namespaceRegistry = new WeakObjectRegistry<String>();
070:
071: /*---------*
072: * Methods *
073: *---------*/
074:
075: /**
076: * Returns a previously created MemValue that is equal to the supplied value,
077: * or <tt>null</tt> if the supplied value is a new value or is equal to
078: * <tt>null</tt>.
079: *
080: * @param value
081: * The MemValue equivalent of the supplied value, or <tt>null</tt>.
082: * @return A previously created MemValue that is equal to <tt>value</tt>,
083: * or <tt>null</tt> if no such value exists or if <tt>value</tt>
084: * is equal to <tt>null</tt>.
085: */
086: public MemValue getMemValue(Value value) {
087: if (value instanceof Resource) {
088: return getMemResource((Resource) value);
089: } else if (value instanceof Literal) {
090: return getMemLiteral((Literal) value);
091: } else if (value == null) {
092: return null;
093: } else {
094: throw new IllegalArgumentException(
095: "value is not a Resource or Literal: " + value);
096: }
097: }
098:
099: /**
100: * See getMemValue() for description.
101: */
102: public MemResource getMemResource(Resource resource) {
103: if (resource instanceof URI) {
104: return getMemURI((URI) resource);
105: } else if (resource instanceof BNode) {
106: return getMemBNode((BNode) resource);
107: } else if (resource == null) {
108: return null;
109: } else {
110: throw new IllegalArgumentException(
111: "resource is not a URI or BNode: " + resource);
112: }
113: }
114:
115: /**
116: * See getMemValue() for description.
117: */
118: public MemURI getMemURI(URI uri) {
119: if (isOwnMemValue(uri)) {
120: return (MemURI) uri;
121: } else {
122: return uriRegistry.get(uri);
123: }
124: }
125:
126: /**
127: * See getMemValue() for description.
128: */
129: public MemBNode getMemBNode(BNode bnode) {
130: if (isOwnMemValue(bnode)) {
131: return (MemBNode) bnode;
132: } else {
133: return bnodeRegistry.get(bnode);
134: }
135: }
136:
137: /**
138: * See getMemValue() for description.
139: */
140: public MemLiteral getMemLiteral(Literal literal) {
141: if (isOwnMemValue(literal)) {
142: return (MemLiteral) literal;
143: } else {
144: return literalRegistry.get(literal);
145: }
146: }
147:
148: /**
149: * Checks whether the supplied value is an instance of <tt>MemValue</tt>
150: * and whether it has been created by this MemValueFactory.
151: */
152: private boolean isOwnMemValue(Value value) {
153: return value instanceof MemValue
154: && ((MemValue) value).getCreator() == this ;
155: }
156:
157: /**
158: * Gets all URIs that are managed by this value factory.
159: *
160: * @return An unmodifiable Set of MemURI objects.
161: */
162: public Set<MemURI> getMemURIs() {
163: return Collections.unmodifiableSet(uriRegistry);
164: }
165:
166: /**
167: * Gets all bnodes that are managed by this value factory.
168: *
169: * @return An unmodifiable Set of MemBNode objects.
170: */
171: public Set<MemBNode> getMemBNodes() {
172: return Collections.unmodifiableSet(bnodeRegistry);
173: }
174:
175: /**
176: * Gets all literals that are managed by this value factory.
177: *
178: * @return An unmodifiable Set of MemURI objects.
179: */
180: public Set<MemLiteral> getMemLiterals() {
181: return Collections.unmodifiableSet(literalRegistry);
182: }
183:
184: /**
185: * Creates a MemValue for the supplied Value. The supplied value should not
186: * already have an associated MemValue. The created MemValue is returned.
187: *
188: * @param value
189: * A Resource or Literal.
190: * @return The created MemValue.
191: */
192: public MemValue createMemValue(Value value) {
193: if (value instanceof Resource) {
194: return createMemResource((Resource) value);
195: } else if (value instanceof Literal) {
196: return createMemLiteral((Literal) value);
197: } else {
198: throw new IllegalArgumentException(
199: "value is not a Resource or Literal: " + value);
200: }
201: }
202:
203: /**
204: * See createMemValue() for description.
205: */
206: public MemResource createMemResource(Resource resource) {
207: if (resource instanceof URI) {
208: return createMemURI((URI) resource);
209: } else if (resource instanceof BNode) {
210: return createMemBNode((BNode) resource);
211: } else {
212: throw new IllegalArgumentException(
213: "resource is not a URI or BNode: " + resource);
214: }
215: }
216:
217: /**
218: * See createMemValue() for description.
219: */
220: public MemURI createMemURI(URI uri) {
221: // Namespace strings are relatively large objects and are shared
222: // between uris
223: String namespace = uri.getNamespace();
224: String sharedNamespace = namespaceRegistry.get(namespace);
225:
226: if (sharedNamespace == null) {
227: // New namespace, add it to the registry
228: namespaceRegistry.add(namespace);
229: } else {
230: // Use the shared namespace
231: namespace = sharedNamespace;
232: }
233:
234: // Create a MemURI and add it to the registry
235: MemURI memURI;
236: if (isOwnMemValue(uri) && namespace == uri.getNamespace()) {
237: // Supplied parameter is a MemURI that can be reused
238: memURI = (MemURI) uri;
239: } else {
240: memURI = new MemURI(this , namespace, uri.getLocalName());
241: }
242:
243: boolean wasNew = uriRegistry.add(memURI);
244: assert wasNew : "Created a duplicate MemURI for URI " + uri;
245:
246: return memURI;
247: }
248:
249: /**
250: * See createMemValue() for description.
251: */
252: public MemBNode createMemBNode(BNode bnode) {
253: MemBNode memBNode = new MemBNode(this , bnode.getID());
254:
255: boolean wasNew = bnodeRegistry.add(memBNode);
256: assert wasNew : "Created a duplicate MemBNode for bnode "
257: + bnode;
258:
259: return memBNode;
260: }
261:
262: /**
263: * See createMemValue() for description.
264: */
265: public MemLiteral createMemLiteral(Literal literal) {
266: MemLiteral memLiteral = null;
267:
268: String label = literal.getLabel();
269: URI datatype = literal.getDatatype();
270: if (datatype != null) {
271: try {
272: if (XMLDatatypeUtil.isIntegerDatatype(datatype)) {
273: memLiteral = new IntegerMemLiteral(this , label,
274: literal.integerValue(), datatype);
275: } else if (datatype.equals(XMLSchema.DECIMAL)) {
276: memLiteral = new DecimalMemLiteral(this , label,
277: literal.decimalValue(), datatype);
278: } else if (datatype.equals(XMLSchema.FLOAT)) {
279: memLiteral = new NumericMemLiteral(this , label,
280: literal.floatValue(), datatype);
281: } else if (datatype.equals(XMLSchema.DOUBLE)) {
282: memLiteral = new NumericMemLiteral(this , label,
283: literal.doubleValue(), datatype);
284: } else if (datatype.equals(XMLSchema.BOOLEAN)) {
285: memLiteral = new BooleanMemLiteral(this , label,
286: literal.booleanValue());
287: } else if (datatype.equals(XMLSchema.DATETIME)) {
288: memLiteral = new CalendarMemLiteral(this , label,
289: literal.calendarValue());
290: } else {
291: memLiteral = new MemLiteral(this , literal
292: .getLabel(), datatype);
293: }
294: } catch (IllegalArgumentException e) {
295: // Unable to parse literal label to primitive type
296: memLiteral = new MemLiteral(this , literal.getLabel(),
297: datatype);
298: }
299: } else if (literal.getLanguage() != null) {
300: memLiteral = new MemLiteral(this , literal.getLabel(),
301: literal.getLanguage());
302: } else {
303: memLiteral = new MemLiteral(this , literal.getLabel());
304: }
305:
306: boolean wasNew = literalRegistry.add(memLiteral);
307: assert wasNew : "Created a duplicate MemLiteral for literal "
308: + literal;
309:
310: return memLiteral;
311: }
312:
313: public URI createURI(String uri) {
314: URI tempURI = new URIImpl(uri);
315: MemURI memURI = getMemURI(tempURI);
316:
317: if (memURI == null) {
318: memURI = createMemURI(tempURI);
319: }
320:
321: return memURI;
322: }
323:
324: public URI createURI(String namespace, String localName) {
325: URI tempURI = null;
326:
327: // Reuse supplied namespace and local name strings if possible
328: if (URIUtil.isCorrectURISplit(namespace, localName)) {
329: if (namespace.indexOf(':') == -1) {
330: throw new IllegalArgumentException(
331: "Not a valid (absolute) URI: " + namespace
332: + localName);
333: }
334:
335: tempURI = new MemURI(this , namespace, localName);
336: } else {
337: tempURI = new URIImpl(namespace + localName);
338: }
339:
340: MemURI memURI = uriRegistry.get(tempURI);
341:
342: if (memURI == null) {
343: memURI = createMemURI(tempURI);
344: }
345:
346: return memURI;
347: }
348:
349: public BNode createBNode(String nodeID) {
350: BNode tempBNode = new BNodeImpl(nodeID);
351: MemBNode memBNode = getMemBNode(tempBNode);
352:
353: if (memBNode == null) {
354: memBNode = createMemBNode(tempBNode);
355: }
356:
357: return memBNode;
358: }
359:
360: public Literal createLiteral(String value) {
361: Literal tempLiteral = new LiteralImpl(value);
362: MemLiteral memLiteral = literalRegistry.get(tempLiteral);
363:
364: if (memLiteral == null) {
365: memLiteral = createMemLiteral(tempLiteral);
366: }
367:
368: return memLiteral;
369: }
370:
371: public Literal createLiteral(String value, String language) {
372: Literal tempLiteral = new LiteralImpl(value, language);
373: MemLiteral memLiteral = literalRegistry.get(tempLiteral);
374:
375: if (memLiteral == null) {
376: memLiteral = createMemLiteral(tempLiteral);
377: }
378:
379: return memLiteral;
380: }
381:
382: public Literal createLiteral(String value, URI datatype) {
383: Literal tempLiteral = new LiteralImpl(value, datatype);
384: MemLiteral memLiteral = literalRegistry.get(tempLiteral);
385:
386: if (memLiteral == null) {
387: memLiteral = createMemLiteral(tempLiteral);
388: }
389:
390: return memLiteral;
391: }
392:
393: @Override
394: public Literal createLiteral(boolean value) {
395: MemLiteral newLiteral = new BooleanMemLiteral(this , value);
396: return getSharedLiteral(newLiteral);
397: }
398:
399: @Override
400: protected Literal createIntegerLiteral(Number n, URI datatype) {
401: MemLiteral newLiteral = new IntegerMemLiteral(this , BigInteger
402: .valueOf(n.longValue()), datatype);
403: return getSharedLiteral(newLiteral);
404: }
405:
406: @Override
407: protected Literal createFPLiteral(Number n, URI datatype) {
408: MemLiteral newLiteral = new NumericMemLiteral(this , n, datatype);
409: return getSharedLiteral(newLiteral);
410: }
411:
412: @Override
413: public Literal createLiteral(XMLGregorianCalendar calendar) {
414: MemLiteral newLiteral = new CalendarMemLiteral(this , calendar);
415: return getSharedLiteral(newLiteral);
416: }
417:
418: private Literal getSharedLiteral(MemLiteral newLiteral) {
419: MemLiteral sharedLiteral = literalRegistry.get(newLiteral);
420:
421: if (sharedLiteral == null) {
422: boolean wasNew = literalRegistry.add(newLiteral);
423: assert wasNew : "Created a duplicate MemLiteral for literal "
424: + newLiteral;
425: sharedLiteral = newLiteral;
426: }
427:
428: return sharedLiteral;
429: }
430:
431: public Statement createStatement(Resource subject, URI predicate,
432: Value object) {
433: return new StatementImpl(subject, predicate, object);
434: }
435:
436: public Statement createStatement(Resource subject, URI predicate,
437: Value object, Resource context) {
438: if (context == null) {
439: return new StatementImpl(subject, predicate, object);
440: } else {
441: return new ContextStatementImpl(subject, predicate, object,
442: context);
443: }
444: }
445: }
|