Use Java controller classes
diff --git a/src/main/java/org/template/recommendation/Algorithm.java b/src/main/java/org/template/recommendation/Algorithm.java
index 3f5d1ab..1931686 100644
--- a/src/main/java/org/template/recommendation/Algorithm.java
+++ b/src/main/java/org/template/recommendation/Algorithm.java
@@ -1,10 +1,10 @@
 package org.template.recommendation;
 
 import com.google.common.collect.Sets;
-import io.prediction.controller.P2LAlgorithm;
+import io.prediction.controller.java.P2LJavaAlgorithm;
 import io.prediction.data.storage.Event;
-import io.prediction.data.store.JavaOptionHelper;
-import io.prediction.data.store.LJavaEventStore;
+import io.prediction.data.store.java.OptionHelper;
+import io.prediction.data.store.java.LJavaEventStore;
 import org.apache.spark.SparkContext;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaRDD;
@@ -21,7 +21,6 @@
 import scala.Option;
 import scala.Tuple2;
 import scala.concurrent.duration.Duration;
-import scala.reflect.ClassTag$;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -31,13 +30,12 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
-public class Algorithm extends P2LAlgorithm<PreparedData, Model, Query, PredictedResult> {
+public class Algorithm extends P2LJavaAlgorithm<PreparedData, Model, Query, PredictedResult> {
 
     private static final Logger logger = LoggerFactory.getLogger(Algorithm.class);
     private final AlgorithmParams ap;
 
     public Algorithm(AlgorithmParams ap) {
-        super(ClassTag$.MODULE$.<Model>apply(Model.class), ClassTag$.MODULE$.<Query>apply(Query.class));
         this.ap = ap;
     }
 
@@ -200,13 +198,13 @@
                     ap.getAppName(),
                     "user",
                     query.getUserEntityId(),
-                    JavaOptionHelper.<String>none(),
-                    JavaOptionHelper.some(ap.getSimilarItemEvents()),
-                    JavaOptionHelper.some(JavaOptionHelper.some("item")),
-                    JavaOptionHelper.<Option<String>>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.some(10),
+                    OptionHelper.<String>none(),
+                    OptionHelper.some(ap.getSimilarItemEvents()),
+                    OptionHelper.some(OptionHelper.some("item")),
+                    OptionHelper.<Option<String>>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.some(10),
                     true,
                     Duration.apply(10, TimeUnit.SECONDS));
 
@@ -341,13 +339,13 @@
                     ap.getAppName(),
                     "constraint",
                     "unavailableItems",
-                    JavaOptionHelper.<String>none(),
-                    JavaOptionHelper.some(Collections.singletonList("$set")),
-                    JavaOptionHelper.<Option<String>>none(),
-                    JavaOptionHelper.<Option<String>>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.some(1),
+                    OptionHelper.<String>none(),
+                    OptionHelper.some(Collections.singletonList("$set")),
+                    OptionHelper.<Option<String>>none(),
+                    OptionHelper.<Option<String>>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.some(1),
                     true,
                     Duration.apply(10, TimeUnit.SECONDS));
 
@@ -373,13 +371,13 @@
                     ap.getAppName(),
                     "user",
                     userEntityId,
-                    JavaOptionHelper.<String>none(),
-                    JavaOptionHelper.some(ap.getSeenItemEvents()),
-                    JavaOptionHelper.some(JavaOptionHelper.some("item")),
-                    JavaOptionHelper.<Option<String>>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.<DateTime>none(),
-                    JavaOptionHelper.<Integer>none(),
+                    OptionHelper.<String>none(),
+                    OptionHelper.some(ap.getSeenItemEvents()),
+                    OptionHelper.some(OptionHelper.some("item")),
+                    OptionHelper.<Option<String>>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.<DateTime>none(),
+                    OptionHelper.<Integer>none(),
                     true,
                     Duration.apply(10, TimeUnit.SECONDS));
 
diff --git a/src/main/java/org/template/recommendation/DataSource.java b/src/main/java/org/template/recommendation/DataSource.java
index 1b400fb..30c819c 100644
--- a/src/main/java/org/template/recommendation/DataSource.java
+++ b/src/main/java/org/template/recommendation/DataSource.java
@@ -3,11 +3,11 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import io.prediction.controller.EmptyParams;
-import io.prediction.controller.PDataSource;
+import io.prediction.controller.java.PJavaDataSource;
 import io.prediction.data.storage.Event;
 import io.prediction.data.storage.PropertyMap;
-import io.prediction.data.store.JavaOptionHelper;
-import io.prediction.data.store.PJavaEventStore;
+import io.prediction.data.store.java.OptionHelper;
+import io.prediction.data.store.java.PJavaEventStore;
 import org.apache.spark.SparkContext;
 import org.apache.spark.api.java.JavaPairRDD;
 import org.apache.spark.api.java.JavaRDD;
@@ -24,7 +24,7 @@
 import java.util.Map;
 import java.util.Set;
 
-public class DataSource extends PDataSource<TrainingData, EmptyParams, Query, Object> {
+public class DataSource extends PJavaDataSource<TrainingData, EmptyParams, Query, Object> {
 
     private final DataSourceParams dsp;
 
@@ -37,10 +37,10 @@
         JavaPairRDD<String,User> usersRDD = PJavaEventStore.aggregateProperties(
                 dsp.getAppName(),
                 "user",
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<List<String>>none(),
+                OptionHelper.<String>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<List<String>>none(),
                 sc)
                 .mapToPair(new PairFunction<Tuple2<String, PropertyMap>, String, User>() {
                     @Override
@@ -60,10 +60,10 @@
         JavaPairRDD<String, Item> itemsRDD = PJavaEventStore.aggregateProperties(
                 dsp.getAppName(),
                 "item",
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<List<String>>none(),
+                OptionHelper.<String>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<List<String>>none(),
                 sc)
                 .mapToPair(new PairFunction<Tuple2<String, PropertyMap>, String, Item>() {
                     @Override
@@ -77,14 +77,14 @@
 
         JavaRDD<UserItemEvent> viewEventsRDD = PJavaEventStore.find(
                 dsp.getAppName(),
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.some("user"),
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.some(Collections.singletonList("view")),
-                JavaOptionHelper.<Option<String>>none(),
-                JavaOptionHelper.<Option<String>>none(),
+                OptionHelper.<String>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.some("user"),
+                OptionHelper.<String>none(),
+                OptionHelper.some(Collections.singletonList("view")),
+                OptionHelper.<Option<String>>none(),
+                OptionHelper.<Option<String>>none(),
                 sc)
                 .map(new Function<Event, UserItemEvent>() {
                     @Override
@@ -95,14 +95,14 @@
 
         JavaRDD<UserItemEvent> buyEventsRDD = PJavaEventStore.find(
                 dsp.getAppName(),
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.<DateTime>none(),
-                JavaOptionHelper.some("user"),
-                JavaOptionHelper.<String>none(),
-                JavaOptionHelper.some(Collections.singletonList("buy")),
-                JavaOptionHelper.<Option<String>>none(),
-                JavaOptionHelper.<Option<String>>none(),
+                OptionHelper.<String>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.<DateTime>none(),
+                OptionHelper.some("user"),
+                OptionHelper.<String>none(),
+                OptionHelper.some(Collections.singletonList("buy")),
+                OptionHelper.<Option<String>>none(),
+                OptionHelper.<Option<String>>none(),
                 sc)
                 .map(new Function<Event, UserItemEvent>() {
                     @Override
diff --git a/src/main/java/org/template/recommendation/Model.java b/src/main/java/org/template/recommendation/Model.java
index d9bf1dc..bb8c541 100644
--- a/src/main/java/org/template/recommendation/Model.java
+++ b/src/main/java/org/template/recommendation/Model.java
@@ -69,12 +69,12 @@
 
     public static Model load(String id, Params params, SparkContext sc) {
         JavaSparkContext jsc = JavaSparkContext.fromSparkContext(sc);
-        JavaPairRDD<Integer, double[]> userFeatures = JavaPairRDD.fromJavaRDD(jsc.<Tuple2<Integer, double[]>>objectFile("/tmp/" + id + "/userFeatures"));
-        JavaPairRDD<Integer, Tuple2<String, double[]>> indexItemFeatures = JavaPairRDD.fromJavaRDD(jsc.<Tuple2<Integer, Tuple2<String, double[]>>>objectFile("/tmp/" + id + "/indexItemFeatures"));
-        JavaPairRDD<String, Integer> userIndex = JavaPairRDD.fromJavaRDD(jsc.<Tuple2<String, Integer>>objectFile("/tmp/" + id + "/userIndex"));
-        JavaPairRDD<String, Integer> itemIndex = JavaPairRDD.fromJavaRDD(jsc.<Tuple2<String, Integer>>objectFile("/tmp/" + id + "/itemIndex"));
+        JavaPairRDD<Integer, double[]> userFeatures = JavaPairRDD.<Integer, double[]>fromJavaRDD(jsc.<Tuple2<Integer, double[]>>objectFile("/tmp/" + id + "/userFeatures"));
+        JavaPairRDD<Integer, Tuple2<String, double[]>> indexItemFeatures = JavaPairRDD.<Integer, Tuple2<String, double[]>>fromJavaRDD(jsc.<Tuple2<Integer, Tuple2<String, double[]>>>objectFile("/tmp/" + id + "/indexItemFeatures"));
+        JavaPairRDD<String, Integer> userIndex = JavaPairRDD.<String, Integer>fromJavaRDD(jsc.<Tuple2<String, Integer>>objectFile("/tmp/" + id + "/userIndex"));
+        JavaPairRDD<String, Integer> itemIndex = JavaPairRDD.<String, Integer>fromJavaRDD(jsc.<Tuple2<String, Integer>>objectFile("/tmp/" + id + "/itemIndex"));
         JavaRDD<ItemScore> itemPopularityScore = jsc.objectFile("/tmp/" + id + "/itemPopularityScore");
-        JavaPairRDD<String, Item> items = JavaPairRDD.fromJavaRDD(jsc.<Tuple2<String, Item>>objectFile("/tmp/" + id + "/items"));
+        JavaPairRDD<String, Item> items = JavaPairRDD.<String, Item>fromJavaRDD(jsc.<Tuple2<String, Item>>objectFile("/tmp/" + id + "/items"));
 
         logger.info("loaded model");
         return new Model(userFeatures, indexItemFeatures, userIndex, itemIndex, itemPopularityScore, items);
diff --git a/src/main/java/org/template/recommendation/Preparator.java b/src/main/java/org/template/recommendation/Preparator.java
index 4029185..003855b 100644
--- a/src/main/java/org/template/recommendation/Preparator.java
+++ b/src/main/java/org/template/recommendation/Preparator.java
@@ -1,9 +1,9 @@
 package org.template.recommendation;
 
-import io.prediction.controller.PPreparator;
+import io.prediction.controller.java.PJavaPreparator;
 import org.apache.spark.SparkContext;
 
-public class Preparator extends PPreparator<TrainingData, PreparedData> {
+public class Preparator extends PJavaPreparator<TrainingData, PreparedData> {
 
     @Override
     public PreparedData prepare(SparkContext sc, TrainingData trainingData) {
diff --git a/src/main/java/org/template/recommendation/Serving.java b/src/main/java/org/template/recommendation/Serving.java
index 72a4c44..6a122da 100644
--- a/src/main/java/org/template/recommendation/Serving.java
+++ b/src/main/java/org/template/recommendation/Serving.java
@@ -1,9 +1,9 @@
 package org.template.recommendation;
 
-import io.prediction.controller.LServing;
+import io.prediction.controller.java.LJavaServing;
 import scala.collection.Seq;
 
-public class Serving extends LServing<Query, PredictedResult> {
+public class Serving extends LJavaServing<Query, PredictedResult> {
 
     @Override
     public PredictedResult serve(Query query, Seq<PredictedResult> predictions) {