Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ianj-als/omtc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Johnson <ian.johnson@appliedlanguage.com>2013-02-01 19:07:25 +0400
committerIan Johnson <ian.johnson@appliedlanguage.com>2013-02-01 19:07:25 +0400
commitc155a98dd4c7ee990cf1fecd3b8eb0c99e70a699 (patch)
treeab375d8730b52aaac52b89c135584a379490dc48
parente7ae25e69208c7428f237b138906b0b139e177f9 (diff)
Added Java code.
-rw-r--r--.gitignore8
-rw-r--r--README.md2
-rw-r--r--pom.xml81
-rw-r--r--src/main/java/com/capitati/omtc/core/commons/IDisposable.java23
-rw-r--r--src/main/java/com/capitati/omtc/core/commons/IStoppable.java23
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IComposableEngine.java61
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IEngine.java42
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IEvaluatableEngine.java73
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IParameterisableEngine.java54
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IQueryableEngine.java51
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IRetrainableEngine.java55
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IScore.java52
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IScoreScheme.java40
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/ITestableEngine.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/ITicketableEngine.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/ITrainableEngine.java55
-rw-r--r--src/main/java/com/capitati/omtc/core/engine/IUpdatableEngine.java63
-rw-r--r--src/main/java/com/capitati/omtc/core/integration/data/IDataExchangeFormatSpecification.java60
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/Capability.java48
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/CapabilityGroup.java37
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IAPICapability.java34
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/ICapability.java34
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityRequest.java48
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityResponse.java63
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IFeatureCapability.java36
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/INegotiator.java38
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IPrerequisiteCapability.java28
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IResourceCapability.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/ISemanticVersion.java62
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IServiceResourceCapability.java35
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/IVersion.java40
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/Negotiator.java141
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/SemanticVersion.java196
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComparator.java223
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComponent.java27
-rw-r--r--src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionParseException.java53
-rw-r--r--src/main/java/com/capitati/omtc/core/notification/IResourceDownloadObserver.java24
-rw-r--r--src/main/java/com/capitati/omtc/core/notification/IResourceTaskObserver.java55
-rw-r--r--src/main/java/com/capitati/omtc/core/notification/IResourceUploadObserver.java23
-rw-r--r--src/main/java/com/capitati/omtc/core/resources/IDerivedResource.java25
-rw-r--r--src/main/java/com/capitati/omtc/core/resources/IPrimaryResource.java23
-rw-r--r--src/main/java/com/capitati/omtc/core/resources/IResource.java29
-rw-r--r--src/main/java/com/capitati/omtc/core/resources/IResourceReader.java26
-rw-r--r--src/main/java/com/capitati/omtc/core/resources/IResourceWriter.java26
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/CompositionTicket.java49
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/EngineTicket.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/EvaluationTicket.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/IPriority.java36
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/IPriorityMechanism.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/ITicketObserver.java58
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/QueryTicket.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/TestingTicket.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/Ticket.java66
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/TrainingTicket.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/TranslationTicket.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/scheduling/UpdateTicket.java41
-rw-r--r--src/main/java/com/capitati/omtc/core/security/IUser.java42
-rw-r--r--src/main/java/com/capitati/omtc/core/security/Role.java43
-rw-r--r--src/main/java/com/capitati/omtc/core/security/User.java39
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IEngineAssignableSession.java60
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IEngineRetrievableSession.java10
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IResourceTransferDelegate.java71
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IRoleAssignableSession.java50
-rw-r--r--src/main/java/com/capitati/omtc/core/session/ISession.java120
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IUserRetrievableSession.java28
-rw-r--r--src/main/java/com/capitati/omtc/core/session/IUserSession.java36
-rw-r--r--src/main/java/com/capitati/omtc/core/session/Session.java232
-rw-r--r--src/main/java/com/capitati/omtc/core/session/UserSession.java88
-rw-r--r--src/main/java/com/capitati/omtc/core/translation/Translator.java120
-rw-r--r--src/test/java/com/capitati/omtc/core/negotiation/NegotiatorTests.java248
-rw-r--r--src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionComparatorTests.java528
-rw-r--r--src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionTests.java37
-rw-r--r--src/test/java/com/capitati/omtc/core/session/PrimaryResource.java75
-rw-r--r--src/test/java/com/capitati/omtc/core/session/ResourceUploadDelegate.java79
-rw-r--r--src/test/java/com/capitati/omtc/core/session/SessionTestException.java7
-rw-r--r--src/test/java/com/capitati/omtc/core/session/SessionTests.java203
76 files changed, 4903 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 0f182a0..7d84a36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,11 @@
*.jar
*.war
*.ear
+
+# Maven and Eclipse directories
+/target
+/.settings
+
+# Eclipse files
+.classpath
+.project
diff --git a/README.md b/README.md
index c37837f..8222fea 100644
--- a/README.md
+++ b/README.md
@@ -5,4 +5,6 @@ This is a reference implementation of OMTC, an open API Standard for Machine Tra
It is a Java implementation that is Java v1.5 compliant.
+Use Maven v3.x to build.
+
Documentation coming soon.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ee84f46
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,81 @@
+<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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.capitati.omtc</groupId>
+ <artifactId>omtc-core</artifactId>
+ <version>1.0</version>
+ <packaging>jar</packaging>
+
+ <name>omtc</name>
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>20040616</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.1</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- Guava, formerly Google Collections -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>13.0.1</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jmock</groupId>
+ <artifactId>jmock-junit4</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.12</version>
+ <executions>
+ <execution>
+ <id>default-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>**/*Tests.class</include>
+ <include>**/*Test.class</include>
+ </includes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
+
diff --git a/src/main/java/com/capitati/omtc/core/commons/IDisposable.java b/src/main/java/com/capitati/omtc/core/commons/IDisposable.java
new file mode 100644
index 0000000..e4bf66e
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/commons/IDisposable.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.commons;
+
+public interface IDisposable {
+ void dispose();
+}
diff --git a/src/main/java/com/capitati/omtc/core/commons/IStoppable.java b/src/main/java/com/capitati/omtc/core/commons/IStoppable.java
new file mode 100644
index 0000000..3e1b1f1
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/commons/IStoppable.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.commons;
+
+public interface IStoppable {
+ void stop();
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IComposableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IComposableEngine.java
new file mode 100644
index 0000000..a4cba1b
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IComposableEngine.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import com.capitati.omtc.core.integration.data.IDataExchangeFormatSpecification;
+import com.capitati.omtc.core.scheduling.CompositionTicket;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin for composing two engines. Implementers are to mixin this
+ * interface with their {@link com.capitati.omtc.core.engine.IEngine}
+ * implementation.
+ *
+ * @author ian
+ *
+ * @param <V> - the priority's type.
+ */
+public interface IComposableEngine<V> extends ITicketableEngine<V> {
+ /**
+ * Compose two engines. Suppose two engines E<sub>1</sub> and E<sub>2</sub>,
+ * this composition shall produce an engine that is
+ * E<sub>resultant</sub> = E<sub>2</sub>(E<sub>1</sub>(s)).
+ *
+ * @param session - the invoking session.
+ * @param engine - the other engine to compose, i.e., E<sub>2</sub>.
+ * @param exchangeFormat - the exchange data format that the engines will use
+ * to communicate.
+ * @param resultantEngine - the engine that the composition operation
+ * shall create if successful.
+ * @param priority - the priority of this task.
+ * @param engineObserver - the observer that will be notified on completion
+ * of the task.
+ * @return A {@link com.capitati.omtc.core.scheduling.CompositionTicket} object.
+ * @throws Exception On an error.
+ */
+ CompositionTicket<V> compose(
+ ISession session,
+ IEngine engine,
+ IDataExchangeFormatSpecification exchangeFormat,
+ IEngine resultantEngine,
+ IPriority<V> priority,
+ ITicketObserver<CompositionTicket<V>, V> engineObserver) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IEngine.java b/src/main/java/com/capitati/omtc/core/engine/IEngine.java
new file mode 100644
index 0000000..485cb52
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IEngine.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import com.capitati.omtc.core.resources.IDerivedResource;
+
+/**
+ * A translation engine.
+ *
+ * @author ian
+ */
+public interface IEngine extends IDerivedResource {
+ /**
+ * Retrieve the assigned name for the engine.
+ *
+ * @return The engine's name.
+ */
+ String getName();
+
+ /**
+ * Retrieve some descriptive free text about the engine.
+ *
+ * @return The engine's descriptive text.
+ */
+ String getDescription();
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IEvaluatableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IEvaluatableEngine.java
new file mode 100644
index 0000000..d1f7452
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IEvaluatableEngine.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+import com.capitati.omtc.core.scheduling.EvaluationTicket;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin to provide support for evaluating an engine. Implementers are to
+ * mixin this interface with their implementation of
+ * {@link com.capitati.omtc.core.engine.IEngine}.
+ *
+ * @author ian
+ *
+ * @param <V> - the task's priority type.
+ */
+public interface IEvaluatableEngine<V> extends ITicketableEngine<V> {
+ /**
+ * Evaluate an engine. On completion of this the evaluation task the
+ * implementation should store the scores calculated so that
+ * {@link com.capitati.omtc.core.engine.IEvaluatableEngine#getScores} can
+ * return appropriate data.
+ *
+ * @param session - the invoking session.
+ * @param evaluationResources - the primary resources to use for evaluation.
+ * @param priority - the priority of the task.
+ * @param engineObserver - the observer to listen for evaluation completion.
+ * @return An evaluation ticket.
+ * @throws Exception On an error.
+ */
+ EvaluationTicket<V> evaluate(
+ ISession session,
+ Set<IPrimaryResource> evaluationResources,
+ IPriority<V> priority,
+ ITicketObserver<EvaluationTicket<V>, V> engineObserver) throws Exception;
+
+ /**
+ * Retrieve any scores associated with an engine. The method
+ * {@link com.capitati.omtc.core.engine.IEvaluatableEngine#evaluate}
+ * should provided information, internally, to enable this method to
+ * return the scores calculated during a call, and subsequent calls, to
+ * {@link com.capitati.omtc.core.engine.IEvaluatableEngine#evaluate}.
+ * Without running an evaluation, it is implementation defined whether,this
+ * method returns an empty set.
+ *
+ * @param session - the invoking session.
+ * @return A {@link java.util.Set} of
+ * {@link com.capitati.omtc.core.engine.IScore} objects the represent the
+ * scores from an evaluation.
+ */
+ Set<IScore> getScores(ISession session) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IParameterisableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IParameterisableEngine.java
new file mode 100644
index 0000000..a412a74
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IParameterisableEngine.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Map;
+
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin to provide support for a parameterisable engine. Parameters are keyed
+ * with a type K whose type shall be P. Methods are to be implemented that
+ * fetch engine parameters and allow updating of parameters.
+ *
+ * @author ian
+ *
+ * @param <K> - the type of the parameter key.
+ * @param <P> - the type of the parameter value.
+ */
+public interface IParameterisableEngine<K, P> {
+ /**
+ * Return the current parameters for an engine.
+ *
+ * @param session - the invoking session.
+ *
+ * @return A map of parameters.
+ * @throws Exception On an error.
+ */
+ Map<K, P> getParamters(ISession session) throws Exception;
+
+ /**
+ * Update the current parameters with the parameters provided.
+ *
+ * @param session - the invoking session.
+ * @param newParameters - the parameters used to update the current ones.
+ * @throws Exception On an error.
+ */
+ void updateParameters(ISession session, Map<K, P> newParameters) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IQueryableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IQueryableEngine.java
new file mode 100644
index 0000000..f2ec9ab
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IQueryableEngine.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.QueryTicket;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin to add support to querying an engine. A single source sentence
+ * is sent to an engine which can be used, amongst other things, for testing.
+ * Implementers should mixin this interface with their
+ * {@link com.capitati.omtc.core.engine.IEngine} implementations.
+ *
+ * @author ian
+ *
+ * @param <V> - the type of the task's priority value.
+ */
+public interface IQueryableEngine<V> extends ITicketableEngine<V> {
+ /**
+ * Send a source sentence to an engine.
+ *
+ * @param session - the invoking session.
+ * @param sourceSentence - the source sentence to send to the engine
+ * @param engineObserver - an observer to be notified of completion.
+ * @return A query ticket object.
+ * @throws Exception On an error.
+ */
+ QueryTicket<V> query(
+ ISession session,
+ String sourceSentence,
+ IPriority<V> priority,
+ ITicketObserver<QueryTicket<V>, V> ticketObserver) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IRetrainableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IRetrainableEngine.java
new file mode 100644
index 0000000..7202cf9
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IRetrainableEngine.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.TrainingTicket;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin to provide retraining capability if the engine implementation
+ * can support it.
+ *
+ * @author ian
+ *
+ * @param <V> - the type of the priority value.
+ */
+public interface IRetrainableEngine<V> extends ITicketableEngine<V> {
+ /**
+ * Retain an engine using a set of primary resources.
+ *
+ * @param session - the invoking session.
+ * @param retrainingResources - a {@link java.util.Set} of
+ * {@link com.capitati.omtc.core.resources.IPrimaryResource} objects that
+ * shall be used to retain the engine.
+ * @param priority - the priority of the retraining task.
+ * @param engineObserver - the observer listening for the retrain to complete.
+ * @return A training ticket.
+ * @throws Exception On an error.
+ */
+ TrainingTicket<V> retrain(
+ ISession session,
+ Set<IPrimaryResource> retrainingResources,
+ IPriority<V> priority,
+ ITicketObserver<TrainingTicket<V>, V> engineObserver) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IScore.java b/src/main/java/com/capitati/omtc/core/engine/IScore.java
new file mode 100644
index 0000000..e9a6868
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IScore.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+
+/**
+ * A representation of a single evaluation score.
+ *
+ * @author ian
+ */
+public interface IScore {
+ /**
+ * Retrieve the score scheme. Or, which algorithm was used to generate the
+ * score.
+ *
+ * @return A scoring scheme description object.
+ */
+ IScoreScheme getScheme();
+
+ /**
+ * The evaluated score.
+ *
+ * @return The score for the scheme used.
+ */
+ double getScore();
+
+ /**
+ * Retrieve the resources that generated the score.
+ *
+ * @return A {@link java.util.Set} of primary resource objects.
+ */
+ Set<IPrimaryResource> getResources();
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IScoreScheme.java b/src/main/java/com/capitati/omtc/core/engine/IScoreScheme.java
new file mode 100644
index 0000000..5f6ec6a
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IScoreScheme.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+/**
+ * The name and descriptive text for a scoring scheme.
+ *
+ * @author ian
+ */
+public interface IScoreScheme {
+ /**
+ * Retrieve the name of a scoring scheme.
+ *
+ * @return The name of the scheme.
+ */
+ String getName();
+
+ /**
+ * Retrieve the descriptive text for a scoring scheme.
+ *
+ * @return The descriptive free text.
+ */
+ String getDescription();
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/ITestableEngine.java b/src/main/java/com/capitati/omtc/core/engine/ITestableEngine.java
new file mode 100644
index 0000000..7d488e8
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/ITestableEngine.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.TestingTicket;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ *
+ * @author ian
+ *
+ * @param <P>
+ */
+public interface ITestableEngine<V> extends ITicketableEngine<V> {
+ TestingTicket<V> test(
+ ISession session,
+ Set<IPrimaryResource> testingResources,
+ IPriority<V> priority,
+ ITicketObserver<TestingTicket<V>, V> engineObserver) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/ITicketableEngine.java b/src/main/java/com/capitati/omtc/core/engine/ITicketableEngine.java
new file mode 100644
index 0000000..1001a2b
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/ITicketableEngine.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.scheduling.EngineTicket;
+import com.capitati.omtc.core.session.ISession;
+import com.google.common.base.Predicate;
+
+/**
+ * A mixin that provides support for engines that, on submiting tasks, return
+ * task tickets. This inferface should be used with the implementer's
+ * {@link com.capitati.omtc.core.engine.IEngine} concrete classes to
+ * provide a mechanism to return <em>running</em> tickets. It is the
+ * responsibility of the concrete class to manage the appropriate collection
+ * of dispensed tickets.
+ *
+ * @author ian
+ *
+ * @param <V> - the type of the priority's value.
+ */
+public interface ITicketableEngine<V> {
+ Set<EngineTicket<V>> retrieveTickets(
+ ISession session, Predicate<EngineTicket<V>> filter)
+ throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/ITrainableEngine.java b/src/main/java/com/capitati/omtc/core/engine/ITrainableEngine.java
new file mode 100644
index 0000000..199ae41
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/ITrainableEngine.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.TrainingTicket;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin to offer support for training engines. Implementers of the
+ * {@link com.capitati.omtc.core.engine.IEngine} interface should mixin this
+ * interface to their concrete classes.
+ *
+ * @author ian
+ *
+ * @param <V> - the type of the priority's value.
+ */
+public interface ITrainableEngine<V> extends ITicketableEngine<V> {
+ /**
+ * Train an engine.
+ *
+ * @param session - the invoking session.
+ * @param trainingResources - a {@link java.util.Set} of primary resources
+ * used to train the engine.
+ * @param priority - the priority of the train task.
+ * @param engineObserver - the observer that listens for task completion.
+ * @return A training ticket.
+ * @throws Exception On an error.
+ */
+ TrainingTicket<V> train(
+ ISession session,
+ Set<IPrimaryResource> trainingResources,
+ IPriority<V> priority,
+ ITicketObserver<TrainingTicket<V>, V> engineObserver) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/engine/IUpdatableEngine.java b/src/main/java/com/capitati/omtc/core/engine/IUpdatableEngine.java
new file mode 100644
index 0000000..dd111ee
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/engine/IUpdatableEngine.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.engine;
+
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.UpdateTicket;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A mixin for engines that support updating. The update operation is ticketed
+ * since the operation be computationally expensive. The update operation
+ * shall typically mutate the engine. It is recommended that the engine,
+ * during an update operation, is mutually excluded.
+ *
+ * @author ian
+ *
+ * @param <V> - the type of the priority's value.
+ */
+public interface IUpdatableEngine<V, P> extends ITicketableEngine<V> {
+ /**
+ * Update an engine's parameters using key-value pairs specified in a
+ * {@link java.util.Map} object.
+ *
+ * @param session - the invoking session.
+ * @param parameters - the update parameters for the engine.
+ * @param priority - the task's priority.
+ * @param engineObserver - the observer listening for the starting and
+ * completion of the task.
+ * @return An updating ticket.
+ * @throws Exception On an error.
+ */
+ UpdateTicket<V> updateParameters(
+ ISession session,
+ P parameters,
+ IPriority<V> priority,
+ ITicketObserver<UpdateTicket<V>, V> engineObserver) throws Exception;
+
+ /**
+ * Retrieve the current parameters of the engine.
+ *
+ * @param - the invoking session.
+ * @return An object that holds the engine's current parameters.
+ * @throws Exception On an error.
+ */
+ P getParameters(ISession session) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/integration/data/IDataExchangeFormatSpecification.java b/src/main/java/com/capitati/omtc/core/integration/data/IDataExchangeFormatSpecification.java
new file mode 100644
index 0000000..9d8c43a
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/integration/data/IDataExchangeFormatSpecification.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.integration.data;
+
+import com.capitati.omtc.core.negotiation.IVersion;
+
+/**
+ * A description of a data exchange format, specification or standard.
+ * Implementers of this interface shall decide on a unique identifier for
+ * the data exchange format.
+ *
+ * @author ian
+ */
+public interface IDataExchangeFormatSpecification
+extends Comparable<IDataExchangeFormatSpecification> {
+ /**
+ * The short name, probably and acronym, for the format, specification, or
+ * standard.
+ *
+ * @return The short name of the data exchange format.
+ */
+ String getShortName();
+
+ /**
+ * The long name for the format, specification standard.
+ *
+ * @return The long name of the data exchange format.
+ */
+ String getLongName();
+
+ /**
+ * The lowest version of the data exchange format at which the client supports.
+ *
+ * @return The lowest supported version.
+ */
+ IVersion getLowestVersion();
+
+ /**
+ * The highest version of the data exchange format the client supports.
+ *
+ * @return The highest supported version.
+ */
+ IVersion getHighestVersion();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/Capability.java b/src/main/java/com/capitati/omtc/core/negotiation/Capability.java
new file mode 100644
index 0000000..6d4aeb9
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/Capability.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+public enum Capability {
+ INVALID(CapabilityGroup.INVALID),
+
+ API_VERSION(CapabilityGroup.API),
+
+ RES_FILE_TMX(CapabilityGroup.RESOURCE),
+ RES_FILE_TBX(CapabilityGroup.RESOURCE),
+ RES_FILE_UTX(CapabilityGroup.RESOURCE),
+ RES_FILE_SRX(CapabilityGroup.RESOURCE),
+ RES_FILE_ITS(CapabilityGroup.RESOURCE),
+ RES_FILE_XLIFF(CapabilityGroup.RESOURCE),
+ RES_FILE_TTX(CapabilityGroup.RESOURCE),
+
+ FET_RES_UPLOAD(CapabilityGroup.FEATURE),
+ FET_RES_DOWNLOAD(CapabilityGroup.FEATURE),
+
+ PRE_REQ_PAYMENT(CapabilityGroup.PREREQUISITE);
+
+ private CapabilityGroup group;
+
+ private Capability(final CapabilityGroup theGroup) {
+ group = theGroup;
+ }
+
+ public CapabilityGroup getGroup() {
+ return group;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/CapabilityGroup.java b/src/main/java/com/capitati/omtc/core/negotiation/CapabilityGroup.java
new file mode 100644
index 0000000..22c9eb1
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/CapabilityGroup.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+public enum CapabilityGroup {
+ INVALID("INVALID"),
+ API("API"),
+ RESOURCE("Resource"),
+ FEATURE("Feature"),
+ PREREQUISITE("Prerequisite");
+
+ final private String name;
+
+ private CapabilityGroup(final String theName) {
+ name = theName;
+ }
+
+ public String toString() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IAPICapability.java b/src/main/java/com/capitati/omtc/core/negotiation/IAPICapability.java
new file mode 100644
index 0000000..0c9a41b
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IAPICapability.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * The semantic version capability of the API.
+ *
+ * @author ian
+ */
+public interface IAPICapability extends ICapability {
+ /**
+ * Retrieve the semantic version of the API.
+ *
+ * @return An instance of {@link com.capitati.omtc.core.negotiation.ISemanticVersion}
+ * which represents the semantic version of the API.
+ */
+ ISemanticVersion getVersion();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/ICapability.java b/src/main/java/com/capitati/omtc/core/negotiation/ICapability.java
new file mode 100644
index 0000000..0f1c6ab
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/ICapability.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * The base capability interface. Specifies only the unique aspect of a
+ * capability.
+ *
+ * @author ian
+ */
+public interface ICapability {
+ /**
+ * Get the unique capability
+ *
+ * @return the capability's unique name
+ */
+ Capability getName();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityRequest.java b/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityRequest.java
new file mode 100644
index 0000000..2e834be
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityRequest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.Set;
+
+
+/**
+ * A description of the client's capabilities.
+ *
+ * @author ian
+ */
+public interface IClientCapabilityRequest {
+ /**
+ * Implementers shall return the client's supported API version capability.
+ *
+ * @return A {@link com.capitati.omtc.core.negotiation.IAPICapability}
+ * objects which represent the client's supported API version.
+ */
+ IAPICapability getVersionCapability();
+
+ /**
+ * Implementers shall return a set of the
+ * {@link com.capitati.omtc.core.negotiation.IResourceCapability} objects
+ * which shall represent the resource kinds which it expects the service
+ * to support.
+ *
+ * @return A set of {@link com.capitati.omtc.core.negotiation.IResourceCapability}
+ * objects.
+ */
+ Set<IResourceCapability> getResourceCapabilities();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityResponse.java b/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityResponse.java
new file mode 100644
index 0000000..0bb74c5
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IClientCapabilityResponse.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.Set;
+
+/**
+ * The response to a client negotiation.
+ *
+ * @author ian
+ */
+public interface IClientCapabilityResponse {
+ /**
+ * Does the service support the client's API revision. If this method returns
+ * false then the service should send the response back to the client and
+ * disconnect the session.
+ *
+ * @return True if the client's API is supported. Otherwise, returns false.
+ */
+ boolean isClientAPISupported();
+
+ /**
+ * The collection of data exchange formats that the service does not support
+ * but the client does. If the set of service supported data exchange formats
+ * is <em>S</em>, and the client supported data exchange formats is <em>C</em>
+ * then the returned collection shall be <em>C - S</em>. This is based, firstly,
+ * on the capability, and then the resource capability's version range.
+ * <p>
+ * When the client receives this set it needs to make a decision whether to
+ * continue with its session. For example, if all of the client's supported
+ * exchange formats are returned here then it is pointless continuing with
+ * the session. The service does not "talk" any of client's supported formats.
+ *
+ * @return A set of
+ * {@link com.capitati.omtc.core.negotiation.IResourceCapability}
+ * objects that the client supports but the service does not.
+ */
+ Set<IResourceCapability> getUnsupportedResourceCapabilities();
+
+ /**
+ * The supported feature capabilities of the service.
+ *
+ * @return A set of {@link com.capitati.omtc.core.negotiation.IFeatureCapability}
+ * objects.
+ */
+ Set<IFeatureCapability> getFeatureCapabilities();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IFeatureCapability.java b/src/main/java/com/capitati/omtc/core/negotiation/IFeatureCapability.java
new file mode 100644
index 0000000..25f3916
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IFeatureCapability.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.Set;
+
+/**
+ * Implementations of this interface specify a feature capability.
+ *
+ * @author ian
+ */
+public interface IFeatureCapability extends ICapability {
+ /**
+ * Implementers shall return the set of prerequisites for this feature.
+ *
+ * @return A set of {@link com.capitati.omtc.core.negotiation.IPrerequisiteCapability}
+ * objects.
+ */
+ Set<IPrerequisiteCapability> getPrerequisiteCapabilities();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/INegotiator.java b/src/main/java/com/capitati/omtc/core/negotiation/INegotiator.java
new file mode 100644
index 0000000..6bd42d1
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/INegotiator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * The negotiator that determines whether a client's capabilities are
+ * matched with the server's.
+ *
+ * @author ian
+ *
+ */
+public interface INegotiator {
+ /**
+ * Negotiate a client's capabilities. This method accepts a negotiation request
+ * and constructs a response.
+ *
+ * @param negotiationRequest - the client's negotiation request.
+ * @return A {@link com.capitati.omtc.core.negotiation.IClientCapabilityResponse}
+ * object that holds the server's response to the client request.
+ */
+ IClientCapabilityResponse negotiate(IClientCapabilityRequest negotiationRequest);
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IPrerequisiteCapability.java b/src/main/java/com/capitati/omtc/core/negotiation/IPrerequisiteCapability.java
new file mode 100644
index 0000000..b0903b6
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IPrerequisiteCapability.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * Implementations of this interface specify a prerequisite capability.
+ *
+ * @author ian
+ */
+public interface IPrerequisiteCapability extends ICapability {
+
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IResourceCapability.java b/src/main/java/com/capitati/omtc/core/negotiation/IResourceCapability.java
new file mode 100644
index 0000000..b1f1714
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IResourceCapability.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * Implementations of this interface shall specify the version range
+ * of a specific resource kind, e.g., XLIFF.
+ *
+ * @author ian
+ */
+public interface IResourceCapability extends ICapability {
+ /**
+ * The lowest version of the resource that is supported.
+ *
+ * @return A string that represents the resource kind's lower supported
+ * version.
+ */
+ String getLowerVersion();
+
+ /**
+ * The highest version of the resource that is supported.
+ *
+ * @return A string that represents the resource kind's highest supported
+ * version.
+ */
+ String getHigherVersion();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/ISemanticVersion.java b/src/main/java/com/capitati/omtc/core/negotiation/ISemanticVersion.java
new file mode 100644
index 0000000..9147aec
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/ISemanticVersion.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * Semantic versioning.
+ *
+ * @author ian
+ * @see <a href="http://semver.org/">Semantic Versioning 2.0.0-rc.1</a>
+ */
+public interface ISemanticVersion extends Comparable<ISemanticVersion> {
+ /**
+ * Returns the major version number.
+ *
+ * @return The major version number.
+ */
+ int getMajor();
+
+ /**
+ * Returns the minor version number.
+ *
+ * @return The minor version number.
+ */
+ int getMinor();
+
+ /**
+ * Return the patch number of the semantic version.
+ *
+ * @return The patch version number.
+ */
+ int getPatch();
+
+ /**
+ * Returns the parsed pre-release information from the version.
+ *
+ * @return A string array containing the dot delimited pre-release components.
+ */
+ String[] getPreRelease();
+
+ /**
+ * Returns the parsed build information from the version.
+ *
+ * @return A string array containing the dot delimited build components.
+ */
+ String[] getBuild();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IServiceResourceCapability.java b/src/main/java/com/capitati/omtc/core/negotiation/IServiceResourceCapability.java
new file mode 100644
index 0000000..1796878
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IServiceResourceCapability.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * Extends the {@link com.capitati.omtc.core.negotiation.IResourceCapability}
+ * to allow resource capability versions to be compared.
+ *
+ * @author ian
+ */
+public interface IServiceResourceCapability extends IResourceCapability {
+ /**
+ * Comparator method to compare resource kind versions.
+ *
+ * @param otherResourceCapability
+ * @return
+ */
+ int compareVersion(IResourceCapability otherResourceCapability);
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/IVersion.java b/src/main/java/com/capitati/omtc/core/negotiation/IVersion.java
new file mode 100644
index 0000000..7af1de5
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/IVersion.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+/**
+ * A base version interface. Major and minor versions.
+ *
+ * @author ian
+ */
+public interface IVersion extends Comparable<IVersion> {
+ /**
+ * Returns the major version number.
+ *
+ * @return The major version number.
+ */
+ int getMajor();
+
+ /**
+ * Returns the minor version number.
+ *
+ * @return The minor version number.
+ */
+ int getMinor();
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/Negotiator.java b/src/main/java/com/capitati/omtc/core/negotiation/Negotiator.java
new file mode 100644
index 0000000..9086fb7
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/Negotiator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+public class Negotiator implements INegotiator {
+ private final ISemanticVersion apiVersion;
+ private final Map<Capability, List<IServiceResourceCapability>> supportedResources;
+ private final Set<IFeatureCapability> featureCapabilities;
+
+ public Negotiator(
+ final String theApiVersion,
+ final Collection<IServiceResourceCapability> theResourceCapabilities,
+ final Collection<IFeatureCapability> theFeatureCapabilities)
+ throws SemanticVersionParseException {
+ super();
+ apiVersion = SemanticVersion.parseVersion(theApiVersion);
+
+ featureCapabilities = (theFeatureCapabilities == null) ?
+ new HashSet<IFeatureCapability>() :
+ new HashSet<IFeatureCapability>(theFeatureCapabilities);
+
+ /*
+ * Group resource capabilities by their unique identifier for possibly
+ * different version of the resource revision.
+ */
+ supportedResources = new HashMap<Capability, List<IServiceResourceCapability>>();
+ if(theResourceCapabilities != null) {
+ for(IServiceResourceCapability resourceCap : theResourceCapabilities) {
+ final Capability capabilityName = resourceCap.getName();
+
+ if(supportedResources.containsKey(capabilityName) == true) {
+ final List<IServiceResourceCapability> yeah =
+ supportedResources.get(capabilityName);
+ yeah.add(resourceCap);
+ } else {
+ final List<IServiceResourceCapability> yeah =
+ new ArrayList<IServiceResourceCapability>();
+ yeah.add(resourceCap);
+ supportedResources.put(capabilityName, yeah);
+ }
+ }
+ }
+ }
+
+ public final IClientCapabilityResponse negotiate(
+ final IClientCapabilityRequest negotiationRequest) {
+ final ISemanticVersion clientAPIVersion =
+ negotiationRequest.getVersionCapability().getVersion();
+ final boolean isClientAPISupported = isClientAPISupported(clientAPIVersion);
+ final Set<IResourceCapability> unsupportedResources =
+ new HashSet<IResourceCapability>();
+
+ /*
+ * Work out which of the clients resource kinds are supported by the
+ * service.
+ */
+ for(IResourceCapability resourceCap :
+ negotiationRequest.getResourceCapabilities()) {
+ final Capability capabilityName = resourceCap.getName();
+
+ /*
+ * First check if the resource kind is supported.
+ */
+ if(supportedResources.containsKey(capabilityName) == true) {
+ boolean supported = false;
+
+ for(IServiceResourceCapability svcResourceCap :
+ supportedResources.get(capabilityName)) {
+ if(svcResourceCap.compareVersion(resourceCap) == 0) {
+ supported = true;
+ }
+ }
+
+ if(supported == false) {
+ unsupportedResources.add(resourceCap);
+ }
+ } else {
+ unsupportedResources.add(resourceCap);
+ }
+ }
+
+ return new IClientCapabilityResponse() {
+ public boolean isClientAPISupported() {
+ return isClientAPISupported;
+ }
+ public Set<IResourceCapability> getUnsupportedResourceCapabilities() {
+ return unsupportedResources;
+ }
+ public Set<IFeatureCapability> getFeatureCapabilities() {
+ return featureCapabilities;
+ }
+ };
+ }
+
+ private boolean isClientAPISupported(ISemanticVersion version) {
+ final ImmutablePair<Integer, SemanticVersionComponent> versionComp =
+ SemanticVersionComparator.compare(apiVersion, version);
+ boolean isApiSupported = false;
+
+ switch(versionComp.getRight()) {
+ case PRE_RELEASE_AND_BUILD_VERSION:
+ case PATCH_VERSION:
+ case MINOR_VERSION:
+ isApiSupported = true;
+ break;
+
+ case MAJOR_VERSION:
+ case INVALID:
+ isApiSupported = (versionComp.getLeft() == 0) ? true : false;
+ break;
+ }
+
+ return isApiSupported;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersion.java b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersion.java
new file mode 100644
index 0000000..998f604
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersion.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Implementation of semantic versioning.
+ *
+ * @author ian
+ * @see <a href="http://semver.org/">Semantic Versioning 2.0.0-rc.1</a>
+ */
+public class SemanticVersion implements ISemanticVersion {
+ public static final String IDENTIFIER_SEPARATOR = ".";
+ private static final String PRE_RELEASE_SEPARATOR = "-";
+ private static final String BUILD_SEPARATOR = "+";
+ private static final String GROUP_NAME_MAJOR = "major";
+ private static final String GROUP_NAME_MINOR = "minor";
+ private static final String GROUP_NAME_PATCH = "patch";
+ private static final String GROUP_NAME_PRERELEASE = "prerelease";
+ private static final String GROUP_NAME_BUILD = "build";
+ private static final Pattern versionPattern =
+ Pattern.compile(
+ "(?<" + GROUP_NAME_MAJOR + ">\\d+)\\." +
+ "(?<" + GROUP_NAME_MINOR + ">\\d+)\\." +
+ "(?<" + GROUP_NAME_PATCH + ">\\d+)" +
+ "(([" + PRE_RELEASE_SEPARATOR + "](?<" + GROUP_NAME_PRERELEASE + ">[0-9A-Z-.]+))?" +
+ "([" + BUILD_SEPARATOR + "](?<" + GROUP_NAME_BUILD + ">[0-9A-Z-.]+))?)?",
+ Pattern.CASE_INSENSITIVE);
+
+ public static ISemanticVersion parseVersion(final String version)
+ throws SemanticVersionParseException {
+ final Matcher matcher = versionPattern.matcher(version);
+
+ if(matcher.matches() == false) {
+ throw new SemanticVersionParseException(version);
+ }
+
+ final int theMajor = Integer.parseInt(matcher.group(GROUP_NAME_MAJOR));
+ final int theMinor = Integer.parseInt(matcher.group(GROUP_NAME_MINOR));
+ final int thePatch = Integer.parseInt(matcher.group(GROUP_NAME_PATCH));
+ final String thePreRelease = matcher.group(GROUP_NAME_PRERELEASE);
+ final String theBuild = matcher.group(GROUP_NAME_BUILD);
+
+ return new SemanticVersion(
+ theMajor,
+ theMinor,
+ thePatch,
+ thePreRelease,
+ theBuild);
+ }
+
+ private final int major;
+ private final int minor;
+ private final int patch;
+ private final String[] preRelease;
+ private final String[] build;
+
+ public SemanticVersion(
+ final int theMajorVersion,
+ final int theMinorVersion,
+ final int thePatchVersion) {
+ super();
+ if((theMajorVersion < 0) ||
+ (theMinorVersion < 0) ||
+ (thePatchVersion <0)) {
+ throw new IllegalArgumentException(
+ "Major, minor, or patch version cannot be negative.");
+ }
+ major = theMajorVersion;
+ minor = theMinorVersion;
+ patch = thePatchVersion;
+ preRelease = null;
+ build = null;
+ }
+
+ public SemanticVersion(
+ final int theMajorVersion,
+ final int theMinorVersion,
+ final int thePatchVersion,
+ final String thePreRelease,
+ final String theBuild) {
+ super();
+ if((theMajorVersion < 0) ||
+ (theMinorVersion < 0) ||
+ (thePatchVersion <0)) {
+ throw new IllegalArgumentException(
+ "Major, minor, or patch version cannot be negative.");
+ }
+ major = theMajorVersion;
+ minor = theMinorVersion;
+ patch = thePatchVersion;
+ preRelease = (thePreRelease != null) ?
+ thePreRelease.split("[" + IDENTIFIER_SEPARATOR + "]") :
+ null;
+ build = (theBuild != null) ?
+ theBuild.split("[" + IDENTIFIER_SEPARATOR + "]") :
+ null;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getPatch() {
+ return patch;
+ }
+
+ public String[] getPreRelease() {
+ return preRelease;
+ }
+
+ public String[] getBuild() {
+ return build;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(build);
+ result = prime * result + major;
+ result = prime * result + minor;
+ result = prime * result + patch;
+ result = prime * result + Arrays.hashCode(preRelease);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj)
+ return true;
+ if(obj == null)
+ return false;
+ if(getClass() != obj.getClass())
+ return false;
+ SemanticVersion other = (SemanticVersion) obj;
+ if(!Arrays.equals(build, other.build))
+ return false;
+ if(major != other.major)
+ return false;
+ if(minor != other.minor)
+ return false;
+ if(patch != other.patch)
+ return false;
+ if(!Arrays.equals(preRelease, other.preRelease))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer repr =
+ new StringBuffer(String.format("%d.%d.%d", major, minor, patch));
+
+ if(preRelease != null) {
+ repr.append(PRE_RELEASE_SEPARATOR);
+ repr.append(StringUtils.join(preRelease, IDENTIFIER_SEPARATOR));
+ }
+
+ if(build != null) {
+ repr.append(BUILD_SEPARATOR);
+ repr.append(StringUtils.join(build, IDENTIFIER_SEPARATOR));
+ }
+
+ return repr.toString();
+ }
+
+ public int compareTo(final ISemanticVersion theOtherVersion) {
+ return SemanticVersionComparator.compare(this, theOtherVersion).getLeft();
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComparator.java b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComparator.java
new file mode 100644
index 0000000..017d675
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComparator.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.collections.iterators.ArrayIterator;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+/**
+ * A comparator for two semantic versions.
+ *
+ * @author ian
+ * @see <a href="http://semver.org/">Semantic Versioning 2.0.0-rc.1</a> for
+ * the specification on how this comparator operates.
+ */
+public class SemanticVersionComparator {
+ public static final ImmutablePair<Integer, SemanticVersionComponent> compare(
+ final ISemanticVersion verOne,
+ final ISemanticVersion verTwo) {
+ if(verOne.equals(verTwo) == true) {
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ 0, SemanticVersionComponent.INVALID);
+ }
+
+ if(verOne.getMajor() == verTwo.getMajor()) {
+ if(verOne.getMinor() == verTwo.getMinor()) {
+ if(verOne.getPatch() == verTwo.getPatch()) {
+ /*
+ * Compare the pre-release components.
+ */
+ final ImmutablePair<Integer, Boolean> preReleaseCompResult =
+ compareArray(verOne.getPreRelease(), verTwo.getPreRelease());
+ /*
+ * Compare the build components.
+ */
+ final ImmutablePair<Integer, Boolean> buildCompResult =
+ compareArray(verOne.getBuild(), verTwo.getBuild());
+
+ /*
+ * Unpack the comparison values.
+ */
+ final int prc = preReleaseCompResult.getLeft();
+ final int bc = buildCompResult.getLeft();
+
+ if((preReleaseCompResult.getRight() == true) &&
+ (buildCompResult.getRight() == true)) {
+ /*
+ * There was at most one pre-release component, and at most one
+ * build component in both versions.
+ */
+ if((Math.abs(prc) == 1) && (Math.abs(bc) == 1)) {
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ (Math.signum((float )prc) == 1.0) ? -1 : 1,
+ SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION);
+ } else if((Math.abs(prc) == 1) && (bc == 0)) {
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ (Math.signum((float )prc) == 1.0) ? -1 : 1,
+ SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION);
+ }
+
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ bc, SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION);
+ } else if((preReleaseCompResult.getRight() == true) &&
+ (buildCompResult.getRight() == false)) {
+ /*
+ * One of the versions had a null pre-release.
+ */
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ bc, SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION);
+ }
+
+ /*
+ * Either one of the version has a null build or both versions where
+ * fully specified.
+ */
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ (Math.abs(prc) == 1) ? prc : bc,
+ SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION);
+ } else {
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ verOne.getPatch() - verTwo.getPatch(),
+ SemanticVersionComponent.PATCH_VERSION);
+ }
+ } else {
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ verOne.getMinor() - verTwo.getMinor(),
+ SemanticVersionComponent.MINOR_VERSION);
+ }
+ }
+
+ return new ImmutablePair<Integer, SemanticVersionComponent>(
+ verOne.getMajor() - verTwo.getMajor(),
+ SemanticVersionComponent.MAJOR_VERSION);
+ }
+
+ /**
+ * Lexically compare the components of two string arrays.
+ *
+ * @param one - First string array.
+ * @param two - The array that is compared to one.
+ * @return If one array is determined to be lexically less than two then
+ * -1 is returned. If one is determined to be lexically greater then two then
+ * 1 is returned. Otherwise, 0 is returned.
+ */
+ private static ImmutablePair<Integer, Boolean> compareArray(
+ final String[] one,
+ final String[] two) {
+ if((one == null) && (two == null)) {
+ return new ImmutablePair<Integer, Boolean>(0, true);
+ }
+
+ if((one == null) && (two != null)) {
+ return new ImmutablePair<Integer, Boolean>(-1, true);
+ }
+
+ if((one != null) && (two == null)) {
+ return new ImmutablePair<Integer, Boolean>(1, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ final Iterator<String> oneIterator = new ArrayIterator(one);
+ @SuppressWarnings("unchecked")
+ final Iterator<String> twoIterator = new ArrayIterator(two);
+ String oneComp = null;
+ String twoComp = null;
+ int comp = 0;
+
+ while(true) {
+ try {
+ oneComp = oneIterator.next();
+ } catch(final NoSuchElementException ex) {
+ oneComp = null;
+ }
+
+ try {
+ twoComp = twoIterator.next();
+ } catch(final NoSuchElementException ex) {
+ twoComp = null;
+ }
+
+ if((oneComp == null) && (twoComp == null)) {
+ break;
+ }
+
+ comp = componentCompare(oneComp, twoComp);
+ if(comp != 0) {
+ break;
+ }
+ }
+
+ return new ImmutablePair<Integer, Boolean>(comp, false);
+ }
+
+ /**
+ * Compare two components from the pre-release and build string arrays as
+ * detailed in the Semantic Versioning 2.0.0-rc.1 specification.
+ *
+ * @param oneComp - first value.
+ * @param twoComp - second value.
+ * @return If first value is determined to be less than the second value then
+ * return -1. If one value is determined to be greater than the second value
+ * then return 1. Otherwise, 0 is returned.
+ * @see <a href="http://semver.org/">Semantic Versioning 2.0.0-rc.1</a>
+ */
+ private static int componentCompare(
+ final String oneComp, final String twoComp) {
+ if((oneComp == null) && (twoComp == null)) {
+ return 0;
+ }
+
+ if((oneComp == null) && (twoComp != null)) {
+ return -1;
+ }
+
+ if((oneComp != null) && (twoComp == null)) {
+ return 1;
+ }
+
+ boolean isOneInt = false;
+ boolean isTwoInt = false;
+ int oneInt = 0;
+ int twoInt = 0;
+
+ try {
+ oneInt = Integer.parseInt(oneComp);
+ isOneInt = true;
+ } catch(final NumberFormatException ex) {
+ isOneInt = false;
+ }
+
+ try {
+ twoInt = Integer.parseInt(twoComp);
+ isTwoInt = true;
+ } catch(final NumberFormatException ex) {
+ isTwoInt = false;
+ }
+
+ final int comp = ((isOneInt == true) && (isTwoInt == true)) ?
+ oneInt - twoInt :
+ oneComp.compareTo(twoComp);
+ final int compValue = (comp > 0) ? 1 : (comp < 0) ? -1 : 0;
+
+ return compValue;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComponent.java b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComponent.java
new file mode 100644
index 0000000..306a5dd
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionComponent.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+public enum SemanticVersionComponent {
+ INVALID,
+ PRE_RELEASE_AND_BUILD_VERSION,
+ PATCH_VERSION,
+ MINOR_VERSION,
+ MAJOR_VERSION
+}
diff --git a/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionParseException.java b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionParseException.java
new file mode 100644
index 0000000..c11a013
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/negotiation/SemanticVersionParseException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.negotiation;
+
+public class SemanticVersionParseException extends Exception {
+ private static final long serialVersionUID = -3118190471319312408L;
+
+ private final String invalidVersion;
+
+ public SemanticVersionParseException(final String theInvalidVersion) {
+ super();
+ invalidVersion = theInvalidVersion;
+ }
+
+ public SemanticVersionParseException(
+ final String theInvalidVersion, final Throwable theThrowable) {
+ super(theThrowable);
+ invalidVersion = theInvalidVersion;
+ }
+
+ public SemanticVersionParseException(
+ final String theInvalidVersion,
+ final Throwable theThrowable,
+ final boolean isSuppressionEnabled,
+ final boolean isWritableStackTrace) {
+ super(null, theThrowable, isSuppressionEnabled, isWritableStackTrace);
+ invalidVersion = theInvalidVersion;
+ }
+
+ public String getInvalidVersion() {
+ return invalidVersion;
+ }
+
+ public String getMessage() {
+ return String.format("Invalid semantic version: [%s]", invalidVersion);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/notification/IResourceDownloadObserver.java b/src/main/java/com/capitati/omtc/core/notification/IResourceDownloadObserver.java
new file mode 100644
index 0000000..ca6db59
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/notification/IResourceDownloadObserver.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.notification;
+
+public interface IResourceDownloadObserver
+extends IResourceTaskObserver {
+
+}
diff --git a/src/main/java/com/capitati/omtc/core/notification/IResourceTaskObserver.java b/src/main/java/com/capitati/omtc/core/notification/IResourceTaskObserver.java
new file mode 100644
index 0000000..2dccf7e
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/notification/IResourceTaskObserver.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.notification;
+
+import com.capitati.omtc.core.resources.IResource;
+import com.capitati.omtc.core.session.ISession;
+
+/**
+ * A generic resource task observer. On successful completion of a task the
+ * onSuccess() method shall be called. Whereas, on an error the onError()
+ * method shall be called. The onError() method provides an object, of type F,
+ * shall be provided which is the object that was used to invoke the task.
+ *
+ * @author ianjohnson
+ */
+public interface IResourceTaskObserver {
+ /**
+ * Called on successful completion of a resource task.
+ *
+ * @param notification
+ * @param resource
+ * @param invokingSession
+ */
+ void onSuccess(
+ ISession invokingSession,
+ IResource resource);
+
+ /**
+ * Called when a resource task has failed.
+ *
+ * @param notification
+ * @param invokingSession
+ * @param exception
+ */
+ void onError(
+ ISession session,
+ IResource resource,
+ Exception exception);
+}
diff --git a/src/main/java/com/capitati/omtc/core/notification/IResourceUploadObserver.java b/src/main/java/com/capitati/omtc/core/notification/IResourceUploadObserver.java
new file mode 100644
index 0000000..b406a7f
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/notification/IResourceUploadObserver.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.notification;
+
+public interface IResourceUploadObserver extends IResourceTaskObserver {
+
+}
diff --git a/src/main/java/com/capitati/omtc/core/resources/IDerivedResource.java b/src/main/java/com/capitati/omtc/core/resources/IDerivedResource.java
new file mode 100644
index 0000000..51ce2fa
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/resources/IDerivedResource.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.resources;
+
+import java.util.Date;
+
+public interface IDerivedResource extends IResource {
+ Date getLastChanged();
+}
diff --git a/src/main/java/com/capitati/omtc/core/resources/IPrimaryResource.java b/src/main/java/com/capitati/omtc/core/resources/IPrimaryResource.java
new file mode 100644
index 0000000..e62941b
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/resources/IPrimaryResource.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.resources;
+
+public interface IPrimaryResource extends IResource {
+
+}
diff --git a/src/main/java/com/capitati/omtc/core/resources/IResource.java b/src/main/java/com/capitati/omtc/core/resources/IResource.java
new file mode 100644
index 0000000..72787df
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/resources/IResource.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.resources;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.UUID;
+
+public interface IResource {
+ UUID getIdentifier();
+ URI getURI();
+ Date getBirthDate();
+}
diff --git a/src/main/java/com/capitati/omtc/core/resources/IResourceReader.java b/src/main/java/com/capitati/omtc/core/resources/IResourceReader.java
new file mode 100644
index 0000000..c74539f
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/resources/IResourceReader.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.resources;
+
+import java.io.IOException;
+
+public interface IResourceReader {
+ int read(byte[] buffer) throws IOException;
+ void close() throws IOException;
+}
diff --git a/src/main/java/com/capitati/omtc/core/resources/IResourceWriter.java b/src/main/java/com/capitati/omtc/core/resources/IResourceWriter.java
new file mode 100644
index 0000000..f605e26
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/resources/IResourceWriter.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.resources;
+
+import java.io.IOException;
+
+public interface IResourceWriter {
+ void write(byte[] chunk, int chunkLength) throws IOException;
+ void close() throws IOException;
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/CompositionTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/CompositionTicket.java
new file mode 100644
index 0000000..b9d1535
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/CompositionTicket.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class CompositionTicket<V> extends EngineTicket<V> {
+ private final IEngine composingEngine;
+
+ public CompositionTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine,
+ final IEngine theComposingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ composingEngine = theComposingEngine;
+ }
+
+ public IEngine getComposingEngine() {
+ return composingEngine;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/EngineTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/EngineTicket.java
new file mode 100644
index 0000000..d81bda6
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/EngineTicket.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class EngineTicket<V> extends Ticket<V> {
+ private final IEngine participatingEngine;
+
+ public EngineTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(theIdentifier, theStartDate, theSession, thePriority);
+ participatingEngine = theParticipatingEngine;
+ }
+
+ public IEngine getParticipatingEngine() {
+ return participatingEngine;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/EvaluationTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/EvaluationTicket.java
new file mode 100644
index 0000000..63f5423
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/EvaluationTicket.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class EvaluationTicket<V> extends EngineTicket<V> {
+ public EvaluationTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/IPriority.java b/src/main/java/com/capitati/omtc/core/scheduling/IPriority.java
new file mode 100644
index 0000000..021cc5c
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/IPriority.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+/**
+ * This presents a priority that will be used to schedule a task in the MT API.
+ *
+ * @author ianjohnson
+ *
+ * @param <V> the type of the priority value.
+ */
+public interface IPriority<V> {
+ /**
+ * A getter function to provide the caller with a task's priority. This allows
+ * late binding of any priority parameters at call time.
+ *
+ * @return The priority's value of type V.
+ */
+ V getPriority();
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/IPriorityMechanism.java b/src/main/java/com/capitati/omtc/core/scheduling/IPriorityMechanism.java
new file mode 100644
index 0000000..d38d1b8
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/IPriorityMechanism.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+/**
+ * Implementers should define the priority policy for their product. A priority
+ * description is used to provide the parameters that shall be used to generate
+ * a priority object. The description may include SLA, due date, user's price
+ * plan, one-off task payment details that would improve a task's priority etc.
+ *
+ * @author ianjohnson
+ *
+ * @param <V> the type of the priority value.
+ * @param <D> the type of the priority description. This is a type that provides
+ * all the parameters that will be combined to create a priority object.
+ */
+public interface IPriorityMechanism<V, D> {
+ /**
+ * Taking a priority description generate a priority object that is the
+ * combination of the description.
+ *
+ * @param priorityDescription - the parameters to use to generate the priority.
+ * @return A priority object.
+ * @throws Exception
+ */
+ IPriority<V> getPriority(D priorityDescription) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/ITicketObserver.java b/src/main/java/com/capitati/omtc/core/scheduling/ITicketObserver.java
new file mode 100644
index 0000000..7d778a1
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/ITicketObserver.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+/**
+ * An observer that watches for tickets starting and completing.
+ *
+ * @author ian
+ *
+ * @param <T> - the type of the ticket that has completed.
+ */
+public interface ITicketObserver<T extends Ticket<V>, V> {
+ /**
+ * Notify the observer that a ticketed task has been submitted. This method
+ * shall be called at post-submission and pre-starting time.
+ *
+ * @param ticket - the ticket representing the submitted task.
+ */
+ void notifySubmitted(T ticket);
+
+ /**
+ * Notify the observer that the ticketed task as begun.
+ *
+ * @param ticket - the ticket that has started.
+ */
+ void notifyStarted(T ticket);
+
+ /**
+ * Notify the observer that the ticketed task has ended successfully.
+ *
+ * @param ticket - the ticket that has completed.
+ */
+ void notifySuccess(T ticket);
+
+ /**
+ * Notify the observer that the ticketed task has generated an error.
+ *
+ * @param ticket - the ticket that has completed.
+ * @param exception - the exception that represents the error.
+ */
+ void notifyError(T ticket, Exception exception);
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/QueryTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/QueryTicket.java
new file mode 100644
index 0000000..3147f49
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/QueryTicket.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class QueryTicket<V> extends EngineTicket<V> {
+ public QueryTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/TestingTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/TestingTicket.java
new file mode 100644
index 0000000..0c6735d
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/TestingTicket.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class TestingTicket<V> extends EngineTicket<V> {
+ public TestingTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/Ticket.java b/src/main/java/com/capitati/omtc/core/scheduling/Ticket.java
new file mode 100644
index 0000000..0bd7114
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/Ticket.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.session.ISession;
+
+public abstract class Ticket<V> {
+ private final UUID identifier;
+ private final Date startDate;
+ private final ISession session;
+ private final V priority;
+
+ protected Date endDate;
+
+ protected Ticket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority) {
+ super();
+ identifier = theIdentifier;
+ startDate = theStartDate;
+ session = theSession;
+ priority = thePriority;
+ endDate = null;
+ }
+
+ public UUID getIdentifier() {
+ return identifier;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ public ISession getSession() {
+ return session;
+ }
+
+ public V getPriority() {
+ return priority;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/TrainingTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/TrainingTicket.java
new file mode 100644
index 0000000..741311f
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/TrainingTicket.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class TrainingTicket<V> extends EngineTicket<V> {
+ public TrainingTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/TranslationTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/TranslationTicket.java
new file mode 100644
index 0000000..aa1a5c7
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/TranslationTicket.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.session.ISession;
+import com.capitati.omtc.core.translation.Translator;
+
+public class TranslationTicket<V> extends Ticket<V> {
+ private final Translator<V> translator;
+
+ public TranslationTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final Translator<V> theTranslator) {
+ super(theIdentifier, theStartDate, theSession, thePriority);
+ translator = theTranslator;
+ }
+
+ public Translator<V> getTranslator() {
+ return translator;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/scheduling/UpdateTicket.java b/src/main/java/com/capitati/omtc/core/scheduling/UpdateTicket.java
new file mode 100644
index 0000000..10955c4
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/scheduling/UpdateTicket.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.scheduling;
+
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.session.ISession;
+
+public class UpdateTicket<V> extends EngineTicket<V> {
+ public UpdateTicket(
+ final UUID theIdentifier,
+ final Date theStartDate,
+ final ISession theSession,
+ final V thePriority,
+ final IEngine theParticipatingEngine) {
+ super(
+ theIdentifier,
+ theStartDate,
+ theSession,
+ thePriority,
+ theParticipatingEngine);
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/security/IUser.java b/src/main/java/com/capitati/omtc/core/security/IUser.java
new file mode 100644
index 0000000..092cddd
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/security/IUser.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.security;
+
+import java.util.UUID;
+
+/**
+ * A machine translation service user.
+ *
+ * @author ian
+ */
+public interface IUser {
+ /**
+ * The unique identifier for the user.
+ *
+ * @return The user's unique identity.
+ */
+ UUID getIdentifier();
+
+ /**
+ * Retrieve the user's roles.
+ *
+ * @return The roles of the user.
+ */
+ Role[] getRoles();
+}
diff --git a/src/main/java/com/capitati/omtc/core/security/Role.java b/src/main/java/com/capitati/omtc/core/security/Role.java
new file mode 100644
index 0000000..bf1e3c4
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/security/Role.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.security;
+
+public enum Role {
+ INVALID(-1, "Invalid"),
+ TRANSLATOR(1, "Translator"),
+ ENGINE_MANAGER(3, "Engine Manager"),
+ ADMINISTRATOR(7, "Administrator"),
+ SERVICE_ADMINISTRATOR(8, "Service Administrator");
+
+ private final int code;
+ private final String name;
+
+ private Role(final int theCode, final String theName) {
+ code = theCode;
+ name = theName;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/security/User.java b/src/main/java/com/capitati/omtc/core/security/User.java
new file mode 100644
index 0000000..bca6e0e
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/security/User.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.security;
+
+import java.util.UUID;
+
+public abstract class User implements IUser {
+ private final UUID userId;
+ private final Role role;
+
+ protected User(final UUID theUserId, final Role theRole) {
+ userId = theUserId;
+ role = theRole;
+ }
+
+ public UUID getIdentifier() {
+ return userId;
+ }
+
+ public Role getRole() {
+ return role;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/IEngineAssignableSession.java b/src/main/java/com/capitati/omtc/core/session/IEngineAssignableSession.java
new file mode 100644
index 0000000..d838e72
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IEngineAssignableSession.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.security.IUser;
+
+/**
+ * A mixin to provide methods to grant and revoke users access to constructed
+ * engines in the machine translation service. Implementers of this interface
+ * should associate an engine. And optionally storing the record of a grant or
+ * revocation into some persistent backing store. Whether the backing store is
+ * a database or authorisation service is implementation defined.
+ *
+ * @author ianjohnson
+ */
+public interface IEngineAssignableSession
+extends IEngineRetrievableSession, IUserRetrievableSession {
+ /**
+ * Associate a user with an engine. This association should allow the user
+ * to use the engine for a {@link com.capitati.omtc.core.translation.Translator}
+ * object. Optionally, the implementation should back this association to some
+ * persistent backing store.
+ *
+ * @param engine - the engine to grant.
+ * @param theUser - the grantee.
+ * @throws Exception Any error that is encountered.
+ */
+ void grantEngineToUser(IEngine engine, IUser theUser) throws Exception;
+
+ /**
+ * Dissociate a user from an engine. The user shall no longer be able to use
+ * an engine to build a {@link com.capitati.omtc.core.translation.Translator}
+ * object. Whether the existing translator objects, that use the engine,
+ * shall be destroyed immediately, or that the engine is no longer available
+ * for use in a translator is to implementation defined. Optionally, the
+ * implementation should back the dissociation to a persistent backing store.
+ *
+ * @param engine - the engine to revoke.
+ * @param theUser - the revokee.
+ * @throws Exception Any error that is encountered.
+ */
+ void revokeEngineFromUser(IEngine engine, IUser theUser) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/IEngineRetrievableSession.java b/src/main/java/com/capitati/omtc/core/session/IEngineRetrievableSession.java
new file mode 100644
index 0000000..d2ee5bb
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IEngineRetrievableSession.java
@@ -0,0 +1,10 @@
+package com.capitati.omtc.core.session;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.google.common.base.Predicate;
+
+public interface IEngineRetrievableSession {
+ Set<IEngine> retrieveEngines(Predicate<IEngine> filter) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/IResourceTransferDelegate.java b/src/main/java/com/capitati/omtc/core/session/IResourceTransferDelegate.java
new file mode 100644
index 0000000..489bdde
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IResourceTransferDelegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import com.capitati.omtc.core.resources.IResource;
+import com.capitati.omtc.core.resources.IResourceReader;
+import com.capitati.omtc.core.resources.IResourceWriter;
+
+/**
+ * The delegated resource transfer mechanism.
+ *
+ * @author ianjohnson
+ */
+public interface IResourceTransferDelegate {
+ /**
+ * Constructs an instance of {@link com.capitati.omtc.core.resources.IResourceReader}
+ * which is an object that is used to read chunks of data from a source
+ * resource. Implementers of this method should take this opportunity to
+ * open a resource where ever that may be, e.g., local disk, remote client.
+ *
+ * @param theInvokingSession - the session for whom this method is being called.
+ * @return An implementation of the {@link com.capitati.omtc.core.resources.IResourceReader}
+ * interface that shall provide data for a resource.
+ * @throws Exception On any error encountered.
+ */
+ IResourceReader getResourceReader(ISession theInvokingSession) throws Exception;
+
+ /**
+ * Constructs an instance of {@link com.capitati.omtc.core.resources.IResourceWriter}
+ * which is an object that is used to write chunks of data to a destination
+ * resource. Implementers of this method should take this opportunity to
+ * open a resource where ever it may needed to be, e.g., local disk, remote client.
+ *
+ * @param theInvokingSession - the session for whom this method is being called.
+ * @return An implementation of the {@link com.capitati.omtc.core.resources.IResourceWriter}
+ * interface that is to handle the writing of resource data.
+ * @throws Exception On any error encountered.
+ */
+ IResourceWriter getResourceWriter(ISession theInvokingSession) throws Exception;
+
+ /**
+ * Implementers of this method should return a {@link com.capitati.omtc.core.resources.IResource}
+ * object that represents the resource that is begin transfered.
+ * Please note: for documents, translation memories, and glossaries etc instances of
+ * {@link com.capitati.omtc.core.resources.IPrimaryResource} should be
+ * constructed. However, for resources that are derived, e.g., engines, then
+ * instances of type {@link com.capitati.omtc.core.resources.IDerivedResource}
+ * should be returned.
+ *
+ * @param theInvokingSession - the session that invoked the transfer action.
+ * @return A {@link com.capitati.omtc.core.resources.IResource}
+ * object that presents the resource uploaded
+ */
+ IResource getResource(ISession theInvokingSession);
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/IRoleAssignableSession.java b/src/main/java/com/capitati/omtc/core/session/IRoleAssignableSession.java
new file mode 100644
index 0000000..8948634
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IRoleAssignableSession.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import com.capitati.omtc.core.security.IUser;
+import com.capitati.omtc.core.security.Role;
+
+/**
+ * A mixin for providing a session the ability to grant and revoke roles from
+ * users of the machine translation service. Implementers of this interface
+ * should integrate with any back-end authorisation service that may be used
+ * alongside the concrete service.
+ *
+ * @author ianjohnson
+ */
+public interface IRoleAssignableSession extends IUserRetrievableSession {
+ /**
+ * Grant a role to a user.
+ *
+ * @param theRole - the role to grant.
+ * @param theUser - the user.
+ * @throws Exception On any errors that occur during the granting process.
+ */
+ void grantRoleToUser(Role theRole, IUser theUser) throws Exception;
+
+ /**
+ * Revoke a role from a user.
+ *
+ * @param theRole - the role to revoke from the user.
+ * @param theUser - the user.
+ * @throws Exception On any errors that occur during the revocation process.
+ */
+ void revokeRoleFromUser(Role theRole, IUser theUser) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/ISession.java b/src/main/java/com/capitati/omtc/core/session/ISession.java
new file mode 100644
index 0000000..d6245ed
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/ISession.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Future;
+
+import javax.naming.OperationNotSupportedException;
+
+import com.capitati.omtc.core.notification.IResourceDownloadObserver;
+import com.capitati.omtc.core.notification.IResourceUploadObserver;
+import com.capitati.omtc.core.resources.IResource;
+import com.google.common.base.Predicate;
+
+/**
+ * A machine translation service session. This session is <em>user-less</em>;
+ * this session is for services where user identity is not crucial for using the
+ * service.
+ *
+ * @author ian
+ */
+public interface ISession {
+ /**
+ * Get the session's unique identifier.
+ *
+ * @return The unique identifier that is of type {@link java.util.UUID}.
+ */
+ UUID getIdentifier();
+
+ /**
+ * Upload a resource to the service. The upload delegate shall be called to
+ * implement the actual mechanism that shall transfer resource data. If
+ * specified the {@link com.capitati.omtc.core.notification.IResourceUploadObserver}
+ * object shall be notified when the uploading of the resource has completed:
+ * either on success or failure.
+ *
+ * <p>The returning {@link java.util.concurrent.Future} object,
+ * and the optional observer, allows callers to wait synchronously or
+ * asynchronously for upload completion.
+ *
+ * @param theResourceUploaderDelegate - the delegated uploader mechanism.
+ * @param theResourceUploadObserver - optional observer that is notified
+ * once the uploading task has completed, either successfully or unsuccessfully.
+ * @return A {@link java.util.concurrent.Future} object that waits on the
+ * availability of the {@link com.capitati.omtc.core.resources.IResource} object
+ * that represents the resource once uploaded.
+ * @throws OperationNotSupportedException If no executor service was specified.
+ * @throws IllegalArgumentException If no uploading delegate has been
+ * provided.
+ */
+ Future<IResource> uploadResource(
+ IResourceTransferDelegate theResourceUploaderDelegate,
+ IResourceUploadObserver theResourceUploadObserver)
+ throws OperationNotSupportedException;
+
+ /**
+ * Download a resource from the service. The download delegate shall be called to
+ * implement the actual mechanism that shall transfer resource data. If
+ * specified the {@link com.capitati.omtc.core.notification.IResourceDownloadObserver}
+ * object shall be notified when the downloading of the resource has completed:
+ * either on success or failure.
+ *
+ * <p>The returning {@link java.util.concurrent.Future} object,
+ * and the optional observer, allows callers to wait synchronously or
+ * asynchronously for the downloading to complete.
+ *
+ * @param theResourceDownloaderDelegate - the delegated downloading mechanism.
+ * @param theResourceDownloadObserver - optional observer that is notified
+ * once the downloading task has completed, either successfully or unsuccessfully.
+ * @return A {@link java.util.concurrent.Future} object that waits on the
+ * availability of the {@link com.capitati.omtc.core.resources.IResource} object
+ * that represents the resource once downloaded.
+ * @throws OperationNotSupportedException If no executor service was specified.
+ * @throws IllegalArgumentException If no uploading delegate had been
+ * provided.
+ */
+ Future<IResource> downloadResource(
+ IResourceTransferDelegate theResourceDownloaderDelegate,
+ IResourceDownloadObserver theResourceDownloadObserver)
+ throws OperationNotSupportedException;
+
+ /**
+ * Remove a resource. If the resource implements
+ * {@link com.capitati.omtc.core.commons.IDisposable} the the method
+ * {@link com.capitati.omtc.core.commons.IDisposable#dispose} should be
+ * called to dispose of any used system resources, e.g., disk space.
+ *
+ * @param resource - the resource to remove.
+ * @throws Exception On an error.
+ */
+ void removeResource(IResource resource) throws Exception;
+
+ /**
+ * This method shall return a set of resources that belong to the session.
+ *
+ * @param theFilter - the predicate that shall filter the resources returned.
+ * @return A {@link java.util.Set} of {@link com.capitati.omtc.core.resource.IResource}
+ * objects that are owned by the session and meet the predicate.
+ * @throws Exception on error evaluating the predicate.
+ */
+ Set<IResource> retrieveResources(Predicate<IResource> theFilter)
+ throws Exception;
+} \ No newline at end of file
diff --git a/src/main/java/com/capitati/omtc/core/session/IUserRetrievableSession.java b/src/main/java/com/capitati/omtc/core/session/IUserRetrievableSession.java
new file mode 100644
index 0000000..6c4eb05
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IUserRetrievableSession.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import java.util.Set;
+
+import com.capitati.omtc.core.security.IUser;
+import com.google.common.base.Predicate;
+
+public interface IUserRetrievableSession {
+ Set<IUser> retrieveUsers(Predicate<IUser> filter) throws Exception;
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/IUserSession.java b/src/main/java/com/capitati/omtc/core/session/IUserSession.java
new file mode 100644
index 0000000..02754af
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/IUserSession.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import com.capitati.omtc.core.security.IUser;
+
+/**
+ * A session that is associated with a user. This session would be used by a
+ * service implementation that requires user identity.
+ *
+ * @author ian
+ */
+public interface IUserSession extends ISession {
+ /**
+ * Retrieve the associated user object for the session.
+ *
+ * @return The session's associated user object.
+ */
+ IUser getUser();
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/Session.java b/src/main/java/com/capitati/omtc/core/session/Session.java
new file mode 100644
index 0000000..6731325
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/Session.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.naming.OperationNotSupportedException;
+
+import com.capitati.omtc.core.notification.IResourceDownloadObserver;
+import com.capitati.omtc.core.notification.IResourceUploadObserver;
+import com.capitati.omtc.core.resources.IResource;
+import com.capitati.omtc.core.resources.IResourceReader;
+import com.capitati.omtc.core.resources.IResourceWriter;
+
+/**
+ * A machine translation service session. This session is <em>user-less</em>;
+ * this session is for services where user identity is not crucial for using the
+ * service.
+ *
+ * @author ianjohnson
+ */
+public abstract class Session implements ISession {
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024; // 1Mb
+
+ private final UUID id;
+ private final int bufferSize;
+ protected final ExecutorService executor;
+
+ /**
+ * Construct a session that does not support uploading or downloading of
+ * resources.
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ */
+ protected Session(final UUID theIdentifier) {
+ super();
+ id = theIdentifier;
+ bufferSize = DEFAULT_BUFFER_SIZE;
+ executor = null;
+ }
+
+ /**
+ * Construct a session that supports uploading and downloading of resources.
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ * @param theDelegateExecutorService - the executor service in which the
+ * upload and download delegates shall run.
+ */
+ protected Session(
+ final UUID theIdentifier,
+ final ExecutorService theDelegationExecutorService) {
+ super();
+ id = theIdentifier;
+ executor = theDelegationExecutorService;
+ bufferSize = (executor != null) ? DEFAULT_BUFFER_SIZE : -1;
+ }
+
+ /**
+ * Construct a session that supports uploading and downloading of resources.
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ * @param theDelegateExecutorService - the executor service in which the
+ * upload and download delegates shall run.
+ * @param theTransferBufferSize - the number of bytes available to the
+ * upload and download transfer buffer.
+ */
+ protected Session(
+ final UUID theIdentifier,
+ final ExecutorService theDelegationExecutorService,
+ final int theTransferBufferSize) {
+ super();
+ id = theIdentifier;
+ bufferSize = (theTransferBufferSize > 0) ? theTransferBufferSize : DEFAULT_BUFFER_SIZE;
+ executor = theDelegationExecutorService;
+ }
+
+ public UUID getIdentifier() {
+ return id;
+ }
+
+ public Future<IResource> uploadResource(
+ final IResourceTransferDelegate theResourceUploaderDelegate,
+ final IResourceUploadObserver theResourceUploadObserver)
+ throws OperationNotSupportedException {
+ if(executor == null) {
+ throw new OperationNotSupportedException("");
+ }
+
+ if(theResourceUploaderDelegate == null) {
+ throw new IllegalArgumentException("No uploader delegate specified.");
+ }
+
+ final ISession invokingSession = this;
+ final Callable<IResource> uploadTask = new Callable<IResource>() {
+ public IResource call() throws Exception {
+ final IResource resource =
+ theResourceUploaderDelegate.getResource(invokingSession);
+
+ try {
+ upload();
+
+ if(theResourceUploadObserver != null) {
+ theResourceUploadObserver.onSuccess(invokingSession, resource);
+ }
+ } catch(final Exception ex) {
+ if(theResourceUploadObserver != null) {
+ theResourceUploadObserver.onError(invokingSession, resource, ex);
+ }
+ throw ex;
+ }
+
+ return resource;
+ }
+
+ private void upload() throws Exception {
+ final IResourceReader resourceReader =
+ theResourceUploaderDelegate.getResourceReader(invokingSession);
+
+ try {
+ final IResourceWriter resourceWriter =
+ theResourceUploaderDelegate.getResourceWriter(invokingSession);
+
+ try {
+ Session.copyBytes(resourceReader, resourceWriter, bufferSize);
+ } finally {
+ resourceWriter.close();
+ }
+ } finally {
+ resourceReader.close();
+ }
+ }
+ };
+ final Future<IResource> future = executor.submit(uploadTask);
+
+ return future;
+ }
+
+ public Future<IResource> downloadResource(
+ final IResourceTransferDelegate theResourceDownloaderDelegate,
+ final IResourceDownloadObserver theResourceDownloadObserver) {
+ if(theResourceDownloaderDelegate == null) {
+ throw new IllegalArgumentException("No downloader delegate specified.");
+ }
+
+ final ISession invokingSession = this;
+ final Callable<IResource> downloadTask = new Callable<IResource>() {
+ public IResource call() throws Exception {
+ final IResource resource =
+ theResourceDownloaderDelegate.getResource(invokingSession);
+
+ try {
+ download();
+
+ if(theResourceDownloadObserver != null) {
+ theResourceDownloadObserver.onSuccess(invokingSession, resource);
+ }
+ } catch(final Exception ex) {
+ if(theResourceDownloadObserver != null) {
+ theResourceDownloadObserver.onError(invokingSession, resource, ex);
+ throw ex;
+ }
+ }
+
+ return resource;
+ }
+
+ private void download() throws Exception {
+ final IResourceWriter resourceWriter =
+ theResourceDownloaderDelegate.getResourceWriter(invokingSession);
+
+ try {
+ final IResourceReader resourceReader =
+ theResourceDownloaderDelegate.getResourceReader(invokingSession);
+
+ try {
+ Session.copyBytes(resourceReader, resourceWriter, bufferSize);
+ } finally {
+ resourceReader.close();
+ }
+ } finally {
+ resourceWriter.close();
+ }
+ }
+ };
+ final Future<IResource> future = executor.submit(downloadTask);
+
+ return future;
+ }
+
+ /**
+ * Writes bytes, read from a resource reader, to a resource writer. This
+ * copies the bytes from a source resource to a destination resource,
+ * respectively.
+ *
+ * @param resourceReader - the object that shall read the source resource data.
+ * @param resourceWriter - the object that shall write the resource data to
+ * the destination resource.
+ * @param bufferSize - the number of bytes used to build the buffer.
+ * @throws Exception on an error reading from, or writing to the resources.
+ */
+ private static void copyBytes(
+ final IResourceReader resourceReader,
+ final IResourceWriter resourceWriter,
+ final int bufferSize) throws Exception {
+ final byte[] readBuffer = new byte[bufferSize];
+ int bytesRead = resourceReader.read(readBuffer);
+
+ while(bytesRead > -1) {
+ resourceWriter.write(readBuffer, bytesRead);
+ bytesRead = resourceReader.read(readBuffer);
+ }
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/session/UserSession.java b/src/main/java/com/capitati/omtc/core/session/UserSession.java
new file mode 100644
index 0000000..6fa549c
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/session/UserSession.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.session;
+
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+
+import com.capitati.omtc.core.security.IUser;
+
+/**
+ * A session that is associated with a user. This session would be used by a
+ * service implementation that requires user identity.
+ *
+ * @author ianjohnson
+ */
+public abstract class UserSession extends Session implements IUserSession {
+ protected final IUser user;
+
+ /**
+ * Construct a user session that does not support downloading or uploading.
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ * @param theUser - the associated user object.
+ */
+ protected UserSession(final UUID theIdentifier, final IUser theUser) {
+ super(theIdentifier);
+ user = theUser;
+ }
+
+ /**
+ * Construct a user session that supports downloading and uploading.
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ * @param theUser - the associated user object.
+ * @param theDelegateExecutorService - the executor service in which the
+ * upload and download delegates shall run.
+ */
+ protected UserSession(
+ final UUID theIdentifier,
+ final IUser theUser,
+ final ExecutorService theDelegationExecutorService) {
+ super(theIdentifier, theDelegationExecutorService);
+ user = theUser;
+ }
+
+ /**
+ *
+ * @param theIdentifier - the unique identifier for the session.
+ * @param theUser - the associated user object.
+ * @param theDelegationExecutorService -the executor service in which the
+ * upload and download delegates shall run.
+ * @param theTransferBufferSize - the number of bytes available to the
+ * upload and download transfer buffer.
+ */
+ protected UserSession(
+ final UUID theIdentifier,
+ final IUser theUser,
+ final ExecutorService theDelegationExecutorService,
+ final int theTransferBufferSize) {
+ super(theIdentifier, theDelegationExecutorService, theTransferBufferSize);
+ user = theUser;
+ }
+
+ /**
+ * Retrieve the associated user object for the session.
+ *
+ * @return The session's associated user object.
+ */
+ public IUser getUser() {
+ return user;
+ }
+}
diff --git a/src/main/java/com/capitati/omtc/core/translation/Translator.java b/src/main/java/com/capitati/omtc/core/translation/Translator.java
new file mode 100644
index 0000000..3ef63a3
--- /dev/null
+++ b/src/main/java/com/capitati/omtc/core/translation/Translator.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright Capita Translation and Interpreting 2013
+ *
+ * This file is part of OMTC.
+ *
+ * OMTC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OMTC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OMTC. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.capitati.omtc.core.translation;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.capitati.omtc.core.engine.IEngine;
+import com.capitati.omtc.core.resources.IPrimaryResource;
+import com.capitati.omtc.core.scheduling.IPriority;
+import com.capitati.omtc.core.scheduling.ITicketObserver;
+import com.capitati.omtc.core.scheduling.TranslationTicket;
+import com.google.common.base.Predicate;
+
+/**
+ * An associative class that brings together an engine, glossaries and
+ * translation memories. These resources are to be used as a translator.
+ *
+ * @author ian
+ *
+ * @param <P> - the type of the priority's value.
+ */
+public abstract class Translator<V> {
+ private final IEngine engine;
+ private final Set<IPrimaryResource> glossaries =
+ new HashSet<IPrimaryResource>();
+ private final Set<IPrimaryResource> translationMemories =
+ new HashSet<IPrimaryResource>();
+
+ protected Translator(final IEngine theEngine) {
+ super();
+ engine = theEngine;
+ }
+
+ protected Translator(
+ final IEngine theEngine,
+ final Set<IPrimaryResource> theGlossaries,
+ final Set<IPrimaryResource> theTranslationMemories) {
+ super();
+ engine = theEngine;
+ glossaries.addAll(theGlossaries);
+ translationMemories.addAll(theTranslationMemories);
+ }
+
+ public IEngine getEngine() {
+ return engine;
+ }
+
+ public Set<IPrimaryResource> getGlossaries() {
+ return glossaries;
+ }
+
+ public Set<IPrimaryResource> getTranslationMemories() {
+ return translationMemories;
+ }
+
+ /**
+ * Schedule a translation for a primary resource. It is implementation
+ * defined which kind of primary resources shall be translated.
+ *
+ * @param session - the invoking session.
+ * @param resourceToTranslate - the primary resource to translate.
+ * @param thePriority - the requested priority.
+ * @param translationObserver - the observer that listens for the translation
+ * task to starting and complete.
+ * @return A translation ticket.
+ * @throws Exception On an error.
+ */
+ public abstract TranslationTicket<V> scheduleTranslation(
+ IPrimaryResource resourceToTranslate,
+ IPriority<V> thePriority,
+ ITicketObserver<TranslationTicket<V>, V> translationObserver)
+ throws Exception;
+
+ /**
+ * Schedule a translation for a single sentence.
+ *
+ * @param session - the invoking session.
+ * @param sourceSentence - the sentence to translate.
+ * @param thePriority - the requested priority.
+ * @param translationObserver - the observer that listens for the translation
+ * task to starting and complete.
+ * @return A translation ticket.
+ * @throws Exception On an error.
+ */
+ public abstract TranslationTicket<V> scheduleTranslation(
+ String sourceSentence,
+ IPriority<V> thePriority,
+ ITicketObserver<TranslationTicket<V>, V> translationObserver)
+ throws Exception;
+
+ /**
+ * Retrieve the dispensed translation tickets.
+ *
+ * @param filter - a predicate used to filter the translation tickets.
+ * @return A {@link java.util.Set} of currently scheduled translation
+ * tickets. It is the implementations responsibility to manage the in-flight
+ * collection of tickets.
+ *
+ * @throws Exception
+ */
+ public abstract Set<TranslationTicket<V>> retrieveTranslations(
+ Predicate<TranslationTicket<V>> filter) throws Exception;
+}
diff --git a/src/test/java/com/capitati/omtc/core/negotiation/NegotiatorTests.java b/src/test/java/com/capitati/omtc/core/negotiation/NegotiatorTests.java
new file mode 100644
index 0000000..2c94427
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/negotiation/NegotiatorTests.java
@@ -0,0 +1,248 @@
+package com.capitati.omtc.core.negotiation;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NegotiatorTests {
+ public Mockery mockery;
+ public IServiceResourceCapability resourceOne;
+ public IServiceResourceCapability resourceTwo;
+ public IServiceResourceCapability resourceThree;
+ public IServiceResourceCapability resourceFour;
+ public IFeatureCapability featureOne;
+ public IFeatureCapability featureTwo;
+ public IPrerequisiteCapability prereq;
+ public List<IServiceResourceCapability> resources;
+ public Set<IFeatureCapability> features;
+
+ @Before
+ public void setUp() {
+ mockery = new JUnit4Mockery();
+ resourceOne = mockery.mock(IServiceResourceCapability.class, "resourceOne");
+ resourceTwo = mockery.mock(IServiceResourceCapability.class, "resourceTwo");
+ resourceThree = mockery.mock(IServiceResourceCapability.class, "resourceThree");
+ resourceFour = mockery.mock(IServiceResourceCapability.class, "resourceFour");
+ featureOne = mockery.mock(IFeatureCapability.class, "featureOne");
+ featureTwo = mockery.mock(IFeatureCapability.class, "featureTwo");
+ prereq = mockery.mock(IPrerequisiteCapability.class, "prereqOne");
+
+ resources =
+ new ArrayList<IServiceResourceCapability>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(resourceOne);
+ add(resourceTwo);
+ add(resourceThree);
+ add(resourceFour);
+ }};
+
+ features =
+ new HashSet<IFeatureCapability>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(featureOne);
+ add(featureTwo);
+ }};
+ }
+
+ @Test
+ public void testNegotiation() throws SemanticVersionParseException {
+ final ISemanticVersion clientVersion = SemanticVersion.parseVersion("1.3.7");
+ final IResourceCapability clientResourceCapOne = new IResourceCapability() {
+ public Capability getName() {
+ return Capability.RES_FILE_XLIFF;
+ }
+ public String getLowerVersion() {
+ return "1.6";
+ }
+ public String getHigherVersion() {
+ return "2.0";
+ }
+ };
+ final IResourceCapability clientResourceCapTwo = new IResourceCapability() {
+ public Capability getName() {
+ return Capability.RES_FILE_XLIFF;
+ }
+ public String getLowerVersion() {
+ return "7.0";
+ }
+ public String getHigherVersion() {
+ return "10.0";
+ }
+ };
+ final IResourceCapability clientResourceCapThree = new IResourceCapability() {
+ public Capability getName() {
+ return Capability.RES_FILE_TMX;
+ }
+ public String getLowerVersion() {
+ return "0.8";
+ }
+ public String getHigherVersion() {
+ return "10.5";
+ }
+ };
+ final IResourceCapability clientResourceCapFour = new IResourceCapability() {
+ public Capability getName() {
+ return Capability.RES_FILE_TTX;
+ }
+ public String getLowerVersion() {
+ return "2.718";
+ }
+ public String getHigherVersion() {
+ return "3.141";
+ }
+ };
+ final Set<IResourceCapability> clientResourceCapabilities =
+ new HashSet<IResourceCapability>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(clientResourceCapOne);
+ add(clientResourceCapTwo);
+ add(clientResourceCapThree);
+ add(clientResourceCapFour);
+ }};
+
+ mockery.checking(new Expectations() {{
+ allowing(resourceOne).getName();
+ will(returnValue(Capability.RES_FILE_XLIFF));
+ allowing(resourceOne).getLowerVersion();
+ will(returnValue("1.5"));
+ allowing(resourceOne).getHigherVersion();
+ will(returnValue("2.3"));
+ allowing(resourceOne).compareVersion(with(clientResourceCapOne));
+ will(returnValue(0));
+ allowing(resourceOne).compareVersion(with(clientResourceCapTwo));
+ will(returnValue(1));
+ allowing(resourceOne).compareVersion(with(any(IResourceCapability.class)));
+ will(returnValue(-1));
+
+ allowing(resourceTwo).getName();
+ will(returnValue(Capability.RES_FILE_XLIFF));
+ allowing(resourceTwo).getLowerVersion();
+ will(returnValue("3.7"));
+ allowing(resourceTwo).getHigherVersion();
+ will(returnValue("4.2"));
+ allowing(resourceTwo).compareVersion(with(any(IResourceCapability.class)));
+ will(returnValue(-1));
+
+ allowing(resourceThree).getName();
+ will(returnValue(Capability.RES_FILE_TMX));
+ allowing(resourceThree).getLowerVersion();
+ will(returnValue("0.2"));
+ allowing(resourceThree).getHigherVersion();
+ will(returnValue("1.0"));
+ allowing(resourceThree).compareVersion(clientResourceCapThree);
+ will(returnValue(0));
+ allowing(resourceThree).compareVersion(with(any(IResourceCapability.class)));
+ will(returnValue(-1));
+
+ allowing(resourceFour).getName();
+ will(returnValue(Capability.RES_FILE_TBX));
+ allowing(resourceFour).getLowerVersion();
+ will(returnValue("0.8"));
+ allowing(resourceFour).getHigherVersion();
+ will(returnValue("10.5"));
+ allowing(resourceFour).compareVersion(with(any(IResourceCapability.class)));
+ will(returnValue(-1));
+
+ allowing(featureOne).getName();
+ will(returnValue(Capability.FET_RES_DOWNLOAD));
+ allowing(featureOne).getPrerequisiteCapabilities();
+ will(returnValue(new HashSet<IPrerequisiteCapability>()));
+
+ allowing(featureTwo).getName();
+ will(returnValue(Capability.FET_RES_UPLOAD));
+ allowing(featureTwo).getPrerequisiteCapabilities();
+ will(returnValue(new HashSet<IPrerequisiteCapability>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(new IPrerequisiteCapability() {
+ public Capability getName() {
+ return Capability.PRE_REQ_PAYMENT;
+ }
+ });
+ }}));
+ }});
+
+ final INegotiator negotiator = new Negotiator("1.5.1", resources, features);
+ final IClientCapabilityRequest request = new IClientCapabilityRequest() {
+ public IAPICapability getVersionCapability() {
+ return new IAPICapability() {
+ public Capability getName() {
+ return Capability.API_VERSION;
+ }
+ public ISemanticVersion getVersion() {
+ return clientVersion;
+ }
+ };
+ }
+ public Set<IResourceCapability> getResourceCapabilities() {
+ return clientResourceCapabilities;
+ }
+ };
+ final IClientCapabilityResponse response = negotiator.negotiate(request);
+
+ final Set<IResourceCapability> targetUnsupportedResources =
+ new HashSet<IResourceCapability>() {
+ private static final long serialVersionUID = 4358016718704699346L;
+ {
+ add(clientResourceCapTwo);
+ add(clientResourceCapFour);
+ }};
+
+ Assert.assertTrue(response.isClientAPISupported());
+ Assert.assertEquals(
+ targetUnsupportedResources,
+ response.getUnsupportedResourceCapabilities());
+ Assert.assertEquals(features, response.getFeatureCapabilities());
+ }
+
+ @Test
+ public void testAPIVersionNotSupported() throws SemanticVersionParseException {
+ final INegotiator negotiator = new Negotiator("1.5.1", null, null);
+ final IClientCapabilityRequest requestLow = new IClientCapabilityRequest() {
+ public IAPICapability getVersionCapability() {
+ return new IAPICapability() {
+ public Capability getName() {
+ return Capability.API_VERSION;
+ }
+ public ISemanticVersion getVersion() {
+ return new SemanticVersion(0, 9, 0, "alpha.1", "build.1234");
+ }
+ };
+ }
+ public Set<IResourceCapability> getResourceCapabilities() {
+ return new HashSet<IResourceCapability>();
+ }
+ };
+ final IClientCapabilityResponse responseLow = negotiator.negotiate(requestLow);
+ final IClientCapabilityRequest requestHigh = new IClientCapabilityRequest() {
+ public IAPICapability getVersionCapability() {
+ return new IAPICapability() {
+ public Capability getName() {
+ return Capability.API_VERSION;
+ }
+ public ISemanticVersion getVersion() {
+ return new SemanticVersion(2, 3, 7);
+ }
+ };
+ }
+ public Set<IResourceCapability> getResourceCapabilities() {
+ return new HashSet<IResourceCapability>();
+ }
+ };
+ final IClientCapabilityResponse responseHigh = negotiator.negotiate(requestHigh);
+
+ Assert.assertFalse(responseLow.isClientAPISupported());
+ Assert.assertFalse(responseHigh.isClientAPISupported());
+ }
+}
diff --git a/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionComparatorTests.java b/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionComparatorTests.java
new file mode 100644
index 0000000..adff242
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionComparatorTests.java
@@ -0,0 +1,528 @@
+package com.capitati.omtc.core.negotiation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SemanticVersionComparatorTests {
+ private interface IVersionsWithChecker {
+ ISemanticVersion getLeftVersion();
+ ISemanticVersion getRightVersion();
+ boolean forwardCheck(int comparisonValue);
+ boolean backwardCheck(int comparisonValue);
+ SemanticVersionComponent getChangedComponent();
+ }
+
+ private static final List<ISemanticVersion> orderedVersions =
+ new ArrayList<ISemanticVersion>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(new SemanticVersion(1, 0, 0, "alpha", null));
+ add(new SemanticVersion(1, 0, 0, "alpha.1", null));
+ add(new SemanticVersion(1, 0, 0, "beta.2", null));
+ add(new SemanticVersion(1, 0, 0, "beta.11", null));
+ add(new SemanticVersion(1, 0, 0, "rc.1", null));
+ add(new SemanticVersion(1, 0, 0, "rc.1", "build.1"));
+ add(new SemanticVersion(1, 0, 0, "rc.2", null));
+ add(new SemanticVersion(1, 0, 0));
+ add(new SemanticVersion(1, 0, 1));
+ add(new SemanticVersion(1, 1, 2));
+ add(new SemanticVersion(2, 0, 0));
+ add(new SemanticVersion(2, 0, 0, null, "0.3.7"));
+ add(new SemanticVersion(2, 3, 7, null, "build"));
+ add(new SemanticVersion(2, 3, 7, null, "build.2.b8f12d7"));
+ add(new SemanticVersion(2, 3, 7, null, "build.11.e0f985a"));
+ }};
+
+ @Test
+ public void testComparatorWithLexicalOrdering() {
+ for(int idx = 0; idx < orderedVersions.size() - 1; idx++) {
+ final ISemanticVersion one = orderedVersions.get(idx);
+ final ISemanticVersion two = orderedVersions.get(idx + 1);
+
+ System.err.printf(
+ "Version [%s] and [%s]...%s",
+ one,
+ two,
+ System.lineSeparator());
+
+ Assert.assertTrue(
+ String.format(
+ "Semantic version [%s] is greater than [%s]",
+ one, two),
+ SemanticVersionComparator.compare(one, two).getLeft() < 0);
+ Assert.assertTrue(
+ String.format(
+ "Semantic version [%s] is less than [%s]",
+ two, one),
+ SemanticVersionComparator.compare(two, one).getLeft() > 0);
+ Assert.assertTrue(
+ String.format(
+ "Semantic version [%s] is not equal to itself!", one),
+ SemanticVersionComparator.compare(one, one).getLeft() == 0);
+ Assert.assertTrue(
+ String.format(
+ "Semantic version [%s] is not equal to itself!", two),
+ SemanticVersionComparator.compare(two, two).getLeft() == 0);
+ }
+ }
+
+ /*
+ * Versions with both pre-release and build
+ */
+ private static final List<IVersionsWithChecker> versionsWithPreReleaseAndBuild =
+ new ArrayList<IVersionsWithChecker>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ // Arrrgh, v4!
+ return new SemanticVersion(4, 0, 0, "rc.1", "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.MAJOR_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 5, 0, "rc.1", "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.MINOR_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 8, "rc.1", "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PATCH_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.2", "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.2", "build.1");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+ }};
+
+ @Test
+ public void testPreReleaseAndBuildComponentOrdering() {
+ runVersionsWithCheckTest(versionsWithPreReleaseAndBuild);
+ }
+
+ /*
+ * These versions invoke the true, true code path for pre-release and
+ * build comparisons.
+ */
+ private static final List<IVersionsWithChecker> versionWithNullComponents =
+ new ArrayList<IVersionsWithChecker>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 1);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PATCH_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 2, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.MINOR_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(3, 2, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.MAJOR_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", null);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.2");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.2");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue == 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return forwardCheck(comparisonValue);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.INVALID;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", null);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.2");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.2");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0);
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "beta.11", null);
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.11.e0f985a");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.2");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.2");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.1");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+
+ add(new IVersionsWithChecker() {
+ public ISemanticVersion getLeftVersion() {
+ return new SemanticVersion(1, 0, 0, "rc.1", "build.1");
+ }
+ public ISemanticVersion getRightVersion() {
+ return new SemanticVersion(1, 0, 0, null, "build.2.b8f12d7");
+ }
+ public boolean forwardCheck(int comparisonValue) {
+ return (comparisonValue < 0);
+ }
+ public boolean backwardCheck(int comparisonValue) {
+ return (comparisonValue > 0);
+ }
+ public SemanticVersionComponent getChangedComponent() {
+ return SemanticVersionComponent.PRE_RELEASE_AND_BUILD_VERSION;
+ }
+ });
+ }};
+
+ @Test
+ public void testVersionsWithNullPreReleaseOrBuild() {
+ runVersionsWithCheckTest(versionWithNullComponents);
+ }
+
+ @Test
+ public void testVersionParser() throws SemanticVersionParseException {
+ final List<ISemanticVersion> versions = new ArrayList<ISemanticVersion>() {
+ private static final long serialVersionUID = -1726840289543320508L;
+ {
+ add(new SemanticVersion(4, 5, 9));
+ add(new SemanticVersion(3, 6, 2, "rc.2.deadbeef", null));
+ add(new SemanticVersion(10, 0, 8, null, "build.667"));
+ add(new SemanticVersion(0, 5, 10, "rc.10.a4b56", "build.b39de2"));
+ }};
+
+ for(ISemanticVersion version : versions) {
+ Assert.assertEquals(
+ String.format("Failed to parse version [%s]", version),
+ SemanticVersion.parseVersion(version.toString()),
+ version);
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNegativeMajorVersionConstruction() {
+ @SuppressWarnings("unused")
+ final ISemanticVersion sv = new SemanticVersion(-1, 5, 8);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNegativeMinorVersionConstruction() {
+ @SuppressWarnings("unused")
+ final ISemanticVersion sv = new SemanticVersion(1, -5, 8);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNegativePatchVersionConstruction() {
+ @SuppressWarnings("unused")
+ final ISemanticVersion sv = new SemanticVersion(1, 5, -8);
+ }
+
+ private void runVersionsWithCheckTest(
+ final List<IVersionsWithChecker> vwcCollection) {
+ for(IVersionsWithChecker vwc : vwcCollection) {
+ System.err.printf(
+ "Version [%s] and [%s]...%s",
+ vwc.getLeftVersion(),
+ vwc.getRightVersion(),
+ System.lineSeparator());
+
+ final ImmutablePair<Integer, SemanticVersionComponent> comparison =
+ SemanticVersionComparator.compare(
+ vwc.getLeftVersion(),
+ vwc.getRightVersion());
+
+ Assert.assertTrue(
+ String.format(
+ "Semantic versions [%s] and [%s] failed check.",
+ vwc.getLeftVersion(), vwc.getRightVersion()),
+ vwc.forwardCheck(comparison.getLeft()));
+ Assert.assertTrue(
+ String.format(
+ "Semantic versions [%s] and [%s] failed expected component change:" +
+ "got [%s], expected [%s]",
+ vwc.getLeftVersion(),
+ vwc.getRightVersion(),
+ comparison.getRight(),
+ vwc.getChangedComponent()),
+ comparison.getRight() == vwc.getChangedComponent());
+ }
+ }
+}
diff --git a/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionTests.java b/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionTests.java
new file mode 100644
index 0000000..1866fc3
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/negotiation/SemanticVersionTests.java
@@ -0,0 +1,37 @@
+package com.capitati.omtc.core.negotiation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class SemanticVersionTests {
+ private static final Collection<ISemanticVersion> versions =
+ new ArrayList<ISemanticVersion>() {
+ private static final long serialVersionUID = 1L;
+ {
+ add(new SemanticVersion(1, 0, 0, "alpha", null));
+ add(new SemanticVersion(1, 0, 0, "alpha.1", null));
+ add(new SemanticVersion(1, 0, 0, "beta.2", null));
+ add(new SemanticVersion(1, 0, 0, "beta.11", null));
+ add(new SemanticVersion(1, 0, 0, "rc.1", null));
+ add(new SemanticVersion(1, 0, 0, "rc.1", "build.1"));
+ add(new SemanticVersion(1, 0, 0));
+ add(new SemanticVersion(1, 0, 0, null, "0.3.7"));
+ add(new SemanticVersion(1, 3, 7, null, "build"));
+ add(new SemanticVersion(1, 3, 7, null, "build.2.b8f12d7"));
+ add(new SemanticVersion(1, 3, 7, null, "build.11.e0f985a"));
+ }};
+
+ @Test
+ public void testSemanticVersionParsing()
+ throws SemanticVersionParseException {
+ for(ISemanticVersion target : versions) {
+ final ISemanticVersion version =
+ SemanticVersion.parseVersion(target.toString());
+ Assert.assertEquals(target, version);
+ }
+ }
+}
diff --git a/src/test/java/com/capitati/omtc/core/session/PrimaryResource.java b/src/test/java/com/capitati/omtc/core/session/PrimaryResource.java
new file mode 100644
index 0000000..dedf86b
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/session/PrimaryResource.java
@@ -0,0 +1,75 @@
+package com.capitati.omtc.core.session;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.UUID;
+
+import com.capitati.omtc.core.resources.IPrimaryResource;
+
+public class PrimaryResource implements IPrimaryResource {
+ final UUID resourceId;
+ final URI resourceUri;
+ final Date resourceBirthDate;
+
+ public PrimaryResource(
+ final UUID resourceId,
+ final URI resourceUri,
+ final Date resourceBirthDate) {
+ super();
+ this.resourceId = resourceId;
+ this.resourceUri = resourceUri;
+ this.resourceBirthDate = resourceBirthDate;
+ }
+
+ public UUID getIdentifier() {
+ return resourceId;
+ }
+
+ public URI getURI() {
+ return resourceUri;
+ }
+
+ public Date getBirthDate() {
+ return resourceBirthDate;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((resourceBirthDate == null) ? 0 : resourceBirthDate.hashCode());
+ result = prime * result
+ + ((resourceId == null) ? 0 : resourceId.hashCode());
+ result = prime * result
+ + ((resourceUri == null) ? 0 : resourceUri.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj)
+ return true;
+ if(obj == null)
+ return false;
+ if(getClass() != obj.getClass())
+ return false;
+ PrimaryResource other = (PrimaryResource) obj;
+ if(resourceBirthDate == null) {
+ if(other.resourceBirthDate != null)
+ return false;
+ } else if(!resourceBirthDate.equals(other.resourceBirthDate))
+ return false;
+ if(resourceId == null) {
+ if(other.resourceId != null)
+ return false;
+ } else if(!resourceId.equals(other.resourceId))
+ return false;
+ if(resourceUri == null) {
+ if(other.resourceUri != null)
+ return false;
+ } else if(!resourceUri.equals(other.resourceUri))
+ return false;
+ return true;
+ }
+}
diff --git a/src/test/java/com/capitati/omtc/core/session/ResourceUploadDelegate.java b/src/test/java/com/capitati/omtc/core/session/ResourceUploadDelegate.java
new file mode 100644
index 0000000..208122f
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/session/ResourceUploadDelegate.java
@@ -0,0 +1,79 @@
+package com.capitati.omtc.core.session;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+import com.capitati.omtc.core.resources.IResource;
+import com.capitati.omtc.core.resources.IResourceReader;
+import com.capitati.omtc.core.resources.IResourceWriter;
+
+public class ResourceUploadDelegate implements IResourceTransferDelegate {
+ private final IResource resource;
+ private final String source;
+ private byte[] destination;
+
+ public ResourceUploadDelegate(
+ final String theSource,
+ final UUID theResourceId,
+ final URI theResourceUri,
+ final Date theResourceBirthDate) {
+ source = theSource;
+ resource = new PrimaryResource(
+ theResourceId, theResourceUri, theResourceBirthDate);
+ }
+
+ public IResourceReader getResourceReader(final ISession theInvokingSession)
+ throws Exception {
+ return new IResourceReader() {
+ private final byte[] readerSource = source.getBytes();
+ private int noBytesRead = 0;
+
+ public int read(final byte[] buffer) throws IOException {
+ if(noBytesRead >= readerSource.length) {
+ return -1;
+ }
+
+ int bytesRead = 0;
+ for(int idx = 0;
+ (idx < buffer.length) && ((noBytesRead + bytesRead) < readerSource.length);
+ idx++) {
+ buffer[idx] = readerSource[noBytesRead + idx];
+ bytesRead += 1;
+ }
+
+ noBytesRead += bytesRead;
+
+ return bytesRead;
+ }
+
+ public void close() throws IOException {
+ }
+ };
+ }
+
+ public IResourceWriter getResourceWriter(final ISession theInvokingSession)
+ throws Exception {
+ return new IResourceWriter() {
+ public void write(byte[] chunk, int chunkLength) throws IOException {
+ destination = ArrayUtils.addAll(
+ destination,
+ ArrayUtils.subarray(chunk, 0, chunkLength));
+ }
+
+ public void close() throws IOException {
+ }
+ };
+ }
+
+ public IResource getResource(final ISession theInvokingSession) {
+ return resource;
+ }
+
+ public byte[] getDestination() {
+ return destination;
+ }
+}
diff --git a/src/test/java/com/capitati/omtc/core/session/SessionTestException.java b/src/test/java/com/capitati/omtc/core/session/SessionTestException.java
new file mode 100644
index 0000000..372a8ef
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/session/SessionTestException.java
@@ -0,0 +1,7 @@
+package com.capitati.omtc.core.session;
+
+import java.io.IOException;
+
+public class SessionTestException extends IOException {
+ private static final long serialVersionUID = 7413491732377268653L;
+}
diff --git a/src/test/java/com/capitati/omtc/core/session/SessionTests.java b/src/test/java/com/capitati/omtc/core/session/SessionTests.java
new file mode 100644
index 0000000..986a696
--- /dev/null
+++ b/src/test/java/com/capitati/omtc/core/session/SessionTests.java
@@ -0,0 +1,203 @@
+package com.capitati.omtc.core.session;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.capitati.omtc.core.notification.IResourceUploadObserver;
+import com.capitati.omtc.core.resources.IResource;
+import com.capitati.omtc.core.resources.IResourceReader;
+import com.capitati.omtc.core.resources.IResourceWriter;
+import com.google.common.base.Predicate;
+
+public class SessionTests {
+ class TestSession extends Session {
+ protected TestSession(
+ final UUID theIdentifier,
+ final AbstractExecutorService theDelegationExecutorService,
+ final int bufferSize) {
+ super(theIdentifier, theDelegationExecutorService, bufferSize);
+ }
+
+ public Set<IResource> retrieveResources(final Predicate<IResource> theFilter)
+ throws Exception {
+ return null;
+ }
+
+ public void removeResource(final IResource resource) throws Exception {
+ }
+ }
+
+ private static final String MESSAGE =
+ "Whose was it? His who is gone. " +
+ "Who shall have it? He who will come. " +
+ "Where was the sun? Over the oak. " +
+ "Where was the shadow? Under the elm. " +
+ "How was it stepped? North by ten and by ten, east by five and by five, " +
+ "south by two and by two, west by one and by one, and so under. " +
+ "What shall we give for it? All that is ours. " +
+ "Why should we give it? For the sake of the trust.";
+
+ private final UUID resourceId = UUID.randomUUID();
+ private final Date resourceBirthDate = new Date();
+
+ private URI resourceUri;
+ private Mockery mockery;
+ private AbstractExecutorService executor;
+ private Session session;
+
+ @Before
+ public void setUp() throws URISyntaxException {
+ mockery = new JUnit4Mockery();
+ resourceUri = new URI("test://some_resource_or_other");
+ executor = new ThreadPoolExecutor(
+ 1,
+ 1,
+ 0,
+ TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
+ session = new TestSession(UUID.randomUUID(), executor, MESSAGE.length() / 4);
+ }
+
+ @After
+ public void tearDown() {
+ executor.shutdown();
+ }
+
+ @Test
+ public void testSuccessfulUpload() throws Exception {
+ final IResourceTransferDelegate delegate = new ResourceUploadDelegate(
+ MESSAGE,
+ resourceId,
+ resourceUri,
+ resourceBirthDate);
+ final IResourceUploadObserver observer =
+ mockery.mock(IResourceUploadObserver.class, "successUploadObserver");
+ final IResource targetResource = delegate.getResource(session);
+
+ mockery.checking(new Expectations() {{
+ oneOf(observer).onSuccess(
+ with(equal(session)),
+ with(equal(targetResource)));
+ }});
+
+ final Future<IResource> futureResource = session.uploadResource(delegate, observer);
+ final IResource resource = futureResource.get();
+
+ Assert.assertSame("Wrong resource", targetResource, resource);
+ }
+
+ @Test(expected = SessionTestException.class)
+ public void testReaderReadFailureOnUpload() throws Throwable {
+ final Exception targetException = new SessionTestException();
+ final IResourceReader resourceReader =
+ mockery.mock(IResourceReader.class, "resourceReader");
+ final IResourceWriter resourceWriter =
+ mockery.mock(IResourceWriter.class, "resourceWriter");
+ final IResourceTransferDelegate delegate =
+ mockery.mock(IResourceTransferDelegate.class, "badUploadDelegate");
+ final IResourceUploadObserver observer =
+ mockery.mock(IResourceUploadObserver.class, "badUploadObserver");
+ final IResource resource =
+ mockery.mock(IResource.class, "badResource");
+
+ mockery.checking(new Expectations() {{
+ allowing(delegate).getResource(with(equal(session)));
+ will(returnValue(resource));
+
+ oneOf(resourceReader).read(with(any(byte[].class)));
+ will(throwException(targetException));
+
+ oneOf(resourceReader).close();
+
+ oneOf(resourceWriter).close();
+
+ oneOf(delegate).getResourceReader(with(equal(session)));
+ will(returnValue(resourceReader));
+
+ oneOf(delegate).getResourceWriter(with(equal(session)));
+ will(returnValue(resourceWriter));
+
+ oneOf(observer).onError(
+ with(equal(session)),
+ with(equal(resource)),
+ with(equal(targetException)));
+ }});
+
+ final Future<IResource> futureResource =
+ session.uploadResource(delegate, observer);
+
+ try {
+ @SuppressWarnings("unused")
+ final IResource future = futureResource.get();
+ } catch(final ExecutionException ex) {
+ throw ex.getCause();
+ }
+ }
+
+ @Test(expected = SessionTestException.class)
+ public void testWriterWriteFailureOnUpload() throws Throwable {
+ final Exception targetException = new SessionTestException();
+ final IResourceReader resourceReader =
+ mockery.mock(IResourceReader.class, "resourceReader");
+ final IResourceWriter resourceWriter =
+ mockery.mock(IResourceWriter.class, "resourceWriter");
+ final IResourceTransferDelegate delegate =
+ mockery.mock(IResourceTransferDelegate.class, "badUploadDelegate");
+ final IResourceUploadObserver observer =
+ mockery.mock(IResourceUploadObserver.class, "badUploadObserver");
+ final IResource resource =
+ mockery.mock(IResource.class, "badResource");
+
+ mockery.checking(new Expectations() {{
+ allowing(delegate).getResource(with(equal(session)));
+ will(returnValue(resource));
+
+ oneOf(resourceReader).read(with(any(byte[].class)));
+ will(returnValue(7));
+
+ oneOf(resourceReader).close();
+
+ oneOf(resourceWriter).write(with(any(byte[].class)), with(any(int.class)));
+ will(throwException(targetException));
+
+ oneOf(resourceWriter).close();
+
+ oneOf(delegate).getResourceReader(with(equal(session)));
+ will(returnValue(resourceReader));
+
+ oneOf(delegate).getResourceWriter(with(equal(session)));
+ will(returnValue(resourceWriter));
+
+ oneOf(observer).onError(
+ with(equal(session)),
+ with(equal(resource)),
+ with(equal(targetException)));
+ }});
+
+ final Future<IResource> futureResource =
+ session.uploadResource(delegate, observer);
+
+ try {
+ @SuppressWarnings("unused")
+ final IResource future = futureResource.get();
+ } catch(final ExecutionException ex) {
+ throw ex.getCause();
+ }
+ }
+}