/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s):
* Move to associate XAResource with Resolver Factory
* copyright 2008 The Topaz Foundation
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.resolver.store;
// Java 2 standard packages
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import javax.transaction.xa.XAResource;
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.Node;
import org.jrdf.graph.URIReference;
// Locally written packages
import org.mulgara.query.*;
import org.mulgara.resolver.spi.*;
import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.nodepool.NodePoolException;
import org.mulgara.store.statement.StatementStore;
import org.mulgara.store.statement.StatementStoreException;
import org.mulgara.store.stringpool.SPObject;
import org.mulgara.store.stringpool.SPObjectFactory;
import org.mulgara.store.stringpool.StringPoolException;
import org.mulgara.store.tuples.Tuples;
import org.mulgara.store.xa.SimpleXAResource;
import org.mulgara.store.xa.SimpleXAResourceException;
import org.mulgara.store.xa.XAResolverSession;
import org.mulgara.store.xa.XAStatementStore;
import org.mulgara.util.LongMapper;
/**
* Resolves constraints from the Mulgara {@link StatementStore}.
*
* @created 2003-12-01
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
* @version $Revision: 1.11 $
* @modified $Date: 2005/05/06 04:07:58 $ @maintenanceAuthor $Author: amuys $
* @company <a href="mailto:info@PIsoftware.com">Plugged In Software</a>
* @copyright ©2003-2004 <a href="http://www.PIsoftware.com/">Plugged In
* Software Pty Ltd</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class StatementStoreResolver implements SystemResolver {
/** Logger. */
private static final Logger logger = Logger.getLogger(StatementStoreResolver.class.getName());
/**
* A (non) constraint that selects every statement from every model.
*
* This is used to select the entire contents of the store during
* backup and restore.
*/
public static final Constraint ALL_STATEMENTS =
new ConstraintImpl(StatementStore.VARIABLES[0],
StatementStore.VARIABLES[1],
StatementStore.VARIABLES[2],
StatementStore.VARIABLES[3]);
/**
* The preallocated node for the <code>rdf:type</code> property.
*/
private final long rdfType;
private final ResolverSession resolverSession;
/**
* The preallocated local node identifying the type of models kept in the
* statement store.
*/
private final URI statementStoreModelTypeURI;
/**
* The XA statement store shared with all resolvers from the same factory.
*/
private final XAStatementStore statementStore;
private final XAResolverSession xaResolverSession;
private final XAResource xaresource;
@SuppressWarnings("unused")
private boolean isSystemResolver;
private long systemModel;
//
// Constructors
//
/**
* Construct a {@link StatementStoreResolver}.
*/
StatementStoreResolver(long rdfType,
long systemModel,
URI modelTypeURI,
XAResolverSession resolverSession,
XAStatementStore statementStore,
ResolverFactory resolverFactory)
throws IllegalArgumentException, ResolverFactoryException
{
// Validate parameters
if (modelTypeURI == null) {
throw new IllegalArgumentException("Graph type can't be Null");
}
if (statementStore == null) {
throw new IllegalArgumentException("Null 'statementStore' parameter");
}
// Initialize fields
this.rdfType = rdfType;
this.systemModel = systemModel;
this.resolverSession = resolverSession;
this.statementStoreModelTypeURI = modelTypeURI;
this.statementStore = statementStore;
this.xaResolverSession = resolverSession;
this.isSystemResolver = true;
this.xaresource = new StatementStoreXAResource(
10, // transaction timeout in seconds
resolverSession,
new SimpleXAResource[] { statementStore },
resolverFactory);
}
StatementStoreResolver(Resolver systemResolver,
long rdfType,
long systemModel,
URI modelTypeURI,
XAResolverSession resolverSession,
XAStatementStore statementStore,
ResolverFactory resolverFactory)
throws IllegalArgumentException, ResolverFactoryException
{
// Validate parameters
if (modelTypeURI == null) {
throw new IllegalArgumentException("Graph type can't be Null");
}
if (statementStore == null) {
throw new IllegalArgumentException("Null 'statementStore' parameter");
}
// Initialize fields
this.rdfType = rdfType;
this.resolverSession = resolverSession;
this.statementStoreModelTypeURI = modelTypeURI;
this.statementStore = statementStore;
this.xaResolverSession = resolverSession;
this.isSystemResolver = false;
this.xaresource = new StatementStoreXAResource(
10, // transaction timeout in seconds
resolverSession,
new SimpleXAResource[] { statementStore },
resolverFactory);
}
//
// Methods implementing the Resolver interface
//
/**
* @return a {@link StatementStoreXAResource} with a 10 second transaction timeout
*/
public XAResource getXAResource()
{
return xaresource;
}
/**
* Create model in the statement store.
*/
public void createModel(long model, URI modelTypeURI) throws ResolverException, LocalizeException
{
if (logger.isDebugEnabled()) {
logger.debug("Create XA store model " + model + " of type " + modelTypeURI);
}
// Validate the "modelType" parameter
if (!modelTypeURI.equals(statementStoreModelTypeURI)) {
throw new ResolverException(
"Can't create " + model + " of type " + modelTypeURI +
", which was never registered by " + getClass() + ": " +
statementStoreModelTypeURI
);
}
}
public void createSystemModel(long model, long modelType)
throws ResolverException, LocalizeException
{
modifyModel(model,
new SingletonStatements(model, rdfType, modelType),
true);
}
public void write(Writer w) throws IOException, ResolverException
{
Tuples tuples;
try {
tuples = resolve(ALL_STATEMENTS);
} catch (QueryException e) {
throw new ResolverException("Unable to write backup", e);
}
assert tuples != null;
try {
assert tuples.getVariables()[0] == StatementStore.VARIABLES[0];
assert tuples.getVariables()[1] == StatementStore.VARIABLES[1];
assert tuples.getVariables()[2] == StatementStore.VARIABLES[2];
assert tuples.getVariables()[3] == StatementStore.VARIABLES[3];
// Dump the triples.
for (tuples.beforeFirst(); tuples.next(); ) {
w.write(Long.toString(tuples.getColumnValue(0)));
w.write(' ');
w.write(Long.toString(tuples.getColumnValue(1)));
w.write(' ');
w.write(Long.toString(tuples.getColumnValue(2)));
w.write(' ');
w.write(Long.toString(tuples.getColumnValue(3)));
w.write('\n');
}
} catch (TuplesException e) {
throw new ResolverException("Unable to write backup", e);
} finally {
try {
tuples.close();
} catch (TuplesException e) {
logger.warn("Unable to close tuples after backup", e);
}
}
}
public void writeStringPool(Writer w) throws IOException, ResolverException
{
w.write("The "+getClass()+".writeStringPool method isn't implemented");
/*
Iterator si = sessionStringPool.iterator();
while (si.hasNext()) {
StringPool.Entry e = (StringPool.Entry) si.next();
w.write(Long.toString(e.getGNode()));
w.write(' ');
SPObject spObject = e.getSPObject();
if (spObject instanceof SPURI) { URI uri = ((SPURI) spObject).getURI(); URI relativeURI = database.getURI().relativize(uri);
// Be suspicious about relative URIs -- we're only expecting the
// names of models from this server
if (!relativeURI.isAbsolute()) {
if ((relativeURI.getAuthority() != null) ||
((relativeURI.getPath() != null) && (relativeURI.getPath().length() > 0)) || (relativeURI.getFragment() == null)) {
logger.warn("Unusual relative URI in backup: " + relativeURI + " authority=\"" + relativeURI.getAuthority() + "\"" +
" path=\"" + relativeURI.getPath() + "\"" +
" fragment=\"" +
relativeURI.getFragment() + "\"");
}
spObject = sessionStringPool.newSPObject(relativeURI);
}
}
w.write(spObject.getEncodedString());
w.write('\n');
}
*/
w.write("\n");
}
/**
* Remove model in the statement store.
*/
public void removeModel(long model) throws ResolverException
{
// Globalize model
URIReference modelURIReference;
try {
Node node = resolverSession.globalize(model);
if (!(node instanceof URIReference)) {
throw new ResolverException(
"Graph " + model + " is " + node + ", not a URI reference");
}
modelURIReference = (URIReference) node;
} catch (GlobalizeException e) {
throw new ResolverException("Couldn't globalize model " + model, e);
}
assert modelURIReference != null;
try {
statementStore.removeTriples(NodePool.NONE, NodePool.NONE, NodePool.NONE, model);
} catch (StatementStoreException se) {
throw new ResolverException ("Failed to remove statements from model " + model, se);
}
}
public boolean modelExists(long model) throws ResolverException {
try {
return statementStore.existsTriples(model, rdfType, NodePool.NONE,
systemModel);
} catch (StatementStoreException se) {
throw new ResolverException("Failed to find model " + model, se);
}
}
/**
* Insert or delete statements in a model in the statement store.
*/
public void modifyModel(long model, Statements statements, boolean occurs)
throws ResolverException
{
// Modify the membership of the statements within the model
try {
statements.beforeFirst();
while (statements.next()) {
long subject = statements.getSubject();
long predicate = statements.getPredicate();
long object = statements.getObject();
if (occurs) {
// statement is asserted to be true
if (logger.isDebugEnabled()) logger.debug("Inserting statement: [" + subject + " "
+ predicate + " "
+ object + "] in " + model);
statementStore.addTriple(subject, predicate, object, model);
} else {
// statement is asserted to be false
statementStore.removeTriples(subject, predicate, object, model);
}
}
} catch (StatementStoreException e) {
try {
logger.warn("Failed to modifyModel: [" + resolverSession.globalize(statements.getSubject()) + " "
+ resolverSession.globalize(statements.getPredicate()) + " "
+ resolverSession.globalize(statements.getObject()) + " "
+ resolverSession.globalize(model) + "]", e);
} catch (Exception eg) {
throw new ResolverException("Failed to globalize in debug", eg);
}
throw new ResolverException("Couldn't make statement " + occurs + " in " + model, e);
} catch (TuplesException e) {
throw new ResolverException("Unable to read input statements", e);
}
}
/**
* Resolve a constraint from the statement store.
*/
public Resolution resolve(Constraint constraint) throws QueryException
{
try {
if (constraintResolvable(constraint)) {
if (!constraint.isRepeating()) {
if (constraint instanceof ConstraintImpl) {
return new StatementStoreResolution(constraint, statementStore);
} else {
throw new QueryException("Unable to resolve constraint " + constraint + " unknown type");
}
} else {
throw new QueryException("Duplicate variable found during resolution");
}
} else {
return new EmptyResolution(constraint, true);
}
} catch (TuplesException e) {
throw new QueryException("Couldn't resolve " + constraint, e);
}
}
private boolean constraintResolvable(Constraint constraint) {
for (int i = 0; i < 3; i++) {
if (constraint.getElement(i) instanceof LocalNode &&
((LocalNode)constraint.getElement(i)).getValue() < 0) {
return false;
}
}
return true;
}
//
// ResolverSession methods
//
public Node globalize(long node) throws GlobalizeException
{
return resolverSession.globalize(node);
}
public long lookup(Node node) throws LocalizeException
{
return resolverSession.lookup(node);
}
public long lookupPersistent(Node node) throws LocalizeException
{
return resolverSession.lookupPersistent(node);
}
public long localize(Node node) throws LocalizeException
{
return resolverSession.localize(node);
}
public long localizePersistent(Node node) throws LocalizeException
{
return resolverSession.localizePersistent(node);
}
public long newBlankNode() throws NodePoolException {
return resolverSession.newBlankNode();
}
public Tuples findStringPoolRange(
SPObject lowValue, boolean inclLowValue,
SPObject highValue, boolean inclHighValue
) throws StringPoolException {
return xaResolverSession.findStringPoolRange(lowValue, inclLowValue, highValue, inclHighValue);
}
public Tuples findStringPoolType(
SPObject.TypeCategory typeCategory, URI typeURI
) throws StringPoolException {
return xaResolverSession.findStringPoolType(typeCategory, typeURI);
}
/**
* Finds a stringpool object based on the given node.
*
* @param gNode The node to find the stringppol object for
*
* @return The string equivalent of the given node
*
* @throws StringPoolException
*/
public SPObject findStringPoolObject(long gNode) throws StringPoolException {
return resolverSession.findStringPoolObject(gNode);
}
/**
* Retrieve the SPObject factory from the stringpool to allow for the creation
* of new SPObjects.
*
* @return The factory to allow for creation of SPObjects
*/
public SPObjectFactory getSPObjectFactory() {
return resolverSession.getSPObjectFactory();
}
public SPObject findSPObject(long gNode) throws StringPoolException {
return resolverSession.findSPObject(gNode);
}
public long findGNode(SPObject spObject) throws StringPoolException {
return resolverSession.findGNode(spObject);
}
/** @see org.mulgara.resolver.spi.BackupRestoreSession#getRestoreMapper() */
public LongMapper getRestoreMapper() throws Exception {
return resolverSession.getRestoreMapper();
}
//
// Internal methods
//
public void abort() {
try {
try {
statementStore.rollback();
} finally {
try {
xaResolverSession.rollback();
} finally {
try {
statementStore.release();
} finally {
xaResolverSession.release();
}
}
}
} catch (SimpleXAResourceException es) {
throw new IllegalStateException("Failed to Abort store", es);
}
}
/**
* @see org.mulgara.resolver.spi.SystemResolver#initializeSystemNodes(long, long, long)
*/
public void initializeSystemNodes(long systemGraphNode, long rdfTypeNode, long systemGraphTypeNode) throws StatementStoreException {
statementStore.initializeSystemNodes(systemGraphNode, rdfTypeNode, systemGraphTypeNode);
}
}