[MOBY-guts] biomoby commit

Paul Gordon gordonp at dev.open-bio.org
Thu Feb 7 20:03:27 UTC 2008


gordonp
Thu Feb  7 15:03:26 EST 2008
Update of /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util
In directory dev.open-bio.org:/tmp/cvs-serv8915/src/main/ca/ucalgary/services/util

Modified Files:
	XHTMLForm.java 
Log Message:
Version of XHTMLForm and unit tests that pass parsing, meta-data and logic tests
moby-live/Java/src/main/ca/ucalgary/services/util XHTMLForm.java,1.2,1.3
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/XHTMLForm.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/XHTMLForm.java	2008/02/06 16:00:57	1.2
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/services/util/XHTMLForm.java	2008/02/07 20:03:26	1.3
@@ -34,7 +34,7 @@
     private Map<String,String> serviceDescs;
     private Map<String,String> providerURIs;
     private Map<String,String> centralEndpoints;
-    private Map<String,String> contactEmails;
+    private String contactEmail;
 
     private Map<String,Map<String,String>> serviceInputs;
     private Map<String,Map<String,String>> serviceSecondaries;
@@ -65,7 +65,7 @@
 
     private final String MOBY_PREFIX_PLACEHOLDER = "%MOBYPREFIX%";
 
-    private final String META_AUTHOR_XPATH = "/xhtml:html/xhtml:head/xhtml:meta[@name = \""+MOBY_PREFIX_PLACEHOLDER+":author\"]";
+    private final String META_CONTACT_XPATH = "/xhtml:html/xhtml:head/xhtml:meta[@name = \""+MOBY_PREFIX_PLACEHOLDER+":contact\"]";
     private final String META_SERVICE_XPATH = "/xhtml:html/xhtml:head/xhtml:meta[@name = \""+MOBY_PREFIX_PLACEHOLDER+":service\"]";
     private final String SERVICE_SCHEME_ATTR = "scheme";
     private final String SERVICE_SPEC_ATTR = "content";
@@ -107,7 +107,6 @@
 	serviceDescs = new HashMap<String,String>();
 	providerURIs = new HashMap<String,String>();
 	centralEndpoints = new HashMap<String,String>();
-	contactEmails = new HashMap<String,String>();
 	fixedParams = new HashMap<String,Map<String,String>>();
 	serviceInputs  = new HashMap<String,Map<String,String>>();
 	serviceSecondaries = new HashMap<String,Map<String,String>>();
@@ -150,12 +149,46 @@
 		
     }
 
-    protected List<String> parseMetaData(String mobyPrefix) throws Exception{
-	// Find the author info (email contact, or md5 hash of an address for privacy reasons)
-	String authorInfo = xPath.evaluate(META_AUTHOR_XPATH.replaceAll(MOBY_PREFIX_PLACEHOLDER, mobyPrefix), 
-					   xhtmlDoc);
+    protected String parseAuthorData(String mobyPrefix) throws Exception{
+	String contactXPathString = META_CONTACT_XPATH.replaceAll(MOBY_PREFIX_PLACEHOLDER, mobyPrefix);
 
+	// Find the contact info (email contact, or md5 hash of an address for privacy reasons)
+	NodeList contactTags = (NodeList) xPath.evaluate(contactXPathString,
+							 xhtmlDoc,
+							 XPathConstants.NODESET);
+	if(contactTags.getLength() == 0){
+	    throw new Exception("Could not find any service author tags of the required form '" + 
+				contactXPathString + "'");
+	}
+	if(contactTags.getLength() > 1){
+	    throw new Exception("Found multiple (hence ambiguous) service author tags of the form '" + 
+				contactXPathString + "'");
+	}
+	Node contactElement = contactTags.item(0);
+	if(!(contactElement instanceof Element)){
+	    throw new Exception("The XPath to retrieve the service contact info '" + 
+				contactXPathString + "' did not return an element as expected (" +
+				"got a " + contactElement.getClass().getName() + " instead)");
+	}
+
+	String contactInfo = ((Element) contactElement).getAttribute(SERVICE_SPEC_ATTR);
+	if(contactInfo == null || contactInfo.trim().length() == 0){
+	    throw new Exception("The service contact info is missing or blank in the HTML meta data headers" +
+				" (the XPath used was " + 
+				contactXPathString + ")");
+	}
+	contactInfo = contactInfo.trim();
+	// Make sure it's an MD5 hash, or a real (probably qualified) SMTP e-mail format 
+	if(!contactInfo.matches("[0-9a-f]{40}") &&
+	   !contactInfo.matches("\\S+@\\S+\\.\\S{2,}")){
+	    throw new Exception("The value of the service contact info (" + contactInfo +
+				" appears to be neither a qualified email address (e.g." +
+				" foo at bar.tld), nor an md5 hash of one");
+	}
+	return contactInfo;
+    }
 
+    protected List<String> parseMetaData(String mobyPrefix) throws Exception{
 	List<String> serviceNames = new Vector<String>();
 	NodeList serviceTags = (NodeList) xPath.evaluate(META_SERVICE_XPATH.replaceAll(MOBY_PREFIX_PLACEHOLDER, mobyPrefix), 
 							 xhtmlDoc, 
@@ -173,6 +206,10 @@
 	    }
 	    serviceNames.add(parseServiceTag((Element) serviceTag));
 	}
+
+	// There can be only one contact email for the form, so this call is not in the loop
+	setContactEmail(parseAuthorData(mobyPrefix));
+
 	return serviceNames;
     }
 
@@ -220,7 +257,7 @@
 	    throw new Exception(errorPrefix + " (serviceName was blank)");
 	}
 	serviceName = serviceName.trim();
-	String serviceDesc = firstColonIndex < spec.length()-1 ? spec.substring(firstColonIndex+1) : "";
+	String serviceDesc = firstColonIndex < spec.length()-1 ? spec.substring(firstColonIndex+1).trim() : "";
 
 	currentService = serviceName;
 	setCentralEndpoint(scheme);
@@ -289,9 +326,6 @@
 	for(int i = 0; i < formParams.getLength(); i++){
 	    Element input = (Element) formParams.item(i);
 	    String mobySpec = parseMobySpec(input, mobyPrefix);
-	    if(mobySpec != null && mobySpec.length() > mobyPrefix.length()+1){
-		mobySpec = mobySpec.substring(mobyPrefix.length()+1);
-	    }
 	    parseFormField(input, serviceName, mobySpec, inputSpecs, secondarySpecs, fixed, submits, images);
 	}
 	Map<String,String> inputSpecsAsStrings = new HashMap<String,String>();
@@ -304,7 +338,7 @@
 	}
 	for(Map.Entry<String,String[]> spec: secondarySpecs.entrySet()){
 	    String[] value = spec.getValue();
-	    if(value[3] != null && !value[3].matches("\\[.*\\]")){
+	    if(value[3] != null && value[3].length() > 0 && !value[3].matches("\\[.*\\]")){
 		value[3] = "["+value[3]+"]";
 	    }
 	    secondarySpecsAsStrings.put(spec.getKey(), join(":", value));
@@ -361,6 +395,8 @@
 	// if spec says to ignore the value as a Moby parameter
 	if(specFields.length == 1 && specFields[0].equals(NULL_NAME)){
 	    // don't send this value, nor make it part of the moby params
+	    // If it is a file type input, remove it from the form file list
+	    removeFormFile(defaultSpec[0]);
 	    return;
 	}
 	else if(specFields.length != 3 && specFields.length != 4){
@@ -379,7 +415,7 @@
 				    specFields[0]+"\" specifies an allowable data range of \"" +
 				    specFields[3]+"\", but submission parameters are only allowed " +
 				    "fixed values (in this case \"" + specFields[2] + "\"). Please " +
-				    "remove the data range parameter in order top avoid a " +
+				    "remove the data range parameter in order to avoid a " +
 				    "conflicting specification.");
 	    }
 	    if(specFields[1] != null && specFields[1].length() > 0 &&
@@ -475,7 +511,7 @@
 		    }
 		    // else: ignore any other radio value, we're sticking with the fixed value 
 		}
-		// Did the user manually set a fixed value for the readio button?
+		// Did the user manually set a fixed value for the radio button?
 		else if(specFields[2] != null && specFields[2].length() > 0 && 
 			!specFields[2].equals(defaultSpec[2])){
 		    // first time we're fixing the radio param value to send
@@ -495,11 +531,12 @@
 					    "Moby specs as \"" + existingSpec[0] + 
 					    "\" and \"" + specFields[0]);
 		    }
-		    // otherwise it's the default name maintained,
 		    // or we're renaming for the first time
-		    if(!existingSpec[0].equals(specFields[0])){
+		    else if(existingSpec[0].equals(defaultSpec[0]) && !existingSpec[0].equals(specFields[0])){
 			existingSpec[0] = specFields[0];
 		    }
+		    // otherwise it's the default name maintained
+
 		    if(isRadioDefault){  //we've been told this item is the default value 
 			existingSpec[2] = specFields[2];
 		    }
@@ -558,6 +595,8 @@
 	if(SUBMIT_DATATYPE.equals(defaultSpec[1])){
 	    if(defaultSpec[2].equals(submits.get(defaultSpec[0]))){
 		// TODO: how do we handle multiple submits with the same name but different values??
+		System.err.println("Overriding submit with same name but with new different value: " + 
+				   defaultSpec[0] + ", " + defaultSpec[2]);		
 	    }
 	    submits.put(defaultSpec[0], defaultSpec[2]);
 	}
@@ -607,8 +646,26 @@
 
 	// The output datatype of the service is also declared in the form tag
 	List<String> outputSpecs = parseMobySpecs(serviceFormElement, mobyPrefix);
+	String[] cleanOutputSpecs = new String[outputSpecs.size()];
+	for(int i = 0; i < outputSpecs.size(); i++){
+	    String spec = outputSpecs.get(i);
+	    if(!outputSpecs.get(i).startsWith(serviceName+":")){
+		throw new Exception("The form for service '" + serviceName +
+				    "' also contains moby specs (" + spec  + 
+				    ") not of the required form '"+mobyPrefix+":"+
+				    serviceName+":paramName:DataType'.  " +
+				    "You can only specify one service per form.");
+	    }
+	    if(spec.length() < serviceName.length()+4){
+		throw new Exception("The form for service '" + serviceName +
+				    "' contains moby specs (" + spec + 
+				    ") not of the required form '"+mobyPrefix+":"+
+				    serviceName+":paramName:DataType'");
+	    }
+	    cleanOutputSpecs[i] = spec.substring(serviceName.length()+1);
+	}
 
-	setPrimaryOutputs(outputSpecs.toArray(new String[outputSpecs.size()]));
+	setPrimaryOutputs(cleanOutputSpecs);
 	String encType = URLENCODED;  // This is the default XHTML value
 	setFormEncodingType(encType);
 
@@ -670,8 +727,8 @@
 	}
 	for(String classSpec: classSpecs.split("\\s")){
 	    String[] classParts = classSpec.split(":");
-	    if(classParts[0].equals(mobyPrefix)){
-		mobySpecs.add(classSpec);
+	    if(classParts.length > 1 && classParts[0].equals(mobyPrefix)){
+		mobySpecs.add(classSpec.substring(mobyPrefix.length()+1));
 	    }
 	}
 
@@ -807,20 +864,24 @@
 		addFormFile(nameAttr);
 	    }
 
-	    // Try to parse the default value multiple ways
-	    dataType = MobyTags.MOBYINTEGER;
-
-	    try{new BigInteger(valueAttr);
-	    }catch(Exception e){
-		dataType = MobyTags.MOBYFLOAT;}
-	    
-	    try{new BigDecimal(valueAttr);
-	    }catch(Exception e){
-		dataType = MobyTags.MOBYDATETIME;}
-
-	    try{MobyDataDateTime.parseISO8601(valueAttr);
-	    }catch(Exception e){
-		dataType = MobyTags.MOBYSTRING;}
+	    if(valueAttr != null && valueAttr.length() > 0){
+		
+		// Try to parse the default value multiple ways
+		dataType = MobyTags.MOBYINTEGER;
+		
+		try{new BigInteger(valueAttr);
+		}catch(Exception e){
+		    dataType = MobyTags.MOBYFLOAT;}
+		
+		try{new BigDecimal(valueAttr);
+		}catch(Exception e){
+		    dataType = MobyTags.MOBYDATETIME;}
+		
+		try{MobyDataDateTime.parseISO8601(valueAttr);
+		}catch(Exception e){
+		    dataType = MobyTags.MOBYSTRING;}
+	    }
+	    //else we keep the default of MobyTags.MOBYSTRING
 	}
 	
 	return new String[]{nameAttr, dataType, valueAttr, range};
@@ -861,7 +922,7 @@
 	    }
 
 	    String selAttr = option.getAttributeNS(MobyPrefixResolver.XHTML_NAMESPACE, "selected");
-	    if(selAttr == null){
+	    if(selAttr == null || selAttr.length() == 0){
 		selAttr = option.getAttribute("selected");
 	    }
 	    if(selAttr != null && selAttr.length() > 0 && !"0".equals(selAttr) && !"false".equals(selAttr)){
@@ -919,11 +980,11 @@
     }
 
     public void setContactEmail(String email){
-	contactEmails.put(currentService, email);
+	contactEmail = email;
     }
 
     public String getContactEmail(){
-	return contactEmails.get(currentService);
+	return contactEmail;
     }
 
     /**
@@ -981,7 +1042,7 @@
    
     // Note that the map is not cloned...
     public void setImageOptions(Map<String,String> options){
-	formSubmitOptions.put(currentService, options);
+	formImageOptions.put(currentService, options);
     }
 
     /**
@@ -1036,6 +1097,12 @@
 	formFiles.get(currentService).add(paramName);
     }
 
+    public void removeFormFile(String paramName){
+	if(currentService != null && formFiles.containsKey(currentService)){
+	    formFiles.get(currentService).remove(paramName);
+	}
+    }
+
     /**
      * @return the list of input parameters (primary and/or secondary) that should be submitted in "file" style
      */




More information about the MOBY-guts mailing list