http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-client/pom.xml b/taverna-server-client/pom.xml
new file mode 100644
index 0000000..d16b07a
--- /dev/null
+++ b/taverna-server-client/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.apache.taverna.server</groupId>
+               <artifactId>taverna-server</artifactId>
+               <version>3.1.0-incubating-SNAPSHOT</version>
+       </parent>
+       <artifactId>taverna-server-client</artifactId>
+       <packaging>bundle</packaging>
+       <name>Apache Taverna Server Client OSGi Module</name>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.jvnet.ws.wadl</groupId>
+                       <artifactId>wadl-core</artifactId>
+                       <version>1.1.6</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.sun.jersey</groupId>
+                       <artifactId>jersey-client</artifactId>
+                       <version>1.8</version>
+               </dependency>
+               <dependency>
+                       <groupId>commons-io</groupId>
+                       <artifactId>commons-io</artifactId>
+                       <version>2.4</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.tika</groupId>
+                       <artifactId>tika-core</artifactId>
+                       <version>1.5</version>
+               </dependency>
+               <dependency>
+                       <groupId>${project.parent.groupId}</groupId>
+                       <artifactId>taverna-server-usagerecord</artifactId>
+                       <version>${project.parent.version}</version>
+               </dependency>
+       </dependencies>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               
<Export-Package>uk.org.taverna.server.client</Export-Package>
+                                               
<Private-Package>uk.org.taverna.server.client.*</Private-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.jvnet.ws.wadl</groupId>
+                               <artifactId>wadl-client-plugin</artifactId>
+                               <version>1.1.6</version>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>generate</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       
<packageName>org.taverna.server.client.wadl</packageName>
+                                       <includes>*.wadl</includes>
+                                       <customClassNames>
+                                               <property>
+                                                       
<name>http://example.com/taverna/rest</name>
+                                                       
<value>TavernaServer</value>
+                                               </property>
+                                       </customClassNames>
+                               </configuration>
+                       </plugin>
+               </plugins>
+               <pluginManagement>
+                       <plugins>
+                               <!--This plugin's configuration is used to 
store Eclipse m2e settings
+                                       only. It has no influence on the Maven 
build itself. -->
+                               <plugin>
+                                       <groupId>org.eclipse.m2e</groupId>
+                                       
<artifactId>lifecycle-mapping</artifactId>
+                                       <version>1.0.0</version>
+                                       <configuration>
+                                               <lifecycleMappingMetadata>
+                                                       <pluginExecutions>
+                                                               
<pluginExecution>
+                                                                       
<pluginExecutionFilter>
+                                                                               
<groupId>
+                                                                               
        org.jvnet.ws.wadl
+                                                                               
</groupId>
+                                                                               
<artifactId>
+                                                                               
        wadl-client-plugin
+                                                                               
</artifactId>
+                                                                               
<versionRange>
+                                                                               
        [1.1.6,)
+                                                                               
</versionRange>
+                                                                               
<goals>
+                                                                               
        <goal>generate</goal>
+                                                                               
</goals>
+                                                                       
</pluginExecutionFilter>
+                                                                       <action>
+                                                                               
<execute />
+                                                                       
</action>
+                                                               
</pluginExecution>
+                                                       </pluginExecutions>
+                                               </lifecycleMappingMetadata>
+                                       </configuration>
+                               </plugin>
+                       </plugins>
+               </pluginManagement>
+       </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
new file mode 100644
index 0000000..263034c
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
@@ -0,0 +1,20 @@
+package uk.org.taverna.server.client;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+abstract class Connected {
+       void checkError(ClientResponse response) throws ClientException,
+                       ServerException {
+               ClientResponse.Status s = response.getClientResponseStatus();
+               if (s.getStatusCode() == 401)
+                       throw new TavernaServer.AuthorizationException("not 
authorized",
+                                       null);
+               if (s.getStatusCode() >= 500)
+                       throw new 
TavernaServer.ServerException(s.getReasonPhrase(), null);
+               if (s.getStatusCode() >= 400)
+                       throw new 
TavernaServer.ClientException(s.getReasonPhrase(), null);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
new file mode 100644
index 0000000..267707d
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
@@ -0,0 +1,39 @@
+package uk.org.taverna.server.client;
+
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd.Path2;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public abstract class DirEntry extends Connected {
+       final Path2 handle;
+       final String path;
+       final Run run;
+
+       protected DirEntry(Run run, String path) {
+               this.run = run;
+               this.path = path.replaceFirst("/+$", "");
+               this.handle = run.run.wd().path2(this.path);
+       }
+
+       public void delete() throws ClientException, ServerException {
+               checkError(handle.deleteAsXml(ClientResponse.class));
+       }
+
+       String path(ClientResponse response) throws ClientException, 
ServerException {
+               checkError(response);
+               String[] bits = response.getLocation().getPath().split("/");
+               return concat(bits[bits.length - 1]);
+       }
+
+       String localName() {
+               String[] bits = path.split("/");
+               return bits[bits.length - 1];
+       }
+
+       String concat(String name) {
+               return path + "/" + name.split("/", 2)[0];
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
new file mode 100644
index 0000000..38dc394
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
@@ -0,0 +1,94 @@
+package uk.org.taverna.server.client;
+
+import static java.io.File.createTempFile;
+import static javax.ws.rs.client.Entity.entity;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipFile;
+
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+import uk.org.taverna.server.client.generic.DirectoryEntry;
+import uk.org.taverna.server.client.generic.DirectoryReference;
+import uk.org.taverna.server.client.generic.FileReference;
+import uk.org.taverna.server.client.rest.DirectoryContents;
+import uk.org.taverna.server.client.rest.MakeDirectory;
+import uk.org.taverna.server.client.rest.UploadFile;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public class Directory extends DirEntry {
+       private final Wd wd;
+
+       Directory(Run run) {
+               super(run, "");
+               this.wd = run.run.wd();
+       }
+
+       Directory(Run run, String path) {
+               super(run, path);
+               this.wd = run.run.wd();
+       }
+
+       public List<DirEntry> list() {
+               List<DirEntry> result = new ArrayList<>();
+               for (DirectoryEntry de : wd.path3(path)
+                               
.getAsXml(DirectoryContents.class).getDirOrFile())
+                       if (de instanceof DirectoryReference)
+                               result.add(new Directory(run, de.getValue()));
+                       else if (de instanceof FileReference)
+                               result.add(new File(run, de.getValue()));
+               return result;
+       }
+
+       public File createFile(String name, byte[] content) throws 
ClientException,
+                       ServerException {
+               UploadFile uf = new UploadFile();
+               uf.setName(name);
+               uf.setValue(content);
+               return new File(run, path(wd.path(path).putAsXml(uf,
+                               ClientResponse.class)));
+       }
+
+       public File createFile(String name, java.io.File content)
+                       throws ClientException, ServerException {
+               return new File(run, 
path(wd.path(concat(name)).putOctetStreamAsXml(
+                               entity(content, APPLICATION_OCTET_STREAM_TYPE),
+                               ClientResponse.class)));
+       }
+
+       public File createFile(String name, URI source) throws ClientException,
+                       ServerException {
+               return new File(run, 
path(wd.path(concat(name)).postTextUriListAsXml(
+                               source.toString(), ClientResponse.class)));
+       }
+
+       public Directory createDirectory(String name) throws ClientException,
+                       ServerException {
+               MakeDirectory mkdir = new MakeDirectory();
+               mkdir.setName(name);
+               return new Directory(run, path(wd.path(path).putAsXml(mkdir,
+                               ClientResponse.class)));
+       }
+
+       public byte[] getZippedContents() {
+               return wd.path3(path).getAsZip(byte[].class);
+       }
+
+       public ZipFile getZip() throws IOException {
+               byte[] contents = getZippedContents();
+               java.io.File tmp = createTempFile(localName(), ".zip");
+               try (OutputStream os = new FileOutputStream(tmp)) {
+                       os.write(contents);
+               }
+               return new ZipFile(tmp);
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
new file mode 100644
index 0000000..0287afb
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
@@ -0,0 +1,95 @@
+package uk.org.taverna.server.client;
+
+import static java.io.File.createTempFile;
+import static javax.ws.rs.client.Entity.entity;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.apache.tika.mime.MimeTypes.getDefaultMimeTypes;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+
+import org.apache.tika.mime.MimeTypeException;
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+public class File extends DirEntry {
+       private final Wd wd;
+
+       File(Run run, String path) {
+               super(run, path);
+               wd = run.run.wd();
+       }
+
+       public InputStream getAsStream() {
+               return wd.path3(path).getAsOctetStream(InputStream.class);
+       }
+
+       public byte[] get() {
+               return wd.path3(path).getAsOctetStream(byte[].class);
+       }
+
+       public String get(Charset encoding) {
+               return new String(wd.path3(path).getAsOctetStream(byte[].class),
+                               encoding);
+       }
+
+       public java.io.File getAsFile() throws ClientHandlerException,
+                       UniformInterfaceException, IOException, 
MimeTypeException,
+                       ClientException, ServerException {
+               ClientResponse cr = wd.path3(path).getAsOctetStream(
+                               ClientResponse.class);
+               checkError(cr);
+               String[] bits = localName().split("[.]");
+               String ext = getDefaultMimeTypes().forName(
+                               
cr.getHeaders().getFirst("Content-Type")).getExtension();
+               if (ext == null)
+                       ext = bits[bits.length - 1];
+               java.io.File tmp = createTempFile(bits[0], ext);
+               try (OutputStream os = new FileOutputStream(tmp);
+                               InputStream is = 
cr.getEntity(InputStream.class)) {
+                       copy(is, os);
+               }
+               return tmp;
+       }
+
+       public void setContents(byte[] newContents) throws ClientException,
+                       ServerException {
+               checkError(wd.path(path).putOctetStreamAsXml(newContents,
+                               ClientResponse.class));
+       }
+
+       public void setContents(String newContents) throws ClientException,
+                       ServerException {
+               checkError(wd.path(path).putOctetStreamAsXml(newContents,
+                               ClientResponse.class));
+       }
+
+       public void setContents(String newContents, Charset encoding)
+                       throws ClientException, ServerException {
+               checkError(wd.path(path).putOctetStreamAsXml(
+                               newContents.getBytes(encoding), 
ClientResponse.class));
+       }
+
+       public void setContents(InputStream newContents) throws ClientException,
+                       ServerException {
+               checkError(wd.path(path).putOctetStreamAsXml(newContents,
+                               ClientResponse.class));
+       }
+
+       public void setContents(java.io.File newContents) throws IOException,
+                       ClientException, ServerException {
+               checkError(wd.path(path).putOctetStreamAsXml(
+                               entity(newContents, 
APPLICATION_OCTET_STREAM_TYPE),
+                               ClientResponse.class));
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
new file mode 100644
index 0000000..0e6542f
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
@@ -0,0 +1,18 @@
+package uk.org.taverna.server.client;
+
+public enum Property {
+       STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), 
READY_TO_NOTIFY(
+                       "readyToNotify"), EMAIL("notificationAddress"), USAGE(
+                       "usageRecord");
+
+       private String s;
+
+       private Property(String s) {
+               this.s = s;
+       }
+
+       @Override
+       public String toString() {
+               return s;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
new file mode 100644
index 0000000..5c6875e
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
@@ -0,0 +1,215 @@
+package uk.org.taverna.server.client;
+
+import static org.joda.time.format.ISODateTimeFormat.dateTime;
+import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.io.IOUtils;
+import org.joda.time.DateTime;
+import org.ogf.usage.JobUsageRecord;
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName;
+import org.w3c.dom.Element;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+import uk.org.taverna.server.client.generic.KeyPairCredential;
+import uk.org.taverna.server.client.generic.PasswordCredential;
+import uk.org.taverna.server.client.generic.port.InputPort;
+import uk.org.taverna.server.client.generic.port.OutputPort;
+import uk.org.taverna.server.client.rest.InputDescription;
+import uk.org.taverna.server.client.rest.InputDescription.Value;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public class Run extends Connected {
+       RunsRunName run;
+
+       Run(TavernaServer server, String value) {
+               run = server.root.runsRunName(value);
+       }
+
+       public String getName() {
+               return run.name().getAsTextPlain(ClientResponse.class)
+                               .getEntity(String.class);
+       }
+
+       public void setName(String name) {
+               run.name().putTextPlain(name, String.class);
+       }
+
+       public Date getExpiry() {
+               return dateTimeParser().parseDateTime(
+                               
run.expiry().getAsTextPlain(String.class)).toDate();
+       }
+
+       public void setExpiry(Date expiryTimestamp) {
+               run.expiry().putTextPlain(
+                               dateTime().print(new 
DateTime(expiryTimestamp)), String.class);
+       }
+
+       public Date getCreate() {
+               String timestamp = 
run.createTime().getAsTextPlain(String.class);
+               if (timestamp == null || timestamp.trim().isEmpty())
+                       return null;
+               return dateTimeParser().parseDateTime(timestamp).toDate();
+       }
+
+       public Date getStart() {
+               String timestamp = run.startTime().getAsTextPlain(String.class);
+               if (timestamp == null || timestamp.trim().isEmpty())
+                       return null;
+               return dateTimeParser().parseDateTime(timestamp).toDate();
+       }
+
+       public Date getFinish() {
+               String timestamp = 
run.finishTime().getAsTextPlain(String.class);
+               if (timestamp == null || timestamp.trim().isEmpty())
+                       return null;
+               return dateTimeParser().parseDateTime(timestamp).toDate();
+       }
+
+       public Status getStatus() {
+               return 
Status.valueOf(run.status().getAsTextPlain(String.class));
+       }
+
+       public void setStatus(Status status) {
+               run.status().putTextPlain(status, String.class);
+       }
+
+       public void start() {
+               setStatus(Status.Operating);
+       }
+
+       public void kill() {
+               setStatus(Status.Finished);
+       }
+
+       public boolean isRunning() {
+               return getStatus() == Status.Operating;
+       }
+
+       public String getStandardOutput() {
+               return run.stdout().getAsTextPlain(String.class);
+       }
+
+       public String getStandardError() {
+               return run.stderr().getAsTextPlain(String.class);
+       }
+
+       public String getLog() {
+               return run.log().getAsTextPlain(String.class);
+       }
+
+       public Integer getExitCode() {
+               String code = run.listeners().name("io")
+                               .propertiesPropertyName("exitCode")
+                               .getAsTextPlain(String.class);
+               if (code == null || code.trim().isEmpty())
+                       return null;
+               return Integer.parseInt(code);
+       }
+
+       public String getProperty(Property prop) {
+               return run.listeners().name("io")
+                               .propertiesPropertyName(prop.toString())
+                               .getAsTextPlain(String.class);
+       }
+
+       public void setGenerateRunBundle(boolean generateRunBundle) {
+               run.generateProvenance().putTextPlain(generateRunBundle, 
String.class);
+       }
+
+       public byte[] getRunBundle() {
+               return run.runBundle().getAsVndWf4everRobundleZip(byte[].class);
+       }
+
+       public List<InputPort> getInputs() {
+               return 
run.input().expected().getAsInputDescriptionXml().getInput();
+       }
+
+       public List<OutputPort> getOutputs() {
+               return run.output().getAsOutputDescriptionXml().getOutput();
+       }
+
+       public void setInput(String name, String value) {
+               Value v = new Value();
+               v.setValue(value);
+               InputDescription idesc = new InputDescription();
+               idesc.setValue(v);
+               run.input().inputName(name).putXmlAsInputDescription(idesc);
+       }
+
+       public void setInput(String name, String value, char listSeparator) {
+               Value v = new Value();
+               v.setValue(value);
+               InputDescription idesc = new InputDescription();
+               idesc.setValue(v);
+               idesc.setListDelimiter(new String(new char[] { listSeparator 
}));
+               run.input().inputName(name).putXmlAsInputDescription(idesc);
+       }
+
+       public byte[] getWorkflow() {
+               return run.workflow().getAsVndTavernaT2flowXml(byte[].class);
+       }
+
+       // TODO Consider better ways to do this
+       public Element getInteractionFeed() {
+               return run.interaction().getAsAtomXml(Element.class);
+       }
+
+       public Element getInteractionEntry(String id) {
+               return run.interaction().id(id).getAsAtomXml(Element.class);
+       }
+
+       public JobUsageRecord getUsageRecord() throws JAXBException {
+               return 
JobUsageRecord.unmarshal(run.usage().getAsXml(Element.class));
+       }
+
+       public Directory getWorkingDirectory() {
+               return new Directory(this);
+       }
+
+       public String getOwner() {
+               return run.security().owner().getAsTextPlain(String.class);
+       }
+
+       // TODO permissions
+
+       public void grantPasswordCredential(URI contextService, String username,
+                       String password) throws ClientException, 
ServerException {
+               PasswordCredential pc = new PasswordCredential();
+               pc.setServiceURI(contextService.toString());
+               pc.setUsername(username);
+               pc.setPassword(password);
+               checkError(run.security().credentials()
+                               .postXmlAsOctetStream(pc, 
ClientResponse.class));
+       }
+
+       public void grantKeyCredential(URI contextService, java.io.File source,
+                       String unlockPassword, String aliasEntry) throws 
IOException,
+                       ClientException, ServerException {
+               KeyPairCredential kpc = new KeyPairCredential();
+               kpc.setServiceURI(contextService.toString());
+               try (InputStream in = new FileInputStream(source)) {
+                       byte[] buffer = new byte[(int) source.length()];
+                       IOUtils.read(in, buffer);
+                       kpc.setCredentialBytes(buffer);
+               }
+               if (source.getName().endsWith(".p12"))
+                       kpc.setFileType("PKCS12");
+               else
+                       kpc.setFileType("JKS");
+               kpc.setCredentialName(aliasEntry);
+               kpc.setUnlockPassword(unlockPassword);
+               checkError(run.security().credentials()
+                               .postXmlAsOctetStream(kpc, 
ClientResponse.class));
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
new file mode 100644
index 0000000..9c375ad
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
@@ -0,0 +1,36 @@
+package uk.org.taverna.server.client;
+
+/**
+ * States of a workflow run. They are {@link #Initialized Initialized},
+ * {@link #Operating Operating}, {@link #Stopped Stopped}, and
+ * {@link #Finished Finished}. Conceptually, there is also a
+ * <tt>Destroyed</tt> state, but the workflow run does not exist (and hence
+ * can't have its state queried or set) in that case.
+ * 
+ * @author Donal Fellows
+ */
+public enum Status {
+       /**
+        * The workflow run has been created, but is not yet running. The run
+        * will need to be manually moved to {@link #Operating Operating} when
+        * ready.
+        */
+       Initialized,
+       /**
+        * The workflow run is going, reading input, generating output, etc.
+        * Will eventually either move automatically to {@link #Finished
+        * Finished} or can be moved manually to {@link #Stopped Stopped} (where
+        * supported).
+        */
+       Operating,
+       /**
+        * The workflow run is paused, and will need to be moved back to
+        * {@link #Operating Operating} manually.
+        */
+       Stopped,
+       /**
+        * The workflow run has ceased; data files will continue to exist until
+        * the run is destroyed (which may be manual or automatic).
+        */
+       Finished
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
new file mode 100644
index 0000000..7c0dcdd
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
@@ -0,0 +1,128 @@
+package uk.org.taverna.server.client;
+
+import static java.nio.file.Files.readAllBytes;
+import static org.taverna.server.client.wadl.TavernaServer.createClient;
+import static org.taverna.server.client.wadl.TavernaServer.root;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.taverna.server.client.wadl.TavernaServer.Root;
+
+import uk.org.taverna.server.client.generic.Capability;
+import uk.org.taverna.server.client.generic.TavernaRun;
+import uk.org.taverna.server.client.generic.VersionedElement;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+
+public class TavernaServer extends Connected {
+       final Root root;
+       private final URI location;
+       private final boolean authenticated;
+
+       TavernaServer(URI serviceRoot) {
+               root = root(createClient(), location = serviceRoot);
+               authenticated = false;
+       }
+
+       TavernaServer(URI serviceRoot, String username, String password) {
+               Client client = createClient();
+               client.addFilter(new HTTPBasicAuthFilter(username, password));
+               authenticated = true;
+               root = root(client, location = serviceRoot);
+       }
+
+       TavernaServer(TavernaServer service, String username, String password) {
+               Client client = createClient();
+               client.addFilter(new HTTPBasicAuthFilter(username, password));
+               authenticated = true;
+               root = root(client, location = service.location);
+               getServerVersionInfo();
+       }
+
+       public TavernaServer upgradeToAuth(String username, String password) {
+               if (authenticated)
+                       throw new IllegalStateException("may only upgrade an 
unauthenticated connection");
+               return new TavernaServer(this, username, password);
+       }
+
+       public List<Capability> getCapabilities() {
+               return root.policy().capabilities().getAsCapabilitiesXml()
+                               .getCapability();
+       }
+
+       public int getRunLimit() {
+               return root.policy().runLimit().getAsTextPlain(Integer.class);
+       }
+
+       public int getOperatingLimit() {
+               return 
root.policy().operatingLimit().getAsTextPlain(Integer.class);
+       }
+
+       public List<String> getPermittedWorkflows() {
+               return 
root.policy().permittedWorkflows().getAsPermittedWorkflowsXml()
+                               .getWorkflow();
+       }
+
+       public List<Run> getExistingRuns() {
+               List<Run> runs = new ArrayList<>();
+               for (TavernaRun run : root.runs().getAsRunListXml().getRun())
+                       runs.add(new Run(this, run.getValue()));
+               return runs;
+       }
+
+       public VersionedElement getServerVersionInfo() {
+               return root.getAsServerDescriptionXml();
+       }
+
+       private Run response2run(ClientResponse response) throws 
ClientException, ServerException {
+               checkError(response);
+               if (response.getClientResponseStatus().getStatusCode() == 201) {
+                       String[] path = 
response.getLocation().getPath().split("/");
+                       return new Run(this, path[path.length - 1]);
+               }
+               return null;
+       }
+
+       public Run createWorkflowRun(byte[] t2flowBytes) throws 
ClientException, ServerException {
+               return 
response2run(root.runs().postVndTavernaT2flowXmlAsOctetStream(
+                               t2flowBytes, ClientResponse.class));
+       }
+
+       public Run createWorkflowRun(File t2flowFile) throws IOException, 
ClientException, ServerException {
+               return createWorkflowRun(readAllBytes(t2flowFile.toPath()));
+       }
+
+       public Run createWorkflowRun(URI t2flowUri) throws ClientException, 
ServerException {
+               return response2run(root.runs().postTextUriListAsOctetStream(
+                               t2flowUri.toString(), ClientResponse.class));
+       }
+
+
+       public static class ClientException extends Exception {
+               private static final long serialVersionUID = 1L;
+
+               ClientException(String msg, Throwable cause) {
+                       super(msg, cause);
+               }
+       }
+       public static class AuthorizationException extends ClientException {
+               private static final long serialVersionUID = 1L;
+
+               AuthorizationException(String msg, Throwable cause) {
+                       super(msg, cause);
+               }
+       }
+       static class ServerException extends Exception {
+               private static final long serialVersionUID = 1L;
+
+               ServerException(String msg, Throwable cause) {
+                       super(msg, cause);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
new file mode 100644
index 0000000..b00b075
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
@@ -0,0 +1,23 @@
+package uk.org.taverna.server.client;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TavernaServerConnectionFactory {
+       private Map<URI, TavernaServer> cache = new HashMap<>();
+
+       public synchronized TavernaServer connectNoAuth(URI uri) {
+               TavernaServer conn = cache.get(uri);
+               if (conn == null)
+                       cache.put(uri, conn = new TavernaServer(uri));
+               return conn;
+       }
+
+       public TavernaServer connectAuth(URI uri, String username, String 
password) {
+               TavernaServer conn = new TavernaServer(uri, username, password);
+               // Force a check of the credentials by getting the server 
version
+               conn.getServerVersionInfo();
+               return conn;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
new file mode 100644
index 0000000..59e809d
--- /dev/null
+++ 
b/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Implementation of a basic client for Taverna Server.
+ * @author Donal Fellows
+ */
+package uk.org.taverna.server.client;
\ No newline at end of file

Reply via email to