[MOBY-guts] biomoby commit
Paul Gordon
gordonp at dev.open-bio.org
Wed Dec 6 16:07:10 UTC 2006
gordonp
Wed Dec 6 11:07:10 EST 2006
Update of /home/repository/moby/moby-live/Java/src/main/org/biomoby/service
In directory dev.open-bio.org:/tmp/cvs-serv24370/src/main/org/biomoby/service
Modified Files:
MobyServlet.java
Added Files:
Asynchronous.java
Log Message:
Major commit to allow automated construction of MobyServlet.war, and revised cvode for Java annotation-based service meta-data specification
moby-live/Java/src/main/org/biomoby/service Asynchronous.java,NONE,1.1 MobyServlet.java,1.2,1.3
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/org/biomoby/service/MobyServlet.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- /home/repository/moby/moby-live/Java/src/main/org/biomoby/service/MobyServlet.java 2006/11/22 22:23:55 1.2
+++ /home/repository/moby/moby-live/Java/src/main/org/biomoby/service/MobyServlet.java 2006/12/06 16:07:10 1.3
@@ -7,6 +7,9 @@
* the documentation on <a href="http://biomoby.open-bio.org/CVS_CONTENT/moby-live/Java/docs/deployingServices.html">how to use this servlet</a>.
*/
+import org.biomoby.service.test.TestServletConfig;
+import org.biomoby.service.test.TestServletContext;
+
import org.biomoby.shared.*;
import org.biomoby.shared.data.*;
import org.biomoby.shared.parser.*;
@@ -29,6 +32,13 @@
import java.util.StringTokenizer;
import java.util.Vector;
+ at mobyService(name="MobyServlet",
+ type="Testing",
+ provider="moby.ucalgary.ca",
+ author="gordonp at ucalgary.ca",
+ in={},
+ out={},
+ description={"No-operation base service implementation"})
public class MobyServlet extends HttpServlet implements Remote{
public static final String MOBY_CENTRAL_URL_PARAM = "mobyCentralURL";
@@ -37,6 +47,7 @@
public static final String MOBY_SERVICE_DESC_PARAM = "mobyServiceDescription";
public static final String MOBY_PROVIDER_URI_PARAM = "mobyProviderURI";
public static final String MOBY_SERVICETYPE_PARAM = "mobyServiceType";
+ public static final String MOBY_SERVICENAME_PARAM = "mobyServiceName";
public static final String MOBY_INPUT_PARAM = "mobyInput";
public static final String MOBY_SECONDARY_PARAM = "mobySecondaryInput";
public static final String MOBY_OUTPUT_PARAM = "mobyOutput";
@@ -45,8 +56,9 @@
public static final String ADMIN_MODE = "admin";
public static final int INIT_OUTPUT_BUFFER_SIZE = 100000;
+ private static boolean shouldExit = true;
+
protected static MobyRequest mobyRequest;
- protected static MobyService thisService;
protected static DocumentBuilder docBuilder;
// Members used to wrap the response in SOAP
@@ -57,18 +69,20 @@
protected final static String stringEncAttrValue = "xsd:string";
protected static Name faultName;
+ protected MobyService thisService;
protected MobyContentInstance currentContent = null;
protected boolean isInitialized = false;
/** Changing this value makes logging more or less verbose */
protected boolean isDebug = false;
- protected void doGet(HttpServletRequest request,
+ public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException{
if(thisService == null){
try{
thisService = createServiceFromConfig(request);
} catch(Exception e){
+ log("While attempting to configure service on first run:", e);
throw new ServletException("While attempting to configure service on first run: " + e);
}
}
@@ -183,10 +197,11 @@
*/
protected boolean validSOAPEndPoint(HttpServletRequest request,
HttpServletResponse response){
- String methodName = "http://biomoby.org/#"+getServletName();
+ String methodName = "http://biomoby.org/#"+getServiceName();
String qMethodName = "\""+methodName+"\"";
String requestedActionName = null;
boolean endPointMatches = false;
+ // TODO: This is where we should add code to deal with asynchronous calls
for(java.util.Enumeration actionsCalled = request.getHeaders("SOAPAction");
actionsCalled.hasMoreElements();){
@@ -223,7 +238,7 @@
return false;
} catch(Exception e){
- log("While writing SOAP fault response to client for " + getServletName(), e);
+ log("While writing SOAP fault response to client for " + getServiceName(), e);
return false;
}
}
@@ -377,7 +392,6 @@
// The SOAP envelope (headerless) consists of a body with one string element inside it
if(soapMessageFactory == null){
soapMessageFactory = MessageFactory.newInstance();
- log("SOAP Message Factory (when writeResponse is called) is " + soapMessageFactory);
}
SOAPMessage message = soapMessageFactory.createMessage();
message.getSOAPHeader().detachNode();
@@ -394,7 +408,7 @@
out.write(outBuffer.toByteArray());
} catch(Exception e){
- log("While writing SOAP response to client for " + getServletName(), e);
+ log("While writing SOAP response to client for " + getServiceName(), e);
return;
}
@@ -407,10 +421,10 @@
if(currentContent != null){
currentContent.addException(se);
if(isInitialized){
- log("While executing Moby Service " + getServletName(), se);
+ log("While executing Moby Service (initialized) " + getServiceName(), se);
}
- else{
- System.err.println("While executing Moby Service " + getClass().getName());
+ else if(thisService != null){
+ System.err.println("While executing Moby Service (uninitialized) " + getClass().getName());
se.printStackTrace();
}
}
@@ -437,10 +451,10 @@
ex.toString()));
}
if(isInitialized){
- log("While executing Moby Service " + getServletName(), ex);
+ log("While executing Moby Service (initialized) " + getServiceName(), ex);
}
- else{
- System.err.println("While executing Moby Service " + getClass().getName());
+ else if(thisService != null){
+ System.err.println("While executing Moby Service (uninitialized) " + getClass().getName());
ex.printStackTrace();
}
}
@@ -461,10 +475,10 @@
ex.toString()));
}
if(isInitialized){
- log("While executing Moby Service " + getServletName() + ", job '" + job.getID()+"'", ex);
+ log("While executing Moby Service (initialized) " + getServiceName() + ", job '" + job.getID()+"'", ex);
}
- else{
- System.err.println("While executing Moby Service " + getClass().getName() + ", job '" + job.getID()+"'");
+ else if(thisService != null){
+ System.err.println("While executing Moby Service (uninitialized) " + getClass().getName() + ", job '" + job.getID()+"'");
ex.printStackTrace();
}
}
@@ -492,17 +506,17 @@
"org.apache.axis.soap.MessageFactoryImpl");
}
soapMessageFactory = MessageFactory.newInstance(); // Should find Axis by default
- log("SOAP Message Factory (when init is called) is " + soapMessageFactory);
+ //log("SOAP Message Factory (when init is called) is " + soapMessageFactory);
- if(System.getProperty("javax.xml.soap.MessageFactory") == null){
+ if(System.getProperty("javax.xml.soap.SOAPFactory") == null){
System.setProperty("javax.xml.soap.SOAPFactory",
"org.apache.axis.soap.SOAPFactoryImpl");
}
SOAPFactory soapFactory = SOAPFactory.newInstance();
- bodyContentsName = soapFactory.createName(getServletName()+"Return",
+ bodyContentsName = soapFactory.createName(getServiceName()+"Return",
MobyPrefixResolver.MOBY_TRANSPORT_PREFIX,
MobyPrefixResolver.MOBY_TRANSPORT_NAMESPACE);
- bodyName = soapFactory.createName(getServletName()+"Response",
+ bodyName = soapFactory.createName(getServiceName()+"Response",
MobyPrefixResolver.MOBY_TRANSPORT_PREFIX,
MobyPrefixResolver.MOBY_TRANSPORT_NAMESPACE);
stringEncAttrName = soapFactory.createName("type",
@@ -531,46 +545,60 @@
isInitialized = true;
}
- private synchronized MobyService createServiceFromConfig(HttpServletRequest request) throws Exception{
- MobyService service = new MobyService(getServletName());
+ public synchronized MobyService createServiceFromConfig(HttpServletRequest request) throws Exception{
+ MobyService service = new MobyService(getServiceName());
Vector<MobyPrimaryData> inputTypes = new Vector<MobyPrimaryData>();
Vector<MobyPrimaryData> outputTypes = new Vector<MobyPrimaryData>();
- javax.servlet.ServletContext context = getServletContext();
+ mobyService ann =
+ this.getClass().getAnnotation(mobyService.class);
+ if(ann == null){
+ throw new Exception("The servlet does not have a @mobyService() class annotation as required, " +
+ "cannot configure the service");
+ }
+ else{
+ //log("Reading service meta-data from Java class annotation for "+ann.name());
+ }
+
+ javax.servlet.ServletConfig config = getServletConfig();
- java.util.Enumeration paramNamesEnum = context.getInitParameterNames();
String paramNames = "";
- if(paramNamesEnum.hasMoreElements()){
- paramNames = paramNamesEnum.nextElement().toString();
- }
- while(paramNamesEnum.hasMoreElements()){
- paramNames += ", "+paramNamesEnum.nextElement();
+ if(config != null){
+ java.util.Enumeration paramNamesEnum = config.getInitParameterNames();
+ if(paramNamesEnum.hasMoreElements()){
+ paramNames = paramNamesEnum.nextElement().toString();
+ }
+ while(paramNamesEnum.hasMoreElements()){
+ paramNames += ", "+paramNamesEnum.nextElement();
+ }
}
// Inputs and outputs and service type must be defined
- String ins = context.getInitParameter(MOBY_INPUT_PARAM);
+ String[] ins = ann.in();
+ if(config != null && config.getInitParameter(MOBY_INPUT_PARAM) != null){
+ ins = config.getInitParameter(MOBY_INPUT_PARAM).split(",");
+ }
if(ins == null){
throw new Exception("Could not find required " + MOBY_INPUT_PARAM +
- " parameter in servlet context, available parameters were: " + paramNames);
+ " parameter in servlet config, available parameters were: " + paramNames);
}
- StringTokenizer st = new StringTokenizer(ins, ",");
- while(st.hasMoreTokens()){
- String value = st.nextToken();
+ for(int i = 0; i < ins.length; i++){
// non-void param
- inputTypes.add(stringToPrimaryDataTemplate(value));
+ inputTypes.add(stringToPrimaryDataTemplate(ins[i]));
}
- String outs = context.getInitParameter(MOBY_OUTPUT_PARAM);
+ String[] outs = ann.out();
+ if(config != null && config.getInitParameter(MOBY_OUTPUT_PARAM) != null){
+ outs = config.getInitParameter(MOBY_OUTPUT_PARAM).split(",");
+ }
if(outs == null){
throw new Exception("Could not find required " + MOBY_OUTPUT_PARAM +
- " parameter in servlet context ");
+ " parameter in servlet config ");
}
- st = new StringTokenizer(outs, ",");
- while(st.hasMoreTokens()){
- String value = st.nextToken();
- if(value.length() > 0){// non-void param
- outputTypes.add(stringToPrimaryDataTemplate(value));
+ for(int i = 0; i < outs.length; i++){
+ if(outs[i] != null && outs[i].length() > 0){// non-void param
+ outputTypes.add(stringToPrimaryDataTemplate(outs[i]));
}
}
@@ -578,14 +606,18 @@
service.setOutputs(outputTypes.toArray(new MobyData[outputTypes.size()]));
// A description and provider URI must be available too
- String param = context.getInitParameter(MOBY_SERVICETYPE_PARAM);
+ String param = ann.type();
+ // Did we override the service type in the web.xml?
+ if(config != null && config.getInitParameter(MOBY_SERVICETYPE_PARAM) != null){
+ param = config.getInitParameter(MOBY_SERVICETYPE_PARAM);
+ }
if(param == null){
throw new Exception("Could not find required " + MOBY_SERVICETYPE_PARAM +
- " parameter in servlet context ");
+ " parameter in servlet config ");
}
if(param.length() == 0){
throw new Exception("Required " + MOBY_SERVICETYPE_PARAM +
- " parameter in servlet context cannot be blank");
+ " parameter in servlet config cannot be blank");
}
MobyServiceType serviceType = MobyServiceType.getServiceType(param);
if(serviceType == null){
@@ -594,80 +626,126 @@
}
service.setServiceType(serviceType);
- param = context.getInitParameter(MOBY_SERVICE_DESC_PARAM);
- if(param == null){
+ String[] desc = ann.description();
+ // Did we override the service type in the web.xml?
+ if(config != null && config.getInitParameter(MOBY_SERVICETYPE_PARAM) != null){
+ desc = new String[1];
+ desc[0] = config.getInitParameter(MOBY_SERVICETYPE_PARAM);
+ }
+ if(desc == null){
throw new Exception("Could not find required " + MOBY_SERVICE_DESC_PARAM +
- " parameter in servlet context ");
+ " parameter in servlet config ");
}
- if(param.length() == 0){
+ if(desc.length == 0){
throw new Exception("Required " + MOBY_SERVICE_DESC_PARAM +
- " parameter in servlet context cannot be blank");
+ " parameter in servlet config cannot be blank");
+ }
+ StringBuffer descBuffer = new StringBuffer();
+ for(int i = 0; i < desc.length; i++){
+ descBuffer.append(desc[i]);
+ }
+ service.setDescription(descBuffer.toString());
+
+ param = ann.provider();
+ // Did we override the provider info in web.xml?
+ if(config != null && config.getInitParameter(MOBY_PROVIDER_URI_PARAM) != null){
+ param = config.getInitParameter(MOBY_PROVIDER_URI_PARAM);
}
- service.setDescription(param);
-
- param = context.getInitParameter(MOBY_PROVIDER_URI_PARAM);
if(param == null){
throw new Exception("Could not find required " + MOBY_PROVIDER_URI_PARAM +
- " parameter in servlet context ");
+ " parameter in servlet config ");
}
if(param.length() == 0){
throw new Exception("Required " + MOBY_PROVIDER_URI_PARAM +
- " parameter in servlet context cannot be blank");
+ " parameter in servlet config cannot be blank");
}
service.setAuthority(param);
+
// Now we have all the info we need to create the LSID for the service
String time = MobyDataDateTime.getString(
new java.util.GregorianCalendar(
java.util.TimeZone.getTimeZone("Zulu"))).replaceAll(":", "-");
- service.setLSID("urn:lsid:biomoby.org:serviceinstance:"+param+","+getServletName()+":"+time);
+ service.setLSID("urn:lsid:biomoby.org:serviceinstance:"+param+","+getServiceName()+":"+time);
- param = context.getInitParameter(MOBY_CONTACT_PARAM);
+ param = ann.author();
+ // Did we override the contact info in web.xml?
+ if(config != null && config.getInitParameter(MOBY_CONTACT_PARAM) != null){
+ param = config.getInitParameter(MOBY_CONTACT_PARAM);
+ }
if(param == null){
throw new Exception("Could not find required " + MOBY_CONTACT_PARAM +
- " parameter in servlet context ");
+ " parameter in servlet config ");
}
if(param.length() == 0){
throw new Exception("Required " + MOBY_CONTACT_PARAM +
- " parameter in servlet context cannot be blank " +
+ " parameter in servlet config cannot be blank " +
"(must have form name at mail.domain)");
}
if(param.indexOf("@") < 2 || param.indexOf("@") > param.length()-2 ||
param.indexOf(".") < 2 || param.indexOf(".") > param.length()-2 ||
param.lastIndexOf("@") > param.lastIndexOf(".")){
throw new Exception("Required " + MOBY_CONTACT_PARAM +
- " parameter in servlet context did not have the form \"name at mail.domain\")");
+ " parameter in servlet config did not have the form \"name at mail.domain\")");
}
service.setEmailContact(param);
// From the request, determine the URL used to access this service
- String endPointURL = HttpUtils.getRequestURL(request).toString();
+ String endPointURL = request == null ? "" : request.getRequestURL().toString();
// When we POST this URL, the service is executed
service.setURL(endPointURL);
// When we GET this URL, the RDF is returned
service.setSignatureURL(endPointURL+"?"+MODE_HTTP_PARAM+"="+RDF_MODE);
// Other fields (authoritative and contact info) are highly recommended, but optional
- param = context.getInitParameter(MOBY_AUTHORITATIVE_PARAM);
- if(param != null){
- if("YES".equals(param.toUpperCase()) || "Y".equals(param.toUpperCase()) || "1".equals(param)){
- service.setAuthoritative(true);
+ if(config != null){
+ param = config.getInitParameter(MOBY_AUTHORITATIVE_PARAM);
+ if(param != null){
+ if("YES".equals(param.toUpperCase()) || "Y".equals(param.toUpperCase()) || "1".equals(param)){
+ service.setAuthoritative(true);
+ }
+ else{
+ log("Interpreting config parameter '" + param + "' as NO for authoritative property of the service");
+ service.setAuthoritative(false);
+ }
}
else{
- log("Interpreting config parameter '" + param + "' as NO for authoritative property of the service");
- service.setAuthoritative(false);
+ service.setAuthoritative(ann.authoritative());
}
}
else{
- service.setAuthoritative(false);
+ service.setAuthoritative(ann.authoritative());
}
-
mobyRequest.setService(service);
return service;
}
/**
+ * Reads the service name from the mobyService annotation.
+ */
+ public String getServiceName(){
+ mobyService ann =
+ this.getClass().getAnnotation(mobyService.class);
+
+ javax.servlet.ServletConfig config = getServletConfig();
+ String param = null;
+ // Did we override the service type in the web.xml?
+ if(config != null && config.getInitParameter(MOBY_SERVICENAME_PARAM) != null){
+ param = config.getInitParameter(MOBY_SERVICENAME_PARAM);
+ if(param != null && param.length() != 0){
+ return param;
+ }
+ }
+
+ if(ann == null){
+ return "AnonymousService"; // this should never happen unless the class files are out of sync...
+ }
+
+ return ann.name();
+ }
+
+ /**
* Strings have the form name:objectType:namespace, with ":namespace" optional
* If the input is expected to be a Collection, then the syntax is name:Collection(objectType):namespace
*/
@@ -694,10 +772,12 @@
MobyPrimaryData dataTemplate = null;
+ boolean isCollection = false;
if(objectType.indexOf("Collection(") == 0 &&
objectType.lastIndexOf(")") == objectType.length()-1){
objectType = objectType.substring(11, objectType.length()-1);
dataTemplate = new MobyPrimaryDataSet(name);
+ isCollection = true;
}
else{
dataTemplate = new MobyPrimaryDataSimple(name);
@@ -712,6 +792,12 @@
System.exit(1);
}
dataTemplate.setDataType(type);
+ if(isCollection){
+ // Example data element in set needed for RDF creator to recognize the data type
+ MobyPrimaryDataSimple exampleData = new MobyPrimaryDataSimple(name);
+ exampleData.setDataType(type);
+ ((MobyPrimaryDataSet) dataTemplate).addElement(exampleData);
+ }
// namespace is optional
if(st.hasMoreTokens()){
@@ -763,7 +849,13 @@
// Should happen, unless main() was called
validateArguments(currentRequest, thisService, "While executing service");
}
- processRequest(currentRequest, resultContents.get(jobName));
+ MobyDataJob currentResult = resultContents.get(jobName);
+ if(currentResult == null){
+ currentResult = new MobyDataJob();
+ currentResult.setID(jobName);
+ resultContents.put(jobName, currentResult);
+ }
+ processRequest(currentRequest, currentResult);
}catch(Throwable e){
addException(resultContents, requestContents.get(jobName), e);
}
@@ -787,6 +879,15 @@
}
/**
+ * Determines whether call to main() that terminate on error should call System.exit()
+ * or not. This is the default behaviour, and should generally be switched only for unit testing
+ * purposes.
+ */
+ public static void setMainTerminationExit(boolean b){
+ shouldExit = b;
+ }
+
+ /**
* Expects one argument, an example MOBY XML input file or URL.
* processRequest() is then called for every job in the input data,
* and the results are printed to the screen.
@@ -794,9 +895,10 @@
public static void main(String[] args) throws Exception{
if(args.length != 2){
- System.err.println("MobyServlet is ignoring the main method, executing the subclass's main method.");
+ System.err.println("MobyServlet is ignoring the main method (called with " + args.length + " args) " +
+ ", executing the subclass's main method.");
System.err.println("If you wish to run the Servlet test, the usage is: ");
- System.err.println("java ServletName ServetName <mobyInputExample.xml | mobyExampleURL>");
+ System.err.println("java ServletName SerlvetName <mobyInputExample.xml | mobyExampleURL>");
return;
}
@@ -837,30 +939,45 @@
} catch(Exception e){
System.err.println("The test data was invalid:");
e.printStackTrace();
- System.exit(2);
+ if(shouldExit)
+ System.exit(2);
+ else
+ throw e;
}
// TO DO: Should we validate the input somehow?
// They'll find out when they run the servlet tests later, but the earlier the better...
MobyContentInstance testResults = new MobyContentInstance();
- // Create as many output slots (blank) as there were input slots
- // According to the MOBY spec, there must be a 1:1 relationship here
- for(String jobName : testData.keySet()){
- MobyDataJob result = new MobyDataJob();
- result.setID(jobName);
- testResults.put(jobName, result);
- }
-
+ // Configure the service, minimally, to check the input data
+ servlet.init(new TestServletConfig(args[0], new TestServletContext()));
+ servlet.thisService = servlet.createServiceFromConfig(null);
+
// It should populate the testResults
try{
servlet.processRequests(testData, testResults);
} catch(Exception e){
System.err.println("An error occured while testing your code's processRequest method:");
e.printStackTrace();
- }
+ if(shouldExit){
+ System.exit(2);
+ }
+ else{
+ throw e;
+ }
+ }
- System.out.println(testResults.toString());
- System.exit(0); //so that subclasses's main methods don;t executed if the test was run
+ if(testResults.hasExceptions(ServiceException.WARNING)){
+ for(ServiceException se: testResults.getExceptions()){
+ se.printStackTrace();
+ }
+ throw new Exception("Executing service " + args[0] + " cause exceptions");
+ }
+ else{
+ System.out.println(testResults.toString());
+ }
+ if(shouldExit){
+ System.exit(0); //so that subclasses's main methods don't executed if the test was run
+ }
}
}
More information about the MOBY-guts
mailing list