http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationPanel.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationPanel.java
new file mode 100644
index 0000000..536a87d
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationPanel.java
@@ -0,0 +1,271 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.Color.WHITE;
+import static java.awt.Font.BOLD;
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.EAST;
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.SOUTHEAST;
+import static java.lang.Integer.MIN_VALUE;
+import static java.lang.String.format;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.getObjectName;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+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.util.List;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+
+import org.apache.jena.ontology.OntProperty;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Statement;
+import org.apache.taverna.lang.ui.DeselectingButton;
+
+public class SemanticAnnotationPanel extends JPanel {
+       private static final long serialVersionUID = -5949183295606132775L;
+
+       private List<PropertyPanelFactorySPI> propertyPanelFactories; //FIXME 
beaninject
+       private final AbstractSemanticAnnotationContextualView 
semanticAnnotationContextualView;
+       private final SemanticAnnotationProfile semanticAnnotationProfile;
+       private final Set<Statement> statements;
+       private final boolean allowChange;
+       private final PropertyPanelFactorySPI bestFactory;
+
+       public SemanticAnnotationPanel(
+                       AbstractSemanticAnnotationContextualView 
semanticAnnotationContextualView,
+                       SemanticAnnotationProfile semanticAnnotationProfile,
+                       Set<Statement> statements, boolean allowChange) {
+               this.semanticAnnotationContextualView = 
semanticAnnotationContextualView;
+               this.semanticAnnotationProfile = semanticAnnotationProfile;
+               this.statements = statements;
+               this.allowChange = allowChange;
+               this.bestFactory = findBestPanelFactory();
+               initialise();
+       }
+
+       private void initialise() {
+               setLayout(new GridBagLayout());
+               // setBorder(new AbstractBorder() {
+               // @Override
+               // public void paintBorder(Component c, Graphics g, int x, int 
y, int
+               // width, int height) {
+               // g.setColor(Color.GRAY);
+               // g.drawLine(x, y+height-1, x+width-1, y+height-1);
+               // }
+               // });
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.anchor = SOUTHEAST;
+               c.fill = BOTH;
+               c.weightx = 1;
+               c.gridx = 0;
+
+               OntProperty predicate = 
semanticAnnotationProfile.getPredicate();
+               c.gridwidth = 3;
+               JLabel label = new JLabel(format("Annotation type : %s",
+                               getDisplayName(predicate)));
+               label.setBorder(new EmptyBorder(5, 5, 5, 5));
+               label.setBackground(WHITE);
+               label.setOpaque(true);
+               add(label, c);
+
+               c.insets = new Insets(7, 0, 0, 0);
+               c.anchor = EAST;
+               c.fill = HORIZONTAL;
+               if (statements.isEmpty()) {
+                       c.gridwidth = 2;
+                       // c.weightx = 1;
+                       // c.gridy++;
+                       add(new JLabel("No semantic annotations"), c);
+               } else {
+                       c.gridwidth = 1;
+                       for (Statement statement : statements) {
+                               c.gridx = 0;
+                               c.weightx = 1;
+                               if (bestFactory != null) {
+                                       add(bestFactory.getDisplayComponent(
+                                                       
semanticAnnotationProfile, statement), c);
+                               } else {
+                                       JTextArea value = new 
JTextArea(getObjectName(statement));
+                                       value.setLineWrap(true);
+                                       value.setWrapStyleWord(true);
+                                       value.setEditable(false);
+                                       value.setBackground(WHITE);
+                                       value.setOpaque(true);
+                                       value.setBorder(new EmptyBorder(2, 4, 
2, 4));
+                                       add(value, c);
+                               }
+                               if (allowChange) {
+                                       c.gridx = 1;
+                                       c.weightx = 0;
+                                       add(createChangeButton(statement), c);
+
+                                       c.gridx = 2;
+                                       add(createDeleteButton(statement), c);
+                               }
+                       }
+               }
+
+               if (allowChange
+                               && !enoughAlready(statements,
+                                               
semanticAnnotationProfile.getMaxOccurs())) {
+                       c.gridx = 0;
+                       c.gridwidth = 3;
+                       c.anchor = SOUTHEAST;
+                       c.fill = NONE;
+                       add(createAddButton(), c);
+               }
+       }
+
+       private boolean enoughAlready(Set<Statement> statements, Integer 
maxOccurs) {
+               return (maxOccurs != null) && (statements.size() >= maxOccurs);
+       }
+
+       private JButton createChangeButton(final Statement statement) {
+               return new DeselectingButton("Change", new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               addOrChangeAnnotation(statement);
+                       }
+               });
+       }
+
+       private JButton createDeleteButton(final Statement statement) {
+               return new DeselectingButton("Delete", new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               
semanticAnnotationContextualView.removeStatement(statement);
+                       }
+               });
+       }
+
+       private JButton createAddButton() {
+               return new DeselectingButton("Add Annotation", new 
ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               addOrChangeAnnotation(null);
+                       }
+               });
+       }
+
+       private void addOrChangeAnnotation(Statement statement) {
+               JPanel annotationPanel = null;
+               JComponent inputComponent = null;
+
+               if (bestFactory != null) {
+                       inputComponent = bestFactory.getInputComponent(
+                                       semanticAnnotationProfile, statement);
+                       annotationPanel = getPropertyPanel(
+                                       
getDisplayName(semanticAnnotationProfile.getPredicate()),
+                                       inputComponent);
+               }
+
+               if (annotationPanel == null) {
+                       showMessageDialog(null, format("Unable to handle %s",
+                                       
semanticAnnotationProfile.getPredicateString()),
+                                       "Annotation problem", ERROR_MESSAGE);
+                       return;
+               }
+
+               int answer = showConfirmDialog(null, annotationPanel,
+                               "Add/change annotation", OK_CANCEL_OPTION);
+               if (answer == OK_OPTION) {
+                       RDFNode response = 
bestFactory.getNewTargetNode(statement,
+                                       inputComponent);
+                       if (response == null)
+                               return;
+                       if (statement != null)
+                               
semanticAnnotationContextualView.changeStatement(statement,
+                                               
semanticAnnotationProfile.getPredicate(), response);
+                       else
+                               semanticAnnotationContextualView.addStatement(
+                                               
semanticAnnotationProfile.getPredicate(), response);
+               }
+       }
+
+       private PropertyPanelFactorySPI findBestPanelFactory() {
+               PropertyPanelFactorySPI result = null;
+               int currentRating = MIN_VALUE;
+               for (PropertyPanelFactorySPI factory : propertyPanelFactories) {
+                       int ratingForSemanticAnnotation = factory
+                                       
.getRatingForSemanticAnnotation(semanticAnnotationProfile);
+                       if (ratingForSemanticAnnotation > currentRating) {
+                               currentRating = ratingForSemanticAnnotation;
+                               result = factory;
+                       }
+               }
+               return result;
+       }
+
+       public static JPanel getPropertyPanel(String displayName,
+                       Component inputComponent) {
+               JPanel result = new JPanel();
+               result.setLayout(new BorderLayout());
+               JPanel messagePanel = new JPanel(new BorderLayout());
+               messagePanel.setBorder(new EmptyBorder(5, 5, 0, 0));
+               messagePanel.setBackground(WHITE);
+               result.add(messagePanel, NORTH);
+
+               JLabel inputLabel = new JLabel("Enter a value for the 
annotation");
+               inputLabel.setBackground(WHITE);
+               Font baseFont = inputLabel.getFont();
+               inputLabel.setFont(baseFont.deriveFont(BOLD));
+               messagePanel.add(inputLabel, NORTH);
+
+               JTextArea messageText = new JTextArea(format(
+                               "Enter a value for the annotation '%s'", 
displayName));
+               messageText.setMargin(new Insets(5, 10, 10, 10));
+               messageText.setMinimumSize(new Dimension(0, 30));
+               messageText.setFont(baseFont.deriveFont(11f));
+               messageText.setEditable(false);
+               messageText.setFocusable(false);
+               messagePanel.add(messageText, CENTER);
+
+               result.add(new JScrollPane(inputComponent), CENTER);
+               return result;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationUtils.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationUtils.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationUtils.java
new file mode 100644
index 0000000..68050c0
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/SemanticAnnotationUtils.java
@@ -0,0 +1,190 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.profile.Profile;
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+
+import org.apache.taverna.scufl2.api.annotation.Annotation;
+import org.apache.taverna.scufl2.api.common.AbstractNamed;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+import org.apache.jena.ontology.OntProperty;
+import org.apache.jena.ontology.OntResource;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.Statement;
+
+/**
+ * @author David Withers
+ */
+public class SemanticAnnotationUtils {
+       protected static final String ENCODING = "TURTLE";
+       /* Pretend-base for making relative URIs */
+       private static String BASE = 
"widget://4aa8c93c-3212-487c-a505-3e337adf54a3/";
+       private static Logger logger = getLogger(SemanticAnnotationUtils.class);
+
+       public static String getObjectName(Statement statement) {
+               return getDisplayName(statement.getObject());
+       }
+
+       public static String getDisplayName(RDFNode node) {
+               if (node == null)
+                       return "unknown";
+               else if (node.isAnon())
+                       return "anon";
+               else if (node.isLiteral())
+                       return node.asLiteral().getLexicalForm();
+               else if (node.isResource()) {
+                       Resource resource = node.asResource();
+                       if (resource instanceof OntResource) {
+                               String label = ((OntResource) 
resource).getLabel(null);
+                               if (label != null)
+                                       return label;
+                       }
+                       String localName = resource.getLocalName();
+                       if ((localName != null) && !localName.isEmpty())
+                               return localName;
+                       return resource.toString();
+               } else
+                       return "unknown";
+       }
+
+       public static Annotation findSemanticAnnotation(AbstractNamed 
annotated) {
+               for (Annotation annotation : annotated.getAnnotations())
+                       return annotation;
+               return null;
+       }
+
+       public static String getStrippedAnnotationContent(Annotation annotation)
+                       throws IOException {
+               AbstractNamed target = (AbstractNamed) annotation.getTarget();
+               return annotation.getRDFContent().replace(
+                               
target.getRelativeURI(annotation).toASCIIString(), BASE);
+       }
+
+       public static Annotation createSemanticAnnotation(WorkflowBundle bundle,
+                       AbstractNamed target, Model model) throws IOException {
+               Calendar now = new GregorianCalendar();
+               Annotation annotation = new Annotation();
+               annotation.setParent(bundle);
+               String path = annotation.getResourcePath();
+               annotation.setTarget(target);
+               // annotation.setAnnotatedBy(annotatedBy);
+               annotation.setAnnotatedAt(now);
+               // annotation.setSerializedBy(serializedBy);
+               annotation.setSerializedAt(now);
+               bundle.getResources().addResource(
+                               "@base<" + 
target.getRelativeURI(annotation).toASCIIString()
+                                               + "> .\n" + 
createTurtle(model), path, "text/rdf+n3");
+               return annotation;
+       }
+
+       /**
+        * @param model
+        * @return
+        */
+       public static String createTurtle(Model model) {
+               StringWriter stringWriter = new StringWriter();
+               model.write(stringWriter, ENCODING, BASE);
+               // Workaround for https://issues.apache.org/jira/browse/JENA-132
+               return stringWriter.toString().replace(BASE, "");
+       }
+
+       public static Model populateModel(WorkflowBundle annotated) {
+               Model result = createDefaultModel();
+               try {
+                       for (Annotation a : annotated.getAnnotations())
+                               populateModelFromString(result, 
a.getRDFContent());
+               } catch (Exception e) {
+                       logger.error("failed to construct semantic annotation 
model", e);
+               }
+               return result;
+       }
+
+       public static void populateModel(Model result, Annotation annotation)
+                       throws IOException {
+               AbstractNamed target = (AbstractNamed) annotation.getTarget();
+               String content = annotation.getRDFContent().replace(
+                               
target.getRelativeURI(annotation).toASCIIString(), BASE);
+               populateModelFromString(result, content);
+       }
+
+       public static void populateModelFromString(Model result, String 
content) {
+               result.read(new StringReader(content), BASE, ENCODING);
+       }
+
+       public static Resource createBaseResource(Model model) {
+               return model.createResource(BASE);
+       }
+
+       /**
+        * Check if a profile is satisfied by a component.
+        * 
+        * @param bundle
+        *            The component definition.
+        * @param componentProfile
+        *            The profile definition.
+        * @return The set of failed constraints. If empty, the profile is 
satisfied
+        *         by the component.
+        */
+       public static Set<SemanticAnnotationProfile> checkComponent(
+                       WorkflowBundle bundle, Profile componentProfile) {
+               // TODO Check port presence by name
+               Set<SemanticAnnotationProfile> problemProfiles = new 
HashSet<>();
+               Model model = populateModel(bundle);
+               Set<Statement> statements = model.listStatements().toSet();
+               try {
+                       for (SemanticAnnotationProfile saProfile : 
componentProfile
+                                       .getSemanticAnnotations()) {
+                               OntProperty predicate = 
saProfile.getPredicate();
+                               if (predicate == null)
+                                       continue;
+                               int count = 0;
+                               for (Statement statement : statements)
+                                       if 
(statement.getPredicate().equals(predicate))
+                                               count++;
+                               if (count < saProfile.getMinOccurs())
+                                       problemProfiles.add(saProfile);
+                               if (saProfile.getMaxOccurs() != null
+                                               && count > 
saProfile.getMaxOccurs())
+                                       // The UI should prevent this, but 
check anyway
+                                       problemProfiles.add(saProfile);
+                       }
+               } catch (ComponentException e) {
+                       logger.error("failed to look up profiles for semantic 
annotations", e);
+               }
+               return problemProfiles;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleContextualView.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleContextualView.java
new file mode 100644
index 0000000..8489fe6
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleContextualView.java
@@ -0,0 +1,93 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static java.awt.BorderLayout.CENTER;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.findSemanticAnnotation;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.getStrippedAnnotationContent;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.awt.BorderLayout;
+import java.io.IOException;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+
+import org.slf4j.Logger;
+
+import org.apache.taverna.scufl2.api.annotation.Annotation;
+import org.apache.taverna.scufl2.api.common.AbstractNamed;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.ui.views.contextualviews.ContextualView;
+
+/**
+ * @author alanrw
+ */
+public class TurtleContextualView extends ContextualView {
+       private static final long serialVersionUID = -3401885589263647202L;
+       private static final Logger log = getLogger(TurtleContextualView.class);
+       private JPanel panel;
+       private String annotationContent = "";
+
+       public TurtleContextualView(AbstractNamed selection, WorkflowBundle 
bundle)  {
+               Annotation annotation = findSemanticAnnotation(selection);
+               try {
+                       if (annotation != null)
+                               annotationContent = 
getStrippedAnnotationContent(annotation);
+               } catch (IOException e) {
+                       log.info("failed to read semantic annotation; using 
empty string", e);
+               }
+               initialise();
+               initView();
+       }
+
+       @Override
+       public JComponent getMainFrame() {
+               return panel;
+       }
+
+       @Override
+       public int getPreferredPosition() {
+               return 512;
+       }
+
+       @Override
+       public String getViewTitle() {
+               return "Turtle representation";
+       }
+
+       @Override
+       public void refreshView() {
+               initialise();
+       }
+
+       protected final void initialise() {
+               if (panel == null)
+                       panel = new JPanel(new BorderLayout());
+               else
+                       panel.removeAll();
+               JTextArea textArea = new JTextArea(20, 80);
+               textArea.setEditable(false);
+               textArea.setText(annotationContent);
+               panel.add(textArea, CENTER);
+               revalidate();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleInputPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleInputPanel.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleInputPanel.java
new file mode 100644
index 0000000..7356cc9
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/TurtleInputPanel.java
@@ -0,0 +1,105 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static org.apache.jena.rdf.model.ModelFactory.createOntologyModel;
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.EAST;
+import static java.awt.BorderLayout.SOUTH;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.populateModelFromString;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import org.apache.jena.ontology.Individual;
+import org.apache.jena.ontology.OntClass;
+import org.apache.jena.ontology.OntModel;
+import org.apache.taverna.lang.ui.DeselectingButton;
+import org.apache.taverna.lang.ui.ReadOnlyTextArea;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public class TurtleInputPanel extends JPanel {
+       JTextArea turtleTextArea = new JTextArea(30, 80);
+       ReadOnlyTextArea errors = new ReadOnlyTextArea(1, 80);
+       private OntClass clazz;
+
+       public TurtleInputPanel(OntClass clazz) {
+               super(new BorderLayout());
+               this.clazz = clazz;
+
+               add(new JScrollPane(turtleTextArea), CENTER);
+
+               turtleTextArea.setText("<#changeme> a <" + clazz.getURI() + 
">\n\n\n.");
+
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new BorderLayout());
+               JButton validateButton = new DeselectingButton(new 
AbstractAction(
+                               "Validate") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               getContentAsModel();
+                       }
+               });
+               buttonPanel.add(errors, CENTER);
+               errors.setOpaque(false);
+               buttonPanel.add(validateButton, EAST);
+               add(buttonPanel, SOUTH);
+       }
+
+       public OntModel getContentAsModel() {
+               OntModel result = createOntologyModel();
+               try {
+                       populateModelFromString(result, getContentAsString());
+
+                       // Check it is not still called changeme
+                       List<Individual> individuals = 
result.listIndividuals(clazz)
+                                       .toList();
+                       if (individuals.isEmpty()) {
+                               errors.setText("No valid individuals");
+                               return null;
+                       }
+                       for (Individual i : individuals)
+                               if (i.getURI().endsWith("changeme")) {
+                                       errors.setText("Name has not been 
changed");
+                                       return null;
+                               }
+
+                       errors.setText("No errors found");
+                       return result;
+               } catch (Throwable ex) { // syntax error?
+                       errors.setText(ex.getMessage());
+                       return null;
+               }
+       }
+
+       public String getContentAsString() {
+               return turtleTextArea.getText();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnrecognizedStatementPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnrecognizedStatementPanel.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnrecognizedStatementPanel.java
new file mode 100644
index 0000000..67d806d
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnrecognizedStatementPanel.java
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static java.lang.String.format;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.jena.rdf.model.Statement;
+
+/**
+ * @author alanrw
+ * 
+ */
+@SuppressWarnings("serial")
+public class UnrecognizedStatementPanel extends JPanel {
+       public UnrecognizedStatementPanel(Statement statement) {
+               setLayout(new BorderLayout());
+               setBorder(new GreyBorder());
+               add(new JLabel(format("Unable to find %s in the profile",
+                               statement.getPredicate())));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnresolveablePredicatePanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnresolveablePredicatePanel.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnresolveablePredicatePanel.java
new file mode 100644
index 0000000..a7e2c89
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/annotation/UnresolveablePredicatePanel.java
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.annotation;
+
+import static java.lang.String.format;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public class UnresolveablePredicatePanel extends JPanel {
+       public UnresolveablePredicatePanel(
+                       SemanticAnnotationProfile semanticAnnotationProfile) {
+               setLayout(new BorderLayout());
+               setBorder(new GreyBorder());
+               add(new JLabel(format("Unable to resolve %s in the ontology",
+                               
semanticAnnotationProfile.getPredicateString())));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigurationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigurationPanel.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigurationPanel.java
new file mode 100644
index 0000000..712b861
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigurationPanel.java
@@ -0,0 +1,171 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.config;
+
+import static java.awt.event.ItemEvent.SELECTED;
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.api.config.ComponentPropertyNames.COMPONENT_NAME;
+import static 
io.github.taverna_extras.component.api.config.ComponentPropertyNames.COMPONENT_VERSION;
+import static 
io.github.taverna_extras.component.api.config.ComponentPropertyNames.FAMILY_NAME;
+import static 
io.github.taverna_extras.component.api.config.ComponentPropertyNames.REGISTRY_BASE;
+import static io.github.taverna_extras.component.ui.util.Utils.SHORT_STRING;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.SortedMap;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.panel.ComponentListCellRenderer;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.services.ServiceRegistry;
+import 
org.apache.taverna.workbench.ui.views.contextualviews.activity.ActivityConfigurationPanel;
+
+@SuppressWarnings("serial")
+public class ComponentConfigurationPanel extends ActivityConfigurationPanel {
+       private static Logger logger = 
getLogger(ComponentConfigurationPanel.class);
+
+       private ComponentFactory factory;//FIXME beaninject
+       private ServiceRegistry sr;
+
+       private final JComboBox<Object> componentVersionChoice = new 
JComboBox<>();
+
+       public ComponentConfigurationPanel(Activity activity,
+                       ComponentFactory factory, ServiceRegistry 
serviceRegistry) {
+               super(activity);
+               sr = serviceRegistry;
+               this.factory = factory;
+               componentVersionChoice.setPrototypeDisplayValue(SHORT_STRING);
+               initGui();
+       }
+
+       private Version getSelectedVersion() {
+               return (Version) componentVersionChoice.getSelectedItem();
+       }
+       private URI getRegistryBase() {
+               return URI.create(getProperty(REGISTRY_BASE));
+       }
+       private String getFamilyName() {
+               return getProperty(FAMILY_NAME);
+       }
+       private String getComponentName() {
+               return getProperty(COMPONENT_NAME);
+       }
+       private Integer getComponentVersion() {
+               return Integer.parseInt(getProperty(COMPONENT_VERSION));
+       }
+
+       protected void initGui() {
+               removeAll();
+               setLayout(new GridLayout(0, 2));
+
+               componentVersionChoice.setRenderer(new 
ComponentListCellRenderer<>());
+               componentVersionChoice.addItemListener(new ItemListener() {
+                       @Override
+                       public void itemStateChanged(ItemEvent event) {
+                               if (event.getStateChange() == SELECTED)
+                                       updateToolTipText();
+                       }
+               });
+               updateComponentVersionChoice();
+
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.insets = new Insets(0, 5, 0, 5);
+               gbc.gridx = 0;
+               gbc.anchor = GridBagConstraints.WEST;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               gbc.gridy = 2;
+               this.add(new JLabel("Component version:"), gbc);
+               gbc.gridx = 1;
+               gbc.weightx = 1;
+               this.add(componentVersionChoice, gbc);
+
+               // Populate fields from activity configuration bean
+               refreshConfiguration();
+       }
+
+       /**
+        * Check that user values in UI are valid
+        */
+       @Override
+       public boolean checkValues() {
+               return true;
+       }
+
+       /**
+        * Check if the user has changed the configuration from the original
+        */
+       @Override
+       public boolean isConfigurationChanged() {
+               return !getSelectedVersion().getVersionNumber().equals(
+                               getComponentVersion());
+       }
+
+       /**
+        * Prepare a new configuration bean from the UI, to be returned with
+        * getConfiguration()
+        */
+       @Override
+       public void noteConfiguration() {
+               setProperty(COMPONENT_VERSION, 
getSelectedVersion().getVersionNumber()
+                               .toString());
+               //FIXME is this right at all???
+               configureInputPorts(sr);
+               configureOutputPorts(sr);
+       }
+
+       private void updateComponentVersionChoice() {
+               Component component;
+               componentVersionChoice.removeAllItems();
+               componentVersionChoice.setToolTipText(null);
+               try {
+                       component = 
factory.getComponent(getRegistryBase().toURL(),
+                                       getFamilyName(), getComponentName());
+               } catch (ComponentException | MalformedURLException e) {
+                       logger.error("failed to get component", e);
+                       return;
+               }
+               SortedMap<Integer, Version> componentVersionMap = component
+                               .getComponentVersionMap();
+               for (Version v : componentVersionMap.values())
+                       componentVersionChoice.addItem(v);
+               componentVersionChoice.setSelectedItem(componentVersionMap
+                               .get(getComponentVersion()));
+               updateToolTipText();
+       }
+
+       private void updateToolTipText() {
+               Version selectedVersion = (Version) componentVersionChoice
+                               .getSelectedItem();
+               
componentVersionChoice.setToolTipText(selectedVersion.getDescription());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigureAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigureAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigureAction.java
new file mode 100644
index 0000000..81c9d2f
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/config/ComponentConfigureAction.java
@@ -0,0 +1,69 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.config;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import io.github.taverna_extras.component.api.ComponentFactory;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.services.ServiceRegistry;
+import org.apache.taverna.workbench.activityicons.ActivityIconManager;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+import 
org.apache.taverna.workbench.ui.actions.activity.ActivityConfigurationAction;
+import 
org.apache.taverna.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+
+@SuppressWarnings("serial")
+public class ComponentConfigureAction extends ActivityConfigurationAction {
+       private EditManager editManager;
+       private FileManager fileManager;
+       private ServiceRegistry serviceRegistry;
+       private ComponentFactory factory;
+
+       public ComponentConfigureAction(Activity activity, Frame owner,
+                       ComponentFactory factory, ActivityIconManager 
activityIconManager,
+                       ServiceDescriptionRegistry serviceDescriptionRegistry,
+                       EditManager editManager, FileManager fileManager,
+                       ServiceRegistry serviceRegistry) {
+               super(activity, activityIconManager, 
serviceDescriptionRegistry);
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+               this.serviceRegistry = serviceRegistry;
+               this.factory = factory;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               ActivityConfigurationDialog currentDialog = 
getDialog(getActivity());
+               if (currentDialog != null) {
+                       currentDialog.toFront();
+                       return;
+               }
+
+               ComponentConfigurationPanel configView = new 
ComponentConfigurationPanel(
+                               activity, factory, serviceRegistry);
+               ActivityConfigurationDialog dialog = new 
ActivityConfigurationDialog(
+                               getActivity(), configView, editManager);
+               setDialog(getActivity(), dialog, fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthCheckExplainer.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthCheckExplainer.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthCheckExplainer.java
new file mode 100644
index 0000000..7a2442f
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthCheckExplainer.java
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.file;
+
+import static java.util.Collections.sort;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+import static 
io.github.taverna_extras.component.ui.util.ComponentHealthCheck.FAILS_PROFILE;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+import io.github.taverna_extras.component.ui.util.ComponentHealthCheck;
+import org.apache.taverna.visit.VisitKind;
+import org.apache.taverna.visit.VisitReport;
+
+//import net.sf.taverna.t2.workbench.report.explainer.VisitExplainer;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDataflowHealthCheckExplainer implements VisitExplainer {
+       private static final Comparator<SemanticAnnotationProfile> comparator = 
new Comparator<SemanticAnnotationProfile>() {
+               @Override
+               public int compare(SemanticAnnotationProfile a,
+                               SemanticAnnotationProfile b) {
+                       return getDisplayName(a.getPredicate()).compareTo(
+                                       getDisplayName(b.getPredicate()));
+               }
+       };
+
+       @Override
+       public boolean canExplain(VisitKind vk, int resultId) {
+               return vk instanceof ComponentHealthCheck
+                               && resultId == FAILS_PROFILE;
+       }
+
+       @Override
+       public JComponent getExplanation(VisitReport vr) {
+               @SuppressWarnings("unchecked")
+               Set<SemanticAnnotationProfile> problemProfiles = 
(Set<SemanticAnnotationProfile>) vr
+                               .getProperty("problemProfiles");
+               List<SemanticAnnotationProfile> sortedList = new ArrayList<>(
+                               problemProfiles);
+               sort(sortedList, comparator);
+               StringBuilder text = new StringBuilder();
+               for (SemanticAnnotationProfile profile : sortedList)
+                       
text.append(getSemanticProfileExplanation(profile)).append("\n");
+               return new JTextArea(text.toString());
+       }
+
+       @Override
+       public JComponent getSolution(VisitReport vr) {
+               return new JTextArea("Correct the semantic annotation");
+       }
+
+       private static String getSemanticProfileExplanation(
+                       SemanticAnnotationProfile p) {
+               Integer minOccurs = p.getMinOccurs();
+               Integer maxOccurs = p.getMaxOccurs();
+               String displayName = getDisplayName(p.getPredicate());
+               if (maxOccurs == null)
+                       return displayName + " must have at least " + minOccurs 
+ " value";
+               if (minOccurs.equals(maxOccurs))
+                       return displayName + " must have " + minOccurs + " 
value(s)";
+               return displayName + " must have between " + minOccurs + " and "
+                               + maxOccurs + " value(s)";
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthChecker.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthChecker.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthChecker.java
new file mode 100644
index 0000000..7ce0c1b
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentDataflowHealthChecker.java
@@ -0,0 +1,114 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.file;
+
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.checkComponent;
+import static 
io.github.taverna_extras.component.ui.util.ComponentHealthCheck.FAILS_PROFILE;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Version;
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+import io.github.taverna_extras.component.ui.util.ComponentHealthCheck;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.visit.VisitReport;
+import static org.apache.taverna.visit.VisitReport.Status.SEVERE;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workflowmodel.Dataflow;
+import org.apache.taverna.workflowmodel.health.HealthChecker;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDataflowHealthChecker implements HealthChecker<Dataflow> 
{
+       private static final String PROFILE_UNSATISFIED_MSG = "Workflow does 
not satisfy component profile";
+       private static Logger logger = 
getLogger(ComponentDataflowHealthChecker.class);
+
+       private FileManager fm;
+       private ComponentHealthCheck visitType = 
ComponentHealthCheck.getInstance(); //FIXME beaninject?
+       private ComponentFactory factory;
+
+       public void setComponentFactory(ComponentFactory factory) {
+               this.factory = factory;
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       private Version.ID getSource(Object o) {
+               return (Version.ID) fm.getDataflowSource((WorkflowBundle) o);
+       }
+
+       public void checkProfileSatisfied(WorkflowBundle bundle) {
+               //FIXME
+       }
+       @Override
+       public boolean canVisit(Object o) {
+               try {
+                       return getSource(o) != null;
+               } catch (IllegalArgumentException e) {
+                       // Not open?
+               } catch (ClassCastException e) {
+                       // Not dataflow? Not component?
+               }
+               return false;
+       }
+
+       @Override
+       public VisitReport visit(WorkflowBundle dataflow, List<Object> 
ancestry) {
+               try {
+                       Version.ID ident = getSource(dataflow);
+                       Family family = 
factory.getFamily(ident.getRegistryBase(),
+                                       ident.getFamilyName());
+
+                       Set<SemanticAnnotationProfile> problemProfiles = 
checkComponent(
+                                       dataflow, family.getComponentProfile());
+                       if (problemProfiles.isEmpty())
+                               return null;
+
+                       VisitReport visitReport = new VisitReport(visitType, 
dataflow,
+                                       PROFILE_UNSATISFIED_MSG, FAILS_PROFILE, 
SEVERE);
+                       visitReport.setProperty("problemProfiles", 
problemProfiles);
+                       return visitReport;
+               } catch (ComponentException e) {
+                       logger.error(
+                                       "failed to comprehend profile while 
checking for match", e);
+                       return null;
+               }
+       }
+//
+//    @Override
+//    public VisitReport visit(Dataflow o, List<Object> ancestry) {
+//        throw new UnsupportedOperationException("Not supported yet."); //To 
change body of generated methods, choose Tools | Templates.
+//    }
+//
+//    @Override
+//    public boolean isTimeConsuming() {
+//        throw new UnsupportedOperationException("Not supported yet."); //To 
change body of generated methods, choose Tools | Templates.
+//    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentOpener.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentOpener.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentOpener.java
new file mode 100644
index 0000000..f2e16e6
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentOpener.java
@@ -0,0 +1,88 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.file;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.Version.ID;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.AbstractDataflowPersistenceHandler;
+import org.apache.taverna.workbench.file.DataflowInfo;
+import org.apache.taverna.workbench.file.DataflowPersistenceHandler;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.file.exceptions.OpenException;
+
+/**
+ * @author alanrw
+ */
+public class ComponentOpener extends AbstractDataflowPersistenceHandler
+               implements DataflowPersistenceHandler {
+       private static Logger logger = getLogger(ComponentOpener.class);
+
+       private ComponentFactory factory;
+       private FileType fileType;
+
+       public void setComponentFactory(ComponentFactory factory) {
+               this.factory = factory;
+       }
+
+       public void setFileType(FileType fileType) {
+               this.fileType = fileType;
+       }
+       
+       @Override
+       public DataflowInfo openDataflow(FileType fileType, Object source)
+                       throws OpenException {
+               if (!getOpenFileTypes().contains(fileType))
+                       throw new IllegalArgumentException("Unsupported file 
type "
+                                       + fileType);
+               if (!(source instanceof Version.ID))
+                       throw new IllegalArgumentException("Unsupported source 
type "
+                                       + source.getClass().getName());
+
+               WorkflowBundle d;
+               try {
+                       d = factory.getVersion((ID) source).getImplementation();
+               } catch (ComponentException e) {
+                       logger.error("Unable to read dataflow", e);
+                       throw new OpenException("Unable to read dataflow", e);
+               }
+               return new DataflowInfo(fileType, source, d, new Date());
+       }
+
+       @Override
+       public List<FileType> getOpenFileTypes() {
+               return Arrays.<FileType> asList(fileType);
+       }
+
+       @Override
+       public List<Class<?>> getOpenSourceTypes() {
+               return Arrays.<Class<?>> asList(Version.ID.class);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentSaver.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentSaver.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentSaver.java
new file mode 100644
index 0000000..19b52d9
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/ComponentSaver.java
@@ -0,0 +1,185 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.file;
+
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.checkComponent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.Version;
+import 
io.github.taverna_extras.component.api.profile.SemanticAnnotationProfile;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProvider;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.validation.ValidationReport;
+import org.apache.taverna.scufl2.validation.structural.StructuralValidator;
+import org.apache.taverna.workbench.file.AbstractDataflowPersistenceHandler;
+import org.apache.taverna.workbench.file.DataflowInfo;
+import org.apache.taverna.workbench.file.DataflowPersistenceHandler;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.file.exceptions.SaveException;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSaver extends AbstractDataflowPersistenceHandler
+               implements DataflowPersistenceHandler {
+       private static final String UNSATISFIED_PROFILE_WARNING = "The 
component does not satisfy the profile.\n"
+                       + "See validation report.\nDo you still want to save?";
+       private static final Logger logger = getLogger(ComponentSaver.class);
+
+       private ComponentFactory factory;
+       private ComponentServiceProvider provider;
+       private FileType cft;
+
+       public void setComponentFactory(ComponentFactory factory) {
+               this.factory = factory;
+       }
+
+       public void setFileType(FileType fileType) {
+               this.cft = fileType;
+       }
+
+       public void setServiceProvider(ComponentServiceProvider provider) {
+               this.provider = provider;
+       }
+
+       @Override
+       public DataflowInfo saveDataflow(WorkflowBundle bundle, FileType 
fileType,
+                       Object destination) throws SaveException {
+               if (!getSaveFileTypes().contains(fileType))
+                       throw new IllegalArgumentException("Unsupported file 
type "
+                                       + fileType);
+               if (!(destination instanceof Version.ID))
+                       throw new IllegalArgumentException("Unsupported 
destination type "
+                                       + destination.getClass().getName());
+
+               ValidationReport structuralValidity = new StructuralValidator()
+                               .validate(bundle);
+               if (structuralValidity.detectedProblems())
+                       throw new SaveException(
+                                       "Cannot save a structurally invalid 
workflow as a component",
+                                       structuralValidity.getException());
+
+               /*
+                * Saving an invalid dataflow is OK. Validity check is done to 
get
+                * predicted depth for output (if possible)
+                */
+
+               Version.ID ident = (Version.ID) destination;
+
+               if (ident.getComponentVersion() == -1) {
+                       Version.ID newIdent = new Version.Identifier(
+                                       ident.getRegistryBase(), 
ident.getFamilyName(),
+                                       ident.getComponentName(), 0);
+                       return new DataflowInfo(cft, newIdent, bundle);
+               }
+
+               Family family;
+               try {
+                       Registry registry = 
factory.getRegistry(ident.getRegistryBase());
+                       family = 
registry.getComponentFamily(ident.getFamilyName());
+               } catch (ComponentException e) {
+                       throw new SaveException("Unable to read component", e);
+               }
+
+               Version newVersion = null;
+               try {
+                       List<SemanticAnnotationProfile> problemProfiles = new 
ArrayList<>(
+                                       checkComponent(bundle, 
family.getComponentProfile()));
+
+                       if (!problemProfiles.isEmpty()) {
+                               int answer = showConfirmDialog(null,
+                                               UNSATISFIED_PROFILE_WARNING, 
"Profile problem",
+                                               OK_CANCEL_OPTION);
+                               if (answer != OK_OPTION)
+                                       throw new SaveException("Saving 
cancelled");
+                       }
+
+                       JTextArea descriptionArea = new JTextArea(10, 60);
+                       descriptionArea.setLineWrap(true);
+                       descriptionArea.setWrapStyleWord(true);
+                       final JScrollPane descriptionScrollPane = new 
JScrollPane(
+                                       descriptionArea);
+                       if (ident.getComponentVersion() == 0) {
+                               int answer = showConfirmDialog(null, 
descriptionScrollPane,
+                                               "Component description", 
OK_CANCEL_OPTION);
+                               if (answer != OK_OPTION)
+                                       throw new SaveException("Saving 
cancelled");
+                               newVersion = family.createComponentBasedOn(
+                                               ident.getComponentName(), 
descriptionArea.getText(),
+                                               bundle);
+                       } else {
+                               Component component = family.getComponent(ident
+                                               .getComponentName());
+                               int answer = showConfirmDialog(null, 
descriptionScrollPane,
+                                               "Version description", 
OK_CANCEL_OPTION);
+                               if (answer != OK_OPTION)
+                                       throw new SaveException("Saving 
cancelled");
+                               newVersion = component.addVersionBasedOn(bundle,
+                                               descriptionArea.getText());
+                       }
+               } catch (ComponentException e) {
+                       logger.error("Unable to save new version of component", 
e);
+                       throw new SaveException("Unable to save new version of 
component",
+                                       e);
+               }
+
+               Version.ID newIdent = new 
Version.Identifier(ident.getRegistryBase(),
+                               ident.getFamilyName(), ident.getComponentName(),
+                               newVersion.getVersionNumber());
+               provider.refreshProvidedComponent(ident);
+               return new DataflowInfo(cft, newIdent, bundle);
+       }
+
+       @Override
+       public List<FileType> getSaveFileTypes() {
+               return Arrays.<FileType> asList(cft);
+       }
+
+       @Override
+       public List<Class<?>> getSaveDestinationTypes() {
+               return Arrays.<Class<?>> asList(Version.ID.class);
+       }
+
+       @Override
+       public boolean wouldOverwriteDataflow(WorkflowBundle dataflow,
+                       FileType fileType, Object destination, DataflowInfo 
lastDataflowInfo) {
+               if (!getSaveFileTypes().contains(fileType))
+                       throw new IllegalArgumentException("Unsupported file 
type "
+                                       + fileType);
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/FileManagerObserver.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/FileManagerObserver.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/FileManagerObserver.java
new file mode 100644
index 0000000..8ee99b9
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/file/FileManagerObserver.java
@@ -0,0 +1,146 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.file;
+
+import static java.awt.Color.WHITE;
+import static java.awt.Font.BOLD;
+import static javax.swing.SwingUtilities.invokeLater;
+import static javax.swing.SwingUtilities.isEventDispatchThread;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.border.Border;
+
+import org.apache.batik.swing.JSVGCanvas;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.StartupSPI;
+import org.apache.taverna.workbench.configuration.colour.ColourManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.events.FileManagerEvent;
+import org.apache.taverna.workbench.models.graph.svg.SVGGraphController;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+public class FileManagerObserver implements StartupSPI {
+       private static final Color COLOR = new Color(230, 147, 210);
+
+       private FileManager fileManager;
+       private ColourManager colours;
+       private GraphViewComponent graphView;
+       private Utils utils;
+
+       public void setFileManager(FileManager fileManager) {
+               this.fileManager = fileManager;
+       }
+
+       public void setColourManager(ColourManager colours) {
+               this.colours = colours;
+       }
+
+       public void setGraphView(GraphViewComponent graphView) {
+               this.graphView = graphView;
+       }
+
+       public void setUtils(Utils utils) {
+               this.utils = utils;
+       }
+
+       @Override
+       public boolean startup() {
+               colours.setPreferredColour(
+                               
"io.github.taverna_extras.component.registry.Component", COLOR);
+               colours.setPreferredColour(
+                               
"io.github.taverna_extras.component.ComponentActivity", COLOR);
+               fileManager.addObserver(new Observer<FileManagerEvent>() {
+                       @Override
+                       public void notify(Observable<FileManagerEvent> 
observable,
+                                       FileManagerEvent event) throws 
Exception {
+                               FileManagerObserverRunnable runnable = new 
FileManagerObserverRunnable();
+                               if (isEventDispatchThread())
+                                       runnable.run();
+                               else
+                                       invokeLater(runnable);
+                       }
+               });
+               return true;
+       }
+
+       @Override
+       public int positionHint() {
+               return 200;
+       }
+
+       public class FileManagerObserverRunnable implements Runnable {
+               @Override
+               public void run() {
+                       WorkflowBundle currentDataflow = 
fileManager.getCurrentDataflow();
+                       if (currentDataflow == null)
+                               return;
+                       SVGGraphController graphController = 
(SVGGraphController) graphView
+                                       
.getGraphController(currentDataflow.getMainWorkflow());
+                       if (graphController == null)
+                               return;
+                       JSVGCanvas svgCanvas = graphController.getSVGCanvas();
+                       Object dataflowSource = fileManager
+                                       .getDataflowSource(currentDataflow);
+                       if (utils.currentDataflowIsComponent())
+                               svgCanvas.setBorder(new ComponentBorder(
+                                               (Version.ID) dataflowSource));
+                       else
+                               svgCanvas.setBorder(null);
+                       svgCanvas.repaint();
+               }
+       }
+
+       static class ComponentBorder implements Border {
+               private final Insets insets = new Insets(25, 0, 0, 0);
+               private final String text;
+
+               public ComponentBorder(Version.ID identification) {
+                       text = "Component : " + 
identification.getComponentName();
+               }
+
+               @Override
+               public Insets getBorderInsets(java.awt.Component c) {
+                       return insets;
+               }
+
+               @Override
+               public boolean isBorderOpaque() {
+                       return true;
+               }
+
+               @Override
+               public void paintBorder(java.awt.Component c, Graphics g, int 
x, int y,
+                               int width, int height) {
+                       g.setColor(COLOR);
+                       g.fillRect(x, y, width, 20);
+                       g.setFont(g.getFont().deriveFont(BOLD));
+                       g.setColor(WHITE);
+                       g.drawString(text, x + 5, y + 15);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/localworld/LocalWorld.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/localworld/LocalWorld.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/localworld/LocalWorld.java
new file mode 100644
index 0000000..a35ab61
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/localworld/LocalWorld.java
@@ -0,0 +1,107 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.localworld;
+
+import static org.apache.jena.rdf.model.ModelFactory.createOntologyModel;
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.createTurtle;
+import static 
io.github.taverna_extras.component.ui.annotation.SemanticAnnotationUtils.populateModelFromString;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.apache.jena.ontology.Individual;
+import org.apache.jena.ontology.OntClass;
+import org.apache.jena.ontology.OntModel;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.taverna.configuration.app.ApplicationConfiguration;
+
+/**
+ * @author alanrw
+ */
+public class LocalWorld {
+       private static final String FILENAME = "localWorld.ttl";
+       private static final Logger logger = getLogger(LocalWorld.class);
+       protected static final String ENCODING = "TURTLE";
+       private static LocalWorld instance = null;
+
+       private OntModel model;
+
+       public synchronized static LocalWorld getInstance() {
+               if (instance == null)
+                       instance = new LocalWorld();
+               return instance;
+       }
+
+       private LocalWorld() {
+               File modelFile = new File(calculateComponentsDirectory(), 
FILENAME);
+               model = createOntologyModel();
+               if (modelFile.exists())
+                       try (Reader in = new InputStreamReader(new 
FileInputStream(
+                                       modelFile), "UTF-8")) {
+                               model.read(in, null, ENCODING);
+                       } catch (IOException e) {
+                               logger.error("failed to construct local 
annotation world", e);
+                       }
+       }
+
+       ApplicationConfiguration config;//FIXME beaninject
+
+       public File calculateComponentsDirectory() {
+               return new File(config.getApplicationHomeDir(), "components");
+       }
+
+       public Individual createIndividual(String urlString, OntClass 
rangeClass) {
+               try {
+                       return model.createIndividual(urlString, rangeClass);
+               } finally {
+                       saveModel();
+               }
+       }
+
+       private void saveModel() {
+               File modelFile = new File(calculateComponentsDirectory(), 
FILENAME);
+               try (OutputStream out = new FileOutputStream(modelFile)) {
+                       out.write(createTurtle(model).getBytes("UTF-8"));
+               } catch (IOException e) {
+                       logger.error("failed to save local annotation world", 
e);
+               }
+       }
+
+       public List<Individual> getIndividualsOfClass(Resource clazz) {
+               return model.listIndividuals(clazz).toList();
+       }
+
+       public void addModelFromString(String addedModel) {
+               try {
+                       populateModelFromString(model, addedModel);
+               } finally {
+                       saveModel();
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/AbstractContextComponentMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/AbstractContextComponentMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/AbstractContextComponentMenuAction.java
new file mode 100644
index 0000000..0911a66
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/AbstractContextComponentMenuAction.java
@@ -0,0 +1,58 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import java.net.URI;
+
+import io.github.taverna_extras.component.api.config.ComponentConfig;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+
+public abstract class AbstractContextComponentMenuAction extends 
AbstractContextualMenuAction {
+       public AbstractContextComponentMenuAction(URI parentId, int 
positionHint) {
+               super(parentId, positionHint);
+       }
+
+       public AbstractContextComponentMenuAction(URI parentId, int 
positionHint, URI id) {
+               super(parentId, positionHint, id);
+       }
+
+       protected boolean isComponentActivity(Activity act) {
+               if (act == null)
+                       return false;
+               return act.getType().equals(ComponentConfig.URI);
+       }
+
+       protected Activity findActivity() {
+               if (getContextualSelection() == null)
+                       return null;
+               Object selection = getContextualSelection().getSelection();
+               if (selection instanceof Processor) {
+                       Processor processor = (Processor) selection;
+                       return 
processor.getParent().getParent().getMainProfile()
+                                       
.getProcessorBindings().getByName(processor.getName())
+                                       .getBoundActivity();
+               } else if (selection instanceof Activity)
+                       return (Activity) selection;
+               return null;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentConfigureMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentConfigureMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentConfigureMenuAction.java
new file mode 100644
index 0000000..0feb63e
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentConfigureMenuAction.java
@@ -0,0 +1,81 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import static javax.swing.Action.NAME;
+import static 
io.github.taverna_extras.component.ui.ComponentConstants.ACTIVITY_URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.ui.config.ComponentConfigureAction;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.services.ServiceRegistry;
+import org.apache.taverna.workbench.activityicons.ActivityIconManager;
+import 
org.apache.taverna.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+
+public class ComponentConfigureMenuAction extends
+               AbstractConfigureActivityMenuAction {
+       public ComponentConfigureMenuAction() {
+               super(ACTIVITY_URI);
+       }
+
+       private ActivityIconManager aim;
+       private ServiceDescriptionRegistry sdr;
+       private EditManager em;
+       private FileManager fm;
+       private ServiceRegistry str;
+       private ComponentFactory factory;
+
+       public void setActivityIconManager(ActivityIconManager aim) {
+               this.aim = aim;
+       }
+
+       public void setServiceDescriptionRegistry(ServiceDescriptionRegistry 
sdr) {
+               this.sdr = sdr;
+       }
+
+       public void setEditManager(EditManager em) {
+               this.em = em;
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       public void setServiceTypeRegistry(ServiceRegistry str) {
+               this.str = str;
+       }
+
+       public void setComponentFactory(ComponentFactory factory) {
+               this.factory = factory;
+       }
+
+       @Override
+       protected Action createAction() {
+               Action result = new ComponentConfigureAction(findActivity(),
+                               getParentFrame(), factory, aim, sdr, em, fm, 
str);
+               result.putValue(NAME, "Configure component");
+               addMenuDots(result);
+               return result;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentMenu.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentMenu.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentMenu.java
new file mode 100644
index 0000000..99cec65
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentMenu.java
@@ -0,0 +1,41 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import java.net.URI;
+import org.apache.taverna.ui.menu.AbstractMenu;
+import static org.apache.taverna.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+
+/**
+ * @author alanrw
+ */
+public class ComponentMenu extends AbstractMenu {
+       public static final URI COMPONENT = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#component";);
+       public static final String TITLE = "Components";
+
+       public ComponentMenu() {
+               super(DEFAULT_MENU_BAR, 950, COMPONENT, makeAction());
+       }
+
+       public static DummyAction makeAction() {
+               return new DummyAction(TITLE);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentSection.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentSection.java
new file mode 100644
index 0000000..337ee73
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ComponentSection.java
@@ -0,0 +1,44 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import java.net.URI;
+import org.apache.taverna.ui.menu.AbstractMenuSection;
+
+/**
+ * @author alanrw
+ * 
+ */
+public class ComponentSection extends AbstractMenuSection {
+       public static final String COMPONENT_SECTION = "Components";
+       public static final URI componentSection = URI
+                       
.create("http://taverna.sf.net/2009/contextMenu/components";);
+       public static final URI editSection = URI
+                       .create("http://taverna.sf.net/2009/contextMenu/edit";);
+
+       public ComponentSection() {
+               super(editSection, 100, componentSection);
+       }
+
+       @Override
+       public boolean isEnabled() {
+               return super.isEnabled();
+       }
+}

Reply via email to