[MOBY-guts] biomoby commit

Paul Gordon gordonp at dev.open-bio.org
Wed Apr 14 22:02:05 UTC 2010


gordonp
Wed Apr 14 18:02:04 EDT 2010
Update of /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util
In directory dev.open-bio.org:/tmp/cvs-serv7013/src/main/ca/ucalgary/seahawk/util

Modified Files:
	DataUtils.java FilterSearch.java 
Added Files:
	MobyPayloadRequestListener.java MutableNodeList.java 
Log Message:
Changes to implement explicit 'for each' loops over Seahawk data lists (not quite functional yet, but compiles)
moby-live/Java/src/main/ca/ucalgary/seahawk/util MobyPayloadRequestListener.java,NONE,1.1 MutableNodeList.java,NONE,1.1 DataUtils.java,1.4,1.5 FilterSearch.java,1.4,1.5
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/DataUtils.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/DataUtils.java	2010/04/11 20:15:28	1.4
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/DataUtils.java	2010/04/14 22:02:04	1.5
@@ -4,6 +4,7 @@
 import java.net.URL;
 import java.util.*;
 import java.util.logging.*;
+import java.util.regex.*;
 import javax.xml.parsers.*;
 import javax.xml.transform.*;
 import javax.xml.transform.dom.DOMSource;
@@ -34,8 +35,12 @@
     public static final String TEMP_FILE_PREFIX = "seahawk";
     private static final String OUTPUT_SUFFIX = ".out.xml";
     private static final String INPUT_SUFFIX = ".in.xml";
-    private static DocumentBuilder docBuilder;
+    public static DocumentBuilder docBuilder;
     private static Transformer identityTransform;
+    public static XPathFactory xPathFactory;
+
+    public static final String ARTICLE_PEERS_MODE = "article_peers";
+    public static final String DATATYPE_PEERS_MODE = "datatype_peers";
 
     private static Logger logger = Logger.getLogger(DataUtils.class.getName());
 
@@ -54,6 +59,8 @@
 	} catch(Exception e){
 	    logger.log(Level.SEVERE, "Cannot get identity XSLT transform from configuration", e);
 	}
+
+	xPathFactory = XPathFactory.newInstance();
     }
 
     /**
@@ -176,7 +183,7 @@
 		// User data has the form srcURL#XpathSelectCriteria <tab> xptrActualDataSubmitted <tab> regexFilter 
 		// where the filter is optional 
 		String[] data = sampleData.getUserData().toString().split("\t");
-		System.err.println("Forward user data is " + sampleData.getUserData().toString());
+		//System.err.println("Forward user data is " + sampleData.getUserData().toString());
 		URL dataSrcURL = null;
 		try{
 		    dataSrcURL = new URL(data[0]);
@@ -437,7 +444,7 @@
 						"sync: the instance job '" + jobName + 
 						"' has no parameter '" + paramName + "'");
 			}
-			System.err.println("Setting user data val to " + attrValue + " for " + paramName);
+			//System.err.println("Setting user data val to " + attrValue + " for " + paramName);
       			contentInstance.get(jobName).get(paramName).setUserData(attrValue);		    
 		    }
 		    else{
@@ -451,24 +458,47 @@
     }
 
     /**
-     * Get the data instance object associated with a given XPointer into a Moby XML doc
+     * Loads targetURL, minus the nodes specified by the xpath keys in filteredXPtrs (map values are not currently used).
+     */
+    public static void filterDoc(Document domDoc, Map<String,String> filteredXPtrs){
+	 
+	if(domDoc == null){
+	    logger.log(Level.SEVERE, "Error: Could not get MOBY document as DOM (empty or malformed document?)");
+	    return;
+	}
+	
+	// Remove the filtered data from the doc before deserializing to a moby data instance
+	// That way the request actually reflects what is shown on the screen to the user.
+	if(filteredXPtrs != null){
+	    // Mark and sweep (if we just deleted as we found nodes, the XPointers could be 
+	    // wrong as they refer to ordinality)
+	    Vector<Node> nodesToDelete = new Vector<Node>();
+	    for(String xptr: filteredXPtrs.keySet()){
+		nodesToDelete.add(XPointerResolver.getNodeFromXPointer(domDoc, xptr));
+	    }
+
+	    // Delete
+	    for(Node nodeToDelete: nodesToDelete){
+		Node parent = nodeToDelete.getParentNode();
+		parent.removeChild(nodeToDelete);
+		// Get rid of Simple parents of deleted nodes, because empty Simple
+		// tags are not okay in Moby (causes parsing error)
+		if(MobyTags.SIMPLE.equals(parent.getLocalName())){
+		    parent.getParentNode().removeChild(parent);
+		}
+	    }
+	}
+    }
+
+    /**
+     * Get the data instance object associated with a given XPointer in a Moby XML doc.
      *
      * @param targetURL of the form URLpath#/1/1/2/1 where /1/1/2/1 is an XPointer, or an standard xpath, to the part of the Moby XML doc to deserialize
      * @param filteredXPtrs a map of the xpointers to data that should NOT be deserialized if children of the targetURL XPointer
      * @param docFilter the current filter applied to the document in targetURL
      */
     public static MobyDataInstance loadMobyDataFromXPointer(URL targetURL, Map<String,String> filteredXPtrs, FilterSearch docFilter){
-	// Are we dealing with a simple object or a complex one?
-	MobyDataInstance mobyData = null;
-	
-	// Find the DOM fragment corresponding to the MOBY ID anchor specified
-	// in the link URL by using an XPath statement on the source MOBY doc
-	//System.err.println("Retrieving complex object from XPointer " + targetURL);
-	
-	// A child Xpointer is of the form /1/2/1/1, specifying the DOM child 
-	// descent path from the root node to get to the target node.  The 
-	// equivalent XPath is /*[1]/*[2]/*[1]/*[1]
-	String childXPath = targetURL.getRef().replaceAll("/(\\d+)", "/*[$1]");
+
 	URL currentURL = null;
 	try{currentURL = new URL(targetURL.toString().replaceAll("#"+targetURL.getRef(), ""));}
 	catch(Exception e){
@@ -476,7 +506,6 @@
 	}
 
 	// Build the DOM
-	Element mobyDOMRoot = null;
 	Document domDoc = null;
 	try{
 	    domDoc = docBuilder.parse(targetURL.openStream());
@@ -489,46 +518,29 @@
 		       " could not be read (from " + targetURL + ")", ioe);
 	    return null;
 	}
+	// Does an in-place edit of domDoc
+	filterDoc(domDoc, filteredXPtrs);
+
+	// Are we dealing with a simple object or a complex one?
+	MobyDataInstance mobyData = null;
 	
-	if(domDoc != null){
-	    mobyDOMRoot = domDoc.getDocumentElement();
-	}
-	if(mobyDOMRoot == null){
-	    logger.log(Level.SEVERE, "Error: Could not get MOBY document as DOM from source URL " +
-		       targetURL + " (empty or malformed document?)");
-	    return null;
-	}
+	// Find the DOM fragment corresponding to the MOBY ID anchor specified
+	// in the link URL by using an XPath statement on the source MOBY doc
+	//System.err.println("Retrieving complex object from XPointer " + targetURL);
 	
-	// Remove the filtered data from the doc before deserializing to a moby data instance
-	// That way the request actually reflects what is shown on the screen to the user.
-	if(filteredXPtrs != null){
-	    // Mark and sweep (if we just deleted as we found node, the XPointers could be 
-	    // wrong as they refer to ordinality)
-	    Vector<Node> nodesToDelete = new Vector<Node>();
-	    for(String xptr: filteredXPtrs.keySet()){
-		nodesToDelete.add(XPointerResolver.getNodeFromXPointer(domDoc, xptr));
-	    }
-
-	    // Delete
-	    for(Node nodeToDelete: nodesToDelete){
-		Node parent = nodeToDelete.getParentNode();
-		parent.removeChild(nodeToDelete);
-		// Get rid of Simple parents of deleted nodes, because empty Simple
-		// tags are not okay in Moby (causes parsing error)
-		if(MobyTags.SIMPLE.equals(parent.getLocalName())){
-		    parent.getParentNode().removeChild(parent);
-		}
-	    }
-	}
+	// A child Xpointer is of the form /1/2/1/1, specifying the DOM child 
+	// descent path from the root node to get to the target node.  The 
+	// equivalent XPath is /*[1]/*[2]/*[1]/*[1]
+	String childXPath = targetURL.getRef().replaceAll("/(\\d+)", "/*[$1]");
 
 	// Build and run the XPath statement
 	Element mobyObject = null;
 	NodeList idSearchResult = null;
 	Object xobject = null;
 	try{
-	    xobject = XPathFactory.newInstance().newXPath().evaluate(childXPath, 
-								     domDoc, 
-								     XPathConstants.NODESET);
+	    xobject = xPathFactory.newXPath().evaluate(childXPath, 
+						       domDoc, 
+						       XPathConstants.NODESET);
 						
 	    // Check the results
 	    if(xobject != null){
@@ -603,7 +615,7 @@
      * Generalizes the element instance into an XPath retrieving it and all 
      * similarly nested elements (based on traversing the parent nodes and prepending their names)
      */
-    protected static String elementInContextToNameBasedXPath(Element targetElement){
+    public static String elementInContextToNameBasedXPath(Element targetElement){
 	String xpath = "";
 	
 	for(Element currentElement = targetElement; 
@@ -630,22 +642,20 @@
 		xpath = "/*[@"+MobyTags.OBJ_NAMESPACE + " = '" +
 		    currentElement.getAttribute(MobyTags.OBJ_NAMESPACE)+"']" + xpath;
 	    }
-	    else if(elName.equals(MobyTags.MOBYFLOAT) ||
-		    elName.equals(MobyTags.MOBYSTRING) ||
-		    elName.equals(MobyTags.MOBYBOOLEAN) ||
-		    elName.equals(MobyTags.MOBYINTEGER) ||
-		    elName.equals(MobyTags.MOBYDATETIME)){
+//	    else if(elName.equals(MobyTags.MOBYFLOAT) ||
+//		    elName.equals(MobyTags.MOBYSTRING) ||
+//		    elName.equals(MobyTags.MOBYBOOLEAN) ||
+//		    elName.equals(MobyTags.MOBYINTEGER) ||
+//		    elName.equals(MobyTags.MOBYDATETIME)){
 		// Assume that it isn't the primitive type, but rather the articleName
 		// that makes it appropriate to use.
-		xpath = "/*[@"+MobyTags.ARTICLENAME + " = '" +
-		    articleName+"']" + xpath;
-	    }
+//		xpath = "/*[@"+MobyTags.ARTICLENAME + " = '" +
+//		    articleName+"']" + xpath;
+//	    }
 	    else{
 		// It's a complex type.  Assume the type is why we are picking it.
 		// TODO: In future we may want to check if a parent type is allowed in 
-		// this slot, and generalize to that.  May also want to check that there isn't more
-		// than one member of this type at this level in a HAS relationship...
-		// in that case we probably want to go by articleName to catch the full semantics
+		// this slot, and generalize to that.  
 		xpath = "/"+elName + xpath;
 	    }
 	    if(!(currentElement.getParentNode() instanceof Element)){
@@ -696,6 +706,12 @@
     }
 
     /**
+     * Replace the selection xpath info in the data instance
+     */
+    public static void replaceUserData(MobyDataInstance mdi, String selectionXPath){
+    }
+
+    /**
      * Retrieves processing instructions embedded in Moby XML docs if they have the for <?seahawk attr="val"?>
      */
     public static String getSeahawkAttrFromDoc(URL docURL, String attrName) throws Exception{ 
@@ -777,4 +793,328 @@
 			    "any_namespace");
     }
       
+    // Recursively ascend the DOM tree and find out our place in its branching structure
+    public static String getXPtr(Node n){
+	if(n == null || n instanceof Document){
+	    return "";
+	}
+	Node parent = n.getParentNode();
+        if(parent == null && n instanceof Attr){
+	    parent = ((Attr) n).getOwnerElement();
+	}
+
+	NodeList children = parent.getChildNodes();
+	int nonElementCnt = 0;
+	for(int i = 0; i < children.getLength(); i++){
+	    if(!(children.item(i) instanceof Element)){
+		nonElementCnt++; 
+		continue;
+	    }
+	    if(n == children.item(i)){
+		return getXPtr(parent)+"/"+(i-nonElementCnt+1);
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * If any moby object member is in a HAS relationship, add it to the list of filterable items
+     */
+    public static Boolean addHASXPtrs(List<String> filterList, Element object){
+	String tagName = object.getLocalName();
+	boolean isContainer = false;
+	MobyDataType mobyDataType = null;	
+	if(tagName.equals(MobyTags.MOBYDATA) || tagName.equals(MobyTags.COLLECTION) || tagName.equals(MobyTags.SIMPLE) ||
+	   tagName.equals(MobyTags.CROSSREFERENCE)){
+	    isContainer = true;
+	}
+	else{
+	    mobyDataType = MobyDataType.getDataType(tagName, SeahawkOptions.getRegistry());
+	    if(mobyDataType == null){
+		logger.log(Level.WARNING,
+                           "Found datatype unknown to the registry ("+object.getLocalName()+")");
+		return Boolean.FALSE;
+	    }
+	}
+
+	Boolean hasHAS = Boolean.FALSE; // does the object have a member with a HAS relationship?
+	NodeList members = object.getChildNodes();
+	for(int i = 0; i < members.getLength(); i++){
+	    if(!(members.item(i) instanceof Element)){
+		continue;
+	    }
+
+	    Element member = (Element) members.item(i);
+	    addHASXPtrs(filterList, member);
+
+	    if(!isContainer){
+		String memberName = member.getAttribute(MobyTags.ARTICLENAME);
+		MobyRelationship membership = mobyDataType.getChild(memberName);
+		//System.err.println("Relationship for " + tagName  + " member " + memberName + 
+		//		   " is " + (membership == null ? null : membership.getRelationshipType()));
+		if(membership != null && membership.getRelationshipType() == Central.iHAS){
+		    filterList.add(getXPtr(member));
+		    if(!hasHAS){
+			hasHAS = Boolean.TRUE;
+		    }
+		}
+	    }
+	}
+	return hasHAS;
+    }
+
+    /**
+     * For one-off filtering of a doc. Populates xPtrsToFilter, and returns the 
+     * whole doc which you can manipulate yourself (e.g. removing the nodes identified).
+     */
+    public static Document findFilteredNodes(URL targetURL, FilterSearch filter, 
+                                             Map<String,String> xPtrsToFilter){
+        Document unfilteredDoc = null;
+	try{
+	    unfilteredDoc = docBuilder.parse(targetURL.openStream());
+	} catch(Exception e){
+	    logger.log(Level.SEVERE,
+                       "Could not parse Moby document " + targetURL, e);
+	    return null;
+	}
+	findFilteredNodes(unfilteredDoc, filter, null, xPtrsToFilter, null, null, null, true);
+	return unfilteredDoc;
+    }
+
+    /**
+     * Returns a list of xptrs to filterable nodes in the targetDoc, an populates the list of 
+     * xptrs that should be filtered according to the provided filter.  In-place edited fields are
+     * xPtrsToFilter, jobXPtrs, currentSelectedData, and currentSelectionXPath 
+     * (for caching efficiency on multiple consecutive 
+     * calls to this method, such as a live typed search in the UI).  The latter three can be null if no caching is desired.
+     */
+    public static List<String> findFilteredNodes(Document targetDoc, FilterSearch filter, List<String> filterableXPtrs,
+		    		                 Map<String,String> xPtrsToFilter, Map<String,Boolean> jobXPtrs,
+                                                 MutableNodeList currentSelectedData, StringBuffer currentSelectionXPath, 
+						 boolean apply){
+	xPtrsToFilter.clear();
+
+	// Filter out any moby jobs, parameters, collection members or HAS members that aren't in the matchingNodes
+	if(filterableXPtrs == null){
+	    if(jobXPtrs == null){
+		jobXPtrs = new HashMap<String,Boolean>();
+            }
+            else{
+                jobXPtrs.clear();
+            }
+	    filterableXPtrs = new Vector<String>();
+	    NodeList nodes = targetDoc.getElementsByTagNameNS(MobyTags.MOBY_XML_NS, MobyTags.MOBYDATA);
+	    for(int i = 0; i < nodes.getLength(); i++){
+		String jobXPtr = getXPtr(nodes.item(i));		
+		filterableXPtrs.add(jobXPtr);
+		jobXPtrs.put(jobXPtr, addHASXPtrs(filterableXPtrs, (Element) nodes.item(i)));
+	    }
+		
+	    // Collections
+	    nodes = targetDoc.getElementsByTagNameNS(MobyTags.MOBY_XML_NS, MobyTags.COLLECTION);
+	    for(int i = 0; i < nodes.getLength(); i++){
+		String collectionXPtr = getXPtr(nodes.item(i));
+		NodeList collectionMembers = nodes.item(i).getChildNodes();
+		int nonElementCnt = 0;
+		for(int j = 0; j < collectionMembers.getLength(); j++){		    
+		    if(!(collectionMembers.item(j) instanceof Element)){
+			nonElementCnt++;
+			continue;
+		    }
+		    filterableXPtrs.add(collectionXPtr+"/"+(j-nonElementCnt+1)+"/1");
+		}
+	    }
+	}
+
+	if(!apply || filter == null || filter.getFilterRegex().toString().length() == 0){
+	    return filterableXPtrs;
+	}
+	// Otherwise make a list of xpointers to data that should be filtered
+	XPathOption xsel = filter.getSelectedXPath();
+	
+	// Find the applicable DOM nodes if not yet found, or if selection criteria have changed
+	if(currentSelectedData == null || currentSelectedData.isEmpty() || 
+           currentSelectionXPath == null || !currentSelectionXPath.toString().equals(xsel.getXPath())){
+            if(currentSelectionXPath == null){
+               currentSelectionXPath = new StringBuffer(xsel.getXPath());
+            }
+	    else{
+               currentSelectionXPath.replace(0, currentSelectionXPath.length(), xsel.getXPath());
+            }
+	    try{
+		if(currentSelectedData == null){
+                    currentSelectedData = new MutableNodeList();
+                }
+                else{
+                    currentSelectedData.clear();
+                }
+		currentSelectedData.addAll((NodeList) xPathFactory.newXPath().evaluate(currentSelectionXPath.toString(), 
+                                                                                       targetDoc, 
+                                                                                       XPathConstants.NODESET)); 
+	    } catch(Exception e){
+		logger.log(Level.SEVERE, 
+                           "Could not evaluate XPath (" + xsel.getXPath() + ")", e);
+		return filterableXPtrs;
+	    }
+	    //	    System.err.println("There are " + currentSelectedData.getLength() + 
+	    //		       " items selected in the document using XPath " + currentSelectionXPath);
+	}
+	
+	// Find just the data subset also matching the regex
+	Map<String,Boolean> matchingXPtrs = new LinkedHashMap<String,Boolean>();
+	// Build the FSA only once, for efficiency
+	Pattern regex = Pattern.compile(filter.getFilterRegex().toString(), 
+                                        Pattern.MULTILINE | Pattern.DOTALL | 
+                                         (filter.getCaseSensitivity() ? 0 : Pattern.CASE_INSENSITIVE));
+	for(int i = 0; i < currentSelectedData.getLength(); i++){
+	    Node node = currentSelectedData.item(i);	    
+	    if(node instanceof Element){
+		String elementXPtr = getXPtr(node);
+		if(matchingXPtrs.containsKey(elementXPtr) &&
+		   matchingXPtrs.get(elementXPtr).booleanValue()){
+		    	continue;  // already true, no 
+                    }
+		else if(regex.matcher(((Element) node).getTextContent()).find()){
+		    matchingXPtrs.put(elementXPtr, Boolean.TRUE);
+		    //System.err.println("Adding " + elementXPtr + " as " + matchingXPtrs.get(elementXPtr));
+		}
+		else{
+		    matchingXPtrs.put(elementXPtr, Boolean.FALSE);
+		    //System.err.println("Adding " + elementXPtr + " as " + matchingXPtrs.get(elementXPtr));
+		}
+	    }
+	    else if(node instanceof Attr){
+		String attrParentXPtr = getXPtr(((Attr) node).getOwnerElement());
+		if(matchingXPtrs.containsKey(attrParentXPtr) &&
+	 	   matchingXPtrs.get(attrParentXPtr).booleanValue()){
+		    continue;
+                }
+		else if(regex.matcher(((Attr) node).getValue()).find()){
+		    // Mark the element to which the attribute belongs
+		    matchingXPtrs.put(attrParentXPtr, Boolean.TRUE);
+		    //System.err.println("Adding " + attrParentXPtr + " attr parent as " + matchingXPtrs.get(attrParentXPtr));
+		}
+		// so false doesn't override true for multi-attr elements
+		else if(!matchingXPtrs.containsKey(attrParentXPtr)){ 
+		    matchingXPtrs.put(attrParentXPtr, Boolean.FALSE);
+		    //System.err.println("Adding " + attrParentXPtr + " attr parent as " + matchingXPtrs.get(attrParentXPtr));
+		}
+		
+	    }
+	    else{
+		logger.log(Level.WARNING, 
+			   "Found filter xpath result item that was not an Element or Attribute as expected ("+
+			    node.getClass().getName()+")");
+	    }
+	}
+	
+	boolean inversed = filter.getSelectionInversed();
+	Map<String,Boolean> parentMatchingXPtrs = new LinkedHashMap<String,Boolean>();
+	for(String currXPtr: filterableXPtrs){
+	    for(Map.Entry<String,Boolean> matchingXPtr: matchingXPtrs.entrySet()){
+		if(matchingXPtr.getKey().startsWith(currXPtr+"/")){ // a parent of the matching data
+		    // No positive example yet?
+		    if(!parentMatchingXPtrs.containsKey(currXPtr) || 
+		       !inversed && !parentMatchingXPtrs.get(currXPtr).booleanValue() ||
+		       inversed && parentMatchingXPtrs.get(currXPtr).booleanValue()){
+			//System.err.println("Adding "+ matchingXPtr.getValue() + " for " + currXPtr);
+			parentMatchingXPtrs.put(currXPtr, matchingXPtr.getValue());
+		    }
+		}
+	    }
+	}
+
+	matchingXPtrs.putAll(parentMatchingXPtrs);
+	for(String currXPtr: matchingXPtrs.keySet()){
+	    // Is part of the selection criteria, but doesn't match the regex
+	    boolean shouldFilter = false;
+	    if(!matchingXPtrs.get(currXPtr).booleanValue() &&
+	       // special condition: if "entire response" xpath is given, filter only at the job level
+	       (!currentSelectionXPath.toString().equals(FilterSearch.SELECT_ALL_XPATH) || jobXPtrs.containsKey(currXPtr))){
+		shouldFilter = true;
+	    }
+	    if(!inversed && shouldFilter ||
+	       inversed && !shouldFilter){ 
+		xPtrsToFilter.put(currXPtr, "todo");
+	    }	    
+	}
+
+	//todo: filter objects without the HAS field at all...
+	return filterableXPtrs;
+    }
+    // We need to enumerate the possible peer-sets for the selected data item.  Is the user interested in
+    // items in the same namespace, same data type, or same article name?
+    public static NodeList getPeerElements(Document doc, MobyDataInstance mobyData, String peerMode){
+        if(!(mobyData instanceof MobyPrimaryData)){
+            logger.log(Level.WARNING, "Tried to get peers of data that was not an instanceof MobyPrimaryData (was " + 
+                                      mobyData.getClass().getName()+ ")");
+	    return null;
+	}
+        MobyDataType dataTypeTemplate = ((MobyPrimaryData) mobyData).getDataType();
+
+	NodeList peerElements = null;
+        String peerGroupXPath = null;
+	if(mobyData.getUserData() != null){
+	    String[] userData = ((String) mobyData.getUserData()).split("\t");
+	    // first arg is url#nameBasedXPath 
+	    peerGroupXPath = userData[0].split("#", 2)[1];
+        }
+        else{
+	    // Fallback is to get all nodes with the same name...
+            // warning: need to set this in the userdata sent to the job, to jibe with taverna workflow export selection of nodes!
+	    logger.log(Level.WARNING, "No UserData for data instance, falling back to all peer elements of the same datatype");
+            peerGroupXPath = "//"+dataTypeTemplate.getName();
+	}
+
+        // just look at data type tag, regardless of nesting
+        if(DATATYPE_PEERS_MODE.equals(peerMode)){
+            peerGroupXPath = peerGroupXPath.replaceFirst("^.+/", "//"); 
+        }
+        else if(ARTICLE_PEERS_MODE.equals(peerMode)){ 
+            String xpathArticleCondition = "[@"+MobyTags.ARTICLENAME + "='" + mobyData.getName() +"']";
+            // Pass back modified selection xpath for userdata (enables PBE to capture the additonal semantics)
+            // This is done by replacing first tab delimited field url#selectionXPath with url#newXPath
+            String newUserData = mobyData.getUserData().toString().replaceFirst("^(.*?)#.*?(?=\\t)", 
+                                                                                "$1#"+peerGroupXPath+xpathArticleCondition);
+            mobyData.setUserData(newUserData);
+
+            // keep from job article name down
+            peerGroupXPath = peerGroupXPath.replaceFirst("^.*/(Collection|Simple)", "//*");
+	    // we want to go by articleName too to catch the full semantics of the peer group definition
+            peerGroupXPath += xpathArticleCondition;
+        }
+        else{
+            logger.log(Level.SEVERE, "Got unknown mode for peer selection, aborting (mode was "+peerMode+")");
+            return null;
+        }
+        // For xpaths given above, MOBY namespace is problem in XPath evaluation. 
+        // solution: eliminate Moby envelope path parts: full path doesn't resolve in xpath for unknown reasons
+        //.replaceAll("/(MOBY|mobyContent|mobyData|Collection|Simple)","/moby:$1"); //attempt 1
+        //.replaceAll("/([a-zA-Z_0-9\\-]+)(?=/|$)", "/*[local-name() = '$1']") //attempt 2
+        //.replaceAll("/([a-zA-Z_0-9\\-]+)\\[", "/*[local-name() = '$1' and "); //attempt 2 cont'd
+
+	try{
+            peerElements = (NodeList) xPathFactory.newXPath().evaluate(peerGroupXPath, 
+								       doc, 
+								       XPathConstants.NODESET);
+        } catch(Exception e){
+            logger.log(Level.SEVERE, "Could not evaluate UserData XPath "+peerGroupXPath, e);
+        }
+        System.err.println("Got " + peerElements.getLength() + " peers for " + peerGroupXPath);
+
+        return peerElements;
+    }
+
+    // given a node from a Moby XML dom, find the name of the mobyData job that's its parent
+    public static String findMobyJobName(Node n){
+        while(n != null && !n.getLocalName().equals(MobyTags.MOBYDATA)){
+            n = n.getParentNode();
+        }
+        if(n == null){
+            return null; // no mobyData parent
+        }
+        else{
+            return MobyPrefixResolver.getAttr((Element) n, MobyTags.QUERYID);
+        }
+    }
 }

===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/FilterSearch.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/FilterSearch.java	2010/04/10 00:40:17	1.4
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/util/FilterSearch.java	2010/04/14 22:02:04	1.5
@@ -28,6 +28,20 @@
     public static final String SELECT_ALL_XPATH = "//* | //*/@*";
 
     /**
+     * A c-tor to manually populate the filter with a specific set of filter criteria.  
+     * No autopoulation of options is done.
+     */
+    public FilterSearch(String regex, XPathOption xpath, boolean case_sensitive, boolean inverse_selection){
+	filterRegex = new StringBuffer(regex);
+	xpathOptions = new Vector<XPathOption>();
+	xpathOptions.add(xpath);
+	setCaseSensitivity(case_sensitive);
+	setSelectionInversed(inverse_selection);
+    }
+
+    /**
+     * Autopopulates the possible search field values based on the incoming doc
+     *
      * @param docToFilter the document that will be used to determine what XPaths can be suggested
      * @param docBuilder the xml parser to use on the document
      *
@@ -106,4 +120,15 @@
     public Vector<XPathOption> getXPathOptions(){
 	return xpathOptions;
     }
+
+    public boolean equals(Object o){
+        if(o == null || !(o instanceof FilterSearch)){
+          return false;
+        }
+        FilterSearch other = (FilterSearch) o;
+        return filterRegex.toString().equals(other.filterRegex.toString()) &&
+               getSelectedXPath().getXPath().equals(other.getSelectedXPath().getXPath()) &&
+               caseSensitivity == other.caseSensitivity &&
+	       inverseSelection == other.inverseSelection;
+    }
 }




More information about the MOBY-guts mailing list