/*
* 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
* Northrop Grumman Corporation. All Rights Reserved.
*
* This file is an original work and contains no Original Code. It was
* developed by Netymon Pty Ltd under contract to the Australian
* Commonwealth Government, Defense Science and Technology Organisation
* under contract #4500507038 and is contributed back to the Kowari/Mulgara
* Project as per clauses 4.1.3 and 4.1.4 of the above contract.
*
* Contributor(s): N/A.
*
* Copyright:
* The copyright on this file is held by:
* The Australian Commonwealth Government
* Department of Defense
* Developed by Netymon Pty Ltd
* Copyright (C) 2006
* The Australian Commonwealth Government
* Department of Defense
*
* [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.relational;
// Java 2 standard packages
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.transaction.xa.XAResource;
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.URIReference;
import org.jrdf.graph.Node;
// Locally written packages
import org.mulgara.query.Constraint;
import org.mulgara.query.ConstraintElement;
import org.mulgara.query.LocalNode;
import org.mulgara.query.QueryException;
import org.mulgara.query.TuplesException;
import org.mulgara.query.Variable;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.relational.d2rq.Definition;
import org.mulgara.resolver.spi.DummyXAResource;
import org.mulgara.resolver.spi.GlobalizeException;
import org.mulgara.resolver.spi.LocalizeException;
import org.mulgara.resolver.spi.EmptyResolution;
import org.mulgara.resolver.spi.Resolution;
import org.mulgara.resolver.spi.Resolver;
import org.mulgara.resolver.spi.ResolverFactoryException;
import org.mulgara.resolver.spi.ResolverException;
import org.mulgara.resolver.spi.ResolverSession;
import org.mulgara.resolver.spi.Statements;
/**
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class RelationalResolver implements Resolver {
/** Logger */
private static final Logger logger = Logger.getLogger(RelationalResolver.class);
/** System model's type URI */
private URI systemModelTypeURI;
/** URI representing the file system model's type */
private URI modelTypeURI;
/** Node ID for the rdf:type node */
private long rdfType;
/** The system model's resolver */
private Resolver systemResolver;
/** Resolver session for node resolution */
private ResolverSession resolverSession;
/**
* Constructor.
*
* @param resolverSession The session in which the resolver exists
* @param systemResolver The resolver used for the system model
* @param rdfType The rdf:type predicate
* @param systemModel The system model node id
* @param systemModelType The system model's type node id
* @param modelTypeURI The URI representing the file system's model type
*
* @throws ResolverFactoryException
*/
RelationalResolver(ResolverSession resolverSession, Resolver systemResolver,
long rdfType, long systemModel, long systemModelType,
URI modelTypeURI, long relationalTypeNode)
throws ResolverFactoryException {
if (modelTypeURI == null) {
throw new IllegalArgumentException("Graph type can't be null");
}
// Store the global variable values
this.systemResolver = systemResolver;
this.modelTypeURI = modelTypeURI;
this.rdfType = rdfType;
this.resolverSession = resolverSession;
try {
Node systemModelTypeNode = resolverSession.globalize(systemModelType);
if (systemModelTypeNode instanceof URIReference) {
this.systemModelTypeURI = ((URIReference)systemModelTypeNode).getURI();
} else {
throw new ResolverFactoryException("SystemModelType is not a URI: " + systemModelTypeNode);
}
} catch (GlobalizeException eg) {
throw new ResolverFactoryException("Error globalizing SystemModelTypeURI", eg);
}
}
public XAResource getXAResource() {
return new DummyXAResource(10);
}
/**
* model of type modelTypeURI is already created by wrapper, so we just need to create the
* definition model.
*/
public void createModel(long model, URI modelTypeURI) throws
ResolverException, LocalizeException {
if (logger.isDebugEnabled()) {
logger.debug("Create Relational model " + model + " of type " + modelTypeURI);
}
// Validate the "modelTypeURI" parameter
if (!modelTypeURI.equals(this.modelTypeURI)) {
throw new ResolverException(
"Can't create " + model + " of type " + modelTypeURI +
", which was never registered by " + getClass());
}
// Obtain the node representing the ?def URI of the model
URIReference defNode = new URIReferenceImpl(definitionURI(model));
long defModel = 0;
try {
// Localise the definition node
defModel = resolverSession.localizePersistent(defNode);
} catch (LocalizeException localiseException) {
throw new ResolverException("Error localizing relational definition model", localiseException);
}
systemResolver.createModel(defModel, systemModelTypeURI);
}
/**
* Remove the model.
*/
public void removeModel(long model) throws ResolverException {
if (logger.isDebugEnabled()) {
logger.debug("Remove Relational model " + model);
}
// Container for the definition model node id
long defModel = 0;
try {
// Obtain the node id of the definition model
defModel = resolverSession.lookupPersistent(new URIReferenceImpl(definitionURI(model)));
} catch (LocalizeException localiseException) {
throw new ResolverException("Error localizing uri when removing " +
"file system definition model",
localiseException);
}
// Remove the definition model
systemResolver.removeModel(defModel);
}
/**
* We do not support modification of the underlying relational model.
* Definition model can be modified directly.
*
* @throws ResolverException
*/
public void modifyModel(long model, Statements statements, boolean occurs)
throws ResolverException {
throw new ResolverException("Relational models are read-only");
}
/**
* Resolve a constraint against a model on the Java heap.
*
* @param constraint The constraint to resolve against the model
*
* @return The resolution of our constraint against the model
*
* @throws QueryException
*/
public Resolution resolve(Constraint constraint) throws QueryException {
if (logger.isDebugEnabled()) {
logger.debug("!! Resolve " + constraint);
}
if (!(constraint instanceof RelationalConstraint)) {
if (constraint.getModel() instanceof Variable) return new EmptyResolution(constraint, false);
throw new QueryException("Relational Resolver unable to resolve constraint: " + constraint);
}
// Obtain the model of the constraint
ConstraintElement modelElem = constraint.getModel();
// Verify our model node is a local node
if (!(modelElem instanceof LocalNode)) {
if (logger.isDebugEnabled()) logger.debug("Ignoring non-local model in constraint " + constraint);
return new EmptyResolution(constraint, false);
}
// Get the model id for the node
long model = ((LocalNode)modelElem).getValue();
// Container for our definition model node id
long defModel = 0;
try {
// Obtain the definition mode node id
defModel = resolverSession.lookupPersistent(new URIReferenceImpl(
definitionURI(model)));
} catch (LocalizeException localiseException) {
throw new QueryException("Graph " + model +
" did not exist in Relational" +
" expansion", localiseException);
} catch (ResolverException resolverException) {
throw new QueryException("Failed to find Relational definition node id",
resolverException.getCause());
}
return resolveRelationalConstraint(defModel, (RelationalConstraint)constraint);
}
private Resolution resolveRelationalConstraint(long defModel, RelationalConstraint constraint)
throws QueryException {
Definition defn;
defn = new Definition(systemResolver, resolverSession, rdfType, defModel);
try {
RelationalResolution r = new RelationalResolution(constraint, defn, resolverSession);
return r;
} catch (TuplesException et) {
throw new QueryException("Error creating resolution", et);
}
}
public static String parseTableFromColumn(String column) {
String result = column.substring(0, column.indexOf('.'));
return result;
}
public static Set<String> extractTablesFromJoin(String join) {
Pattern p = Pattern.compile("\\w+\\.\\w+");
Matcher m = p.matcher(join);
Set<String> result = new HashSet<String>();
while (m.find()) {
result.add(parseTableFromColumn(m.group()));
}
return result;
}
private URI definitionURI(long model) throws ResolverException {
try {
Node modelNode = resolverSession.globalize(model);
if (modelNode instanceof URIReference) {
return definitionURI(((URIReference)modelNode).getURI());
} else {
throw new ResolverException("model is not URI: " + modelNode);
}
} catch (GlobalizeException eg) {
throw new ResolverException("Failed to globalize model", eg);
}
}
private URI definitionURI(URI modelURI) throws ResolverException {
try {
URI defURI = new URI(modelURI.getScheme(),
modelURI.getAuthority(),
modelURI.getPath(),
"def",
modelURI.getFragment());
return defURI;
} catch (URISyntaxException eu) {
throw new ResolverException("Invalid URI", eu);
}
}
public void abort() {
// We need to clear the JDBC connections here, but we don't have a handle on
// the Resolutions.
}
}