/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.access;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import org.fcrepo.common.Constants;
import org.fcrepo.server.Context;
import org.fcrepo.server.Module;
import org.fcrepo.server.access.defaultdisseminator.DefaultDisseminatorImpl;
import org.fcrepo.server.access.defaultdisseminator.ServiceMethodDispatcher;
import org.fcrepo.server.errors.GeneralException;
import org.fcrepo.server.errors.MethodNotFoundException;
import org.fcrepo.server.errors.ServerException;
import org.fcrepo.server.search.FieldSearchQuery;
import org.fcrepo.server.search.FieldSearchResult;
import org.fcrepo.server.storage.DOReader;
import org.fcrepo.server.storage.types.DatastreamDef;
import org.fcrepo.server.storage.types.MIMETypedStream;
import org.fcrepo.server.storage.types.MethodDef;
import org.fcrepo.server.storage.types.ObjectMethodsDef;
import org.fcrepo.server.storage.types.Property;
/**
* The implementation of the Dynamic Access module.
*
* <p>The Dynamic Access module will associate dynamic disseminators with a
* digital object. It will look to the Fedora repository configuration file
* to obtain a list of dynamic disseminators. Currently, the system supports
* two types of dynamic disseminators: - Default (SDefPID=fedora-system:3 and
* SDepPID=fedora-system:4) - Bootstrap (SDefPID=fedora-system:1 and
* SDepPID=fedora-system:2). The Default disseminator that is associated with
* every object in the repository. The Default Disseminator endows the objects
* with a set of basic generic behaviors that enable a simplistic view of the
* object contents (the Item Index) and a list of all disseminations available
* on the object (the Dissemination Index). The Bootstrap disseminator is
* associated with every Service Definition and Service Deployment object. It
* defines methods to get the special metadata datastreams out of them, and some
* other methods. (NOTE: The Bootstrap Disseminator functionality is NOT YET
* IMPLEMENTED.
*
* @author Sandy Payette
*/
public class DynamicAccessImpl {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final Access m_access;
private final ServiceMethodDispatcher dispatcher;
private File reposHomeDir = null;
private Hashtable<String, Class<?>> dynamicServiceToDeployment = null;
public DynamicAccessImpl(Access m_access,
File reposHomeDir,
Hashtable<String, Class<?>> dynamicSDefToDep) {
dispatcher = new ServiceMethodDispatcher();
this.m_access = m_access;
this.reposHomeDir = reposHomeDir;
this.dynamicServiceToDeployment = dynamicSDefToDep;
}
/**
* Get a list of Service Definition identifiers for dynamic disseminators
* associated with the digital object.
*
* @param context
* @param PID
* identifier of digital object being reflected upon
* @param asOfDateTime
* @return an array of Service Definition PIDs
* @throws ServerException
*/
public String[] getServiceDefinitions(Context context,
String PID,
Date asOfDateTime)
throws ServerException {
// FIXIT! In FUTURE this method might consult some source that tells
// what Service Definitions are appropriate to dynamically associate
// with the object. The rules for association might be based on the
// context or based on something about the particular object (PID).
// There is one rule that is always true - associate the Default
// Service Definition with EVERY object. For now we will just take the
// dynamic Service Definitions that were loaded by DynamicAccessModule.
// NOTE: AT THIS TIME THERE THERE IS JUST ONE LOADED, NAMELY,
// THE DEFAULT DISSEMINATOR SDEF (sDefPID = fedora-system:3)
ArrayList<String> sdefs = new ArrayList<String>();
Iterator<String> iter = dynamicServiceToDeployment.keySet().iterator();
while (iter.hasNext()) {
sdefs.add(iter.next());
}
return sdefs.toArray(EMPTY_STRING_ARRAY);
}
/**
* Get the method defintions for a given dynamic disseminator that
* is associated with the digital object. The dynamic disseminator is
* identified by the sDefPID.
*
* @param context
* @param PID
* identifier of digital object being reflected upon
* @param sDefPID
* identifier of dynamic Service Definition
* @param asOfDateTime
* @return an array of method definitions
* @throws ServerException
*/
public MethodDef[] getMethods(Context context,
String PID,
String sDefPID,
Date asOfDateTime)
throws ServerException {
Class<?> deploymentClass = dynamicServiceToDeployment.get(sDefPID);
if (deploymentClass != null) {
try {
Method method =
deploymentClass.getMethod("reflectMethods", (Class[]) null);
return (MethodDef[]) method.invoke(null, (Object[]) null);
} catch (Exception e) {
throw new GeneralException("[DynamicAccessImpl] returned error when "
+ "attempting to get dynamic method definitions. "
+ "The underlying error class was: "
+ e.getClass().getName()
+ ". The message "
+ "was \""
+ e.getMessage() + "\"");
}
}
throw new MethodNotFoundException("[DynamicAccessImpl] The object, "
+ PID + " does not have the dynamic Service Definition "
+ sDefPID);
}
/**
* Get an XML encoding of the service defintions for a given dynamic
* disseminator that is associated with the digital object. The dynamic
* disseminator is identified by the sDefPID.
*
* @param context
* @param PID
* identifier of digital object being reflected upon
* @param sDefPID
* identifier of dynamic Service Definition
* @param asOfDateTime
* @return MIME-typed stream containing XML-encoded method definitions
* @throws ServerException
*/
public MIMETypedStream getMethodsXML(Context context,
String PID,
String sDefPID,
Date asOfDateTime)
throws ServerException {
return null;
}
private String getReposBaseURL(String protocol, String port) {
String reposBaseURL = null;
String fedoraServerHost =
((Module) m_access).getServer()
.getParameter("fedoraServerHost");
reposBaseURL = protocol + "://" + fedoraServerHost + ":" + port;
return reposBaseURL;
}
/**
* Perform a dissemination for a method that belongs to a dynamic
* disseminator that is associate with the digital object. The method
* belongs to the dynamic Service Definition and is implemented by a
* dynamic Service Deployment (which is an internal service in the
* repository access subsystem).
*
* @param context
* @param PID
* identifier of the digital object being disseminated
* @param sDefPID
* identifier of dynamic Service Definition
* @param methodName
* @param userParms
* @param asOfDateTime
* @return a MIME-typed stream containing the dissemination result
* @throws ServerException
*/
public MIMETypedStream getDissemination(Context context,
String PID,
String sDefPID,
String methodName,
Property[] userParms,
Date asOfDateTime,
DOReader reader)
throws ServerException {
if (sDefPID.equalsIgnoreCase("fedora-system:3")) {
// FIXIT!! Use lookup to dynamicSDefToDep table to get class for
// DefaultDisseminatorImpl and construct via Java reflection.
String reposBaseURL =
getReposBaseURL(context
.getEnvironmentValue(Constants.HTTP_REQUEST.SECURITY.attributeId)
.equals(Constants.HTTP_REQUEST.SECURE.uri) ? "https"
: "http",
context
.getEnvironmentValue(Constants.HTTP_REQUEST.SERVER_PORT.attributeId));
Object result =
dispatcher
.invokeMethod(new DefaultDisseminatorImpl(context,
asOfDateTime,
reader,
m_access,
reposBaseURL,
reposHomeDir),
methodName,
userParms);
if (result
.getClass()
.getName()
.equalsIgnoreCase("org.fcrepo.server.storage.types.MIMETypedStream")) {
return (MIMETypedStream) result;
} else {
throw new GeneralException("[DynamicAccessImpl] returned error. "
+ "Internal service must return a MIME typed stream. "
+ "(see org.fcrepo.server.storage.types.MIMETypedStream)");
}
} else {
// FIXIT! (FUTURE) Open up the possibility of there being other
// kinds of dynamic behaviors. Use the sDefPID to locate the
// appropriate deployment for the dynamic behavior. In future
// we want the deployment for a dynamic service defintion to
// be able to be either an internal services, a local services,
// or a distributed service. We'll have to rework some things to
// be able to see what kind of deployment we have, and to do the
// request dispatching appropriately.
}
return null;
}
/**
* Get the definitions for all dynamic disseminations on the object. This
* will return the method definitions for all methods for all of the dynamic
* disseminators associated with the object.
*
* @param context
* @param PID
* identifier of digital object being reflected upon
* @param asOfDateTime
* @return an array of object method definitions
* @throws ServerException
*/
public ObjectMethodsDef[] listMethods(Context context,
String PID,
Date asOfDateTime)
throws ServerException {
String[] sDefPIDs = getServiceDefinitions(context, PID, asOfDateTime);
Date versDateTime = asOfDateTime;
ArrayList<ObjectMethodsDef> objectMethods =
new ArrayList<ObjectMethodsDef>();
for (String element : sDefPIDs) {
MethodDef[] methodDefs =
getMethods(context, PID, element, asOfDateTime);
for (MethodDef element2 : methodDefs) {
ObjectMethodsDef method = new ObjectMethodsDef();
method.PID = PID;
method.asOfDate = versDateTime;
method.sDefPID = element;
method.methodName = element2.methodName;
method.methodParmDefs = element2.methodParms;
objectMethods.add(method);
}
}
return objectMethods
.toArray(OBJ_METHOD_DEF_ARRAY_TYPE);
}
private static final ObjectMethodsDef[] OBJ_METHOD_DEF_ARRAY_TYPE =
new ObjectMethodsDef[0];
/**
* Get the profile information for the digital object. This contain key
* metadata and URLs for the Dissemination Index and Item Index of the
* object.
*
* @param context
* @param PID
* identifier of digital object being reflected upon
* @param asOfDateTime
* @return an object profile data structure
* @throws ServerException
*/
public ObjectProfile getObjectProfile(Context context,
String PID,
Date asOfDateTime)
throws ServerException {
// FIXIT! Return something here.
return null;
}
// FIXIT: What do these mean in this context...anything?
// Maybe these methods' exposure needs to be re-thought?
public FieldSearchResult findObjects(Context context,
String[] resultFields,
int maxResults,
FieldSearchQuery query)
throws ServerException {
return null;
}
// FIXIT: What do these mean in this context...anything?
// Maybe these methods' exposure needs to be re-thought?
public FieldSearchResult resumeFindObjects(Context context,
String sessionToken)
throws ServerException {
return null;
}
// FIXIT: What do these mean in this context...anything?
// Maybe these methods' exposure needs to be re-thought?
public RepositoryInfo describeRepository(Context context)
throws ServerException {
return null;
}
// FIXIT: What do these mean in this context...anything?
// Maybe these methods' exposure needs to be re-thought?
public String[] getObjectHistory(Context context, String PID)
throws ServerException {
return null;
}
public boolean isDynamicDeployment(Context context,
String PID,
String sDefPID)
throws ServerException {
if (dynamicServiceToDeployment.containsKey(sDefPID)) {
return true;
}
return false;
}
// FIXIT: What do these mean in this context...anything?
// Maybe these methods' exposure needs to be re-thought?
public MIMETypedStream getDatastreamDissemination(Context context,
String PID,
String dsID,
Date asOfDateTime)
throws ServerException {
return null;
}
public DatastreamDef[] listDatastreams(Context context,
String PID,
Date asOfDateTime)
throws ServerException {
return null;
}
}