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:32 UTC

[18/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/biocatalogue/model/ResourceManager.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourceManager.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourceManager.java
new file mode 100644
index 0000000..666cd6c
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourceManager.java
@@ -0,0 +1,326 @@
+package net.sf.taverna.biocatalogue.model;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.net.URL;
+import java.util.HashMap;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.activities.rest.ui.servicedescription.RESTActivityIcon;
+import net.sf.taverna.t2.activities.wsdl.servicedescriptions.WSDLActivityIcon;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.BioCataloguePerspective;
+
+/**
+ * This class will be a single point of lookup of all resource files.
+ * (Icons, images, CSS files, etc).
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class ResourceManager
+{
+  // subfolders, where some icons / other resources are kept
+  public static final String FAMFAMFAM_PATH = "famfamfam_silk/";    // free collection of icons
+  public static final String SERVICE_ICONS_PATH = "service_icons/"; // icons related to web services (e.g. service types)
+  public static final String FOLDS_PATH = "folds/";                 // icons for 'folding' menus (like 'Search for...')
+  public static final String TRISTATE_TREE_ICONS_PATH = "tristate_checkbox/";  // icons for the tri-state filtering tree
+  
+  // all known resources to follow
+  public static final int FAVICON = 1;
+  
+  public static final int INFORMATION_ICON_LARGE = 10;
+  
+  public static final int SPINNER_STILL = 20;
+  public static final int SPINNER = 21;
+  public static final int BAR_LOADER_GREY = 25;
+  public static final int BAR_LOADER_GREY_STILL = 26;
+  public static final int BAR_LOADER_ORANGE = 30;
+  public static final int BAR_LOADER_ORANGE_STILL = 31;
+  
+  public static final int FOLD_ICON = 40;
+  public static final int UNFOLD_ICON = 41;
+  public static final int FOLD_ICON_16x16 = 42;
+  public static final int UNFOLD_ICON_16x16 = 43;
+  
+  public static final int SERVICE_TYPE_SOAP_ICON = 50;
+  public static final int SERVICE_TYPE_REST_ICON = 51;
+  public static final int SERVICE_TYPE_MULTITYPE_ICON = 65;
+  public static final int SERVICE_TYPE_UNKNOWN_ICON = 70;
+  
+  public static final int TRISTATE_CHECKBOX_CHECKED_ICON = 80;
+  public static final int TRISTATE_CHECKBOX_PARTIAL_ICON = 82;
+  public static final int TRISTATE_CHECKBOX_UNCHECKED_ICON = 85;
+  public static final int UNCHECKED_ICON = 86;
+  
+  public static final int SERVICE_STATUS_PASSED_ICON = 100;
+  public static final int SERVICE_STATUS_PASSED_ICON_LARGE = 101;
+  public static final int SERVICE_STATUS_WARNING_ICON = 110;
+  public static final int SERVICE_STATUS_WARNING_ICON_LARGE = 111;
+  public static final int SERVICE_STATUS_FAILED_ICON = 120;
+  public static final int SERVICE_STATUS_FAILED_ICON_LARGE = 121;
+  public static final int SERVICE_STATUS_UNCHECKED_ICON = 130;
+  public static final int SERVICE_STATUS_UNCHECKED_ICON_LARGE = 131;
+  public static final int SERVICE_STATUS_UNKNOWN_ICON = 140;
+  
+  public static final int UNKNOWN_RESOURCE_TYPE_ICON = 200;
+  public static final int USER_ICON = 205;
+  public static final int REGISTRY_ICON = 210;
+  public static final int SERVICE_PROVIDER_ICON = 215;
+  public static final int SERVICE_ICON = 220;
+  public static final int SOAP_OPERATION_ICON = 225;
+  public static final int REST_METHOD_ICON = 227;
+  public static final int SERVICE_CATEGORY_ICON = 230;
+  public static final int WSDL_DOCUMENT_ICON = 235;
+  public static final int TAG_ICON = 240;
+  
+  public static final int OPEN_IN_BIOCATALOGUE_ICON = 310;
+  public static final int SEARCH_ICON = 315;
+  public static final int HISTORY_ICON = 320;
+  public static final int REFRESH_ICON = 330;
+  public static final int FAVOURITE_ICON = 335;
+  public static final int TICK_ICON = 340;
+  public static final int CROSS_ICON = 341;
+  public static final int WARNING_ICON = 342;
+  public static final int ERROR_ICON = 343;
+  public static final int SAVE_ICON = 345;
+  public static final int DELETE_ITEM_ICON = 350;
+  public static final int CLEAR_ICON = 355;
+  public static final int LOCKED_ICON = 360;
+  public static final int UNLOCKED_ICON = 365;
+  
+  public static final int BACK_ICON = 370;
+  public static final int FORWARD_ICON = 375;
+  public static final int FILTER_ICON = 380;
+  public static final int PREVIEW_ICON = 385;
+  public static final int SUGGESTION_TO_USER_ICON = 390;
+  public static final int ADD_PROCESSOR_TO_WORKFLOW_ICON = 395;
+  public static final int ADD_PROCESSOR_AS_FAVOURITE_ICON = 396;
+  public static final int EXECUTE_HEALTH_CHECK_ICON = 397;
+  public static final int ADD_ALL_SERVICES_AS_FAVOURITE_ICON = 398;
+
+  public static final int SELECT_ALL_ICON = 400;
+  public static final int DESELECT_ALL_ICON = 405;
+  public static final int EXPAND_ALL_ICON = 410;
+  public static final int COLLAPSE_ALL_ICON = 420;
+  
+  public static final int SORT_BY_NAME_ICON = 450;
+  public static final int SORT_BY_COUNTS_ICON = 455;
+  
+  public static final int STYLES_CSS = 1000;
+  
+  
+  /** 
+   * Simple method to retrieve relative path of a required resource.
+   */
+  public static String getResourceRelPath(int resourceId)
+  {
+    String resPath = "";
+    
+    switch (resourceId) {
+      case FAVICON:                           resPath += "favicon.png";
+                                              break;
+      case INFORMATION_ICON_LARGE:            resPath += "info-sphere-35.png";
+                                              break;
+      case SPINNER_STILL:                     resPath += "ajax-loader-still.gif";
+                                              break;
+      case SPINNER:                           resPath += "ajax-loader.gif";
+                                              break;
+      case BAR_LOADER_GREY:                   resPath += "ajax-loader-grey-bert2.gif";
+                                              break;
+      case BAR_LOADER_GREY_STILL:             resPath += "ajax-loader-grey-bert2-still.png";
+                                              break;
+      case BAR_LOADER_ORANGE:                 resPath += "ajax-loader-orange-bert2.gif";
+                                              break;
+      case BAR_LOADER_ORANGE_STILL:           resPath += "ajax-loader-orange-bert2-still.png";
+                                              break;
+      case FOLD_ICON:                         resPath += FOLDS_PATH + "fold.png";
+                                              break;
+      case UNFOLD_ICON:                       resPath += FOLDS_PATH + "unfold.png";
+      										  break;
+      case FOLD_ICON_16x16:                   resPath += FOLDS_PATH + "fold_16x16.png";
+      										  break;
+      case UNFOLD_ICON_16x16:                 resPath += FOLDS_PATH + "unfold_16x16.png";                                              
+      										  break;
+      case SERVICE_TYPE_SOAP_ICON:            resPath += SERVICE_ICONS_PATH + "service_type_soap.png";
+                                              break;
+      case SERVICE_TYPE_REST_ICON:            resPath += SERVICE_ICONS_PATH + "service_type_rest.png";
+                                              break;
+      case SERVICE_TYPE_MULTITYPE_ICON:       resPath += SERVICE_ICONS_PATH + "service_type_multitype.png";
+                                              break;
+      case SERVICE_TYPE_UNKNOWN_ICON:         resPath += SERVICE_ICONS_PATH + "service_type_unknown.png";
+                                              break;
+      case SERVICE_STATUS_PASSED_ICON:        resPath += FAMFAMFAM_PATH + "accept.png";
+                                              break;
+      case SERVICE_STATUS_PASSED_ICON_LARGE:  resPath += "tick-sphere-35.png";
+                                              break;
+      case SERVICE_STATUS_WARNING_ICON:       resPath += FAMFAMFAM_PATH + "error.png";
+                                              break;
+      case SERVICE_STATUS_WARNING_ICON_LARGE: resPath += "pling-sphere-35.png";
+                                              break;
+      case SERVICE_STATUS_FAILED_ICON:        resPath += FAMFAMFAM_PATH + "exclamation.png";
+                                              break;
+      case SERVICE_STATUS_FAILED_ICON_LARGE:  resPath += "cross-sphere-35.png";
+                                              break;
+      case SERVICE_STATUS_UNCHECKED_ICON:     resPath += FAMFAMFAM_PATH + "help.png";
+                                              break;
+      case SERVICE_STATUS_UNCHECKED_ICON_LARGE: resPath += "query-sphere-35.png";
+                                              break;
+      case SERVICE_STATUS_UNKNOWN_ICON:       resPath += FAMFAMFAM_PATH + "grey_circle.png";
+                                              break;
+      case TRISTATE_CHECKBOX_CHECKED_ICON:    resPath += TRISTATE_TREE_ICONS_PATH + "tristate_checkbox_checked.png";
+                                              break;
+      case TRISTATE_CHECKBOX_PARTIAL_ICON:    resPath += TRISTATE_TREE_ICONS_PATH + "tristate_checkbox_partial.png";
+                                              break;
+      case TRISTATE_CHECKBOX_UNCHECKED_ICON:  resPath += TRISTATE_TREE_ICONS_PATH + "tristate_checkbox_unchecked.png";
+                                              break;
+      case UNCHECKED_ICON:  				  resPath += "unchecked.png";
+      										  break;
+      case UNKNOWN_RESOURCE_TYPE_ICON:        resPath += FAMFAMFAM_PATH + "grey_circle.png";
+                                              break;                                        
+      case USER_ICON:                         resPath += FAMFAMFAM_PATH + "user.png";
+                                              break;
+      case REGISTRY_ICON:                     resPath += FAMFAMFAM_PATH + "remote_resource.png";
+                                              break;
+      case SERVICE_PROVIDER_ICON:             resPath += FAMFAMFAM_PATH + "chart_organisation.png";
+                                              break;
+      case SERVICE_ICON:                      resPath += "favicon.png";
+                                              break;
+      case SOAP_OPERATION_ICON:               resPath += FAMFAMFAM_PATH + "plugin.png";
+                                              break;
+      case REST_METHOD_ICON:                  resPath += FAMFAMFAM_PATH + "plugin.png";
+                                              break;
+      case SERVICE_CATEGORY_ICON:             resPath += FAMFAMFAM_PATH + "text_list_numbers.png";
+                                              break;
+      case TAG_ICON:                          resPath += FAMFAMFAM_PATH + "tag_blue.png";
+                                              break;
+      case WSDL_DOCUMENT_ICON:                resPath += FAMFAMFAM_PATH + "page_white_code.png";
+                                              break;                                        
+      case OPEN_IN_BIOCATALOGUE_ICON:         resPath += FAMFAMFAM_PATH + "magnifier.png";
+                                              break;
+      case SEARCH_ICON:                       resPath += FAMFAMFAM_PATH + "magnifier.png";
+                                              break;
+      case HISTORY_ICON:                      resPath += FAMFAMFAM_PATH + "folder_explore.png";
+                                              break;
+      case REFRESH_ICON:                      resPath += FAMFAMFAM_PATH + "arrow_refresh.png";
+                                              break;
+      case FAVOURITE_ICON:                    resPath += FAMFAMFAM_PATH + "star.png";
+                                              break;
+      case TICK_ICON:                         resPath += FAMFAMFAM_PATH + "tick.png";
+                                              break;
+      case CROSS_ICON:                        resPath += FAMFAMFAM_PATH + "cross.png";
+                                              break;
+      case WARNING_ICON:                      resPath += FAMFAMFAM_PATH + "error.png";
+                                              break;
+      case ERROR_ICON:                        resPath += FAMFAMFAM_PATH + "exclamation.png";
+                                              break;
+      case SAVE_ICON:                         resPath += FAMFAMFAM_PATH + "disk.png";
+                                              break;
+      case DELETE_ITEM_ICON:                  resPath += FAMFAMFAM_PATH + "cross.png";
+                                              break;
+      case CLEAR_ICON:                        resPath += "trash.png";
+                                              break;
+      case LOCKED_ICON:                       resPath += FAMFAMFAM_PATH + "lock.png";
+                                              break;
+      case UNLOCKED_ICON:                     resPath += FAMFAMFAM_PATH + "lock_open.png";
+                                              break;
+      case BACK_ICON:                         resPath += FAMFAMFAM_PATH + "arrow_left.png";
+                                              break;
+      case FORWARD_ICON:                      resPath += FAMFAMFAM_PATH + "arrow_right.png";
+                                              break;
+      case FILTER_ICON:                       resPath += FAMFAMFAM_PATH + "arrow_join (flipped vertically).png";
+                                              break;
+      case PREVIEW_ICON:                      resPath += FAMFAMFAM_PATH + "magnifier.png";
+                                              break;
+      case SUGGESTION_TO_USER_ICON:           resPath += FAMFAMFAM_PATH + "lightbulb.png";
+                                              break;
+      case ADD_PROCESSOR_TO_WORKFLOW_ICON:    resPath += "open_in_BioCatalogue.png";
+                                              break;
+      case ADD_PROCESSOR_AS_FAVOURITE_ICON:   resPath += FAMFAMFAM_PATH + "star.png";
+                                              break;
+      case ADD_ALL_SERVICES_AS_FAVOURITE_ICON:resPath += FAMFAMFAM_PATH + "multiple_star.png";
+      										  break;                          
+      case EXECUTE_HEALTH_CHECK_ICON:         resPath += FAMFAMFAM_PATH + "information.png";
+                                              break;                                        
+      case SELECT_ALL_ICON:                   resPath += FAMFAMFAM_PATH + "tick.png";
+                                              break;
+      case DESELECT_ALL_ICON:                 resPath += FAMFAMFAM_PATH + "cross.png";
+                                              break;
+      case EXPAND_ALL_ICON:                   resPath += FAMFAMFAM_PATH + "text_linespacing.png";
+                                              break;
+      case COLLAPSE_ALL_ICON:                 resPath += FAMFAMFAM_PATH + "text_linespacing (collapse).png";
+                                              break;
+      case SORT_BY_NAME_ICON:                 resPath += FAMFAMFAM_PATH + "style.png";
+                                              break;
+      case SORT_BY_COUNTS_ICON:               resPath += FAMFAMFAM_PATH + "sum.png";
+                                              break;
+      case STYLES_CSS:                        resPath += "styles.css";
+                                              break;
+      default:                                return (null);
+    }
+    
+    return (resPath);
+  }
+  
+  
+  private static URL getResourceLocalURL(int resourceId) {
+    return (BioCataloguePerspective.class.getResource(getResourceRelPath(resourceId)));
+  }
+  
+  private static HashMap<Integer, ImageIcon> iconMap = new HashMap<Integer, ImageIcon>();
+  
+  public static ImageIcon getImageIcon(int iconId)
+  {
+	  ImageIcon result = iconMap.get(iconId);
+	  if (result == null) {
+		  result = new ImageIcon(getResourceLocalURL(iconId));
+		  iconMap.put(iconId, result);
+	  }
+	  return result;
+  }
+  
+  public static ImageIcon getImageIcon(URL resourceLocalURL) {
+    return (new ImageIcon(resourceLocalURL));
+  }
+  
+  
+  public static Icon getIconFromTaverna(int iconId) {
+    switch (iconId) {
+      case SOAP_OPERATION_ICON: return (WSDLActivityIcon.getWSDLIcon());
+      case REST_METHOD_ICON:    return (RESTActivityIcon.getRESTActivityIcon());
+      default:                  return (drawMissingIcon());
+    }
+  }
+  
+  
+  /**
+   * This method would be called by other methods in this class
+   * when they were unable to load requested icon.
+   * 
+   * @return A 16x16 pixel icon that represents a missing icon -
+   *         a red cross. 
+   */
+  private static ImageIcon drawMissingIcon()
+  {
+    int w = 16;
+    int h = 16;
+    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+    GraphicsDevice gd = ge.getDefaultScreenDevice();
+    GraphicsConfiguration gc = gd.getDefaultConfiguration();
+    
+    BufferedImage image = gc.createCompatibleImage(w, h, BufferedImage.TYPE_INT_ARGB);
+    Graphics2D g = image.createGraphics();
+    g.setColor(Color.RED);
+    g.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
+    g.drawLine(4, 4, 12, 12);
+    g.drawLine(12, 4, 4, 12);
+    g.dispose();
+    
+    return new ImageIcon(image); 
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourcePreviewContent.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourcePreviewContent.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourcePreviewContent.java
new file mode 100644
index 0000000..7dc1fce
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/ResourcePreviewContent.java
@@ -0,0 +1,38 @@
+package net.sf.taverna.biocatalogue.model;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+
+import net.sf.taverna.biocatalogue.model.connectivity.BioCatalogueClient;
+
+/**
+ * Helper class to hold all data about the generated preview.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class ResourcePreviewContent
+{
+  private Resource resource;
+  private JComponent jcContent;
+  
+  public ResourcePreviewContent(Resource resource, JComponent content)
+  {
+    this.resource = resource;
+    this.jcContent = content;
+  }
+  
+  public Resource getResource() {
+    return(this.resource);
+  }
+  
+  public JComponent getContent() {
+    return(this.jcContent);
+  }
+  
+  
+  public static ResourcePreviewContent createDummyInstance()
+  {
+    Resource r = new Resource(BioCatalogueClient.API_USERS_URL + "/1", "Dummy user");
+    return (new ResourcePreviewContent(r, new JLabel("dummy content - JLabel")));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationIdentity.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationIdentity.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationIdentity.java
new file mode 100644
index 0000000..df16566
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationIdentity.java
@@ -0,0 +1,77 @@
+package net.sf.taverna.biocatalogue.model;
+
+/**
+ * Identifies a SOAP operation (or "processor" in Taverna terms)
+ * in the most straightforward way - by WSDL location and operation name. 
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class SoapOperationIdentity extends SoapServiceIdentity
+{
+  public static final String ACTION_STRING_SEPARATOR = "===";
+  
+  private final String operationName;
+  private final String description;
+
+  public SoapOperationIdentity(String wsdlLocation, String operationName, String description) {
+    super(wsdlLocation);
+    this.operationName = operationName;
+    this.description = description;
+  }
+  
+  public SoapOperationIdentity(Object errorDetails) {
+    super(errorDetails);
+    this.operationName = null;
+    this.description = null;
+  }
+  
+  public String getOperationName() {
+    return operationName;
+  }
+  
+  public String getDescription() {
+    return description;
+  }
+  
+  
+  /**
+   * @return String that can be placed into an action command (i.e. into JClickableLabel)
+   *         to identify a SOAP operation - WSDL location and operation name are concatenated
+   *         with <code>SoapOperationIdentity.ACTION_STRING_SEPARATOR</code>.
+   */
+  public String toActionString() {
+    return (getWsdlLocation() + ACTION_STRING_SEPARATOR + this.operationName);
+  }
+  
+  
+  /**
+   * @param actionString String that includes WSDL location appended by
+   *                     <code>SoapOperationIdentity.ACTION_STRING_SEPARATOR</code>
+   *                     and by the operation name of a SOAP operations.
+   *                     <br/>
+   *                     The action string may either contain only WSDL location and operation
+   *                     name (which are joined by a specified separator) OR the action string
+   *                     may start from <code>BioCataloguePluginConstants.ACTION_PREVIEW_SOAP_OPERATION_AFTER_LOOKUP</code>. 
+   * @return Instance of this class initialised with the values from the <code>actionString</code>
+   *         or <code>null</code> if an error occurred. 
+   */
+  public static SoapOperationIdentity fromActionString(String actionString)
+  {
+    if (actionString == null) return (null);
+    
+    // remove the prefix if it is present
+    if (actionString.startsWith(BioCataloguePluginConstants.ACTION_PREVIEW_SOAP_OPERATION_AFTER_LOOKUP)) {
+      actionString = actionString.substring(BioCataloguePluginConstants.ACTION_PREVIEW_SOAP_OPERATION_AFTER_LOOKUP.length());
+    }
+    
+    String[] parts = actionString.split(ACTION_STRING_SEPARATOR);
+    if (parts == null || parts.length != 2 ||
+        parts[0].length() == 0 || parts[1].length() == 0)
+    {
+      return (null);
+    }
+    
+    return (new SoapOperationIdentity(parts[0], parts[1], null));
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationPortIdentity.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationPortIdentity.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationPortIdentity.java
new file mode 100644
index 0000000..6910e23
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapOperationPortIdentity.java
@@ -0,0 +1,26 @@
+package net.sf.taverna.biocatalogue.model;
+
+public class SoapOperationPortIdentity extends SoapOperationIdentity
+{
+  private String portName;
+  private boolean isInput;
+  
+  public SoapOperationPortIdentity(String wsdlLocation, String operationName, String portName, boolean isInput) {
+    super(wsdlLocation, operationName, null);
+    this.portName = portName;
+    this.isInput = isInput;
+  }
+  
+  public SoapOperationPortIdentity(Object errorDetails) {
+    super(errorDetails);
+  }
+  
+  public String getPortName() {
+    return portName;
+  }
+  
+  public boolean isInput() {
+    return isInput;
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapProcessorIdentity.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapProcessorIdentity.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapProcessorIdentity.java
new file mode 100644
index 0000000..814a701
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapProcessorIdentity.java
@@ -0,0 +1,27 @@
+package net.sf.taverna.biocatalogue.model;
+
+/**
+ * Identifies a SOAP Processor in Taverna terms. Adds a local name
+ * attribute to the details available in <code>SoapOperationIdentity</code>.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class SoapProcessorIdentity extends SoapOperationIdentity
+{
+  private final String localName;
+
+  public SoapProcessorIdentity(String wsdlLocation, String operationName, String localName) {
+    super(wsdlLocation, operationName, null);
+    this.localName = localName;
+  }
+  
+  public SoapProcessorIdentity(Object errorDetails) {
+    super(errorDetails);
+    this.localName = null;
+  }
+  
+  public String getLocalName() {
+    return localName;
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapServiceIdentity.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapServiceIdentity.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapServiceIdentity.java
new file mode 100644
index 0000000..a015ad2
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/SoapServiceIdentity.java
@@ -0,0 +1,45 @@
+package net.sf.taverna.biocatalogue.model;
+
+/**
+ * Identifies a SOAP service in the most straightforward
+ * way - by WSDL location. 
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class SoapServiceIdentity
+{
+  private final String wsdlLocation;
+  
+  // this variable holds an object that will be displayable
+  private final Object errorDetails;
+
+  public SoapServiceIdentity(String wsdlLocation) {
+    this.wsdlLocation = wsdlLocation;
+    this.errorDetails = null;
+  }
+  
+  public SoapServiceIdentity(Object errorDetails) {
+    this.errorDetails = errorDetails;
+    this.wsdlLocation = null;
+  }
+  
+  public String getWsdlLocation() {
+    return (wsdlLocation);
+  }
+  
+  public boolean hasError() {
+    return (errorDetails != null);
+  }
+  
+  /**
+   * @return Returned object contains an object that may be displayed
+   *         in a JOptionPane or printed (in other words defining a
+   *         sensible way of displaying itself), which has details of
+   *         an error that has occurred which prevented from populating
+   *         this instance with the actual details of their SOAP service.
+   */
+  public Object getErrorDetails() {
+    return (errorDetails);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Tag.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Tag.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Tag.java
new file mode 100644
index 0000000..e1ca6b9
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Tag.java
@@ -0,0 +1,218 @@
+package net.sf.taverna.biocatalogue.model;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.lang.StringEscapeUtils;
+
+
+/**
+ * @author Sergejs Aleksejevs
+ */
+public class Tag implements Serializable
+{
+  private static final long serialVersionUID = 784872111173271581L;
+  
+  private String tagURI;          // URI to use on BioCatalogue to fetch all tagged items
+	private String tagNamespace;    // namespace where this tag is defined
+	private String tagDisplayName;  // only the actual tag (for display within the tag cloud)
+  private String fullTagName;     // full tag name - including namespace
+	private int itemCount;          // count of tagged items
+  
+	
+	/**
+	 * Constructs a Tag instance from primitive components.
+	 * All values are set directly, no internal inference made.
+	 * 
+	 * @param tagURI
+	 * @param tagNamespace
+	 * @param tagDisplayName
+	 * @param fullTagName
+	 * @param itemCount
+	 */
+	public Tag(String tagURI, String tagNamespace, String tagDisplayName, String fullTagName, int itemCount)
+	{
+	  this.tagURI = tagURI;
+    this.tagNamespace = tagNamespace;
+    this.tagDisplayName = tagDisplayName;
+    this.setFullTagName(fullTagName);
+    this.itemCount = itemCount;
+	}
+	
+	
+	/**
+	 * Constructs Tag instance from an XML representation of the Tag from BioCatalogue API.
+	 * 
+	 * @param xmlTag
+	 */
+	public Tag(org.biocatalogue.x2009.xml.rest.Tag xmlTag)
+	{
+	  // these values come directly from the XML data obtained via the API 
+	  this.tagURI = xmlTag.getHref();
+	  this.fullTagName = xmlTag.getName();
+	  this.itemCount = xmlTag.getTotalItemsCount().intValue();
+	  
+	  // NB! Namespace and the display name need to be inferred 'manually'.
+	  // First - set the namespace; it's value is taken from the 'namespace'
+	  // attribute of the tag URI.
+    this.tagNamespace = Util.extractURLParameter(this.tagURI, "namespace");
+	  
+	  // Now set the display name; if full tag name is not a part of any ontology,
+	  // display name will be identical to the full name. 
+	  if (this.fullTagName.startsWith("<") && this.fullTagName.endsWith(">")) {
+	    int iStart = this.fullTagName.lastIndexOf('#') + 1;
+	    this.tagDisplayName = this.fullTagName.substring(iStart, this.fullTagName.length() - 1);
+	  }
+	  else {
+	    this.tagDisplayName = this.fullTagName;
+	  }
+	}
+	
+  
+	// *** Various getters and setters ***
+	
+	public void setTagURI(String tagURI) {
+    this.tagURI = tagURI;
+  }
+	
+  public String getTagURI() {
+    return tagURI;
+  }
+  
+  
+  public void setTagNamespace(String tagNamespace) {
+    this.tagNamespace = tagNamespace;
+  }
+  
+  public String getTagNamespace() {
+    return tagNamespace;
+  }
+  
+  
+  public void setTagDisplayName(String tagDisplayName) {
+    this.tagDisplayName = tagDisplayName;
+  }
+  
+  public String getTagDisplayName() {
+	  return tagDisplayName;
+  }
+  
+  
+  public void setFullTagName(String fullTagName) {
+    this.fullTagName = fullTagName;
+  }
+  
+  /**
+   * @return Unique and unambiguous name of this tag on BioCatalogue:<br/>
+   *         <ul>
+   *         <li>for tags with no namespaces, they it is just plain text names;</li>
+   *         <li>for those with namespaces, it will have the following form:<br/>
+   *             "<code>< http://www.mygrid.org.uk/ontology#retrieving ></code>" (without spaces, though), where
+   *             the first part before the '#' symbol is the namespace and the second part
+   *             is the actual tag within that namespace.</li></ul>
+   */
+  public String getFullTagName() {
+    return fullTagName;
+  }
+  
+  
+	public int getItemCount() {
+		return itemCount;
+	}
+	
+	public void setItemCount(int itemCount) {
+		this.itemCount = itemCount;
+	}
+	
+	
+	// *** Tag Comparators ***
+	
+	public static class ReversePopularityComparator implements Comparator<Tag>
+	{
+	  public ReversePopularityComparator() {
+	    super();
+	  }
+	  
+	  public int compare(Tag t1, Tag t2)
+	  {
+	    if (t1.getItemCount() == t2.getItemCount()) {
+	      // in case of the same popularity, compare by full tag names (which are unique)
+	      return (t1.getFullTagName().compareTo(t2.getFullTagName()));
+	    }
+	    else {
+	      // popularity isn't the same; arrange by popularity (more popular first)
+	      return (t2.getItemCount() - t1.getItemCount());
+	    }
+	  }
+	}
+	
+	
+	public static class AlphanumericComparator implements Comparator<Tag>
+  {
+    public AlphanumericComparator() {
+      super();
+    }
+    
+    public int compare(Tag t1, Tag t2) {
+      // full tag names are unique on BioCatalogue
+      return (t1.getFullTagName().compareTo(t2.getFullTagName()));
+    }
+  }
+	
+	public static class AlphabeticalIgnoreCaseComparator implements Comparator<Tag>
+	  {
+	    public AlphabeticalIgnoreCaseComparator() {
+	      super();
+	    }
+	    
+	    public int compare(Tag t1, Tag t2) {
+	      // full tag names are unique on BioCatalogue
+	      return (t1.getTagDisplayName().compareToIgnoreCase(t2.getTagDisplayName()));
+	    }
+	  }
+	
+	/**
+   * This makes sure that things like instanceOf() and remove() in List interface
+   * work properly - this way resources are treated to be the same if they store
+   * identical data, rather than they simply hold the same reference.
+   */
+	public boolean equals(Object other) {
+    // could only be equal to another Tag object, not anything else
+    if (! (other instanceof Tag)) return (false);
+    
+    // 'other' object is a Tag; equality is based on the data stored
+    // in the current and 'other' Tag instances
+    Tag otherTag = (Tag)other;
+    return (this.itemCount == otherTag.itemCount && this.fullTagName.equals(otherTag.fullTagName));
+  }
+	
+  
+  public String toString()
+  {
+    return ("Tag (" + this.fullTagName + ", " + this.itemCount + ")");
+  }
+  
+  
+  /**
+   * This method is used to generate the tooltip to be shown over the tag
+   * in the tagcloud. Shown text will contain the full tag name, namespace
+   * and frequency.
+   * 
+   * @return HTML encoded string ready to be put into the tooltip.
+   */
+  public String getTagCloudTooltip()
+  {
+    StringBuilder tooltip = new StringBuilder("<html>");
+    
+    tooltip.append("&nbsp;<b>" + (this.fullTagName.length() > this.tagDisplayName.length() ? "Full tag" : "Tag") + ": </b>" + StringEscapeUtils.escapeHtml(this.fullTagName));
+    if (this.tagNamespace != null && this.tagNamespace.length() > 0) {
+      tooltip.append("<br>&nbsp;<b>Namespace: </b>" + StringEscapeUtils.escapeHtml(this.tagNamespace));
+    }
+    tooltip.append("<br>&nbsp;<b>Frequency: </b>" + this.itemCount);
+    tooltip.append("</html>");
+    
+    return tooltip.toString();
+  }
+  
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Util.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Util.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Util.java
new file mode 100644
index 0000000..06b30e3
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/Util.java
@@ -0,0 +1,793 @@
+package net.sf.taverna.biocatalogue.model;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+
+import net.sf.taverna.raven.appconfig.ApplicationRuntime;
+import net.sf.taverna.t2.ui.perspectives.biocatalogue.BioCataloguePerspective;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * Class containing various reusable helper methods.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class Util
+
+
+{
+	
+	private static Logger logger = Logger.getLogger(Util.class);
+
+  
+  /**
+   * Makes sure that one component (for example, a window) is centered horizontally and vertically
+   * relatively to the other component. This is achieved by aligning centers of the two components.
+   * 
+   * This method can be used even if the 'dependentComponent' is larger than the 'mainComponent'. In
+   * this case it is probably only useful for centering windows against each other rather than
+   * components inside a container.
+   * 
+   * Method also makes sure that the dependent component will not be placed above the screen's upper
+   * edge and to the left of the left edge.
+   */
+  public static void centerComponentWithinAnother(Component mainComponent, Component dependentComponent)
+  {
+    int iMainComponentCenterX = (int)Math.round(mainComponent.getLocationOnScreen().getX() + (mainComponent.getWidth() / 2));
+    int iPosX = iMainComponentCenterX - (dependentComponent.getWidth() / 2);
+    if (iPosX < 0) iPosX = 0;
+    
+    int iMainComponentCenterY = (int)Math.round(mainComponent.getLocationOnScreen().getY() + (mainComponent.getHeight() / 2));
+    int iPosY = iMainComponentCenterY - (dependentComponent.getHeight() / 2);
+    if (iPosY < 0) iPosY = 0;
+    
+    dependentComponent.setLocation(iPosX, iPosY);
+  }
+  
+  
+  /**
+   * The parameter is the class name to be processed; class name is likely to be in
+   * the form <class_name>$<integer_value>, where the trailing part starting with
+   * the $ sign indicates the anonymous inner class within the base class. This will
+   * strip out that part of the class name to get the base class name.
+   */
+  public static String getBaseClassName(String strClassName)
+  {
+    // strip out the class name part after the $ sign; return
+    // the original value if the dollar sign wasn't found
+    String strResult = strClassName;
+    
+    int iDollarIdx = strResult.indexOf("$");
+    if (iDollarIdx != -1) strResult = strResult.substring(0, iDollarIdx);
+    
+    return (strResult);
+  }
+  
+  
+  /**
+   * Makes sure that the supplied string is no longer than provided length.
+   */
+  public static String ensureStringLength(String str, int iLength) {
+    if (str.length() > iLength) str = str.substring(0, iLength) + " (...)";
+    return (str);
+  }
+  
+  /**
+   * Makes sure that the supplied string doesn't have any lines (separated by HTML line break tag) longer
+   * than specified; assumes that there are no line breaks in the source line.
+   * 
+   * @param str The string to work with.
+   * @param iLineLength Desired length of each line.
+   * @param bIgnoreBrokenWords True if line breaks are to be inserted exactly each <code>iLineLength</code>
+   *                           symbols (which will most likely cause broken words); false to insert line breaks
+   *                           at the first space after <code>iLineLength</code> symbols since last line break.
+   * @return New string with inserted HTML line breaks.
+   */
+  public static String ensureLineLengthWithinString(String str, int iLineLength, boolean bIgnoreBrokenWords)
+  {
+    StringBuilder out = new StringBuilder(str);
+    
+    // keep inserting line breaks from end of the line till the beginning until all done
+    int iLineBreakPosition = 0;
+    while (iLineBreakPosition >= 0 && iLineBreakPosition < out.length())
+    {
+      // insert line break either exactly at calculated position or 
+      iLineBreakPosition += iLineLength;
+      iLineBreakPosition = (bIgnoreBrokenWords ?
+                            iLineBreakPosition :
+                            out.indexOf(" ", iLineBreakPosition));
+      
+      if (iLineBreakPosition > 0 && iLineBreakPosition < out.length()) {
+        out.insert(iLineBreakPosition, "<br>");
+        iLineBreakPosition += 4;  // -- four is the length of "<br>"
+      }
+    }
+    
+    return (out.toString());
+  }
+  
+  
+  /**
+   * This is a convenience method for calling
+   * {@link Util#pluraliseNoun(String, long, boolean)}
+   * with <code>false</code> as a value for third parameter.
+   */
+  public static String pluraliseNoun(String noun, long count) {
+    return (pluraliseNoun(noun, count, false));
+  }
+  
+  /**
+   * Performs naive pluralisation of the supplied noun.
+   * 
+   * @param noun Noun in a singular form.
+   * @param count Number of occurrences of the item, for which the noun is provided.
+   * @param forceAppendingSByDefault <code>true</code> to make sure that "y" -> "ies"
+   *                                 substitution is <b>not made</b>, but instead "s" is appended
+   *                                 to unmodified root of the noun.
+   * @return Pluralised <code>noun</code>: with appended -s or -y replaced with -ies.
+   */
+  public static String pluraliseNoun(String noun, long count, boolean forceAppendingSByDefault)
+  {
+    if (count % 10 != 1 || count == 11) {
+      if (!forceAppendingSByDefault && noun.endsWith("y")) {
+        return (noun.substring(0, noun.length() - 1) + "ies");  // e.g. ENTRY -> ENTRIES
+      }
+      else {
+        return (noun + "s");  // e.g. SHIP -> SHIPS
+      }
+    }
+    else {
+      // no need to pluralise - count is of the type 21, 31, etc.. 
+      return noun;
+    }
+  }
+  
+  
+  /**
+   * Calculates time difference between two {@link Calendar} instances.
+   * 
+   * @param earlier The "earlier" date.
+   * @param later The "later" date.
+   * @param maxDifferenceMillis The maximum allowed time difference between the two
+   *                            {@link Calendar} instances, in milliseconds. If the calculated
+   *                            difference will exceed <code>maxDifferenceMillis</code>,
+   *                            <code>null</code> will be returned. If this parameter has
+   *                            a value <code>less or equal to zero</code>, any time difference
+   *                            between the {@link Calendar} instances will be permitted.
+   * @return String in the form "XX seconds|minutes|hours|days ago". Proper pluralisation will
+   *         be performed on the name of the time unit. <code>null</code> will be returned in
+   *         cases where one of the {@link Calendar} instances is <code>null</code>, time
+   *         difference between the provided instances is greater than <code>maxDifferenceMillis</code>
+   *         or <code>earlier</code> date is not really earlier than <code>later</code> one.
+   */
+  public static String getAgoString(Calendar earlier, Calendar later, long maxDifferenceMillis)
+  {
+    // one of the dates is missing
+    if (earlier == null || later == null) {
+      return null;
+    }
+    
+    if (earlier.before(later)) {
+      long differenceMillis = later.getTimeInMillis() - earlier.getTimeInMillis();
+      
+      if (maxDifferenceMillis <= 0 || (maxDifferenceMillis > 0 && differenceMillis <= maxDifferenceMillis)) 
+      {
+        long result = 0;
+        String unitName = "";
+        
+        if (differenceMillis < 60 * 1000) {
+          result = differenceMillis / 1000;
+          unitName = "second";
+        }
+        else if (differenceMillis < 60 * 60 * 1000) {
+          result = differenceMillis / (60 * 1000);
+          unitName = "minute";
+        }
+        else if (differenceMillis < 24 * 60 * 60 * 1000) {
+          result = differenceMillis / (60 * 60 * 1000);
+          unitName = "hour"; 
+        }
+        else {
+          result = differenceMillis / (24 * 60 * 60 * 1000);
+          unitName = "day";
+        }
+        
+        return (result + " " + Util.pluraliseNoun(unitName, result, true) + " ago");
+      }
+      else {
+        // the difference is too large - larger than the supplied threshold
+        return null;
+      }
+    }
+    else {
+      // the "later" date is not really later than the "earlier" one
+      return null;
+    }
+  }
+  
+  
+  /**
+   * Joins the set of tokens in the provided list into a single string.
+   * This method is a shorthand for {@link Util#join(List, String, String, String)}.
+   * 
+   * @param tokens List of strings to join.
+   * @param separator Separator to insert between individual strings.
+   * @return String of the form <code>[token1][separator][token2][separator]...[tokenN]</code>
+   */
+  public static String join(List<String> tokens, String separator) {
+    return (join(tokens, null, null, separator));
+  }
+  
+  /**
+   * Joins the set of tokens in the provided list into a single string.
+   * 
+   * Any empty strings or <code>null</code> entries in the <code>tokens</code> list 
+   * will be removed to achieve a better resulting joined string.
+   * 
+   * @param tokens List of strings to join.
+   * @param prefix String to prepend to each token.
+   * @param suffix String to append to each token.
+   * @param separator Separator to insert between individual strings.
+   * @return String of the form <code>[prefix][token1][suffix][separator][prefix][token2][suffix][separator]...[prefix][tokenN][suffix]</code>
+   *         <br/><br/>
+   *         Example: call <code>join(["cat","sat","on","the","mat"], "[", "]", ", ")</code> results in the following output:
+   *                  <code>"[cat], [sat], [on], [the], [mat]"</code>
+   */
+  public static String join(List<String> tokens, String prefix, String suffix, String separator)
+  {
+    if (tokens == null) {
+      // nothing to join
+      return (null);
+    }
+    
+    // list of strings is not empty, but some pre-processing is necessary
+    // to remove any empty strings that may be there
+    for (int i = tokens.size() - 1; i >= 0; i--) {
+      if (tokens.get(i) == null || tokens.get(i).length() == 0) {
+        tokens.remove(i);
+      }
+    }
+    
+    // now start the actual processing, but it may be the case that all strings
+    // were empty and we now have an empty list
+    if (tokens.isEmpty()) {
+      // nothing to join - just return an empty string
+      return ("");
+    }
+    else {
+      // there are some tokens -- perform the joining
+      String effectivePrefix = (prefix == null ? "" : prefix);
+      String effectiveSuffix = (suffix == null ? "" : suffix);
+      String effectiveSeparator = (separator == null ? "" : separator);
+      
+      StringBuilder result = new StringBuilder();
+      for (int i = 0; i < tokens.size(); i++) {
+        result.append(effectivePrefix + tokens.get(i) + effectiveSuffix);
+        result.append(i == tokens.size() - 1 ? "" : effectiveSeparator);
+      }
+      
+      return (result.toString());
+    }
+  }
+  
+  /**
+   * Determines whether the plugin is running as a standalone JFrame or inside Taverna Workbench.
+   * This is a naive test, based only on the fact that Taverna uses Raven ApplicationRuntime.
+   */
+  public static boolean isRunningInTaverna()
+  {
+    try {
+      // ApplicationRuntime class is defined within Taverna API. If this is available,
+      // it should mean that the plugin runs within Taverna.
+      ApplicationRuntime.getInstance();
+      return true;
+    }
+    catch (NoClassDefFoundError e) {
+      return false;
+    }
+  }
+  
+  
+  // === STRIPPING OUT HTML FROM STRINGS ===
+  
+  public static String prepareStringForComponent(String source) {
+	  return "<html>" + StringEscapeUtils.escapeHtml(source) + "</html>";
+  }
+
+
+  /*
+   * === The following section is providing URL handling methods. ===
+   */
+  
+  /**
+   * See: {@link Util#appendStringBeforeParametersOfURL(String, String, boolean)}
+   * 
+   * Assumes the last parameter as false, so that the URL encoding will be done.
+   */
+  public static String appendStringBeforeParametersOfURL(String url, String strToAppend) {
+    return (appendStringBeforeParametersOfURL(url, strToAppend, false));
+  }
+  
+  /**
+   * Tiny helper to strip out all HTML tags. This will not leave any HTML tags
+   * at all (so that the content can be displayed in DialogTextArea - and the
+   * like - components. This helps to present HTML content inside JAVA easier.
+   */
+  public static String stripAllHTML(String source) {
+        // don't do anything if not string is provided
+        if (source == null)
+          return ("");
+   
+        // need to preserve at least all line breaks
+        // (ending and starting paragraph also make a line break)
+        source = source.replaceAll("</p>[\r\n]*<p>", "<br/>");
+        source = source.replaceAll("[\\s]+", " ");
+        source = source.replaceAll("\\<br/?\\>", "\n");
+        source = source.replaceAll("\n ", "\n");
+
+       // strip all HTML
+        source = source.replaceAll("\\<.*?\\>", ""); // any HTML tags
+        source = source.replaceAll("&\\w{1,4};", ""); // this is for things like "&nbsp;", "&gt;", etc
+
+        return (source);
+  }
+
+  
+  /**
+   * Appends given string at the end of the provided URL just before the list of parameters in the url.
+   * 
+   * For example, appending ".xml" to URL "http://www.sandbox.biocatalogue.org/services?tag=blast" will
+   * yield "http://www.sandbox.biocatalogue.org/services.xml?tag=blast".
+   * 
+   * No duplication checking is made - if the URL is already ending (before parameters) with the value of
+   * the string to append, that string will still be appended.
+   * 
+   * @param url URL to append the string to.
+   * @param strToAppend The string to append. The value will be url-encode before appending.
+   * @return New string containing modified <code>url</code> with the <code>strToAppend</code> appended
+   *         before the "query string" of the URL.
+   */
+  public static String appendStringBeforeParametersOfURL(String url, String strToAppend, boolean ignoreURLEncoding)
+  {
+    StringBuilder modifiedURL = new StringBuilder(url);
+    
+    int iPositionToInsertProvidedString = modifiedURL.indexOf("?");
+    if (iPositionToInsertProvidedString == -1) iPositionToInsertProvidedString = modifiedURL.length();
+    
+    String stringToInsert = (ignoreURLEncoding ? strToAppend : Util.urlEncodeQuery(strToAppend));
+    modifiedURL.insert(iPositionToInsertProvidedString, stringToInsert);
+    
+    return (modifiedURL.toString());
+  }
+  
+  
+  /**
+   * This method takes a collection of name-value pairs in the form of a map.
+   * It then adds all parameters from this map to the provided URL. 
+   * 
+   * If any parameter has the same name as was already present in the URL, the new value
+   * will replace the existing one.
+   * 
+   * The implementation of this method is not particularly efficient - it makes a
+   * lot of overhead, but it's fine for non-intensive usage.
+   * 
+   * @param url The URL to add a new parameter to.
+   * @param Map of parameters to add to the URL. Keys and values of the map are the names and values for URL parameters.
+   * @return New string which is the original <code>url</code> with all provided
+   *         parameters (in the form <code>name</code>=<code>value</code> pair) added to it.
+   */
+  public static String appendAllURLParameters(String url, Map<String,String> parameterMap)
+  {
+    if (parameterMap == null || parameterMap.size() == 0) {
+      // nothing to add, return the same URL
+      return (url);
+    }
+    else {
+      // just call an overloaded method which has the main logic
+      // to do this action for each name-value pair in the map
+      String out = url;
+      for (Map.Entry<String,String> anotherParameter : parameterMap.entrySet()) {
+        out = appendURLParameter(out, anotherParameter);
+      }
+      return (out);
+    }
+  }
+  
+  
+  
+  /**
+   * This method takes a string representation of a URL and a name-value pair
+   * of strings - in the form of Map.Entry instance to add to the URL as a new parameter.
+   * 
+   * If parameter with the same name was already present in the URL, the new value
+   * will replace the existing one.
+   * 
+   * @param url The URL to add a new parameter to.
+   * @param Map.Entry instance containing the name & the value for the parameter to add.
+   * @return New string which is the original <code>url</code> with the desired
+   *         parameter (<code>name</code>=<code>value</code> pair) added to it.
+   */
+  public static String appendURLParameter(String url, Map.Entry<String,String> parameter)
+  {
+    if (parameter == null) {
+      // nothing to add, return the same URL
+      return (url);
+    }
+    else {
+      // just call an overloaded method which has the main logic to do this action
+      return (appendURLParameter(url, parameter.getKey(), parameter.getValue()));
+    }
+  }
+  
+  
+  /**
+   * This method takes a string representation of a URL and a name-value pair
+   * of strings to add to the URL as a new parameter.
+   * 
+   * If parameter with the same name was already present in the URL, the new value
+   * will replace the existing one.
+   * 
+   * @param url The URL to add a new parameter to.
+   * @param parameter String array with 2 elements - first element is the name
+   *        of the parameter to add, second - the value of the parameter.
+   * @return New string which is the original <code>url</code> with the desired
+   *         parameter (<code>name</code>=<code>value</code> pair) added to it.
+   */
+  public static String appendURLParameter(String url, String[] parameter)
+  {
+    if (parameter == null || parameter.length != 2) {
+      // nothing to add, return the same URL
+      return (url);
+    }
+    else {
+      // just call an overloaded method which has the main logic to do this action
+      return (appendURLParameter(url, parameter[0], parameter[1]));
+    }
+  }
+  
+  
+  /**
+   * This method takes a string representation of a URL and a name-value pair
+   * of strings to add to the URL as a new parameter.
+   * 
+   * If parameter with the same name was already present in the URL, the new value
+   * will replace the existing one.
+   * 
+   * @param url The URL to add a new parameter to.
+   * @param name Name of the parameter to add.
+   * @param value Value of the parameter to add.
+   * @return New string which is the original <code>url</code> with the desired
+   *         parameter (<code>name</code>=<code>value</code> pair) added to it.
+   */
+  public static String appendURLParameter(String url, String name, String value)
+  {
+    // if name of the parameter is not given, ignore this request
+    // (makes sense to return the same URL as the input in this case -
+    //  as appending "nothing" wouldn't make it any different)
+    if (name == null || name.length() == 0) {
+      return (url);
+    }
+    
+    // do everything in the protected block
+    try
+    {
+      // parse the parameters of the given URL
+      Map<String,String> urlParameters = extractURLParameters(url);
+      if (urlParameters == null) {
+        // there were no parameters in the original URL, create new map
+        urlParameters = new HashMap<String,String>();
+      }
+      
+      // add the new parameter (this will replace a parameter with identical
+      // name if it was already present in the map)
+      urlParameters.put(name, value);
+      
+      // parse the URL string into the URL object to extract original query string
+      URL theURL = new URL(url);
+      String originalQueryString = theURL.getQuery();
+      
+      // prepare the basis for the new URL to return
+      String newUrl = null;
+      if (originalQueryString != null) {
+        // replace the original query string with empty space to
+        // give way for appending the new query string
+        newUrl = url.replace(originalQueryString, "");
+      }
+      else {
+        // there were no parameters in the original URL
+        newUrl = url + "?";  
+      }
+      
+      // append the new query string
+      newUrl += constructURLQueryString(urlParameters);
+      
+      return (newUrl);
+    }
+    catch (Exception e)
+    {
+      logger.error("\nCouldn't append parameter ('" + name + "', '" + value + "') to the URL: " + url, e); 
+      return (null);
+    }
+  }
+  
+  
+  /**
+   * Extracts a value of a specific parameter from the supplied URL.
+   *  
+   * @param url The URL to extract the parameter from.
+   * @param parameterName Name of the URL parameter to extract the value for.
+   * @return Value of the parameter with <code>parameterName</code> in the given <code>url</code>.
+   *         If the parameter with specified name is not found in the given <code>url</code>,
+   *         <code>null</code> is returned instead. 
+   */
+  public static String extractURLParameter(String url, String parameterName)
+  {
+    // both URL and the name of the required parameter must be supplied
+    if (url == null || url.length() == 0 || parameterName == null || parameterName.length() == 0) return null;
+    
+    Map<String,String> urlParameters = extractURLParameters(url);
+    if (urlParameters != null) {
+      // the URL has some parameters; check what's the value of the desired parameter
+      return (urlParameters.get(parameterName));
+    }
+    else {
+      // the URL doesn't contain any parameters
+      return (null);
+    }
+  }
+  
+  
+  /**
+   * Extracts the query string from the provided URL. Parses this query string into
+   * a map of parameters.
+   * 
+   * All parameters (both names and values) will have special characters unescaped
+   * (i.e. decoded from the standard url-encoding) and can be used directly.
+   * 
+   * @param url The string representation of the URL to parse.
+   */
+  public static Map<String,String> extractURLParameters(String url)
+  {
+    try {
+      // extract the query part of the supplied URL
+      URL theURL = new URL(url);
+      String queryString = theURL.getQuery();
+      
+      // prepare storage for output
+      Map<String,String> parameterMap = null;
+      
+      // extract each name-value pair from query string (if any are specified in the URL)
+      if (queryString != null && queryString.length() > 0)
+      {
+        // only initialise if there are some parameters
+        parameterMap = new HashMap<String,String>();
+        
+        for (String parameter : queryString.split("&")) {
+          String[] nameValueArr = parameter.split("=");
+          
+          String name = nameValueArr[0]; // parameter name must always be present
+          String value = (nameValueArr.length == 2 ? nameValueArr[1] : null); // could be that parameter value is not set (e.g. "q=") - insert null then
+          
+          // decode possible special characters
+          name = urlDecodeQuery(name);
+          if (value != null) value = urlDecodeQuery(value);
+          
+          parameterMap.put(name, value);
+        }
+      }
+      
+      return (parameterMap);
+    }
+    catch (MalformedURLException e)
+    {
+      // some problem occurred - report it; can't return any data in this case
+      logger.error("Couldn't parse parameters of a URL: " + url + "; details below:", e);
+      return null;
+    }
+  }
+  
+  
+  /**
+   * This method is the opposite for <code>extractURLParameters(String url)</code>.
+   * It takes a map of parameters, performs URL-encoding of each and assembles them
+   * into a query string.
+   * 
+   * The query string then can be added to the <code>URL</code> object by using standard
+   * Java API. 
+   * 
+   * @param urlParameters Map of parameters to use in query string construction.
+   * @return URL-encoded query string.
+   */
+  public static String constructURLQueryString(Map<String,String> urlParameters)
+  {
+    if (urlParameters != null) {
+      StringBuilder queryString = new StringBuilder();
+      
+      // iterate through all parameters and reconstruct the query string
+      for (Map.Entry<String,String> parameter : urlParameters.entrySet())
+      {
+        if (queryString.length() > 0) queryString.append("&"); // parameter separator
+        queryString.append(urlEncodeQuery(parameter.getKey()) + "=" + urlEncodeQuery(parameter.getValue()));
+      }
+      
+      return (queryString.toString());
+    }
+    else {
+      return (null);
+    }
+  }
+  
+  
+  /**
+   * Prepares the string to serve as a part of url query to the server.
+   * @param query The string that needs URL encoding.
+   * @return URL encoded string that can be inserted into the request URL.
+   */
+  public static String urlEncodeQuery(String query)
+  {
+    // "fast exit" - if null supplied, just return an empty string;
+    // this is because in the URLs we have "q=", rather than "q=null" - this will cater for such cases
+    if (query == null) return ("");
+    
+    // encode the query
+    String strRes = "";
+    try {
+      strRes = URLEncoder.encode(query, "UTF-8");
+    }
+    catch (UnsupportedEncodingException e) {
+      // do nothing
+    }
+    
+    return (strRes);
+  }
+  
+  
+  /**
+   * Decodes a string which came as a part of of URL (e.g. a URL parameter). This converts
+   * codes of escaped special characters back into those special characters.
+   * 
+   * @param query The string that needs URL decoded.
+   * @return Decoded string that will contain all the special characters.
+   */
+  public static String urlDecodeQuery(String query)
+  {
+    String strRes = "";
+    
+    try {
+      strRes = URLDecoder.decode(query, "UTF-8");
+    }
+    catch (UnsupportedEncodingException e) {
+      // do nothing
+    }
+    
+    return (strRes);
+  }
+  
+  
+  /**
+   * This method is "clones" an object supplied as an argument. It uses
+   * serialisation to achieve this (as opposed to manually implementing deep
+   * copying of all referenced objects in the graph of the provided object).
+   * This technique is used to make sure that the new object will be exact
+   * replica, but totally independent of the original one.
+   * 
+   * Note that this code works ~100 times slower than it would do if deep copying
+   * was implemented. However, this will not be used in tight loops (and in loops
+   * at all), so for one-off tasks it is fine.
+   * 
+   * @author Dave Miller<br/>
+   * Original version of the code in this method is taken from
+   * <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip76.html?page=2">
+   *    http://www.javaworld.com/javaworld/javatips/jw-javatip76.html?page=2
+   * </a> [accessed on 25/Feb/2010].
+   * <br/><br/>
+   * 
+   * @author Subhajit Dasgupta<br/>
+   * Example of using an alternative class loader during object de-serialisation
+   * was taken from
+   * <a href="http://blogs.sun.com/adventures/entry/desrializing_objects_custom_class_loaders">
+   *    http://blogs.sun.com/adventures/entry/desrializing_objects_custom_class_loaders
+   * </a> [accessed on 29/Mar/2010].
+   * 
+   * @return Deep copy of the provided object. If deep copying doesn't succeed,
+   *         <code>null</code> is returned.
+   */
+  public static Object deepCopy(Object objectToCopy)
+  {
+    // a "safety net" - a class loader of BioCatalogue perspective may be used in
+    // de-serialisation process to make sure that all classes are recognised
+    // (system class loader may not be able to "see" all BioCatalogue plugin's files,
+    //  but just those in Taverna's /lib folder)
+    final ClassLoader[] customClassLoaders = new ClassLoader[] { BioCataloguePerspective.class.getClassLoader() };
+    
+    try
+    {
+      ObjectOutputStream oos = null;
+      ObjectInputStream ois = null;
+      try
+      {
+         ByteArrayOutputStream bos = new ByteArrayOutputStream();
+         oos = new ObjectOutputStream(bos);
+         
+         // serialise and pass the object
+         oos.writeObject(objectToCopy);
+         oos.flush();
+         
+         // read and return the new object
+         ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
+         ois = new ObjectInputStream(bin) {
+                     /**
+                      * <code>resolveClass()</code> method is overridden to make use of
+                      * custom ClassLoader in the de-serialisation process.
+                      * <br/>
+                      * This is needed to make sure that the ClassLoader of the BioCatalogue
+                      * perspective is used as opposed to the system ClassLoader which will
+                      * only be able to see classes from Taverna's /lib folder.
+                      */
+                     protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException
+                     {
+                       String className = desc.getName();
+                       try {
+                         // attempt to use default class loader
+                         return Class.forName(className);
+                       }
+                       catch (ClassNotFoundException exc)
+                       {
+                         // default class loader was unable to locate a required class -
+                         // attempt to use one of the provided class loaders
+                         for (ClassLoader cl : customClassLoaders) {
+                           try {
+                             return cl.loadClass(className);
+                           } 
+                           catch (ClassNotFoundException e) {
+                             /* do nothing here - there may be other class loaders to try */
+                           }
+                         }
+                         // none of the class loaders was able to recognise the currently
+                         // de-serialised class, so it's indeed an exception
+                         throw new ClassNotFoundException(className + 
+                             " -- neither system, nor alternative class loaders were able to load this class");
+                       }
+                     }
+                   };
+         return ois.readObject();
+      }
+      catch(Exception e)
+      {
+         logger.error("Could not perform deep copy of " + objectToCopy.getClass() + " instance", e);
+      }
+      finally
+      {
+         oos.close();
+         ois.close();
+      }
+    }
+    catch (Exception e) {
+      logger.error("Could not close object streams during deep copy of " + objectToCopy.getClass() + " instance");
+    }
+    
+    // Error occurred - couldn't produce the deep copy...
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeanForPOSTToFilteredIndex.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeanForPOSTToFilteredIndex.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeanForPOSTToFilteredIndex.java
new file mode 100644
index 0000000..d879377
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeanForPOSTToFilteredIndex.java
@@ -0,0 +1,12 @@
+package net.sf.taverna.biocatalogue.model.connectivity;
+
+import java.util.Map;
+
+/**
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class BeanForPOSTToFilteredIndex
+{
+  public Map<String, String[]> filters;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeansForJSONLiteAPI.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeansForJSONLiteAPI.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeansForJSONLiteAPI.java
new file mode 100644
index 0000000..ea3b391
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BeansForJSONLiteAPI.java
@@ -0,0 +1,84 @@
+package net.sf.taverna.biocatalogue.model.connectivity;
+
+
+/**
+ * Binding beans for GSON library to instantiate objects
+ * from JSON data obtained from the 'Lite' version of the
+ * BioCatalogue JSON API.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class BeansForJSONLiteAPI
+{
+  
+  public static abstract class ResourceIndex
+  {
+    public ResourceIndex() { }
+    public abstract ResourceLinkWithName[] getResources();
+  }
+  
+  
+  public static class SOAPOperationsIndex extends ResourceIndex {
+    public SOAPOperationsIndex() { }
+    public ResourceLinkWithName[] soap_operations;
+    
+    public ResourceLinkWithName[] getResources() {
+      return soap_operations;
+    }
+  }
+  
+  public static class RESTMethodsIndex extends ResourceIndex {
+    public RESTMethodsIndex() { }
+    public ResourceLinkWithName[] rest_methods;
+    
+    public ResourceLinkWithName[] getResources() {
+      return rest_methods;
+    }
+  }
+  
+  public static class ServicesIndex extends ResourceIndex {
+    public ServicesIndex() { }
+    public ResourceLinkWithName[] services;
+    
+    public ResourceLinkWithName[] getResources() {
+      return services;
+    }
+  }
+  
+  public static class ServiceProvidersIndex extends ResourceIndex {
+    public ServiceProvidersIndex() { }
+    public ResourceLinkWithName[] service_providers;
+    
+    public ResourceLinkWithName[] getResources() {
+      return service_providers;
+    }
+  }
+  
+  public static class UsersIndex extends ResourceIndex {
+    public UsersIndex() { }
+    public ResourceLinkWithName[] users;
+    
+    public ResourceLinkWithName[] getResources() {
+      return users;
+    }
+  }
+  
+  
+  
+  public static class ResourceLinkWithName
+  {
+    private ResourceLinkWithName() { }
+    
+    private String resource;
+    private String name;
+    
+    public String getURL() {
+      return (this.resource);
+    }
+    
+    public String getName() {
+      return (this.name);
+    }
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BioCatalogueAPIRequest.java
----------------------------------------------------------------------
diff --git a/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BioCatalogueAPIRequest.java b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BioCatalogueAPIRequest.java
new file mode 100644
index 0000000..ea55a77
--- /dev/null
+++ b/taverna-perspective-biocatalogue/src/main/java/net/sf/taverna/biocatalogue/model/connectivity/BioCatalogueAPIRequest.java
@@ -0,0 +1,47 @@
+package net.sf.taverna.biocatalogue.model.connectivity;
+
+/**
+ * A class to wrap BioCatalogue API requests - will include
+ * the type (GET, POST, etc), URL and the data to send
+ * if that's a POST / PUT request. 
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class BioCatalogueAPIRequest
+{
+  public static enum TYPE {
+    GET,
+    POST,
+    PUT,
+    DELETE
+  }
+  
+  
+  private TYPE requestType;
+  private String url;
+  private String data;
+  
+  
+  public BioCatalogueAPIRequest(TYPE requestType, String url, String data) {
+    this.requestType = requestType;
+    this.url = url;
+    this.data = data;
+  }
+  
+  
+  public TYPE getRequestType() {
+    return requestType;
+  }
+  
+  public String getURL(){
+    return url;
+  }
+  public void setURL(String url) {
+    this.url = url;
+  }
+  
+  public String getData(){
+    return data;
+  }
+  
+}