[MOBY-guts] biomoby commit

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


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

Modified Files:
	MobyContentPane.java MobyServicesGUI.java 
Added Files:
	MobyPayloadCreator.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/gui MobyPayloadCreator.java,NONE,1.1 MobyContentPane.java,1.26,1.27 MobyServicesGUI.java,1.17,1.18
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyContentPane.java,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyContentPane.java	2010/04/11 20:15:28	1.26
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyContentPane.java	2010/04/14 22:02:04	1.27
@@ -1,4 +1,3 @@
-
 package ca.ucalgary.seahawk.gui;
 
 // For external links
@@ -72,8 +71,8 @@
     public static final String SERVICE_CREATION_MSG = "Create a service returning this datatype";
     private static final int TAB_ICON_SPACER = 2;
 
-    private static String SEARCH_VISIBLE = "Search visible";
-    private static String SEARCH_HIDDEN = "Search hidden";
+    private static final String SEARCH_VISIBLE = "Search visible";
+    private static final String SEARCH_HIDDEN = "Search hidden";
 
     private static ImageIcon hourglassIcon; 
     private static ImageIcon failedIcon; 
@@ -105,10 +104,10 @@
     private Map<String,String> filteredData; //Map<xptrOfFilteredData,>
     private boolean filterChanged;
     private Document currentDoc; //the doc DOM being actively filtered
-    private NodeList currentSelectedData = null;
-    private String currentSelectionXPath = null;
-    private Map<String,Boolean> jobXPtrs = null;  // Map<xptr,has a HAS member>
+    private MutableNodeList currentSelectedData = null;
+    private StringBuffer currentSelectionXPath = null;
     private List<String> filterableNodes = null;  // List<xptr>
+    private Map<String,Boolean> jobXPtrs = null;  // Map<xptr,has a HAS member>
     private List<AttributeSet> origStyles = null;
     private boolean firstDocRendering = true;
 
@@ -141,20 +140,6 @@
     private final static String wsServletPath = "/SOAPServlet";
     private static Acme.Serve.Serve servletContainer;
     private static Map<String,MobyContentGUI> id2GuiMap;
-    private static DocumentBuilder docBuilder;
-    private static XPathFactory xPathFactory;
-
-    static{
-	xPathFactory = XPathFactory.newInstance();
-
-	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-	dbf.setNamespaceAware(true);
-	try{
-	    docBuilder = dbf.newDocumentBuilder();
-	} catch(Exception e){
-	    logger.warn("Cannot get XML parser from configuration", e);
-	}
-    }
 
     public MobyContentPane(MobyContentGUI cGUI, MobyServicesGUI sGUI, JTabbedPane parentComponent, DataFlowRecorder recorder, JLabel statusBar){
 	tabbedPane = parentComponent;
@@ -200,7 +185,9 @@
 	filterHistory = new HashMap<URL,FilterSearch>();
 	deletedFilters = new HashMap<URL,FilterSearch>();
 	xPtrsReferencedInNextService = new Vector<String>();
+        currentSelectedData = new MutableNodeList();
 	filteredData = new HashMap<String,String>();
+	jobXPtrs = new HashMap<String,Boolean>();
 
 	ClassLoader cl = getClass().getClassLoader();
 	if(cl == null){
@@ -738,9 +725,8 @@
 	// If this page has a filter associated with it before reload it
 	try{
 	    currentDoc = null;  // get rid of previous in-memory doc use for interactive filtering, if any
-	    currentSelectedData = null;
-	    currentSelectionXPath = null;
-	    jobXPtrs = null;
+	    currentSelectedData.clear();
+	    currentSelectionXPath = new StringBuffer();
 	    filterableNodes = null;
 	    origStyles = null;
 	    firstDocRendering = true;
@@ -1209,14 +1195,54 @@
 			       "not extract MOBY Data Object from " +targetURL);
 	    return;
 	}
+	if(!(mobyData instanceof MobyPrimaryData)){
+	    logger.warn("Cannot create MOBY service list for non-primary " +
+			"MOBY Data (was " +mobyData.getClass().getName()+")");
+	    return;
+	}
 
 	JPopupMenu popup = new DynamicJPopupMenu();
 	popup.setName(MOBY_SERVICE_POPUP_NAME);
 	addExtraMobyOptions(popup, mobyData, targetURL);
-	JMenuItem checkingLinksPopupItem = new JMenuItem("Check for services...");
+	JMenuItem checkingLinksPopupItem = new JMenuItem("Checking for services...");
 	popup.add(checkingLinksPopupItem);
 	popup.show(this, lastClickX+editorPane.getX(), lastClickY+editorPane.getY());
 	servicesGUI.addPopupOptions(mobyData, popup, true, getDefaultHandler()); // true = asynchronous
+
+	// It's possible that the current node clicked has peers that could also be submitted at the same time.
+	// In this case, create a "for each" option to submit all peers to the service.  We don't actually build
+	// the input data, but provde a callback listener to create the full submission envelope if the user 
+	// chooses the for each option.  The Moby data instance's userData gives us the current context, enabling us 
+        // to construct the correct payload in MobyPayloadCreator.createPayload() at any point in the future.
+        String origUserData = (String) mobyData.getUserData();
+        MobyPayloadRequestListener payloadCreator = new MobyPayloadCreator(this);
+        for(String peerMode: new String[]{DataUtils.ARTICLE_PEERS_MODE, DataUtils.DATATYPE_PEERS_MODE}){
+            // note that getPeerElements() will modify the userData to reflect the semantic of the requested peer mode
+            mobyData.setUserData(origUserData);
+            NodeList peerElements = DataUtils.getPeerElements(getCurrentDoc(), mobyData, peerMode);
+            if(peerElements.getLength() <= 1){
+                continue; // no 'for each' option if only one to process...
+            }
+            String each = "each <i>(" + peerElements.getLength() + " total)</i>";
+            if(peerMode.equals(DataUtils.ARTICLE_PEERS_MODE)){
+                each += " '"+mobyData.getName()+"'";
+            }
+            MobyDataType dataType = ((MobyPrimaryData) mobyData).getDataType();
+            if(mobyData instanceof MobyPrimaryDataSet){	 // Collection
+                servicesGUI.addPopupOptions((MobyPrimaryDataSet) mobyData, popup, true, getDefaultHandler(), payloadCreator, 
+					    (String) mobyData.getUserData(), each);
+            }
+            else if(MobyTags.MOBYOBJECT.equals(dataType.getName())){  
+                MobyNamespace namespace = null;
+                servicesGUI.addPopupOptions(namespace, popup, true, getDefaultHandler(), payloadCreator, 
+                                            (String) mobyData.getUserData(), each);
+            }
+            else{
+                servicesGUI.addPopupOptions(dataType, popup, true, getDefaultHandler(), payloadCreator, 
+                                            (String) mobyData.getUserData(), each);
+            }
+        }
+
 	status.setText("Shift+Click=Service in new tab, Ctrl+Click=Use default 2nd params");
 	if(popup.getSubElements().length > 0){
 	    popup.setSelected(null);
@@ -1228,6 +1254,15 @@
 	}
     }
 
+    Map<String,String> getFilteredData(){
+      return filteredData;
+    }
+
+    Map<String,Boolean> getJobXPtrs(){
+      return jobXPtrs;
+    }
+
+
     /**
      * Subclasses can use this method to expand the popup menu.  Be sure to call super.addExtraMobyOptions()
      */
@@ -1252,7 +1287,7 @@
 
 	//System.err.println("Should create a previous input menu item for " + mdi.getUserData());
 	try{
-	    Document srcDoc = docBuilder.parse(srcURL.openStream());
+	    Document srcDoc = DataUtils.docBuilder.parse(srcURL.openStream());
 
 	    // Get the input data for the *previous* service
 	    MobyDataJob inputData = DataUtils.getInputSample(srcDoc, SeahawkOptions.getRegistry());
@@ -1262,7 +1297,7 @@
 		return;
 	    }
 	    for(MobyDataInstance previousMDI: inputData.getPrimaryData()){		
-		    // add conditional of the current service as a criteria in user data for each previousMDI, 
+		// add conditional of the current service as a criteria in user data for each previousMDI, 
 		// so PbE will properly reflect the logic of if(f1(x) matches filter){f2(x)}
 		DataUtils.addUserData(previousMDI, srcURL, getFilter());
 
@@ -1271,6 +1306,7 @@
 	} catch(Exception e){
 	    logger.warn("Could not load previous service info, 'previous input' option will not be displayed", e);
 	}
+
     }
 
     /**
@@ -1392,231 +1428,41 @@
 	return null;
     }
 
-    /**
-     * Determine the parts of the XML document matching the FilterSearch criteria, and filter the view accordingly.
-     */
-    public void applyFilter(boolean apply){
-	if(!filterChanged){
-	    filterChanged = true;
-	}
-	filteredData.clear();
-
+    protected Document getCurrentDoc(){
 	if(currentDoc == null){  // parse the doc into memory if not already there
 	    try{
-		currentDoc = docBuilder.parse(getCurrentURL().openStream());
+		currentDoc = DataUtils.docBuilder.parse(getCurrentURL().openStream());
 	    } catch(Exception e){
 		logger.error("Could not parse Moby document " + getCurrentURL(), e);
-		return;
-	    }
-	}
-	// Filter out any moby jobs, parameters, collection members or HAS members that aren't in the matchingNodes
-	if(filterableNodes == null){
-	    jobXPtrs = new HashMap<String,Boolean>();
-	    filterableNodes = new Vector<String>();
-	    NodeList nodes = currentDoc.getElementsByTagNameNS(MobyTags.MOBY_XML_NS, MobyTags.MOBYDATA);
-	    for(int i = 0; i < nodes.getLength(); i++){
-		String jobXPtr = getXPtr(nodes.item(i));		
-		filterableNodes.add(jobXPtr);
-		jobXPtrs.put(jobXPtr, addHASXPtrs(filterableNodes, (Element) nodes.item(i)));
-	    }
-		
-	    // Collections
-	    nodes = currentDoc.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;
-		    }
-		    filterableNodes.add(collectionXPtr+"/"+(j-nonElementCnt+1)+"/1");
-		}
+		return null;
 	    }
 	}
-
-	if(!apply || !filterHistory.containsKey(getCurrentURL()) ||
-	   (filterHistory.containsKey(getCurrentURL()) && 
-	    filterHistory.get(getCurrentURL()).getFilterRegex().toString().length() == 0)){
-	    // Show whole doc if no filter or if filter is blank, so nothing to do here
-	    if(firstDocRendering){
-		firstDocRendering = false;
-	    }
-	    else{
-		displayFilterEffect(); //need to cleanup previous state
-	    }
-	    return;
-	}
-	// Otherwise make a list of xpointers to data that should be grayed out
-	FilterSearch fs = filterHistory.get(getCurrentURL());
-	XPathOption xsel = fs.getSelectedXPath();
-	
-	// Find all the matching data
-	XPath xpath = xPathFactory.newXPath();
-	// Find the applicable DOM nodes if not yet found, or if selection criteria have changed
-	if(currentSelectedData == null || currentSelectionXPath == null || !currentSelectionXPath.equals(xsel.getXPath())){
-	    currentSelectionXPath = xsel.getXPath();
-	    try{
-		currentSelectedData = (NodeList) xpath.evaluate(currentSelectionXPath, currentDoc, XPathConstants.NODESET);
-	    } catch(Exception e){
-		logger.error("Could not evaluate XPath (" + xsel.getXPath() + ") over " + getCurrentURL(), e);
-		return;
-	    }
-	    //	    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(fs.getFilterRegex().toString(), 
-                                        Pattern.MULTILINE | Pattern.DOTALL | 
-                                         (fs.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.warn("Found filter xpath result item that was not an Element or Attribute as expected ("+
-			    node.getClass().getName()+")");
-	    }
-	}
-	
-	boolean inversed = fs.getSelectionInversed();
-	Map<String,Boolean> parentMatchingXPtrs = new LinkedHashMap<String,Boolean>();
-	for(String currXPtr: filterableNodes){
-	    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.equals(FilterSearch.SELECT_ALL_XPATH) || jobXPtrs.containsKey(currXPtr))){
-		shouldFilter = true;
-	    }
-	    if(!inversed && shouldFilter ||
-	       inversed && !shouldFilter){ 
-		filteredData.put(currXPtr, "todo");
-	    }	    
-	}
-
-	//todo: filter objects without the HAS field at all...
-	
-	// apply gray out in the document display
-	displayFilterEffect();
+        return currentDoc;
     }
 
-    // If any moby object member is in a HAS relationship, add it to the list of filterable items
-    private 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.warn("Found datatype unknown to the registry ("+object.getLocalName()+")");
-		return Boolean.FALSE;
-	    }
+    /**
+     * Determine the parts of the XML document matching the FilterSearch criteria for the current doc, 
+     * and filter the view accordingly.  Used for interactive filtering in the display.
+     */
+    protected void applyFilter(boolean apply){
+	if(!filterChanged){
+	    filterChanged = true;
 	}
 
-	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;
-		    }
-		}
-	    }
+        FilterSearch filter = filterHistory.get(getCurrentURL());
+	filterableNodes = DataUtils.findFilteredNodes(getCurrentDoc(), filter, filterableNodes, filteredData, jobXPtrs,
+                                                      currentSelectedData, currentSelectionXPath, apply);
+ 
+	if((!apply || filter == null || filter.getFilterRegex().toString().length() == 0) && firstDocRendering){
+	    // Show whole doc if no filter or if filter is blank, so nothing to do here
+	    firstDocRendering = false;
 	}
-	return hasHAS;
+	// apply gray out in the document display, or need to cleanup previous state even if no filter now
+        else{
+	    displayFilterEffect();
+        }
     }
 
-    // Recursively ascend the DOM tree and find out our place in its branching structure
-    private 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;
-    }
 
     /**
      * Gray out parts of the HTML view if they are part of the filtered data.
@@ -1681,7 +1527,7 @@
 	// Gray out the mismatched textual data
 	for(Map.Entry<String,String> dataToFilter: filteredData.entrySet()){	    
 
-	    //System.err.println("Filtering "+dataToFilter.getKey());
+	    System.err.println("Filtering "+dataToFilter.getKey());
 	    javax.swing.text.AbstractDocument.AbstractElement htmlDiv = 
 		(javax.swing.text.AbstractDocument.AbstractElement) d.getElement(dataToFilter.getKey());
 	    if(htmlDiv == null){
@@ -1998,4 +1844,5 @@
     public void lostOwnership(Clipboard clipboard, Transferable contents){
 	//System.err.println("Lost clipboard ownership");
     }
+
 }

===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyServicesGUI.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyServicesGUI.java	2010/04/09 15:55:48	1.17
+++ /home/repository/moby/moby-live/Java/src/main/ca/ucalgary/seahawk/gui/MobyServicesGUI.java	2010/04/14 22:02:04	1.18
@@ -1,11 +1,11 @@
 package ca.ucalgary.seahawk.gui;
 
 import ca.ucalgary.seahawk.services.MobyClient;
-import ca.ucalgary.seahawk.util.HTMLUtils;
-import ca.ucalgary.seahawk.util.SeahawkOptions;
+import ca.ucalgary.seahawk.util.*;
 
 import org.biomoby.shared.*;
 import org.biomoby.shared.data.*;
+import org.biomoby.shared.parser.MobyTags;
 import org.biomoby.client.CentralImpl;
 import org.biomoby.client.MobyRequest;
 import org.biomoby.client.MobyRequestEventHandler;
@@ -182,6 +182,7 @@
 	return handler;
     }
 
+    // synchronized so simultaneous requests don't get their input data mixed up
     public void setupServiceSecondaryData(MobyRequestEventHandler handler){
 	MobyDataInstance[] castInputs = new MobyDataInstance[primaryInput.length];
 	for(int i = 0; i < primaryInput.length; i++){
@@ -194,14 +195,17 @@
 	    castInputs[i] = (MobyDataInstance) primaryInput[i];
 	}
 
-	try{	    
-	    mobyRequest.setInput(castInputs);
-	    mobyRequest.setSecondaryInput(secondaryInputInstances);
-	} catch(MobyException me){
-	    me.printStackTrace();
-	    logger.warn("Error while trying to set service input: " + me);
-	}
-	executeService(handler);
+        // code from mobyRequest.setInput() to executeService() should always be synced to avoid input mixup between requests
+        synchronized(mobyRequest){
+	    try{	    
+	        mobyRequest.setInput(castInputs);
+	        mobyRequest.setSecondaryInput(secondaryInputInstances);
+	    } catch(MobyException me){
+	        me.printStackTrace();
+	        logger.warn("Error while trying to set service input: " + me);
+	    }
+	    executeService(handler);
+        }
     }
 
     protected void setupService(MobyService mobyService, MobyDataInstance mdi, int handlerHashCode, boolean useDefaultSecondaries){
@@ -217,18 +221,21 @@
 	System.arraycopy(primaryInputTemplate, 0, primaryInput, 0, primaryInput.length);
 
 	if(!hasSecondaryInput(mobyService)){
-	    try{
-		// Implement simple input (i.e. only one input argument)
-		mobyRequest.setInput(mdi, "");
-	    }
-	    catch(MobyException me){
-		logger.error("Failure in MOBY input, was not acceptable:" + me);
-		return;
-	    }
+            // code from mobyRequest.setInput() to executeService() should always be synced to avoid input mixup between requests
+            synchronized(mobyRequest){
+	        try{
+		    // Implement simple input (i.e. only one input argument)
+		    mobyRequest.setInput(mdi, "");
+	        }
+	        catch(MobyException me){
+		    logger.error("Failure in MOBY input, was not acceptable:" + me);
+		    return;
+	        }
 
-	    // No need for further info, just launch the request
-	    removePopupOptions();
-	    executeService(getHandlerByHashCode(handlerHashCode));
+	        // No need for further info, just launch the request
+	        removePopupOptions();
+	        executeService(getHandlerByHashCode(handlerHashCode));
+            }
 	}
 	else{
 	    // We need more info from the user to launch this service
@@ -502,7 +509,8 @@
     class OptionLoaderThread extends Thread{
 	Node targetNode = null;
 	MobyRequestEventHandler handler = null;
-	MobyDataInstance mobyData = null;
+	MobyPayloadRequestListener payloadCreator = null;
+	Object mobyData = null;
 	String extraMenuText = null;
 	JPopupMenu popupList;
 
@@ -513,11 +521,13 @@
 	    this.handler = handler;
 	}
 
-	public OptionLoaderThread(MobyDataInstance mobyData, JPopupMenu popupList, MobyRequestEventHandler handler, String extraMenuText){
+	public OptionLoaderThread(Object mobyData, JPopupMenu popupList, MobyRequestEventHandler handler, 
+                                  MobyPayloadRequestListener payloadCreator, String extraMenuText){
 	    super();
 	    this.mobyData = mobyData;
 	    this.popupList = popupList;
 	    this.handler = handler;
+            this.payloadCreator = payloadCreator;
 	    this.extraMenuText = extraMenuText;
 	}
 
@@ -526,7 +536,7 @@
 		addPopupOptions(targetNode, popupList, false, handler);
 	    }
 	    else if(mobyData != null){
-		addPopupOptions(mobyData, popupList, false, handler, extraMenuText);
+		addPopupOptions(mobyData, popupList, false, handler, payloadCreator, extraMenuText);
 	    }
 	    else{
 		logger.warn("Warning: OptionLoaderThread has no data to work with");
@@ -576,6 +586,30 @@
     }
 
     /**
+     * Creates a menu item based on the provided data type.  If a service is selected from here,
+     * a callback will be made to the MobyPayloadRequestListener for the actual submission data.
+     *
+     * @param payloadKey a key that will be used in the callback so the listener knows what payload the create
+     */
+    public void addPopupOptions(MobyDataType mobyDataType, JPopupMenu popupList, boolean asynchronous, 
+                                MobyRequestEventHandler handler, MobyPayloadRequestListener payloadCreator, 
+                                String payloadKey, String extraMenuText){
+        addPopupOptions(mobyDataType, popupList, asynchronous, handler, payloadCreator, extraMenuText);
+    }
+
+    public void addPopupOptions(MobyNamespace mobyNamespace, JPopupMenu popupList, boolean asynchronous, 
+                                MobyRequestEventHandler handler, MobyPayloadRequestListener payloadCreator, 
+                                String payloadKey, String extraMenuText){
+        addPopupOptions(mobyNamespace, popupList, asynchronous, handler, payloadCreator, extraMenuText);
+    }
+
+    public void addPopupOptions(MobyPrimaryDataSet collection, JPopupMenu popupList, boolean asynchronous, 
+                                MobyRequestEventHandler handler, MobyPayloadRequestListener payloadCreator, 
+                                String payloadKey, String extraMenuText){
+        addPopupOptions(collection, popupList, asynchronous, handler, payloadCreator, extraMenuText);
+    }
+
+    /**
      * Same as three arg addPopupOptions, but uses default response handler
      */
     public void addPopupOptions(MobyDataInstance mobyData, JPopupMenu popupList, boolean asynchronous){
@@ -586,13 +620,16 @@
      * Find the list of available services querying MobyCentral directly with a piece of data.
      */
     public void addPopupOptions(MobyDataInstance mobyData, JPopupMenu popupList, boolean asynchronous, MobyRequestEventHandler handler){
-	addPopupOptions(mobyData, popupList, asynchronous, handler, null);
+	addPopupOptions(mobyData, popupList, asynchronous, handler, null, null);
     }
 
     /**
      * Find the list of available services querying MobyCentral directly with a piece of data.
+     *
+     * @param mobyData a MobyDataInstance, or in the case of deferred data to be created by payloadCreator, a MobyDataType, MobyNamespace, or MobyPrimaryDataSet
      */
-    public void addPopupOptions(MobyDataInstance mobyData, JPopupMenu popupList, boolean asynchronous, MobyRequestEventHandler handler, String extraMenuText){
+    public void addPopupOptions(Object mobyData, JPopupMenu popupList, boolean asynchronous, 
+                                MobyRequestEventHandler handler, MobyPayloadRequestListener payloadCreator, String extraMenuText){
 
 	if(asynchronous){
 	    //Show the user that we're doing something...
@@ -605,7 +642,7 @@
 	    }
 
 	    // Call this method synchronously in a different thread
-	    OptionLoaderThread lt = new OptionLoaderThread(mobyData, popupList, handler, extraMenuText);
+	    OptionLoaderThread lt = new OptionLoaderThread(mobyData, popupList, handler, payloadCreator, extraMenuText);
 	    lt.start();
 	    return;
 	}
@@ -625,7 +662,9 @@
 	    popupList.setVisible(true);
 	}
 
-	addClipboardItem(submenu, mobyData);
+	if(mobyData instanceof MobyDataInstance){
+            addClipboardItem(submenu, (MobyDataInstance) mobyData);
+        }
 	submenu.add(getWaitItem(submenu));
 
  	MobyDataServiceAssocInstance serviceAssocObject = null;  
@@ -637,6 +676,15 @@
 	    else if(mobyData instanceof MobyDataObject){
 		serviceAssocObject = mobyClient.getServices((MobyDataObject) mobyData);
 	    }
+            // The data will be loaded later
+            else if(payloadCreator != null){
+                if(mobyData instanceof MobyPrimaryDataSet){
+                    //serviceAssocObject = mobyClient.getServices(new MobyDataObjectSetDeferred(mobyData, payloadCreator, requestKey));
+                }
+                else{
+                    //serviceAssocObject = mobyClient.getServices(new MobyDataObjectDeferred(mobyData, payloadCreator, requestKey));
+                }
+            }
 	    else{
 		logger.warn("Service options for objects other than MobyDataObject " +
 			    "and MobyDataObjectSet are not yet supported.");
@@ -1136,51 +1184,50 @@
 	return menu;
     }
 
-    public JMenu createObjectSubMenu(MobyDataInstance mdi, String extraMenuText){
-	if(!(mdi instanceof MobyPrimaryData)){
-	    logger.warn("Ignoring non-primary data object submitted to menu creation: " + mdi);
-	    return null;
-	}
-	
-	MobyPrimaryData targetData = (MobyPrimaryData) mdi;
-	String id = targetData.getId();
-	if(id == null){
-	    id = "";
-	}
-	else if(id.length() > MAX_ID_LEN+3){
-	    id = id.substring(0, MAX_ID_LEN)+"...";
-	}
-	
-	MobyDataType mobyDataType = targetData.getDataType();
-	String name = null;
-	if(mobyDataType == null){
-	    logger.warn("PG: Warning: no datatype associated with service " + 
-			targetData.getName());
-	}
-	else{
-	    name = mobyDataType.getName();
-	}
-	if("Object".equals(name)){
-	    MobyNamespace namespaces[] = targetData.getNamespaces();
-	    //System.err.println("Got base object with namespaces numbering " + namespaces.length);
-	    if(namespaces != null && namespaces.length > 0 && namespaces[0] != null){
-		//System.err.println("Checking namespace "+ namespaces[0].getName());
-		name = namespaces[0].getName();
+    /**
+     * Template object may be one of MobyPrimaryData, or in case of deferred content loading a 
+     * MobyNamespace, MobyDataType, or MobyPrimaryDataSet.
+     */
+    public JMenu createObjectSubMenu(Object templateObject, String extraMenuText){
+        String id = null;
+        MobyDataType mobyDataType = null;
+        String name = null;
+	MobyNamespace[] namespaces = null;
+	if(templateObject instanceof MobyPrimaryData){
+	    MobyPrimaryData targetData = (MobyPrimaryData) templateObject;
+	    mobyDataType = targetData.getDataType();
+	    namespaces = targetData.getNamespaces();
+	    id = targetData.getId();
+	    if(id == null){
+	        id = "";
 	    }
-	}
-	else{
-	    //System.err.println("Got complex object with datatype name " + name);
-	}
+	    else if(id.length() > MAX_ID_LEN+3){
+	        id = id.substring(0, MAX_ID_LEN)+"...";
+	    }
+	    if(MobyTags.MOBYOBJECT.equals(mobyDataType.getName()) &&
+               namespaces != null && namespaces.length > 0 && namespaces[0] != null){
+		name = namespaces[0].getName();
+            }
+            else{
+                name = mobyDataType.getName();
+            }
+        }
+        else if(templateObject instanceof MobyNamespace){
+            namespaces = new MobyNamespace[]{(MobyNamespace) templateObject};
+            mobyDataType = MobyDataType.getDataType(MobyTags.MOBYOBJECT, SeahawkOptions.getRegistry());
+            name = ((MobyNamespace) templateObject).getName();
+        }
+        else if(templateObject instanceof MobyDataType){
+            mobyDataType = (MobyDataType) templateObject;
+            name = ((MobyDataType) templateObject).getName();
+        }
+        else{
+            logger.error("Could not create submenu for object of unaccepted type "+templateObject.getClass().getName());
+        }
 	
-	// Make sure we have a fully documented data type object
-	mobyDataType = MobyDataType.getDataType(targetData.getDataType().getName(), SeahawkOptions.getRegistry());
 	String desc = null;
 	String datatype = null;
-	if(mobyDataType == null){
-	    logger.warn("PG: Warning (submenu): no datatype associated with service " + 
-			targetData.getName());
-	}
-	else{
+	if(mobyDataType != null){
 	    datatype = mobyDataType.getName();
 	    desc = mobyDataType.getDescription();
 	    if(desc == null || desc.length() == 0){
@@ -1189,19 +1236,12 @@
 	}
 	if(datatype != null && datatype.indexOf("objectclass:") != -1){ 
 	    //LSID type URN, truncate the prefix and keep the part a user would care about (last part, the class name)
-	    
 	    datatype = datatype.substring(datatype.indexOf("objectclass:")+12);
 	}
 
 	JMenu submenu = null;
-	MobyNamespace[] namespaces = targetData.getNamespaces();
 	// If not defined, derive a description from the Data Namespace
-	if(mobyDataType == null){
-	    desc = "Unknown datatype";
-	    submenu = new JMenu("Services for unknown datatype");
-	    assignMenuDataIndex(submenu);
-	}
-	else if("Object".equals(mobyDataType.getName())){
+	if(MobyTags.MOBYOBJECT.equals(mobyDataType.getName())){
 	    String mobydesc = "?";
 	    if(namespaces != null){
 		// Take the longest description
@@ -1214,20 +1254,30 @@
 		}
 	    }
 	    desc = "Record Identifier - " + mobydesc;
-	    submenu = new JMenu("Services for " + (extraMenuText == null ? "" : extraMenuText+" ")+datatype + ":" + id);
+	    if(templateObject instanceof MobyDataObjectSet){
+		datatype += " collection";
+	    }
+	    submenu = new JMenu("<html>Services for " + (extraMenuText == null ? "" : extraMenuText+" ") + 
+                                datatype + (id == null ? "" : ":" + id)+"</html>");
 	    assignMenuDataIndex(submenu);
 	}
-	else if("String".equals(mobyDataType.getName())){
-	    String sample = targetData.getName();
-	    if(sample == null){
-		sample = targetData.toString();
+	else if(MobyTags.MOBYSTRING.equals(mobyDataType.getName())){
+	    String sample = "";
+            if(templateObject instanceof MobyDataInstance){
+                sample = ((MobyDataInstance) templateObject).getName();
+                if(sample == null){
+		    sample = "\""+((MobyDataInstance) templateObject).toString()+"\"";
+	        }
+            }
+	    if(templateObject instanceof MobyDataObjectSet){
+		sample += " collection";
 	    }
 	    if(sample.length() > MAX_ID_LEN+3){
-		sample = sample.substring(0, MAX_ID_LEN)+"...";
+		sample = "\""+sample.substring(0, MAX_ID_LEN)+"...\"";
 	    }
 	    desc = "A piece of text";
-	    submenu = new JMenu("Services for "+(extraMenuText == null ? "" : extraMenuText+" ")+
-				"String \"" + sample + "\"");
+	    submenu = new JMenu("<html>Services for "+(extraMenuText == null ? "" : extraMenuText+" ")+
+				"String " + sample+"</html>");
 	    assignMenuDataIndex(submenu);
 	}
 	// Complex object
@@ -1240,17 +1290,18 @@
 		    desc += "["+namespaceDesc+"]";
 		}
 	    }
-	    if(targetData instanceof MobyDataObject && id != null && id.length() > 0){
+	    if(templateObject instanceof MobyDataObject && id != null && id.length() > 0){
 		objectLabel += ":" + id;
 	    }
-	    else if(targetData instanceof MobyDataObjectSet){
+	    else if(templateObject instanceof MobyDataObjectSet){
 		objectLabel += " collection";
 	    }
-	    submenu = new JMenu("Services for " + (extraMenuText == null ? "" : extraMenuText+" ")+objectLabel);
+	    submenu = new JMenu("<html>Services for " + (extraMenuText == null ? "" : extraMenuText+" ")+objectLabel+"</html>");
 	    assignMenuDataIndex(submenu);
 	}
 	desc = "Input data: " + desc;
 	desc = HTMLUtils.htmlifyToolTipText(desc, MAX_SERVICE_DESC_LEN);
+        System.err.println("New submenu has label " + submenu.getText());
 	submenu.setToolTipText(desc);
 	submenu.setName(SERVICE_SUBMENU_NAME);
 	return submenu;




More information about the MOBY-guts mailing list