/*
* 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):
* getModel() contributed by Netymon Pty Ltd on behalf of
* The Australian Commonwealth Government under contract 4500507038.
*
* [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.url;
// Java 2 standard packages
import java.io.*;
import java.net.*;
import java.util.*;
import javax.transaction.xa.XAResource;
// Third party packages
import com.hp.hpl.jena.rdf.arp.ARP;
import org.apache.log4j.Logger;
import org.jrdf.graph.BlankNode;
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.tuples.LiteralTuples;
/**
* Resolves constraints in models defined by static RDF documents.
*
* @created 2004-04-01
*
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
*
* @version $Revision: 1.10 $
*
* @modified $Date: 2005/05/02 20:07:59 $
*
* @maintenanceAuthor $Author: raboczi $
*
* @company <a href="mailto:info@PIsoftware.com">Plugged In Software</a>
*
* @copyright © 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 URLResolver implements Resolver {
/**
* Logger.
*/
private static final Logger logger = Logger.getLogger(URLResolver.class.getName());
/**
* The session that this resolver is associated with.
*/
private final ResolverSession resolverSession;
/**
* Map from the {@link URIReference} of each document ever parsed by this
* resolver to a {@link Map} from {@link ARP}'s {@link String}-valued blank
* node IDs to {@link BlankNode} instances.
*/
private final Map<URIReference,Map<String,BlankNode>> documentMap = new HashMap<URIReference,Map<String,BlankNode>>();
//
// Constructors
//
/**
* Construct a resolver.
*
* @param resolverSession the session this resolver is associated with
* @throws IllegalArgumentException if <var>resolverSession</var> is
* <code>null</code>
*/
URLResolver(ResolverSession resolverSession, Resolver systemResolver) {
// Validate parameters
if (resolverSession == null) {
throw new IllegalArgumentException("Null 'resolverSession' parameter");
}
if (systemResolver == null) {
throw new IllegalArgumentException("Null 'systemResolver' parameter");
}
// Initialize fields
this.resolverSession = resolverSession;
}
//
// Methods implementing Resolver
//
/**
* Create a model by treating the <var>model</var> as the {@link URL} of an
* RDF document and downloading it into the database.
*
* @param model {@inheritDoc}. In this case, it should be the {@link URL} of
* an RDF/XML document.
* @param modelTypeURI {@inheritDoc}. This field is ignored, because URL models
* are external.
*/
public void createModel(long model, URI modelTypeURI) throws ResolverException {
if (logger.isDebugEnabled()) logger.debug("Create URL model " + model);
// Globalize the model
URIReference modelURIReference;
try {
Node globalModel = resolverSession.globalize(model);
if (!(globalModel instanceof URIReference)) {
throw new ResolverException(
"Graph parameter " + globalModel + " isn't a URI reference");
}
modelURIReference = (URIReference) globalModel;
} catch (GlobalizeException e) {
throw new ResolverException("Couldn't globalize model", e);
}
assert modelURIReference != null;
// Create the new model
try {
URL url = modelURIReference.getURI().toURL();
// Open an output stream to the model URL
OutputStream outputStream;
if ("file".equals(url.getProtocol())) {
// The default file: URL protocol handler doesn't support output, so
// we bypass it here
// Make sure it's a file local to the server
if (url.getAuthority() != null) {
throw new ResolverException(
"Can't access filesystem on " + url.getAuthority());
}
// Open a stream out to the file
outputStream = new FileOutputStream(new File(url.getPath()));
} else {
// Otherwise, we trust that the Java environment has an appropriate URL
// protocol handler, and hope furthermore that it supports output
outputStream = url.openConnection().getOutputStream();
}
assert outputStream != null;
// Write the RDF/XML serialization of an empty model out
try {
PrintWriter writer =
new PrintWriter(new OutputStreamWriter(outputStream));
writer.println("This should be the content of " + modelURIReference);
writer.flush();
} finally {
outputStream.close();
}
} catch (IOException e) {
throw new ResolverException("Can't create RDF document from " + model, e);
}
}
/**
* @return a {@link DummyXAResource} with a 10 second transaction timeout
*/
public XAResource getXAResource() {
return new DummyXAResource(10); // seconds before transaction timeout
}
/**
* Insert or delete RDF statements in a model at a URL.
*/
public void modifyModel(long model, Statements statements, boolean occurs) throws ResolverException {
if (logger.isDebugEnabled()) logger.debug("Modify URL model " + model);
throw new ResolverException("Modification of URLs not implemented");
/*
logger.error("Choosing an arbitrary scratch model node");
long scratchModel = 47;
systemResolver.createModel(scratchModel, scratchModelTypeURI);
try {
// Load the contents of the destination model into the scratch model
systemResolver.modifyModel(scratchModel, null, true);
// Insert/delete the elements of the tripleSet from the scratch model
systemResolver.modifyModel(scratchModel, null, occurs);
// Overwrite the destination model with the contents of the scratch model
} finally {
// Drop the scratch model
systemResolver.removeModel(scratchModel);
}
*/
}
/**
* Remove the cached model containing the contents of a URL.
*/
public void removeModel(long model) throws ResolverException {
if (logger.isDebugEnabled()) logger.debug("Remove URL model " + model);
// Globalize the model
URIReference modelURIReference;
try {
Node globalModel = resolverSession.globalize(model);
if (!(globalModel instanceof URIReference)) {
throw new ResolverException(
"Graph parameter " + globalModel + " isn't a URI reference");
}
modelURIReference = (URIReference) globalModel;
} catch (GlobalizeException e) {
throw new ResolverException("Couldn't globalize model", e);
}
assert modelURIReference != null;
// Remove the model
try {
URL url = modelURIReference.getURI().toURL();
// Java's URL class lacks any facility for removing resources at a URL,
// so we have to handle removal on a protocol-by-protocol basis
if ("file".equals(url.getProtocol())) {
// Make sure it's a file local to the server
if (url.getAuthority() != null) {
throw new ResolverException(
"Can't access filesystem on " + url.getAuthority());
}
// Remove the file
if (!(new File(url.getPath()).delete())) {
logger.warn("Tried to delete nonexistent " + url + " -- ignoring");
}
} else {
// This is a URL protocol for which we have no specific code
throw new ResolverException(
"Can't remove " + url + ": " + url.getProtocol() +
" protocol not supported");
}
} catch (IOException e) {
throw new ResolverException("Can't remove RDF document from " + modelURIReference, e);
}
}
/**
* Resolve a constraint against an RDF/XML document.
*
* Resolution is by filtration of a URL stream, and thus very slow.
*/
public Resolution resolve(Constraint constraint) throws QueryException {
if (logger.isDebugEnabled()) logger.debug("Resolve " + constraint);
// Validate parameters
if (constraint == null) {
throw new IllegalArgumentException("constraint null");
} else if (!(constraint.getModel() instanceof LocalNode)) {
throw new QueryException("Constraint model can't be variable");
}
// Convert the constraint's model to a URI reference
URIReference modelURIReference;
try {
Node node = resolverSession.globalize(((LocalNode) constraint.getElement(3)).getValue());
if (!(node instanceof URIReference)) {
throw new QueryException("Constraint model " + node + " isn't a URI reference");
}
modelURIReference = (URIReference) node;
} catch (GlobalizeException e) {
throw new QueryException("Couldn't globalize model for " + constraint, e);
}
assert modelURIReference != null;
// Return the statements in the document at the model URL
try {
// Find or create the blank node map for this document
Map<String,BlankNode> blankNodeMap = documentMap.get(modelURIReference);
if (blankNodeMap == null) {
blankNodeMap = new HashMap<String,BlankNode>();
documentMap.put(modelURIReference, blankNodeMap);
}
assert blankNodeMap != null;
assert documentMap.get(modelURIReference) == blankNodeMap;
// Generate the resolution
return new StatementsWrapperResolution(
constraint,
new URLStatements(modelURIReference.getURI().toURL(), resolverSession, blankNodeMap),
true // a definitive and complete resolution
);
} catch (MalformedURLException e) {
// This isn't really a document, so return no statements
Variable[] variables = new Variable[] {new Variable("subject"),
new Variable("predicate"),
new Variable("object")};
try {
return new StatementsWrapperResolution(
constraint,
new TuplesWrapperStatements(new LiteralTuples(variables),
variables[0],
variables[1],
variables[2]),
false // not a definitive resolution
);
}
catch (TuplesException e2) {
throw new QueryException("Couldn't generate empty resolution", e2);
}
} catch (TuplesException e) {
throw new QueryException("Couldn't read URL " + modelURIReference, e);
}
}
public void abort() {}
}