You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/20 15:22:27 UTC

[13/51] [abbrv] [partial] incubator-taverna-workbench git commit: taverna-workbench-* -> taverna-*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/Integration.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/Integration.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/Integration.java
new file mode 100644
index 0000000..ec792d4
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/Integration.java
@@ -0,0 +1,518 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.log4j.Logger;
+import org.biocatalogue.x2009.xml.rest.ResourceLink;
+import org.biocatalogue.x2009.xml.rest.RestMethod;
+import org.biocatalogue.x2009.xml.rest.RestService;
+import org.biocatalogue.x2009.xml.rest.Service;
+import org.biocatalogue.x2009.xml.rest.ServiceTechnologyType;
+import org.biocatalogue.x2009.xml.rest.SoapOperation;
+import org.biocatalogue.x2009.xml.rest.SoapService;
+import org.biocatalogue.x2009.xml.rest.Service.Variants;
+
+import net.sf.taverna.biocatalogue.model.HTTPMethodInterpreter;
+import net.sf.taverna.biocatalogue.model.HTTPMethodInterpreter.UnsupportedHTTPMethodException;
+import net.sf.taverna.biocatalogue.model.Resource;
+import net.sf.taverna.biocatalogue.model.Resource.TYPE;
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.SoapOperationIdentity;
+import net.sf.taverna.biocatalogue.model.SoapOperationPortIdentity;
+import net.sf.taverna.biocatalogue.model.SoapProcessorIdentity;
+import net.sf.taverna.biocatalogue.model.Util;
+import net.sf.taverna.t2.activities.rest.RESTActivity;
+import net.sf.taverna.t2.activities.rest.RESTActivity.HTTP_METHOD;
+import net.sf.taverna.t2.activities.wsdl.WSDLActivity;
+import net.sf.taverna.t2.activities.wsdl.servicedescriptions.WSDLServiceDescription;
+import net.sf.taverna.t2.ui.menu.ContextualSelection;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponentFactory;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.service_panel.BioCatalogueRESTServiceProvider;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.service_panel.BioCatalogueWSDLOperationServiceProvider;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.service_panel.RESTFromBioCatalogueServiceDescription;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.service_panel.WSDLOperationFromBioCatalogueServiceDescription;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.workflowview.WorkflowView;
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+import net.sf.taverna.t2.workflowmodel.Port;
+import net.sf.taverna.t2.workflowmodel.Processor;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityOutputPort;
+import net.sf.taverna.t2.workflowmodel.utils.Tools;
+
+/**
+ * This class contains helpers for deeper integration with Taverna UI.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class Integration
+{
+  private static final Logger logger = Logger.getLogger(Integration.class);
+  
+  
+  // deny instantiation of this class
+  private Integration() { }
+  
+  
+  /**
+   * Adds a processor to the current workflow.
+   * The processor is specified by WSDL location and the operation name.
+   * 
+   * @param processorResource Resource to add to the current workflow.
+   * @return Outcome of inserting the processor into the current workflow as a
+   *         HTML-formatted string (with no opening and closing HTML tags).
+   */
+  public static JComponent insertProcessorIntoCurrentWorkflow(ResourceLink processorResource)
+  {
+    // check if this type of resource can be added to workflow diagram
+    TYPE resourceType = Resource.getResourceTypeFromResourceURL(processorResource.getHref());
+    if (resourceType.isSuitableForAddingToWorkflowDiagram()) {
+      switch (resourceType) {
+        case SOAPOperation:
+          SoapOperation soapOp = (SoapOperation) processorResource;
+          try {
+            SoapService soapService = BioCatalogueClient.getInstance().
+                                        getBioCatalogueSoapService(soapOp.getAncestors().getSoapService().getHref());
+            
+            try {
+              WSDLServiceDescription myServiceDescription = new WSDLServiceDescription();
+              myServiceDescription.setOperation(soapOp.getName());
+              myServiceDescription.setUse("literal"); // or "encoded"
+              myServiceDescription.setStyle("document"); // or "rpc"
+              myServiceDescription.setURI(new URI(soapService.getWsdlLocation()));
+              myServiceDescription.setDescription(StringEscapeUtils.escapeHtml(soapService.getDescription()));  // TODO - not sure where this is used
+              
+              if (WorkflowView.importServiceDescription(myServiceDescription, false) != null) {
+                return (new JLabel("Selected " + TYPE.SOAPOperation.getTypeName() + " was successfully added to the current workflow",
+                                 ResourceManager.getImageIcon(ResourceManager.TICK_ICON), JLabel.CENTER));
+              }
+              else {
+                return (new JLabel("<html><center>Taverna was unable to add selected " + TYPE.SOAPOperation.getTypeName() + 
+                    " as a service to the current workflow.<br>This could be because the service is currently not accessible.</center></html>",
+                    ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+              }
+            }
+            catch (URISyntaxException e)
+            {
+              logger.error("Couldn't add " + TYPE.SOAPOperation + " to the current workflow", e);
+              return (new JLabel("<html>Could not add the selected " + TYPE.SOAPOperation.getTypeName() + " to the current workflow.<br>" +
+                                    		"Log file will containt additional details about this error.</html>",
+                                    		ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+            }
+            
+          }
+          catch (Exception e) {
+            logger.error("Failed to fetch required details to add this " + TYPE.SOAPOperation + " into the current workflow.", e);
+            return (new JLabel("<html>Failed to fetch required details to add this<br>" +
+                                      TYPE.SOAPOperation.getTypeName() + " into the current workflow.</html>",
+                                      ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+          
+        case RESTMethod:
+          // received object may only contain limited data, therefore need to fetch full details first
+          try {
+            RestMethod restMethod = BioCatalogueClient.getInstance().
+                                                getBioCatalogueRestMethod(processorResource.getHref());
+            
+            // actual import of the service into the workflow
+            RESTFromBioCatalogueServiceDescription restServiceDescription = createRESTServiceDescriptionFromRESTMethod(restMethod);
+            WorkflowView.importServiceDescription(restServiceDescription, false);
+            
+            // prepare result of the operation to be shown in the the waiting dialog window
+            String warnings = extractWarningsFromRESTServiceDescription(restServiceDescription, false);
+            JLabel outcomes = new JLabel("<html>Selected " + TYPE.RESTMethod.getTypeName() + " was successfully added to the current workflow" + warnings + "</html>",
+                                         ResourceManager.getImageIcon(warnings.length() > 0 ? ResourceManager.WARNING_ICON : ResourceManager.TICK_ICON),
+                                         JLabel.CENTER);
+            outcomes.setIconTextGap(20);
+            return (outcomes);
+          }
+          catch (UnsupportedHTTPMethodException e) {
+            logger.error(e);
+            return (new JLabel(e.getMessage(), ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+          catch (Exception e) {
+            logger.error("Failed to fetch required details to add this " + TYPE.RESTMethod + " as a service to the current workflow.", e);
+            return (new JLabel("<html>Failed to fetch required details to add this " + TYPE.RESTMethod.getTypeName() + "<br>" +
+            		                      "as a service to the current workflow.</html>",
+                                      ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+        
+        // type not currently supported, but maybe in the future?
+        default: return (new JLabel("Adding " + resourceType.getCollectionName() + " to the current workflow is not yet possible",
+                                     ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+      }
+    }
+    
+    // definitely not supported type
+    return (new JLabel("<html>It is not possible to add resources of the provided type<br>" +
+                              "into the current workflow.</html>",
+                              ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+  }
+  
+  
+  /**
+   * 
+   * @param processorResource
+   * @return Outcome of inserting the processor into the current workflow as a
+   *         HTML-formatted string (with no opening and closing HTML tags).
+   */
+  public static JComponent insertProcesorIntoServicePanel(ResourceLink processorResource)
+  {
+    // check if this type of resource can be added to Service Panel
+    TYPE resourceType = Resource.getResourceTypeFromResourceURL(processorResource.getHref());
+    if (resourceType.isSuitableForAddingToServicePanel()) {
+      switch (resourceType) {
+        case SOAPOperation:
+          SoapOperation soapOp = (SoapOperation) processorResource;
+          try {
+            SoapService soapService = BioCatalogueClient.getInstance().
+                                        getBioCatalogueSoapService(soapOp.getAncestors().getSoapService().getHref());
+            SoapOperationIdentity soapOpId = new SoapOperationIdentity(soapService.getWsdlLocation(), soapOp.getName(), StringEscapeUtils.escapeHtml(soapOp.getDescription()));
+            WSDLOperationFromBioCatalogueServiceDescription wsdlOperationDescription = new WSDLOperationFromBioCatalogueServiceDescription(soapOpId);
+            BioCatalogueWSDLOperationServiceProvider.registerWSDLOperation(wsdlOperationDescription, null);
+            
+            return (new JLabel("Selected SOAP operation has been successfully added to the Service Panel.", 
+                               ResourceManager.getImageIcon(ResourceManager.TICK_ICON), JLabel.CENTER));
+          }
+          catch (Exception e) {
+            logger.error("Failed to fetch required details to add this SOAP service into the Service Panel.", e);
+            return (new JLabel("Failed to fetch required details to add this " +
+                               "SOAP service into the Service Panel.", ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+          
+        case RESTMethod:
+          try {
+            // received object may only contain limited data, therefore need to fetch full details first
+            RestMethod restMethod = BioCatalogueClient.getInstance().
+                                                  getBioCatalogueRestMethod(processorResource.getHref());
+            RESTFromBioCatalogueServiceDescription restServiceDescription = createRESTServiceDescriptionFromRESTMethod(restMethod);
+            
+            // actual insertion of the REST method into Service Panel
+            BioCatalogueRESTServiceProvider.registerNewRESTMethod(restServiceDescription, null);
+            
+            // prepare result of the operation to be shown in the the waiting dialog window
+            String warnings = extractWarningsFromRESTServiceDescription(restServiceDescription, true);
+            JLabel outcomes = new JLabel("<html>Selected REST method has been successfully added to the Service Panel" + warnings + "</html>", 
+                                         ResourceManager.getImageIcon(warnings.length() > 0 ? ResourceManager.WARNING_ICON : ResourceManager.TICK_ICON),
+                                         JLabel.CENTER);
+            outcomes.setIconTextGap(20);
+            return (outcomes);
+          }
+          catch (UnsupportedHTTPMethodException e) {
+            logger.error(e);
+            return (new JLabel(e.getMessage(), ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+          catch (Exception e) {
+            logger.error("Failed to fetch required details to add this REST service into the Service Panel.", e);
+            return (new JLabel("Failed to fetch required details to add this " +
+                "REST service into the Service Panel.", ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+          }
+        
+        // type not currently supported, but maybe in the future?
+        default: return (new JLabel("Adding " + resourceType.getCollectionName() + " to the Service Panel is not yet possible",
+            ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+      }
+    }
+    
+    // definitely not supported type
+    return (new JLabel("<html>It is not possible to add resources of the provided type<br>" +
+                              "into the Service Panel.</html>",
+                              ResourceManager.getImageIcon(ResourceManager.ERROR_ICON), JLabel.CENTER));
+  }
+  
+  /**
+   * Inserts all operations of the given parent SOAP or REST Web service resource link
+   * into Service Panel. Works for SOAP operations only at the moment.
+   * 
+   * @return Outcome of inserting operations into Service Panel as a
+   *         HTML-formatted string (with no opening and closing HTML tags).
+   */
+  public static JComponent insertAllOperationsIntoServicePanel(ResourceLink serviceResource)
+  {
+		// Check if this type of resource is a parent SOAP Web service
+		// whose operations can be added to the Service Panel
+		TYPE resourceType = Resource
+				.getResourceTypeFromResourceURL(serviceResource.getHref());
+		
+		Service service = null;
+		if (resourceType == TYPE.SOAPOperation) {
+			SoapService soapService = ((SoapOperation) serviceResource)
+					.getAncestors().getSoapService();
+
+			// Get the WSDL URL of the SOAP service
+			String wsdlURL = soapService.getWsdlLocation();
+
+			// Import this WSDL into Service panel - it will add all
+			// of
+			// its operations
+			if (BioCatalogueWSDLOperationServiceProvider.registerWSDLService(
+					wsdlURL, null)) {
+				return (new JLabel(
+						"Operation(s) of the SOAP service have been successfully added to the Service Panel.",
+						ResourceManager.getImageIcon(ResourceManager.TICK_ICON),
+						JLabel.CENTER));
+			} else {
+				return (new JLabel(
+						"Failed to insert the operations of the SOAP service "
+								+ " to the Service Panel.", ResourceManager
+								.getImageIcon(ResourceManager.ERROR_ICON),
+						JLabel.CENTER));
+			}
+		} else if (resourceType == TYPE.RESTMethod) {
+			RestService restService = ((RestMethod) serviceResource)
+			.getAncestors().getRestService();
+			for (RestMethod method : restService.getMethods().getRestMethodList()) {
+				
+			}
+		}
+
+		return (new JLabel(
+				"<html>It is not possible to add resources of the provided type<br>"
+						+ "into the Service Panel.</html>", ResourceManager
+						.getImageIcon(ResourceManager.ERROR_ICON),
+				JLabel.CENTER));
+	}
+
+  /**
+   * Instantiates a {@link RESTFromBioCatalogueServiceDescription} object from the {@link RestMethod}
+   * XML data obtained from BioCatalogue API.
+   * 
+   * @param restMethod
+   * @return
+   */
+  public static RESTFromBioCatalogueServiceDescription createRESTServiceDescriptionFromRESTMethod(RestMethod restMethod) throws UnsupportedHTTPMethodException
+  {
+    // if the type of the HTTP method is not supported, an exception will be throws
+    HTTP_METHOD httpMethod = HTTPMethodInterpreter.getHTTPMethodForRESTActivity(restMethod.getHttpMethodType());
+    
+    RESTFromBioCatalogueServiceDescription restServiceDescription = new RESTFromBioCatalogueServiceDescription();
+    restServiceDescription.setServiceName(Resource.getDisplayNameForResource(restMethod));
+    restServiceDescription.setDescription(StringEscapeUtils.escapeHtml(restMethod.getDescription()));
+    restServiceDescription.setHttpMethod(httpMethod);
+    restServiceDescription.setURLSignature(restMethod.getUrlTemplate());
+    
+    int outputRepresentationCount = restMethod.getOutputs().getRepresentations().getRestRepresentationList().size();
+    if (outputRepresentationCount > 0) {
+      if (outputRepresentationCount > 1) {
+        restServiceDescription.getDataWarnings().add(RESTFromBioCatalogueServiceDescription.AMBIGUOUS_ACCEPT_HEADER_VALUE);
+      }
+      restServiceDescription.setAcceptHeaderValue(restMethod.getOutputs().getRepresentations().getRestRepresentationList().get(0).getContentType());
+    }
+    else {
+      restServiceDescription.getDataWarnings().add(RESTFromBioCatalogueServiceDescription.DEFAULT_ACCEPT_HEADER_VALUE);
+    }
+    
+    int inputRepresentationCount = restMethod.getInputs().getRepresentations().getRestRepresentationList().size();
+    if (inputRepresentationCount > 0) {
+      if (inputRepresentationCount > 1) {
+        restServiceDescription.getDataWarnings().add(RESTFromBioCatalogueServiceDescription.AMBIGUOUS_CONTENT_TYPE_HEADER_VALUE);
+      }
+      restServiceDescription.setOutgoingContentType(restMethod.getInputs().getRepresentations().getRestRepresentationList().get(0).getContentType());
+    }
+    else if (RESTActivity.hasMessageBodyInputPort(httpMethod)) {
+      restServiceDescription.getDataWarnings().add(RESTFromBioCatalogueServiceDescription.DEFAULT_CONTENT_TYPE_HEADER_VALUE);
+    }
+    
+    return (restServiceDescription);
+  }
+  
+  
+  /**
+   * @param restServiceDescription {@link RESTFromBioCatalogueServiceDescription} to process.
+   * @param addingToServicePanel <code>true</code> indicates that the warning messages
+   *                             will assume that the processor is added to the service panel;
+   *                             <code>false</code> would mean that the processor is added to
+   *                             the current workflow.
+   * @return An HTML-formatted string (with no opening-closing HTML tags) that lists
+   *         any warnings that have been recorded during the {@link RESTFromBioCatalogueServiceDescription}
+   *         object creation. Empty string will be returned if there are no warnings.
+   */
+  public static String extractWarningsFromRESTServiceDescription(RESTFromBioCatalogueServiceDescription restServiceDescription,
+      boolean addingToServicePanel)
+  {
+    String messageSuffix = addingToServicePanel ?
+                           " once you add it into the workflow" :
+                           "";
+    
+    String warnings = "";
+    if (restServiceDescription.getDataWarnings().contains(RESTFromBioCatalogueServiceDescription.AMBIGUOUS_ACCEPT_HEADER_VALUE)) {
+        warnings += "<br><br>Service Catalogue description of this REST method contains more than one<br>" +
+                            "representation of the method's outputs - the first one was used.<br>" +
+                            "Please check value of the 'Accept' header in the configuration<br>" +
+                            "of the imported service" + messageSuffix + ".";
+    }
+    else if (restServiceDescription.getDataWarnings().contains(RESTFromBioCatalogueServiceDescription.DEFAULT_ACCEPT_HEADER_VALUE)) {
+      warnings += "<br><br>Service Catalogue description of this REST method does not contain any<br>" +
+                          "representations of the method's outputs - default value was used.<br>" +
+                          "Please check value of the 'Accept' header in the configuration<br>" +
+                          "of the imported service" + messageSuffix + ".";
+    }
+    
+    if (restServiceDescription.getDataWarnings().contains(RESTFromBioCatalogueServiceDescription.AMBIGUOUS_CONTENT_TYPE_HEADER_VALUE)) {
+        warnings += "<br><br>Service Catalogue description of this REST method contains more than one<br>" +
+                            "representation of the method's input data - the first one was used.<br>" +
+                            "Please check value of the 'Content-Type' header in the configuration<br>" +
+                            "of the imported service" + messageSuffix + ".";
+    }
+    else if (restServiceDescription.getDataWarnings().contains(RESTFromBioCatalogueServiceDescription.DEFAULT_CONTENT_TYPE_HEADER_VALUE)) {
+      warnings += "<br><br>Service Catalogue description of this REST method does not contain any<br>" +
+                          "representations of the method's input data - default value was used.<br>" +
+                          "Please check value of the 'Content-Type' header in the configuration<br>" +
+                          "of the imported service" + messageSuffix + ".";
+    }
+    
+    if (warnings.length() > 0) {
+      warnings = "<br><br>WARNINGS:" + warnings;
+    }
+    
+    return (warnings);
+  }
+  
+  
+  
+  /**
+   * @param activityPort Probably comes from contextual selection - must be either
+   *         ActivityInputPort or ActivityOutputPort.
+   * @return SOAP input / output port details (WSDL location, operation name, port name) from
+   *         ActivityInputPort/ActivityOutputPort which is obtained from contextual selection in the Dataflow.
+   */
+  public static <T extends Port> SoapOperationPortIdentity extractSoapOperationPortDetailsFromActivityInputOutputPort(T activityPort)
+  {
+    // check that we have the correct instance of Port here - either ActivityInputPort or ActivityOutputPort
+    boolean hasInputPort;
+    if (activityPort instanceof ActivityInputPort) {
+      hasInputPort = true;
+    }
+    else if (activityPort instanceof ActivityOutputPort) {
+      hasInputPort = false;
+    }
+    else {
+      // ERROR - wrong type supplied
+      return new SoapOperationPortIdentity("Activity port from the contextual selection was not of correct type. Impossible to create preview.");
+    }
+    
+    // get parent processor details
+    Dataflow currentDataflow = FileManager.getInstance().getCurrentDataflow();
+    Collection<Processor> processors = null;
+    if (hasInputPort) {
+      processors = Tools.getProcessorsWithActivityInputPort(currentDataflow, (ActivityInputPort)activityPort);
+    }
+    else {
+      processors = Tools.getProcessorsWithActivityOutputPort(currentDataflow, (ActivityOutputPort)activityPort);
+    }
+    
+    // TODO - doesn't take into account that it's possible to have several
+    SoapOperationIdentity soapOperationDetails = extractSoapOperationDetailsFromProcessor(processors.toArray(new Processor[]{})[0]);
+    
+    // if no error happened, add port details and return
+    if (!soapOperationDetails.hasError()) {
+      return (new SoapOperationPortIdentity(soapOperationDetails.getWsdlLocation(),
+                                             soapOperationDetails.getOperationName(),
+                                             activityPort.getName(), hasInputPort));
+    }
+    else {
+      // error...
+      return (new SoapOperationPortIdentity(soapOperationDetails.getErrorDetails()));
+    }
+  }
+  
+  
+  /**
+   * Uses contextual selection to extract WSDL location and operation name of the
+   * currently selected processor within the Design view of current workflow. 
+   * 
+   * @param contextualSelection Selection that was made in the Design view.
+   * @return Details of the SOAP operation that acts as a processor wrapped into
+   *         this single instance. If any problems occurred while performing
+   *         contextual selection analysis, these are also recorded into the same
+   *         instance - before using the returned value the caller must check
+   *         <code>SoapOperationIdentity.hasError()</code> value.
+   */
+  public static SoapOperationIdentity extractSoapOperationDetailsFromProcessorContextualSelection(ContextualSelection contextualSelection)
+  {
+    if (!(contextualSelection.getSelection() instanceof Processor)) {
+      return (new SoapOperationIdentity("ERROR: It is only possible to extract " +
+      		"SOAP operation details from the service."));
+    }
+    
+    // now we know it's a Processor
+    Processor processor = (Processor)contextualSelection.getSelection();
+    return (extractSoapOperationDetailsFromProcessor(processor));
+  }
+  
+  
+  /**
+   * Worker method for <code>extractSoapOperationDetailsFromProcessorContextualSelection()</code>.
+   * 
+   * @param processor
+   * @return
+   */
+  public static SoapOperationIdentity extractSoapOperationDetailsFromProcessor(Processor processor)
+  {
+    List<? extends Activity> activityList = (List<? extends Activity>) processor.getActivityList();
+    
+    if (activityList == null || activityList.size() == 0) {
+      return (new SoapOperationIdentity("ERROR: Selected processor doesn't have any activities - " +
+          "impossible to extract SOAP operation details."));
+    }
+    else {
+      // take only the first activity - TODO: figure out what should be done here...
+      Activity activity = activityList.get(0);
+      if (activity instanceof WSDLActivity) {
+        WSDLActivity a = (WSDLActivity)activity;
+        return (new SoapOperationIdentity(a.getConfiguration().getWsdl(), a.getConfiguration().getOperation(), null));
+      }
+      else {
+        return (new SoapOperationIdentity("Service Catalogue integration only works with WSDL Activities at the moment"));
+      }
+    }
+  }
+  
+  
+  /**
+   * @param contextualSelection
+   * @return A list of all WSDL activities (the only supported processors by BioCatalogue plugin for now).
+   */
+  public static List<SoapProcessorIdentity> extractSupportedProcessorsFromDataflow(ContextualSelection contextualSelection)
+  {
+    // check that there was a correct contextual selection
+    if (!(contextualSelection.getSelection() instanceof Dataflow)) {
+      logger.error("It is only possible to extract supported services from the workflow.");
+      return (new ArrayList<SoapProcessorIdentity>());
+    }
+    
+    // first extract all processors
+    Dataflow dataflow = (Dataflow)contextualSelection.getSelection();
+    List<? extends Processor> allProcessors = dataflow.getEntities(Processor.class);
+    
+    // now filter out any processors that are not WSDL activities
+    List<SoapProcessorIdentity> supportedProcessors = new ArrayList<SoapProcessorIdentity>();
+    for (Processor proc : allProcessors) {
+      List<? extends Activity> activityList = (List<? extends Activity>) proc.getActivityList();
+      if (activityList != null && activityList.size() > 0) {
+        // take only the first activity - TODO: figure out what should be done here...
+        Activity activity = activityList.get(0);
+        if (activity instanceof WSDLActivity) {
+          WSDLActivity a = (WSDLActivity)activity;
+          supportedProcessors.add(new SoapProcessorIdentity(a.getConfiguration().getWsdl(),
+                                                            a.getConfiguration().getOperation(),
+                                                            proc.getLocalName()));
+        }
+      }
+    }
+    
+    // return all found processors
+    return (supportedProcessors);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfiguration.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfiguration.java
new file mode 100644
index 0000000..3985ac5
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfiguration.java
@@ -0,0 +1,68 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.org.taverna.configuration.AbstractConfigurable;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+
+/**
+ *
+ *
+ * @author Sergejs Aleksejevs
+ */
+public class BioCataloguePluginConfiguration extends AbstractConfigurable
+{
+  public static final String SERVICE_CATALOGUE_BASE_URL = "ServiceCatalogue_Base_URL";
+  public static final String SOAP_OPERATIONS_IN_SERVICE_PANEL = "SOAP_Operations_in_Service_Panel";
+  public static final String REST_METHODS_IN_SERVICE_PANEL = "REST_Methods_in_Service_Panel";
+
+
+  private static class Singleton {
+    private static BioCataloguePluginConfiguration instance = new BioCataloguePluginConfiguration();
+  }
+
+  // private static Logger logger = Logger.getLogger(MyExperimentConfiguration.class);
+
+  private Map<String, String> defaultPropertyMap;
+
+
+  public static BioCataloguePluginConfiguration getInstance() {
+    return Singleton.instance;
+  }
+
+  public String getCategory() {
+    return "general";
+  }
+
+  public Map<String,String> getDefaultPropertyMap() {
+    if (defaultPropertyMap == null) {
+      defaultPropertyMap = new HashMap<String,String>();
+      defaultPropertyMap.put(SERVICE_CATALOGUE_BASE_URL, BioCatalogueClient.DEFAULT_API_LIVE_SERVER_BASE_URL);
+    }
+    return defaultPropertyMap;
+  }
+
+  public String getDisplayName() {
+    return "Service catalogue";
+  }
+
+  public String getFilePrefix() {
+    return "ServiceCatalogue";
+  }
+
+  public String getUUID() {
+    return "4daac25c-bd56-4f90-b909-1e49babe5197";
+  }
+
+
+  /**
+   * Just a "proxy" method - {@link AbstractConfigurable#store()}
+   * is not visible to the users of instances of this class otherwise.
+   */
+  public void store() {
+    super.store();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationPanel.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationPanel.java
new file mode 100644
index 0000000..a83a223
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationPanel.java
@@ -0,0 +1,448 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.config;
+
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProxySelector;
+import java.net.URL;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+//import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.log4j.Logger;
+import org.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.input.SAXBuilder;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponentFactory;
+
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+@SuppressWarnings("serial")
+public class BioCataloguePluginConfigurationPanel extends JPanel
+{
+	public static final String APPLICATION_XML_MIME_TYPE = "application/xml";
+
+	public static String PROXY_HOST = "http.proxyHost";
+	public static String PROXY_PORT = "http.proxyPort";
+	public static String PROXY_USERNAME = "http.proxyUser";
+	public static String PROXY_PASSWORD = "http.proxyPassword";
+	
+	// 1.0.0b and higher until the first digit changes, as according to "Semantic Versioning" 
+	// from http://www.biocatalogue.org/wiki/doku.php?id=public:api:changelog
+	// "Major version X (X.y.z | X > 0) MUST be incremented if any backwards 
+	// incompatible changes are introduced to the public API. It MAY include minor and patch level changes."
+	public static String[] MIN_SUPPORTED_BIOCATALOGUE_API_VERSION = {"1", "1", "0"}; // major, minor and patch versions
+	public static String API_VERSION = "apiVersion";
+
+	private BioCataloguePluginConfiguration configuration = 
+                          BioCataloguePluginConfiguration.getInstance();
+  
+  
+	// UI elements
+	JTextField tfBioCatalogueAPIBaseURL;
+
+	private Logger logger = Logger.getLogger(BioCataloguePluginConfigurationPanel.class);  
+  
+	public BioCataloguePluginConfigurationPanel() {
+		initialiseUI();
+		resetFields();
+	}
+  
+  private void initialiseUI()
+  {
+    this.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.anchor = GridBagConstraints.NORTHWEST;
+    c.weightx = 1.0;
+    
+    c.gridx = 0;
+    c.gridy = 0;
+    JTextArea taDescription = new JTextArea("Configure the Service Catalogue integration functionality");
+    taDescription.setFont(taDescription.getFont().deriveFont(Font.PLAIN, 11));
+    taDescription.setLineWrap(true);
+    taDescription.setWrapStyleWord(true);
+    taDescription.setEditable(false);
+    taDescription.setFocusable(false);
+    taDescription.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+    this.add(taDescription, c);
+    
+    
+    c.gridy++;
+    c.insets = new Insets(20, 0, 0, 0);
+    JLabel jlBioCatalogueAPIBaseURL = new JLabel("Base URL of the Service Catalogue instance to connect to:");
+    this.add(jlBioCatalogueAPIBaseURL, c);
+    
+    c.gridy++;
+    c.insets = new Insets(0, 0, 0, 0);
+    tfBioCatalogueAPIBaseURL = new JTextField();
+    this.add(tfBioCatalogueAPIBaseURL, c);
+    
+    
+    c.gridy++;
+    c.insets = new Insets(30, 0, 0, 0);
+    // We are not removing BioCatalogue services from its config panel any more - 
+    // they are being handled by the Taverna's Service Registry
+//    JButton bForgetStoredServices = new JButton("Forget services added to Service Panel by BioCatalogue Plugin");
+//    bForgetStoredServices.addActionListener(new ActionListener() {
+//      public void actionPerformed(ActionEvent e)
+//      {
+//        int response = JOptionPane.showConfirmDialog(null, // no way T2ConfigurationFrame instance can be obtained to be used as a parent...
+//                                       "Are you sure you want to clear all SOAP operations and REST methods\n" +
+//                                       "that were added to the Service Panel by the BioCatalogue Plugin?\n\n" +
+//                                       "This action is permanent is cannot be undone.\n\n" +
+//                                       "Do you want to proceed?", "BioCatalogue Plugin", JOptionPane.YES_NO_OPTION);
+//        
+//        if (response == JOptionPane.YES_OPTION)
+//        {
+//          BioCatalogueServiceProvider.clearRegisteredServices();
+//          JOptionPane.showMessageDialog(null,  // no way T2ConfigurationFrame instance can be obtained to be used as a parent...
+//                          "Stored services have been successfully cleared, but will remain\n" +
+//                          "being shown in Service Panel during this session.\n\n" +
+//                          "They will not appear in the Service Panel after you restart Taverna.",
+//                          "BioCatalogue Plugin", JOptionPane.INFORMATION_MESSAGE);
+//        }
+//      }
+//    });
+//    this.add(bForgetStoredServices, c);
+    
+    
+    JButton bLoadDefaults = new JButton("Load Defaults");
+    bLoadDefaults.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        loadDefaults();
+      }
+    });
+    
+    JButton bReset = new JButton("Reset");
+    bReset.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        resetFields();
+      }
+    });
+    
+    JButton bApply = new JButton("Apply");
+    bApply.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        applyChanges();
+      }
+    });
+    
+    JPanel jpActionButtons = new JPanel();
+    jpActionButtons.add(bLoadDefaults);
+    jpActionButtons.add(bReset);
+    jpActionButtons.add(bApply);
+    c.insets = new Insets(30, 0, 0, 0);
+    c.gridy++;
+    c.weighty = 1.0;
+    this.add(jpActionButtons, c);
+  }
+  
+  
+  /**
+   * Resets all fields to the last saved configuration.
+   */
+  private void resetFields() {
+    tfBioCatalogueAPIBaseURL.setText(configuration.getProperty(BioCataloguePluginConfiguration.SERVICE_CATALOGUE_BASE_URL));
+  }
+  
+  /**
+   * Resets all fields to the default values.
+   */
+  private void loadDefaults() {
+    tfBioCatalogueAPIBaseURL.setText(configuration.getDefaultProperty(BioCataloguePluginConfiguration.SERVICE_CATALOGUE_BASE_URL));
+  }
+  
+  /**
+   * Saves recent changes to the configuration parameter map.
+   * Some input validation is performed as well.
+   */
+	private void applyChanges() {
+		// --- BioCatalogue BASE URL ---
+
+		String candidateBaseURL = tfBioCatalogueAPIBaseURL.getText();
+		if (candidateBaseURL.length() == 0) {
+			JOptionPane.showMessageDialog(this,
+					"Service Catalogue base URL must not be blank",
+					"Service Catalogue Configuration", JOptionPane.WARNING_MESSAGE);
+			tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+			return;
+		} else {
+			try {
+				new URL(candidateBaseURL);
+			} catch (MalformedURLException e) {
+				JOptionPane
+						.showMessageDialog(
+								this,
+								"Currently set Service Catalogue instance URL is not valid\n." +
+								"Please check the URL and try again.",
+								"Service Catalogue Configuration",
+								JOptionPane.WARNING_MESSAGE);
+				tfBioCatalogueAPIBaseURL.selectAll();
+				tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+				return;
+			}
+
+			// check if the base URL has changed from the last saved state
+			if (!candidateBaseURL
+					.equals(configuration
+							.getProperty(BioCataloguePluginConfiguration.SERVICE_CATALOGUE_BASE_URL))) {
+					// Perform various checks on the new URL
+
+				// Do a GET with "Accept" header set to "application/xml"
+				// We are expecting a 200 OK and an XML doc in return that
+				// contains the BioCataogue version number element.
+				DefaultHttpClient httpClient = new DefaultHttpClient();
+				
+				// Set the proxy settings, if any
+				if (System.getProperty(PROXY_HOST) != null
+						&& !System.getProperty(PROXY_HOST).equals("")) {
+					// Instruct HttpClient to use the standard
+					// JRE proxy selector to obtain proxy information
+					ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
+							httpClient.getConnectionManager().getSchemeRegistry(), ProxySelector
+									.getDefault());
+					httpClient.setRoutePlanner(routePlanner);
+					// Do we need to authenticate the user to the proxy?
+					if (System.getProperty(PROXY_USERNAME) != null
+							&& !System.getProperty(PROXY_USERNAME).equals("")) {
+						// Add the proxy username and password to the list of credentials
+						httpClient.getCredentialsProvider().setCredentials(
+								new AuthScope(System.getProperty(PROXY_HOST),Integer.parseInt(System.getProperty(PROXY_PORT))),
+								new UsernamePasswordCredentials(System.getProperty(PROXY_USERNAME), System.getProperty(PROXY_PASSWORD)));
+					}
+				}
+				
+				HttpGet httpGet = new HttpGet(candidateBaseURL);
+				httpGet.setHeader("Accept", APPLICATION_XML_MIME_TYPE);
+
+				// Execute the request
+				HttpContext localContext = new BasicHttpContext();
+				HttpResponse httpResponse;
+				try {
+					httpResponse = httpClient.execute(httpGet, localContext);
+				} catch (Exception ex1) {
+					logger.error("Service Catalogue preferences configuration: Failed to do "
+							+ httpGet.getRequestLine(), ex1);
+					// Warn the user
+					JOptionPane.showMessageDialog(this,
+							"Failed to connect to the URL of the Service Catalogue instance.\n"
+									+ "Please check the URL and try again.",
+							"Service Catalogue Configuration",
+							JOptionPane.INFORMATION_MESSAGE);
+					
+					// Release resource
+					httpClient.getConnectionManager().shutdown();
+					
+					tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+					return;
+				}
+
+				if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) { // HTTP/1.1 200 OK
+					HttpEntity httpEntity = httpResponse.getEntity();
+					String contentType = httpEntity.getContentType().getValue()
+							.toLowerCase().trim();
+					logger
+							.info("Service Catalogue preferences configuration: Got 200 OK when testing the Service Catalogue instance by doing "
+									+ httpResponse.getStatusLine()
+									+ ". Content type of response "
+									+ contentType);
+					if (contentType.startsWith(APPLICATION_XML_MIME_TYPE)) {
+						String value = null;
+						Document doc = null;
+						try {
+							value = readResponseBodyAsString(httpEntity)
+									.trim();
+							// Try to read this string into an XML document
+							SAXBuilder builder = new SAXBuilder();
+							byte[] bytes = value.getBytes("UTF-8");
+							doc = builder.build(new ByteArrayInputStream(bytes));
+						} catch (Exception ex2) {
+							logger.error("Service Catalogue preferences configuration: Failed to build an XML document from the response.", ex2);
+							// Warn the user
+							JOptionPane.showMessageDialog(this,
+									"Failed to get the expected response body when testing the Service Catalogue instance.\n"
+											+ "The URL is probably wrong. Please check it and try again.",
+									"Service Catalogue Configuration",
+									JOptionPane.INFORMATION_MESSAGE);
+							tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+							return;
+						}
+						finally{
+							// Release resource
+							httpClient.getConnectionManager().shutdown();
+						}
+						// Get the version element from the XML document
+						Attribute apiVersionAttribute = doc.getRootElement().getAttribute(API_VERSION);
+						if (apiVersionAttribute != null){
+							String apiVersion = apiVersionAttribute.getValue();
+							String versions[] = apiVersion.split("[.]");
+							String majorVersion = versions[0];
+							String minorVersion = versions[1];
+							try {
+							//String patchVersion = versions[2]; // we are not comparing the patch versions
+							String supportedMajorVersion = MIN_SUPPORTED_BIOCATALOGUE_API_VERSION[0];
+							String supportedMinorVersion = MIN_SUPPORTED_BIOCATALOGUE_API_VERSION[1];
+							Integer iSupportedMajorVersion = Integer.parseInt(supportedMajorVersion);
+							Integer iMajorVersion = Integer.parseInt(majorVersion);
+							Integer iSupportedMinorVersion = Integer.parseInt(supportedMinorVersion);
+							Integer iMinorVersion = Integer.parseInt(minorVersion);
+							if (!(iSupportedMajorVersion == iMajorVersion && 
+									iSupportedMinorVersion <= iMinorVersion)){
+								// Warn the user
+								JOptionPane
+										.showMessageDialog(
+												this,
+												"The version of the Service Catalogue instance you are trying to connect to is not supported.\n"
+														+ "Please change the URL and try again.",
+												"Service Catalogue Configuration",
+												JOptionPane.INFORMATION_MESSAGE);
+								tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+								return;		
+							}
+							} catch (Exception e) {
+								logger.error(e);
+							}
+						} // if null - we'll try to do our best to connect to BioCatalogue anyway
+					} else {
+						logger
+								.error("Service Catalogue preferences configuration: Failed to get the expected response content type when testing the Service Catalogue instance. "
+										+ httpGet.getRequestLine()
+										+ " returned content type '"
+										+ contentType
+										+ "'; expected response content type is 'application/xml'.");
+						// Warn the user
+						JOptionPane
+								.showMessageDialog(
+										this,
+										"Failed to get the expected response content type when testing the Service Catalogue instance.\n"
+										+ "The URL is probably wrong. Please check it and try again.",
+										"Service Catalogue Plugin",
+										JOptionPane.INFORMATION_MESSAGE);
+						tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+						return;
+					}
+				}
+				else{
+					logger
+							.error("Service Catalogue preferences configuration: Failed to get the expected response status code when testing the Service Catalogue instance. "
+									+ httpGet.getRequestLine()
+									+ " returned the status code "
+									+ httpResponse.getStatusLine()
+											.getStatusCode() + "; expected status code is 200 OK.");
+					// Warn the user
+					JOptionPane
+							.showMessageDialog(
+									this,
+									"Failed to get the expected response status code when testing the Service Catalogue instance.\n"
+									+ "The URL is probably wrong. Please check it and try again.",
+									"Service Catalogue Configuration",
+									JOptionPane.INFORMATION_MESSAGE);
+					tfBioCatalogueAPIBaseURL.requestFocusInWindow();
+					return;					
+				}
+
+				// Warn the user of the changes in the BioCatalogue base URL
+				JOptionPane
+						.showMessageDialog(
+								this,
+								"You have updated the Service Catalogue base URL.\n"
+										+ "This does not take effect until you restart Taverna.",
+										"Service catalogue Configuration",
+								JOptionPane.INFORMATION_MESSAGE);
+
+			}
+
+			// the new base URL seems to be valid - can save it into config
+			// settings
+			configuration.setProperty(
+					BioCataloguePluginConfiguration.SERVICE_CATALOGUE_BASE_URL,
+					candidateBaseURL);
+
+/*			// also update the base URL in the BioCatalogueClient
+			BioCatalogueClient.getInstance()
+					.setBaseURL(candidateBaseURL);*/
+		}
+
+	}
+  
+  
+  /**
+   * For testing only.
+   */
+  public static void main(String[] args) {
+    JFrame theFrame = new JFrame();
+    theFrame.add(new BioCataloguePluginConfigurationPanel());
+    theFrame.pack();
+    theFrame.setLocationRelativeTo(null);
+    theFrame.setVisible(true);
+  }
+
+	/**
+	 * Worker method that extracts the content of the received HTTP message as a
+	 * string. It also makes use of the charset that is specified in the
+	 * Content-Type header of the received data to read it appropriately.
+	 * 
+	 * @param entity
+	 * @return
+	 * @throws IOException
+	 */
+	// Taken from HTTPRequestHandler in rest-activity by Sergejs Aleksejevs
+	private static String readResponseBodyAsString(HttpEntity entity)
+			throws IOException {
+		// get charset name
+		String charset = null;
+		String contentType = entity.getContentType().getValue().toLowerCase();
+
+		String[] contentTypeParts = contentType.split(";");
+		for (String contentTypePart : contentTypeParts) {
+			contentTypePart = contentTypePart.trim();
+			if (contentTypePart.startsWith("charset=")) {
+				charset = contentTypePart.substring("charset=".length());
+			}
+		}
+
+		// read the data line by line
+		StringBuilder responseBodyString = new StringBuilder();
+		BufferedReader reader = new BufferedReader(new InputStreamReader(entity
+				.getContent(), charset));
+
+		String str;
+		while ((str = reader.readLine()) != null) {
+			responseBodyString.append(str + "\n");
+		}
+
+		return (responseBodyString.toString());
+	}
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationUIFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationUIFactory.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationUIFactory.java
new file mode 100644
index 0000000..f5baa70
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/config/BioCataloguePluginConfigurationUIFactory.java
@@ -0,0 +1,27 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.config;
+
+import javax.swing.JPanel;
+
+import uk.org.taverna.configuration.Configurable;
+import uk.org.taverna.configuration.ConfigurationUIFactory;
+
+/**
+ *
+ * @author Sergejs Aleksejevs
+ */
+public class BioCataloguePluginConfigurationUIFactory implements ConfigurationUIFactory
+{
+
+  public boolean canHandle(String uuid) {
+    return uuid.equals(getConfigurable().getUUID());
+  }
+
+  public Configurable getConfigurable() {
+    return BioCataloguePluginConfiguration.getInstance();
+  }
+
+  public JPanel getConfigurationPanel() {
+    return new BioCataloguePluginConfigurationPanel();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginInputPortContextViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginInputPortContextViewFactory.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginInputPortContextViewFactory.java
new file mode 100644
index 0000000..d067cce
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginInputPortContextViewFactory.java
@@ -0,0 +1,45 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.biocatalogue.model.SoapOperationPortIdentity;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.Integration;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
+
+
+public class BioCataloguePluginInputPortContextViewFactory implements
+		ContextualViewFactory<ActivityInputPort> {
+
+	public boolean canHandle(Object selection)
+	{
+		// TODO - HACK: this would stop showing the contextual view in case of any error,
+    //        not just in case of unsupported contextual selection; this needs to be
+    //        changed, so that useful error messages are still displayed in the
+    //        contextual view
+    if (selection instanceof ActivityInputPort)
+    {
+      SoapOperationPortIdentity portDetails = Integration.
+          extractSoapOperationPortDetailsFromActivityInputOutputPort((ActivityInputPort)selection);
+      boolean canHandleSelection = !portDetails.hasError();
+      if (!canHandleSelection) {
+        Logger.getLogger(BioCataloguePluginProcessorContextViewFactory.class).debug(
+            "Input port contextual view not shown due to some condition: " + portDetails.getErrorDetails());
+      }
+      
+      return (canHandleSelection);
+    }
+    else {
+      return (false);
+    }
+	}
+	
+	public List<ContextualView> getViews(ActivityInputPort selection) {
+		return Arrays.<ContextualView>asList(new ProcessorInputPortView(selection));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginOutputPortContextViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginOutputPortContextViewFactory.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginOutputPortContextViewFactory.java
new file mode 100644
index 0000000..1014a54
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginOutputPortContextViewFactory.java
@@ -0,0 +1,45 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.biocatalogue.model.SoapOperationPortIdentity;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.Integration;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityOutputPort;
+
+
+public class BioCataloguePluginOutputPortContextViewFactory implements
+		ContextualViewFactory<ActivityOutputPort> {
+  
+	public boolean canHandle(Object selection)
+	{
+		// TODO - HACK: this would stop showing the contextual view in case of any error,
+    //        not just in case of unsupported contextual selection; this needs to be
+    //        changed, so that useful error messages are still displayed in the
+    //        contextual view
+    if (selection instanceof ActivityOutputPort)
+    {
+      SoapOperationPortIdentity portDetails = Integration.
+          extractSoapOperationPortDetailsFromActivityInputOutputPort((ActivityOutputPort)selection);
+      boolean canHandleSelection = !portDetails.hasError();
+      if (!canHandleSelection) {
+        Logger.getLogger(BioCataloguePluginProcessorContextViewFactory.class).debug(
+            "Output port contextual view not shown due to some condition: " + portDetails.getErrorDetails());
+      }
+      
+      return (canHandleSelection);
+    }
+    else {
+      return (false);
+    }
+	}
+	
+	public List<ContextualView> getViews(ActivityOutputPort selection) {
+		return Arrays.<ContextualView>asList(new ProcessorOutputPortView(selection));
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginProcessorContextViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginProcessorContextViewFactory.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginProcessorContextViewFactory.java
new file mode 100644
index 0000000..05380d3
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/BioCataloguePluginProcessorContextViewFactory.java
@@ -0,0 +1,43 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.biocatalogue.model.SoapOperationIdentity;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.Integration;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workflowmodel.Processor;
+
+public class BioCataloguePluginProcessorContextViewFactory implements
+		ContextualViewFactory<Processor> {
+  
+	public boolean canHandle(Object selection)
+	{
+		// TODO - HACK: this would stop showing the contextual view in case of any error,
+	  //        not just in case of unsupported contextual selection; this needs to be
+	  //        changed, so that useful error messages are still displayed in the
+	  //        contextual view
+	  if (selection instanceof Processor)
+	  {
+	    SoapOperationIdentity opId = Integration.extractSoapOperationDetailsFromProcessor((Processor) selection);
+	    boolean canHandleSelection = !opId.hasError();
+		  if (!canHandleSelection) {
+	      Logger.getLogger(BioCataloguePluginProcessorContextViewFactory.class).debug(
+	          "Service's contextual view not shown due to some condition: " + opId.getErrorDetails());
+	    }
+		  
+		  return (canHandleSelection);
+	  }
+	  else {
+	    return (false);
+	  }
+	}
+	
+	public List<ContextualView> getViews(Processor selection) {
+		return Arrays.<ContextualView>asList(new ProcessorView(selection));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorInputPortView.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorInputPortView.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorInputPortView.java
new file mode 100644
index 0000000..4e307f1
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorInputPortView.java
@@ -0,0 +1,52 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
+
+
+public class ProcessorInputPortView extends ContextualView
+{
+	private final ActivityInputPort inputPort;
+	private JPanel jPanel;
+
+	public ProcessorInputPortView(ActivityInputPort inputPort) {
+		this.inputPort = inputPort;
+		
+		jPanel = new JPanel();
+		
+		// NB! This is required to have the body of this contextual
+		// view added to the main view; otherwise, body will be
+		// blank
+		initView();
+	}
+	
+	@Override
+	public JComponent getMainFrame()
+	{
+		return jPanel;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Service Catalogue Information";
+	} 
+
+	@Override
+	public void refreshView()
+	{
+	  // this actually causes the parent container to validate itself,
+    // which is what is needed here
+    this.revalidate();
+    this.repaint();
+	}
+	
+	@Override
+	public int getPreferredPosition() {
+		return BioCataloguePluginConstants.CONTEXTUAL_VIEW_PREFERRED_POSITION;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorOutputPortView.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorOutputPortView.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorOutputPortView.java
new file mode 100644
index 0000000..feff0f4
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorOutputPortView.java
@@ -0,0 +1,52 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityOutputPort;
+
+
+public class ProcessorOutputPortView extends ContextualView
+{
+	private final ActivityOutputPort outputPort;
+	private JPanel jPanel;
+
+	public ProcessorOutputPortView(ActivityOutputPort outputPort) {
+		this.outputPort = outputPort;
+		
+		jPanel = new JPanel();
+		
+		// NB! This is required to have the body of this contextual
+		// view added to the main view; otherwise, body will be
+		// blank
+		initView();
+	}
+	
+	@Override
+	public JComponent getMainFrame()
+	{
+		return jPanel;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Service Catalogue Information";
+	} 
+
+	@Override
+	public void refreshView()
+	{
+	  // this actually causes the parent container to validate itself,
+    // which is what is needed here
+    this.revalidate();
+    this.repaint();
+	}
+	
+	@Override
+	public int getPreferredPosition() {
+		return BioCataloguePluginConstants.CONTEXTUAL_VIEW_PREFERRED_POSITION;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorView.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorView.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorView.java
new file mode 100644
index 0000000..ea41805
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/contextual_views/ProcessorView.java
@@ -0,0 +1,229 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.contextual_views;
+
+import java.awt.Component;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URI;
+import java.rmi.activation.UnknownObjectException;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants;
+import net.sf.taverna.biocatalogue.model.ResourceManager;
+import net.sf.taverna.biocatalogue.model.SoapOperationIdentity;
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.MainComponentFactory;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.Integration;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check.ServiceHealthChecker;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check.ServiceMonitoringStatusInterpreter;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workflowmodel.Processor;
+
+import org.apache.log4j.Logger;
+import org.biocatalogue.x2009.xml.rest.Service;
+import org.biocatalogue.x2009.xml.rest.SoapOperation;
+
+
+public class ProcessorView extends ContextualView {
+	private final Processor processor;
+	private JPanel jPanel;
+	
+	private static Logger logger = Logger.getLogger(ProcessorView.class);
+	
+
+
+	public ProcessorView(Processor processor) {
+		this.processor = processor;
+		
+		jPanel = new JPanel();
+		
+		// this is required to have the body of this contextual
+		// view added to the main view; otherwise, body will be
+		// blank
+		initView();
+	}
+	
+
+	
+	@Override
+	public JComponent getMainFrame()
+	{
+	  Thread t = new Thread("loading processor data") {
+      public void run() {
+        final SoapOperationIdentity operationDetails = Integration.extractSoapOperationDetailsFromProcessor(processor);
+        
+        if (operationDetails.hasError()) {
+        	SwingUtilities.invokeLater(new RefreshThread(new JLabel(operationDetails.getErrorDetails().toString(),
+                    UIManager.getIcon("OptionPane.warningIcon"), JLabel.CENTER)));
+           return;
+        }
+        else {
+          BioCatalogueClient client = BioCatalogueClient.getInstance();
+          
+          if (client != null) {
+            try {
+              final SoapOperation soapOperation = client.lookupSoapOperation(operationDetails);
+              if (soapOperation == null) {
+            	  SwingUtilities.invokeLater(new RefreshThread(new JLabel("This service is not registered in the Service Catalogue",
+                          UIManager.getIcon("OptionPane.warningIcon"), JLabel.CENTER)));
+                 return;
+              }
+              
+              Service parentService = client.getBioCatalogueService(soapOperation.getAncestors().getService().getHref());
+              if (parentService == null) {
+               	  SwingUtilities.invokeLater(new RefreshThread(new JLabel("Problem while fetching monitoring data from the Service Catalogue",
+                          UIManager.getIcon("OptionPane.warningIcon"), JLabel.CENTER)));
+                 return;
+              }
+              
+              
+              // *** managed to get all necessary data successfully - present it ***
+              
+              // create status update panel
+              JButton jclServiceStatus = new DeselectingButton(
+                  new AbstractAction("Check monitoring status") {
+                    public void actionPerformed(ActionEvent e) {
+                      ServiceHealthChecker.checkWSDLProcessor(operationDetails);
+                    }
+                  });
+              jclServiceStatus.setAlignmentX(Component.LEFT_ALIGNMENT);
+              JLabel jlStatusMessage = new JLabel(parentService.getLatestMonitoringStatus().getMessage());
+              jlStatusMessage.setAlignmentX(Component.LEFT_ALIGNMENT);             
+              
+              // operation description
+              String operationDescription = (soapOperation.getDescription().length() > 0 ?
+                      soapOperation.getDescription() :
+                      "No description is available for this service");
+
+              ReadOnlyTextArea jlOperationDescription = new ReadOnlyTextArea(operationDescription);
+ 
+              jlOperationDescription.setAlignmentX(Component.LEFT_ALIGNMENT);              
+              
+              // a button to open preview of the service
+              JButton jbLaunchProcessorPreview = new DeselectingButton("Show on the Service Catalogue",
+            		  new ActionListener() {
+                  public void actionPerformed(ActionEvent e) {
+                    if (!operationDetails.hasError()) {
+                  	  String hrefString = soapOperation.getHref();
+     				   try {
+  						Desktop.getDesktop().browse(new URI(hrefString));
+  					    }
+  					    catch (Exception ex) {
+  					      logger.error("Failed while trying to open the URL in a standard browser; URL was: " +
+  					           hrefString, ex);
+  					    };
+                    }
+                    else {
+                      // this error message comes from Integration class extracting SOAP operation details from the contextual selection
+                      JOptionPane.showMessageDialog(null, operationDetails.getErrorDetails(), "Service Catalogue Error", JOptionPane.WARNING_MESSAGE);
+                    }
+                  }
+                },
+                "View this service on the Service Catalogue");
+              
+              JPanel jpPreviewButtonPanel = new JPanel();
+              jpPreviewButtonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+              jbLaunchProcessorPreview.setAlignmentX(Component.LEFT_ALIGNMENT);
+ //             jpPreviewButtonPanel.add(jbLaunchProcessorPreview);
+             // put everything together
+              JPanel jpInnerPane = new JPanel();
+              jpInnerPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+              jpInnerPane.setLayout(new BoxLayout(jpInnerPane, BoxLayout.Y_AXIS));
+              jpInnerPane.add(jlOperationDescription);
+              jpInnerPane.add(Box.createVerticalStrut(10));
+              jpInnerPane.add(jlStatusMessage);
+              jpInnerPane.add(Box.createVerticalStrut(10));
+              jpInnerPane.add(jclServiceStatus);
+              jpInnerPane.add(Box.createVerticalStrut(10));
+              jpInnerPane.add(jbLaunchProcessorPreview);
+             
+              JScrollPane spInnerPane = new JScrollPane(jpInnerPane);
+              
+              SwingUtilities.invokeLater(new RefreshThread(spInnerPane));
+              return;
+           }
+            catch (UnknownObjectException e) {
+            	SwingUtilities.invokeLater(new RefreshThread(new JLabel(e.getMessage(),
+                        UIManager.getIcon("OptionPane.informationIcon"), JLabel.CENTER)));
+            	return;
+             }
+            catch (Exception e) {
+              // a real error occurred while fetching data about selected processor
+             logger.error("ERROR: unexpected problem while trying to ", e);
+             SwingUtilities.invokeLater(new RefreshThread(new JLabel("An unknown problem has prevented Taverna from loading this preview",
+                     UIManager.getIcon("OptionPane.errorIcon"), JLabel.CENTER)));
+             return;
+            }
+          }
+          else {
+        	  SwingUtilities.invokeLater(new RefreshThread(new JLabel("Service Catalogue integration has not initialised yet. Please wait and try again.",
+                                  UIManager.getIcon("OptionPane.warningIcon"), JLabel.CENTER)));
+        	  return;
+         }
+        }
+      }
+	  };
+		
+	  jPanel.removeAll();
+    jPanel.setPreferredSize(new Dimension(200,200));
+    jPanel.setLayout(new GridLayout());
+    jPanel.add(new JLabel(ResourceManager.getImageIcon(ResourceManager.BAR_LOADER_ORANGE), JLabel.CENTER));
+	  t.start();
+		return jPanel;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Service Catalogue Information";
+	} 
+
+	@Override
+	public void refreshView()
+	{
+	  // this actually causes the parent container to validate itself,
+	  // which is what is needed here
+	  this.revalidate();
+	  this.repaint();
+	}
+	
+	@Override
+	public int getPreferredPosition() {
+		return BioCataloguePluginConstants.CONTEXTUAL_VIEW_PREFERRED_POSITION;
+	}
+	
+	class RefreshThread extends Thread {
+		private final Component component;
+
+		public RefreshThread (Component component) {
+			this.component = component;		
+		}
+		
+		public void run() {
+			jPanel.removeAll();
+			if (component != null) {
+				jPanel.add(component);
+			}
+			refreshView();
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheck.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheck.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheck.java
new file mode 100644
index 0000000..2461c2c
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheck.java
@@ -0,0 +1,40 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check;
+
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.Visitor;
+
+/**
+ * A {@link BioCatalogueWSDLActivityHealthCheck} is a kind of visit that determines
+ * if the corresponding WSDL activity in a workflow will work during a workflow run -
+ * checks will be made based on the monitoring status held about that service in BioCatalogue.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class BioCatalogueWSDLActivityHealthCheck extends VisitKind
+{
+  // The following values indicate the type of results that can be associated
+  // with a VisitReport generated by a health-checking visitor.
+  public static final int MESSAGE_IN_VISIT_REPORT = 0;
+  
+  
+  // property names to be placed into VisitReport generated by BioCatalogueWSDLActivityHealthChecker
+  public static final String WSDL_LOCATION_PROPERTY = "wsdlLocation";
+  public static final String OPERATION_NAME_PROPERTY = "soapOperationName";
+  public static final String EXPLANATION_MSG_PROPERTY = "fullExplanationMessage";
+  
+  
+  
+  
+  @Override
+  public Class<? extends Visitor> getVisitorClass() {
+    return BioCatalogueWSDLActivityHealthChecker.class;
+  }
+  
+  private static class Singleton {
+    private static BioCatalogueWSDLActivityHealthCheck instance = new BioCatalogueWSDLActivityHealthCheck();
+  }
+  
+  public static BioCatalogueWSDLActivityHealthCheck getInstance() {
+    return Singleton.instance;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheckVisitExplainer.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheckVisitExplainer.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheckVisitExplainer.java
new file mode 100644
index 0000000..8bee663
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/t2/ui/perspectives/biocatalogue/integration/health_check/BioCatalogueWSDLActivityHealthCheckVisitExplainer.java
@@ -0,0 +1,111 @@
+package net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import net.sf.taverna.biocatalogue.model.SoapOperationIdentity;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.workbench.report.explainer.VisitExplainer;
+
+// import status constants
+import static net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.health_check.BioCatalogueWSDLActivityHealthCheck.*;
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class BioCatalogueWSDLActivityHealthCheckVisitExplainer implements VisitExplainer
+{
+  
+  public boolean canExplain(VisitKind vk, int resultId) {
+    return (vk instanceof BioCatalogueWSDLActivityHealthCheck);
+  }
+  
+  
+  /**
+   * This class only handles {@link VisitReport} instances that are of
+   * {@link BioCatalogueWSDLActivityHealthCheck} kind. Therefore, decisions on
+   * the explanations / solutions are made solely by visit result IDs.
+   */
+  public JComponent getExplanation(final VisitReport vr)
+  {
+    int resultId = vr.getResultId();
+    String explanation = null;
+    
+    switch (resultId) {
+      case MESSAGE_IN_VISIT_REPORT:
+        explanation = (String) vr.getProperty(EXPLANATION_MSG_PROPERTY); break;
+        
+      default:
+        explanation = "Unknown issue - no expalanation available"; break;
+    }
+    
+    
+    JButton bRunBioCatalogueHealthCheck = new JButton("View monitoring status details");
+    bRunBioCatalogueHealthCheck.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        SoapOperationIdentity soapOpIdentity = 
+              new SoapOperationIdentity((String)vr.getProperty(BioCatalogueWSDLActivityHealthCheck.WSDL_LOCATION_PROPERTY),
+                                        (String)vr.getProperty(BioCatalogueWSDLActivityHealthCheck.OPERATION_NAME_PROPERTY), null);
+        
+        ServiceHealthChecker.checkWSDLProcessor(soapOpIdentity);
+      }
+    });
+    JPanel jpButton = new JPanel();
+    jpButton.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
+    jpButton.add(bRunBioCatalogueHealthCheck);
+    jpButton.setOpaque(false);
+    
+    JPanel jpExplanation = new JPanel(new BorderLayout());
+    jpExplanation.add(new ReadOnlyTextArea(explanation), BorderLayout.CENTER);
+    jpExplanation.add(jpButton, BorderLayout.SOUTH);
+    
+    return (jpExplanation);
+  }
+  
+  
+  
+  /**
+   * This class only handles {@link VisitReport} instances that are of
+   * {@link BioCatalogueWSDLActivityHealthCheck} kind. Therefore, decisions on
+   * the explanations / solutions are made solely by visit result IDs.
+   */
+  public JComponent getSolution(VisitReport vr)
+  {
+    String explanation = null;
+    
+    // instead of switching between possible health check resultIDs,
+    // simply choose from possible statuses: for all failures there's
+    // nothing specific that can be done, so no need to differentiate
+    // displayed messages
+    switch (vr.getStatus()) {
+      case OK:
+        explanation = "This WSDL service works fine - no change necessary"; break;
+        
+      case WARNING:
+      case SEVERE:
+        explanation = "This remote WSDL service appears to have an internal problem. There is nothing " +
+        		          "specific that can be done to fix it locally.\n\n" +
+        		          "It is possible that the current state of the service will still allow to execute " +
+        		          "the workflow successfully. Also, the service may have already recovered since the " +
+        		          "last time it's monitoring status has been checked.\n\n" +
+        		          "If this problem does affect the current workflow, it may be resolved by the " +
+        		          "service provider. It may be worth contacting them to report the issue.";
+                      break;
+      
+      default:
+        explanation = "Unknown issue - no solution available"; break;
+    }
+    
+    return (new ReadOnlyTextArea(explanation));
+  }
+  
+}