/*
* Copyright 2008 Fedora Commons, Inc.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mulgara.resolver.distributed;
// Java 2 standard packages
import java.net.URI;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
// Third party packages
import org.apache.log4j.Logger;
// 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.resolver.spi.Resolution;
import org.mulgara.resolver.spi.Resolver;
import org.mulgara.resolver.spi.ResolverException;
import org.mulgara.resolver.spi.ResolverFactory;
import org.mulgara.resolver.spi.ResolverFactoryException;
import org.mulgara.resolver.spi.ResolverSession;
import org.mulgara.resolver.spi.Statements;
/**
* Resolves constraints accessible through a session.
*
* @created 2007-03-20
* @author <a href="mailto:pgearon@users.sourceforge.net">Paula Gearon</a>
* @copyright © 2007 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
*/
public class DistributedResolver implements Resolver, TransactionCoordinator {
/** Logger. */
private static final Logger logger = Logger.getLogger(DistributedResolver.class);
/** The delegator that resolves the constraint on another server. */
private final Delegator delegator;
/** our xa-resource */
private final DistributedXAResource xares;
/**
* Construct a Distributed Resolver.
* @param resolverSession the session this resolver is associated with.
* @param resolverFactory the factory this resolver is associated with.
* @param canWrite whether the current transaction is read-only or r/w
* @param sessionCache the session cache to use
* @throws IllegalArgumentException if <var>resolverSession</var> is <code>null</code>
* @throws ResolverFactoryException if the superclass is unable to handle its arguments
*/
DistributedResolver(ResolverSession resolverSession, ResolverFactory resolverFactory,
boolean canWrite, SessionCache sessionCache) throws ResolverFactoryException {
if (logger.isDebugEnabled()) logger.debug("Instantiating a distributed resolver");
// Validate "resolverSession" parameter
if (resolverSession == null) throw new IllegalArgumentException( "Null \"resolverSession\" parameter");
delegator = new NetworkDelegator(resolverSession, canWrite, this, sessionCache);
xares = new DistributedXAResource(10, resolverFactory, delegator);
}
/**
* Graph creation method. Not supported in this resolver.
* @throws ResolverException The server should not ask this resolver to create a model.
*/
public void createModel(long model, URI modelType) throws ResolverException {
throw new ResolverException("Requesting model creation from a distributed resolver.");
}
/**
* Expose a callback object for enlistment by a transaction manager.
*
* @return an {@link XAResource} that can be used by a transaction manager to
* coordinate this resolver's participation in a distributed transaction.
* @see javax.resource.spi.ManagedConnection#getXAResource
*/
public XAResource getXAResource() {
return xares;
}
/**
* Insert or delete RDF statements in an existing model.
* This is illegal for this model type.
*
* @param model the local node identifying an existing model
* @param statements the {@link Statements} to insert into the
* <var>model</var>
* @param occurs whether to assert the <var>statements</var>, or (if
* <code>false</code>) to deny it
* @throws ResolverException The server should not ask this resolver to modify data.
*/
public void modifyModel(long model, Statements statements, boolean occurs) throws ResolverException {
if (logger.isDebugEnabled()) logger.debug(occurs ? "Adding" : "Removing" + " statements from model");
try {
if (occurs) delegator.add(model, statements);
else delegator.remove(model, statements);
} catch (QueryException qe) {
throw new ResolverException("Error modifying model", qe);
}
}
/**
* Remove the cached model containing the contents of a URL.
* @throws ResolverException The server should not ask this resolver to modify data.
*/
public void removeModel(long model) throws ResolverException {
throw new ResolverException("Distributed models cannot be removed");
}
/**
* Resolve a constraint against an RDF/XML document.
* @param constraint The constraint pattern to be resolved.
* @return A resolution for the constraint against a model.
* @throws IllegalArgumentException The constraint is <code>null</code>, or not set to a non-local model.
* @throws QueryException There was a problem resolving the constraint.
*/
public Resolution resolve(Constraint constraint) throws QueryException {
if (logger.isDebugEnabled()) logger.debug("Resolve " + constraint);
// validate the parameter
if (constraint == null) throw new IllegalArgumentException();
ConstraintElement modelElement = constraint.getElement(3);
if (!(modelElement instanceof LocalNode)) throw new QueryException("Constraint not set to a distributed model.");
try {
return delegator.resolve(constraint, (LocalNode)modelElement);
} catch (ResolverException re) {
throw new QueryException(re.getMessage(), re);
}
}
public void abort() {
delegator.close();
}
public void enlistResource(XAResource xares) throws XAException {
this.xares.enlistResource(xares);
}
/**
* An XAResource which encapsulates and delegates to the all the remote XAResource's.
*
* <p>Note that this can never be really correct because it's basically impossible to get
* the <var>isSameRM</var> semantics correct when proxying multiple XAResource's.
*/
private static class DistributedXAResource extends MultiXAResource {
private final Delegator delegator;
/**
* Construct a {@link DistributedXAResource} with a specified transaction timeout.
*
* @param transactionTimeout transaction timeout period, in seconds
* @param resolverFactory the resolver-factory we belong to
* @param delegator the delegator being used
*/
public DistributedXAResource(int transactionTimeout, ResolverFactory resolverFactory,
Delegator delegator) {
super(transactionTimeout, resolverFactory);
this.delegator = delegator;
}
protected DistributedTxInfo newTransactionInfo() {
DistributedTxInfo txInfo = new DistributedTxInfo();
txInfo.delegator = delegator;
return txInfo;
}
protected void transactionCompleted(MultiXAResource.MultiTxInfo tx) {
try {
((DistributedTxInfo) tx).delegator.close();
} finally {
super.transactionCompleted(tx);
}
}
static class DistributedTxInfo extends MultiXAResource.MultiTxInfo {
public Delegator delegator;
}
}
}