diff options
Diffstat (limited to 'sca-cpp')
27 files changed, 983 insertions, 77 deletions
diff --git a/sca-cpp/trunk/etc/git-exclude b/sca-cpp/trunk/etc/git-exclude index c08230fe5a..023a2c6fc8 100644 --- a/sca-cpp/trunk/etc/git-exclude +++ b/sca-cpp/trunk/etc/git-exclude @@ -61,6 +61,7 @@ doxygen *.pyc *.class *.stamp +*.jar # Specific ignores kernel-test diff --git a/sca-cpp/trunk/modules/java/Makefile.am b/sca-cpp/trunk/modules/java/Makefile.am index f103a232fa..5ef145c6e3 100644 --- a/sca-cpp/trunk/modules/java/Makefile.am +++ b/sca-cpp/trunk/modules/java/Makefile.am @@ -38,6 +38,15 @@ java_shell_LDFLAGS = -L${JAVA_LIB} -R${JAVA_LIB} -R${JAVA_LIB}/server -ljava noinst_JAVA = org/apache/tuscany/*.java test/*.java +jarfile = libmod-tuscany-java-${PACKAGE_VERSION}.jar +jardir = ${libdir} +jar_DATA = ${jarfile} + +${jarfile}: ${noinst_JAVA} + ${JAR} cf $@ org/apache/tuscany/*.class + +CLEANFILES = ${jarfile} org/apache/tuscany/*.class test/*.class + client_test_SOURCES = client-test.cpp client_test_LDFLAGS = -lxml2 -lcurl -lmozjs diff --git a/sca-cpp/trunk/modules/java/driver.hpp b/sca-cpp/trunk/modules/java/driver.hpp index 9bc55915c5..5f117b8e68 100644 --- a/sca-cpp/trunk/modules/java/driver.hpp +++ b/sca-cpp/trunk/modules/java/driver.hpp @@ -48,7 +48,7 @@ const value evalDriverLoop(const JavaRuntime& jr, const JavaClass jc, istream& i const bool evalDriverRun(const char* name, istream& in, ostream& out) { scheme::setupDisplay(out); - const failable<JavaClass> jc = readClass(javaRuntime, name); + const failable<JavaClass> jc = readClass(javaRuntime, ".", name); if (!hasContent(jc)) return true; evalDriverLoop(javaRuntime, content(jc), in, out); diff --git a/sca-cpp/trunk/modules/java/eval.hpp b/sca-cpp/trunk/modules/java/eval.hpp index 7641c5de79..9dbb50abb5 100644 --- a/sca-cpp/trunk/modules/java/eval.hpp +++ b/sca-cpp/trunk/modules/java/eval.hpp @@ -52,31 +52,45 @@ public: JavaVMInitArgs args; args.version = JNI_VERSION_1_6; args.ignoreUnrecognized = JNI_FALSE; - JavaVMOption options[1]; - options[0].optionString = const_cast<char*>("-Djava.class.path=."); + JavaVMOption options[3]; args.options = options; - args.nOptions = 1; + args.nOptions = 0; + + // Configure classpath + const char* envcp = getenv("CLASSPATH"); + const string cp = string("-Djava.class.path=") + (envcp == NULL? "." : envcp); + options[args.nOptions++].optionString = const_cast<char*>(c_str(cp)); + +#ifdef WANT_MAINTAINER_MODE + // Enable assertions + options[args.nOptions++].optionString = const_cast<char*>("-ea"); +#endif + + // Configure Java debugging + const char* jpdaopts = getenv("JPDA_OPTS"); + if (jpdaopts != NULL) { + options[args.nOptions++].optionString = const_cast<char*>(jpdaopts); + } else { + const char* jpdaaddr = getenv("JPDA_ADDRESS"); + if (jpdaaddr != NULL) { + const string jpda = string("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=") + jpdaaddr; + options[args.nOptions++].optionString = const_cast<char*>(c_str(jpda)); + } + } + + // Create the JVM JNI_CreateJavaVM(&jvm, (void**)&env, &args); - // Register our native invocation handler function - invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); - JNINativeMethod nm; - nm.name = const_cast<char*>("invoke"); - nm.signature = const_cast<char*>("(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); - nm.fnPtr = (void*)nativeInvoke; - env->RegisterNatives(invokerClass, &nm, 1); - } else { - // Just hook to existing JVM + // Just point to existing JVM jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); } // Capture JVM standard IO setupIO(); - // Lookup the classes and methods we need + // Lookup System classes and methods classClass = env->FindClass("java/lang/Class"); methodClass = env->FindClass("java/lang/reflect/Method"); objectClass = env->FindClass("java/lang/Object"); @@ -84,6 +98,8 @@ public: booleanClass = env->FindClass("java/lang/Boolean"); stringClass = env->FindClass("java/lang/String"); objectArrayClass = env->FindClass("[Ljava/lang/Object;"); + iterableClass = env->FindClass("Ljava/lang/Iterable;"); + classForName = env->GetStaticMethodID(classClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); doubleValueOf = env->GetStaticMethodID(doubleClass, "valueOf", "(D)Ljava/lang/Double;"); doubleValue = env->GetMethodID(doubleClass, "doubleValue", "()D"); booleanValueOf = env->GetStaticMethodID(booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;"); @@ -91,8 +107,27 @@ public: declaredMethods = env->GetMethodID(classClass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;"); methodName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;"); parameterTypes = env->GetMethodID(methodClass, "getParameterTypes", "()[Ljava/lang/Class;"); + + // Lookup Tuscany classes and methods + loaderClass = env->FindClass("org/apache/tuscany/ClassLoader"); + loaderValueOf = env->GetStaticMethodID(loaderClass, "valueOf", "(Ljava/lang/String;)Ljava/lang/ClassLoader;"); + loaderForName = env->GetStaticMethodID(loaderClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); invokerValueOf = env->GetStaticMethodID(invokerClass, "valueOf", "(Ljava/lang/Class;J)Ljava/lang/Object;"); invokerLambda = env->GetFieldID(invokerClass, "lambda", "J"); + iterableUtilClass = env->FindClass("org/apache/tuscany/IterableUtil"); + iterableValueOf = env->GetStaticMethodID(iterableUtilClass, "list", "([Ljava/lang/Object;)Ljava/lang/Iterable;"); + iterableIsNil = env->GetStaticMethodID(iterableUtilClass, "isNil", "(Ljava/lang/Object;)Z"); + iterableCar = env->GetStaticMethodID(iterableUtilClass, "car", "(Ljava/lang/Object;)Ljava/lang/Object;"); + iterableCdr = env->GetStaticMethodID(iterableUtilClass, "cdr", "(Ljava/lang/Object;)Ljava/lang/Iterable;"); + + // Register our native invocation handler function + JNINativeMethod nm; + nm.name = const_cast<char*>("invoke"); + nm.signature = const_cast<char*>("(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); + nm.fnPtr = (void*)nativeInvoke; + env->RegisterNatives(invokerClass, &nm, 1); + } JavaVM* jvm; @@ -105,6 +140,7 @@ public: jclass booleanClass; jclass stringClass; jclass objectArrayClass; + jclass iterableClass; jmethodID doubleValueOf; jmethodID doubleValue; jmethodID booleanValueOf; @@ -112,10 +148,18 @@ public: jmethodID declaredMethods; jmethodID methodName; jmethodID parameterTypes; - + jmethodID classForName; + jclass loaderClass; + jmethodID loaderValueOf; + jmethodID loaderForName; jclass invokerClass; jmethodID invokerValueOf; jfieldID invokerLambda; + jclass iterableUtilClass; + jmethodID iterableValueOf; + jmethodID iterableCar; + jmethodID iterableCdr; + jmethodID iterableIsNil; } javaRuntime; @@ -137,6 +181,7 @@ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const va const value jobjectToValue(const JavaRuntime& jr, const jobject o); const jobjectArray valuesToJarray(const JavaRuntime& jr, const list<value>& v); const list<value> jarrayToValues(const JavaRuntime& jr, const jobjectArray o); +const list<value> jiterableToValues(const JavaRuntime& jr, const jobject o); /** * Convert a Java class name to a JNI class name. @@ -204,9 +249,11 @@ jobject JNICALL nativeInvoke(JNIEnv* env, jobject self, unused jobject proxy, jo // Build the expression to evaluate const list<value> expr = cons<value>(func, jarrayToValues(jl.jr, args)); + debug(expr, "java::nativeInvoke::expr"); // Invoke the lambda function value result = jl(expr); + debug(result, "java::nativeInvoke::result"); // Convert result to a jobject return valueToJobject(jl.jr, value(), result); @@ -238,12 +285,19 @@ const jobjectArray valuesToJarray(const JavaRuntime& jr, const list<value>& v) { } /** + * Convert a Java jobjectArray to a Java iterable. + */ +const jobject jarrayToJiterable(const JavaRuntime& jr, jobjectArray a) { + return jr.env->CallStaticObjectMethod(jr.iterableClass, jr.iterableValueOf, a); +} + +/** * Convert a value to a Java jobject. */ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const value& v) { switch (type(v)) { case value::List: - return valuesToJarray(jr, v); + return jarrayToJiterable(jr, valuesToJarray(jr, v)); case value::Lambda: return mkJavaLambda(jr, jtype, v); case value::Symbol: @@ -253,7 +307,7 @@ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const va case value::Number: return jr.env->CallStaticObjectMethod(jr.doubleClass, jr.doubleValueOf, (double)v); case value::Bool: - return jr.env->CallStaticObjectMethod(jr.booleanClass, jr.booleanValueOf, (double)v); + return jr.env->CallStaticObjectMethod(jr.booleanClass, jr.booleanValueOf, (bool)v); default: return NULL; } @@ -292,6 +346,23 @@ const list<value> jarrayToValues(const JavaRuntime& jr, jobjectArray o) { } /** + * Convert a Java Iterable to a list of values. + */ +const list<value> jiterableToValuesHelper(const JavaRuntime& jr, jobject o) { + if ((bool)jr.env->CallStaticBooleanMethod(jr.iterableUtilClass, jr.iterableIsNil, o)) + return list<value>(); + jobject car = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCar, o); + jobject cdr = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCdr, o); + return cons(jobjectToValue(jr, car), jiterableToValuesHelper(jr, cdr)); +} + +const list<value> jiterableToValues(const JavaRuntime& jr, jobject o) { + if (o == NULL) + return list<value>(); + return jiterableToValuesHelper(jr, o); +} + +/** * Lambda function used to represent a Java callable object. */ struct javaCallable { @@ -330,8 +401,8 @@ const value jobjectToValue(const JavaRuntime& jr, const jobject o) { return value((bool)jr.env->CallBooleanMethod(o, jr.booleanValue)); if (jr.env->IsSameObject(clazz, jr.doubleClass)) return value((double)jr.env->CallDoubleMethod(o, jr.doubleValue)); - if ((jr.env->IsSameObject(clazz, jr.objectArrayClass))) - return jarrayToValues(jr, (jobjectArray)o); + if ((jr.env->IsAssignableFrom(clazz, jr.iterableClass))) + return jiterableToValues(jr, o); return lambda<value(const list<value>&)>(javaCallable(jr, o)); } @@ -378,12 +449,12 @@ const list<value> methodsToValues(const JavaRuntime& jr, const jclass clazz) { */ class JavaClass { public: - JavaClass() : clazz(NULL), obj(NULL) { + JavaClass() : loader(NULL), clazz(NULL), obj(NULL) { } - - JavaClass(const jclass clazz, const jobject obj, const list<value> m) : clazz(clazz), obj(obj), m(m) { + JavaClass(const jobject loader, const jclass clazz, const jobject obj, const list<value> m) : loader(loader), clazz(clazz), obj(obj), m(m) { } + const jobject loader; const jclass clazz; const jobject obj; const list<value> m; @@ -392,24 +463,34 @@ public: /** * Read a class. */ -const failable<JavaClass> readClass(const JavaRuntime& jr, const string& name) { - const string jname = jniClassName(name); - const jclass clazz = jr.env->FindClass(c_str(jname)); +const failable<JavaClass> readClass(const JavaRuntime& jr, const string& path, const string& name) { + + // Create a class loader from the given path + const jobject jpath = jr.env->NewStringUTF(c_str(path)); + jobject loader = jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderValueOf, jpath); + + // Load the class + const jobject jname = jr.env->NewStringUTF(c_str(name)); + const jclass clazz = (jclass)jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderForName, jname, JNI_TRUE, loader); if (clazz == NULL) return mkfailure<JavaClass>(string("Couldn't load class: ") + name + " : " + lastException(jr)); + + // Create an instance const jmethodID constr = jr.env->GetMethodID(clazz, "<init>", "()V"); if (constr == NULL) return mkfailure<JavaClass>(string("Couldn't find constructor: ") + name + " : " + lastException(jr)); const jobject obj = jr.env->NewObject(clazz, constr); if (obj == NULL) return mkfailure<JavaClass>(string("Couldn't construct object: ") + name + " : " + lastException(jr)); - return JavaClass(clazz, obj, methodsToValues(jr, clazz)); + + return JavaClass(loader, clazz, obj, methodsToValues(jr, clazz)); } /** * Evaluate an expression against a Java class. */ const failable<value> evalClass(const JavaRuntime& jr, const value& expr, const JavaClass jc) { + debug(expr, "java::evalClass::expr"); // Lookup the Java function named as the expression operand const list<value> func = assoc<value>(car<value>(expr), jc.m); @@ -426,7 +507,9 @@ const failable<value> evalClass(const JavaRuntime& jr, const value& expr, const return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastException(jr)); // Convert Java result to a value - return jobjectToValue(jr, result); + const value v = jobjectToValue(jr, result); + debug(v, "java::evalClass::result"); + return v; } } diff --git a/sca-cpp/trunk/modules/java/java-conf b/sca-cpp/trunk/modules/java/java-conf index d81a14a6c1..fb02f7fe57 100755 --- a/sca-cpp/trunk/modules/java/java-conf +++ b/sca-cpp/trunk/modules/java/java-conf @@ -24,3 +24,4 @@ root=`readlink -f $1` cat >>$root/conf/httpd.conf <<EOF LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_java.so EOF + diff --git a/sca-cpp/trunk/modules/java/java-test.cpp b/sca-cpp/trunk/modules/java/java-test.cpp index 7ece2dfc68..da73602f12 100644 --- a/sca-cpp/trunk/modules/java/java-test.cpp +++ b/sca-cpp/trunk/modules/java/java-test.cpp @@ -34,7 +34,7 @@ namespace java { bool testEvalExpr() { gc_scoped_pool pool; { - const failable<JavaClass> obj = readClass(javaRuntime, "test.CalcImpl"); + const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl"); assert(hasContent(obj)); const value exp = mklist<value>("mult", 2, 3); const failable<value> r = evalClass(javaRuntime, exp, content(obj)); @@ -42,13 +42,29 @@ bool testEvalExpr() { assert(content(r) == value(6)); } { - const failable<JavaClass> obj = readClass(javaRuntime, "test.AdderImpl"); + const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl"); + assert(hasContent(obj)); + const value exp = mklist<value>("even", 2); + const failable<value> r = evalClass(javaRuntime, exp, content(obj)); + assert(hasContent(r)); + assert(content(r) == value(true)); + } + { + const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.AdderImpl"); assert(hasContent(obj)); const value exp = mklist<value>("add", 2, 3); const failable<value> r = evalClass(javaRuntime, exp, content(obj)); assert(hasContent(r)); assert(content(r) == value(5)); } + { + const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl"); + assert(hasContent(obj)); + const value exp = mklist<value>("square", mklist<value>(1, 2, 3)); + const failable<value> r = evalClass(javaRuntime, exp, content(obj)); + assert(hasContent(r)); + assert(content(r) == mklist<value>(1, 4, 9)); + } return true; } @@ -61,7 +77,7 @@ const value add(const list<value>& args) { bool testEvalLambda() { gc_scoped_pool pool; - const failable<JavaClass> obj = readClass(javaRuntime, "test.CalcImpl"); + const failable<JavaClass> obj = readClass(javaRuntime, ".", "test.CalcImpl"); assert(hasContent(obj)); const value tcel = mklist<value>("add", 3, 4, lambda<value(const list<value>&)>(add)); const failable<value> r = evalClass(javaRuntime, tcel, content(obj)); @@ -70,14 +86,38 @@ bool testEvalLambda() { return true; } +bool testClassLoader() { + gc_scoped_pool pool; + const failable<JavaClass> obj = readClass(javaRuntime, ".", "org.apache.tuscany.ClassLoader$Test"); + assert(hasContent(obj)); + const value exp = mklist<value>("testClassLoader"); + const failable<value> r = evalClass(javaRuntime, exp, content(obj)); + assert(hasContent(r)); + assert(content(r) == value(true)); + return true; +} + +bool testIterableUtil() { + gc_scoped_pool pool; + const failable<JavaClass> obj = readClass(javaRuntime, ".", "org.apache.tuscany.IterableUtil$Test"); + assert(hasContent(obj)); + const value exp = mklist<value>("testList"); + const failable<value> r = evalClass(javaRuntime, exp, content(obj)); + assert(hasContent(r)); + assert(content(r) == value(true)); + return true; +} + } } int main() { tuscany::cout << "Testing..." << tuscany::endl; - //tuscany::java::testEvalExpr(); + tuscany::java::testEvalExpr(); tuscany::java::testEvalLambda(); + tuscany::java::testClassLoader(); + tuscany::java::testIterableUtil(); tuscany::cout << "OK" << tuscany::endl; return 0; diff --git a/sca-cpp/trunk/modules/java/mod-java.hpp b/sca-cpp/trunk/modules/java/mod-java.hpp index 933550b7c3..a2235fc17f 100644 --- a/sca-cpp/trunk/modules/java/mod-java.hpp +++ b/sca-cpp/trunk/modules/java/mod-java.hpp @@ -63,9 +63,9 @@ struct applyImplementation { * Evaluate a Java component implementation and convert it to an applicable * lambda function. */ -const failable<lambda<value(const list<value>&)> > evalImplementation(unused const string& path, const value& impl, const list<value>& px) { +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) { const string cn(attributeValue("class", impl)); - const failable<java::JavaClass> jc = java::readClass(java::javaRuntime, cn); + const failable<java::JavaClass> jc = java::readClass(java::javaRuntime, path, cn); if (!hasContent(jc)) return mkfailure<lambda<value(const list<value>&)> >(reason(jc)); return lambda<value(const list<value>&)>(applyImplementation(content(jc), px)); diff --git a/sca-cpp/trunk/modules/java/org/apache/tuscany/ClassLoader.java b/sca-cpp/trunk/modules/java/org/apache/tuscany/ClassLoader.java new file mode 100644 index 0000000000..78b9ec7d90 --- /dev/null +++ b/sca-cpp/trunk/modules/java/org/apache/tuscany/ClassLoader.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany; + +import static org.apache.tuscany.ClassLoader.Test.*; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Class loader used to load SCA component implementation classes. + */ +class ClassLoader extends URLClassLoader { + + ClassLoader(final URL... urls) { + super(urls); + } + + /** + * Create a class loader for an SCA contribution path. + */ + static java.lang.ClassLoader valueOf(final String path) throws MalformedURLException { + return new ClassLoader(new File(path).toURI().toURL()); + } + + /** + * Load a class. + */ + static Class<?> forName(final String name, final boolean resolve, final java.lang.ClassLoader loader) throws ClassNotFoundException { + return Class.forName(name, resolve, loader); + } + + /** + * Test the class loader. + */ + static class Test { + Boolean testClassLoader() { + try { + final Class<?> clazz = ClassLoader.forName("test.CalcImpl", true, ClassLoader.valueOf(".")); + assert clazz != null; + } catch(final MalformedURLException e) { + throw new RuntimeException(e); + } catch(final ClassNotFoundException e) { + throw new RuntimeException(e); + } + return true; + } + } + + public static void main(final String[] args) { + System.out.println("Testing..."); + + Test.class.getClassLoader().setDefaultAssertionStatus(true); + new Test().testClassLoader(); + + System.out.println("OK"); + } + +} diff --git a/sca-cpp/trunk/modules/java/org/apache/tuscany/InvocationHandler.java b/sca-cpp/trunk/modules/java/org/apache/tuscany/InvocationHandler.java index 1c159a99d5..5707a07bc7 100644 --- a/sca-cpp/trunk/modules/java/org/apache/tuscany/InvocationHandler.java +++ b/sca-cpp/trunk/modules/java/org/apache/tuscany/InvocationHandler.java @@ -22,14 +22,21 @@ package org.apache.tuscany; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -public class InvocationHandler implements java.lang.reflect.InvocationHandler { +/** + * Proxy Invocation handler used to represent SCA component references. + */ +class InvocationHandler implements java.lang.reflect.InvocationHandler { final long lambda; InvocationHandler(final long lambda) { this.lambda = lambda; } - public static Object valueOf(final Class<?> iface, final long lambda) { + /** + * Create a proxy for an interface and the lambda function representing + * an SCA component reference. + */ + static Object valueOf(final Class<?> iface, final long lambda) { return Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, new InvocationHandler(lambda)); } diff --git a/sca-cpp/trunk/modules/java/org/apache/tuscany/IterableUtil.java b/sca-cpp/trunk/modules/java/org/apache/tuscany/IterableUtil.java new file mode 100644 index 0000000000..ef18b856db --- /dev/null +++ b/sca-cpp/trunk/modules/java/org/apache/tuscany/IterableUtil.java @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany; + +import static java.util.Arrays.*; +import static org.apache.tuscany.IterableUtil.Test.*; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * Utility functions to help work efficiently with iterable lists, inspired from Lisp. + */ +public class IterableUtil { + + /** + * Convert an array or a variable list of arguments to an iterable list. + */ + public static <T> Iterable<T> list(final Object... a) { + return new ArrayIterable<T>(a, 0); + } + + /** + * Convert an iterable list to a java.util.Collection. + */ + @SuppressWarnings("unchecked") + public static <T> Collection<T> collection(final Object l) { + final Collection<T> c = new ArrayList<T>(); + for(final Object x : (Iterable<?>)l) + c.add((T)x); + return c; + } + + /** + * Construct a new list from an element and a list. + */ + public static <T> Iterable<T> cons(final Object car, final Iterable<?> cdr) { + return new PairIterable<T>(car, cdr); + } + + /** + * Return true if a list is nil (empty). + */ + public static boolean isNil(final Object l) { + if(l instanceof BasicIterable<?>) + return ((BasicIterable<?>)l).isNil(); + if(l instanceof Collection<?>) + return ((Collection<?>)l).isEmpty(); + return !((Iterable<?>)l).iterator().hasNext(); + } + + /** + * Return the car (first element) of a list. + */ + @SuppressWarnings("unchecked") + public static <T> T car(final Object l) { + if(l instanceof BasicIterable<?>) + return ((BasicIterable<T>)l).car(); + if(l instanceof List<?>) + return (T)((List<?>)l).get(0); + return (T)((Iterable<?>)l).iterator().next(); + } + + /** + * Return the cdr (rest after the first element) of a list. + */ + @SuppressWarnings("unchecked") + public static <T> Iterable<T> cdr(final Object l) { + if(l instanceof BasicIterable<?>) + return ((BasicIterable<T>)l).cdr(); + if(l instanceof List<?>) + return new ListIterable<T>((List<?>)l, 1); + if(l instanceof Collection<?>) + return new ArrayIterable<T>(((Collection<?>)l).toArray(), 1); + return new Iterable<T>() { + @Override + public Iterator<T> iterator() { + final Iterator<T> i = ((Iterable<T>)l).iterator(); + i.next(); + return i; + } + }; + } + + /** + * Return the car of the cdr of a list. + */ + @SuppressWarnings("unchecked") + public static <T> T cadr(final Object l) { + return (T)car(cdr(l)); + } + + /** + * Return the cdr of the cdr of a list. + */ + public static <T> Iterable<T> cddr(final Object l) { + return cdr(cdr(l)); + } + + /** + * Return the car of the cdr of the cdr of a list. + */ + @SuppressWarnings("unchecked") + public static <T> T caddr(final Object l) { + return (T)car(cddr(l)); + } + + /** + * Return the first pair matching a key from a list of key value pairs. + */ + public static <T> Iterable<T> assoc(final Object k, final Object l) { + if(isNil(l)) + return list(); + if(k.equals(car(car(l)))) + return car(l); + return assoc(k, cdr(l)); + } + + /** + * Internal base implementation class for iterable and immutable lists. + */ + static abstract class BasicIterable<T> extends AbstractList<T> { + abstract T car(); + + abstract Iterable<T> cdr(); + + abstract Boolean isNil(); + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public T get(final int index) { + throw new UnsupportedOperationException(); + } + } + + /** + * Internal implementation of a list backed by an array. + */ + static class ArrayIterable<T> extends BasicIterable<T> { + final Object[] a; + final int start; + + ArrayIterable(final Object[] a, final int start) { + this.a = a; + this.start = start; + } + + @Override + Boolean isNil() { + return this.a.length - this.start == 0; + } + + @SuppressWarnings("unchecked") + @Override + T car() { + return (T)this.a[this.start]; + } + + @Override + BasicIterable<T> cdr() { + return new ArrayIterable<T>(this.a, this.start + 1); + } + + @Override + public Iterator<T> iterator() { + return new Iterator<T>() { + int i = ArrayIterable.this.start; + + @Override + public boolean hasNext() { + return this.i < ArrayIterable.this.a.length; + } + + @SuppressWarnings("unchecked") + @Override + public T next() { + return (T)ArrayIterable.this.a[this.i++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } + + /** + * Internal implementation of a list backed by a java.util.List. + */ + static class ListIterable<T> extends BasicIterable<T> { + final List<?> l; + final int start; + + ListIterable(final List<?> l, final int start) { + this.l = l; + this.start = start; + } + + @Override + Boolean isNil() { + return this.l.size() - this.start == 0; + } + + @SuppressWarnings("unchecked") + @Override + T car() { + return (T)this.l.get(this.start); + } + + @Override + BasicIterable<T> cdr() { + return new ListIterable<T>(this.l, this.start + 1); + } + + @Override + public Iterator<T> iterator() { + return new Iterator<T>() { + int i = ListIterable.this.start; + + @Override + public boolean hasNext() { + return this.i < ListIterable.this.l.size(); + } + + @SuppressWarnings("unchecked") + @Override + public T next() { + return (T)ListIterable.this.l.get(this.i++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } + + /** + * Internal implementation of a list backed by an element / iterable pair. + */ + static class PairIterable<T> extends BasicIterable<T> { + final Object car; + final Iterable<?> cdr; + + PairIterable(final Object car, final Iterable<?> cdr) { + this.car = car; + this.cdr = cdr; + } + + @Override + Boolean isNil() { + return false; + } + + @SuppressWarnings("unchecked") + @Override + T car() { + return (T)this.car; + } + + @SuppressWarnings("unchecked") + @Override + Iterable<T> cdr() { + return (Iterable<T>)this.cdr; + } + + @Override + public Iterator<T> iterator() { + return new Iterator<T>() { + boolean carIterator = true; + Iterator<?> cdrIterator = PairIterable.this.cdr.iterator(); + + @Override + public boolean hasNext() { + if(this.carIterator) + return true; + return this.cdrIterator.hasNext(); + } + + @SuppressWarnings("unchecked") + @Override + public T next() { + if(this.carIterator) { + this.carIterator = false; + return (T)PairIterable.this.car; + } + return (T)this.cdrIterator.next(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } + + /** + * Test the list functions. + */ + static class Test { + Boolean testList() { + final Iterable<Object> l = list(2, 3, 4); + assert car(l) == Integer.valueOf(2); + assert cadr(l) == Integer.valueOf(3); + assert caddr(l) == Integer.valueOf(4); + + final Iterable<Object> c = cons(0, cons(1, l)); + assert car(c) == Integer.valueOf(0); + assert cadr(c) == Integer.valueOf(1); + assert caddr(c) == Integer.valueOf(2); + assert c.toString().equals("[0, 1, 2, 3, 4]"); + + final Iterable<Object> cl = cons(0, cons(1, new ArrayList<Object>(asList(2, 3, 4)))); + assert car(cl) == Integer.valueOf(0); + assert cadr(cl) == Integer.valueOf(1); + assert caddr(cl) == Integer.valueOf(2); + assert cl.toString().equals("[0, 1, 2, 3, 4]"); + + final List<Object> jl = new ArrayList<Object>(collection(cl)); + assert jl.size() == 5; + assert jl.get(0) == Integer.valueOf(0); + assert jl.get(1) == Integer.valueOf(1); + assert jl.get(2) == Integer.valueOf(2); + + final Iterable<Object> n = list(); + assert isNil(n); + assert n.toString().equals("[]"); + + final Iterable<Object> cn = cons(0, n); + assert !isNil(cn); + assert isNil(cdr(cn)); + assert cn.toString().equals("[0]"); + + final Iterable<Object> al = new ArrayList<Object>(Arrays.asList(1, 2, 3)); + assert car(al) == Integer.valueOf(1); + assert cadr(al) == Integer.valueOf(2); + assert caddr(al) == Integer.valueOf(3); + return true; + } + } + + public static void main(final String[] args) { + System.out.println("Testing..."); + + Test.class.getClassLoader().setDefaultAssertionStatus(true); + new Test().testList(); + + System.out.println("OK"); + } + +} diff --git a/sca-cpp/trunk/modules/java/org/apache/tuscany/Service.java b/sca-cpp/trunk/modules/java/org/apache/tuscany/Service.java index c8152463b4..6150b7d1cd 100644 --- a/sca-cpp/trunk/modules/java/org/apache/tuscany/Service.java +++ b/sca-cpp/trunk/modules/java/org/apache/tuscany/Service.java @@ -19,20 +19,45 @@ package org.apache.tuscany; +/** + * Interface used to represent SCA component references providing both REST + * access to a resource and function application. + */ public interface Service { - String post(Object[] item); - - Object[] get(String id); - - Object[] getall(); - - boolean put(String id, Object[] item); - + /** + * Post a new item to a resource. + */ + String post(Iterable<?> item); + + /** + * Return an item. + */ + Iterable<?> get(String id); + + /** + * Return all items in the resource. + */ + Iterable<?> getall(); + + /** + * Update am item. + */ + boolean put(String id, Iterable<?> item); + + /** + * Delete an item. + */ boolean delete(String id); + /** + * Delete all items in the resource. + */ boolean deleteall(); + /** + * Apply a function. + */ <T> T apply(Object... params); } diff --git a/sca-cpp/trunk/modules/java/server-test b/sca-cpp/trunk/modules/java/server-test index 08e381690d..45c5efafb2 100755 --- a/sca-cpp/trunk/modules/java/server-test +++ b/sca-cpp/trunk/modules/java/server-test @@ -29,6 +29,8 @@ SCAComposite domain-test.composite </Location> EOF +export CLASSPATH="`pwd`/libmod-tuscany-java-1.0.jar:`pwd`" + apachectl -k start -d `pwd`/tmp sleep 2 diff --git a/sca-cpp/trunk/modules/java/test/CalcImpl.java b/sca-cpp/trunk/modules/java/test/CalcImpl.java index 51753785e4..37dc642e75 100644 --- a/sca-cpp/trunk/modules/java/test/CalcImpl.java +++ b/sca-cpp/trunk/modules/java/test/CalcImpl.java @@ -19,6 +19,9 @@ package test; +import java.util.List; +import java.util.ArrayList; + public class CalcImpl { public Double add(Double x, Double y, Adder adder) { @@ -29,4 +32,15 @@ public class CalcImpl { return x * y; } + public Boolean even(Double x) { + return (double)(((int)(double)x / 2) * 2) == (double)x; + } + + public Iterable<Double> square(Iterable<Double> l) { + List r = new ArrayList(); + for (Double x: l) + r.add(x * x); + return r; + } + } diff --git a/sca-cpp/trunk/modules/java/test/Client.java b/sca-cpp/trunk/modules/java/test/Client.java index 447b408cd4..ff2d3fee13 100644 --- a/sca-cpp/trunk/modules/java/test/Client.java +++ b/sca-cpp/trunk/modules/java/test/Client.java @@ -23,13 +23,13 @@ public interface Client { String echo(String x); - Object[] getall(); + Iterable<?> getall(); - Object[] get(String id); + Iterable<?> get(String id); - String post(Object[] item); + String post(Iterable<?> item); - Boolean put(String id, Object[] entry); + Boolean put(String id, Iterable<?> entry); Boolean deleteall(); diff --git a/sca-cpp/trunk/modules/java/test/ClientImpl.java b/sca-cpp/trunk/modules/java/test/ClientImpl.java index 3d3063b608..4bd3498dd5 100644 --- a/sca-cpp/trunk/modules/java/test/ClientImpl.java +++ b/sca-cpp/trunk/modules/java/test/ClientImpl.java @@ -25,19 +25,19 @@ public class ClientImpl { return server.echo(x); } - public Object[] getall(Server server) { + public Iterable<?> getall(Server server) { return server.getall(); } - public Object[] get(String id, Server server) { + public Iterable<?> get(String id, Server server) { return server.get(id); } - public String post(Object[] item, Server server) { + public String post(Iterable<?> item, Server server) { return server.post(item); } - public Boolean put(String id, Object[] item, Server server) { + public Boolean put(String id, Iterable<?> item, Server server) { return server.put(id, item); } diff --git a/sca-cpp/trunk/modules/java/test/Server.java b/sca-cpp/trunk/modules/java/test/Server.java index a165988550..917ccfd6b9 100644 --- a/sca-cpp/trunk/modules/java/test/Server.java +++ b/sca-cpp/trunk/modules/java/test/Server.java @@ -23,13 +23,13 @@ public interface Server { String echo(String x); - Object[] getall(); + Iterable<?> getall(); - Object[] get(String id); + Iterable<?> get(String id); - String post(Object[] item); + String post(Iterable<?> item); - Boolean put(String id, Object[] entry); + Boolean put(String id, Iterable<?> entry); Boolean deleteall(); diff --git a/sca-cpp/trunk/modules/java/test/ServerImpl.java b/sca-cpp/trunk/modules/java/test/ServerImpl.java index f82a8a24b5..dd4e227123 100644 --- a/sca-cpp/trunk/modules/java/test/ServerImpl.java +++ b/sca-cpp/trunk/modules/java/test/ServerImpl.java @@ -19,33 +19,31 @@ package test; +import static org.apache.tuscany.IterableUtil.*; + public class ServerImpl { - Object[] list(Object... o) { - return o; - } - public String echo(String x) { return x; } - public Object[] getall() { + public Iterable<?> getall() { return list("Sample Feed", "123456789", list("Item", "111", list(list("'javaClass", "services.Item"), list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99))), list("Item", "222", list(list("'javaClass", "services.Item"), list("'name", "Orange"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 3.55))), - list("Item", "333", list(list("'javaClass", "services.Item"), list("name", "Pear"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 1.55)))); + list("Item", "333", list(list("'javaClass", "services.Item"), list("'name", "Pear"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 1.55)))); } - public Object[] get(String id) { - Object[] entry = list(list("'javaClass", "services.Item"), list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99)); + public Iterable<?> get(String id) { + Iterable<?> entry = list(list("'javaClass", "services.Item"), list("'name", "Apple"), list("'currencyCode", "USD"), list("'currencySymbol", "$"), list("'price", 2.99)); return list("Item", id, entry); } - public String post(Object[] item) { + public String post(Iterable<?> item) { return "123456789"; } - public Boolean put(String id, Object[] entry) { + public Boolean put(String id, Iterable<?> entry) { return true; } diff --git a/sca-cpp/trunk/modules/java/wiring-test b/sca-cpp/trunk/modules/java/wiring-test index b92f76c403..7b47787b28 100755 --- a/sca-cpp/trunk/modules/java/wiring-test +++ b/sca-cpp/trunk/modules/java/wiring-test @@ -31,6 +31,8 @@ SCAComposite domain-test.composite </Location> EOF +export CLASSPATH="`pwd`/libmod-tuscany-java-1.0.jar:`pwd`" + apachectl -k start -d `pwd`/tmp sleep 2 diff --git a/sca-cpp/trunk/test/store-cpp/fruits-catalog.cpp b/sca-cpp/trunk/test/store-cpp/fruits-catalog.cpp index a7d502a9b9..4c93b2a58e 100644 --- a/sca-cpp/trunk/test/store-cpp/fruits-catalog.cpp +++ b/sca-cpp/trunk/test/store-cpp/fruits-catalog.cpp @@ -33,7 +33,7 @@ namespace tuscany { namespace store { /** - * Returns a catalog. + * Returns the catalog. */ struct convert { const lambda<value(const list<value>&)> converter; @@ -61,6 +61,9 @@ const failable<value> get(const lambda<value(const list<value>&)> converter) { mkfruit("Pear", currency, symbol, conv(1.55))); } +/** + * TODO remove this JSON-RPC specific function. + */ const failable<value> listMethods(unused const lambda<value(const list<value>&)> converter) { return value(mklist<value>(string("Service.get"))); } diff --git a/sca-cpp/trunk/test/store-java/Makefile.am b/sca-cpp/trunk/test/store-java/Makefile.am index f18bb991c1..a381f0a3fd 100644 --- a/sca-cpp/trunk/test/store-java/Makefile.am +++ b/sca-cpp/trunk/test/store-java/Makefile.am @@ -15,6 +15,16 @@ # specific language governing permissions and limitations # under the License. +JAVAROOT = ${top_builddir}/test/store-java + if WANT_JAVA +AM_JAVACFLAGS = -classpath ${top_builddir}/modules/java/libmod-tuscany-java-${PACKAGE_VERSION}.jar + +noinst_JAVA = store/*.java + +CLEANFILES = store/*.class + +TESTS = server-test + endif diff --git a/sca-cpp/trunk/test/store-java/start b/sca-cpp/trunk/test/store-java/start index eb8c174999..43a2b90c2a 100755 --- a/sca-cpp/trunk/test/store-java/start +++ b/sca-cpp/trunk/test/store-java/start @@ -28,6 +28,8 @@ SCAComposite store.composite </Location> EOF +export CLASSPATH=`pwd`/../../modules/java/libmod-tuscany-java-1.0.jar:`pwd` + apachectl -k start -d `pwd`/tmp mc="memcached -l 127.0.0.1 -m 4 -p 11211" diff --git a/sca-cpp/trunk/test/store-java/stop b/sca-cpp/trunk/test/store-java/stop index 34731dbbe1..3c4f59e76e 100755 --- a/sca-cpp/trunk/test/store-java/stop +++ b/sca-cpp/trunk/test/store-java/stop @@ -17,6 +17,8 @@ # specific language governing permissions and limitations # under the License. +export CLASSPATH=`pwd`/../../modules/java/libmod-tuscany-java-1.0.jar:`pwd` + apachectl -k stop -d `pwd`/tmp mc="memcached -l 127.0.0.1 -m 4 -p 11211" kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'` diff --git a/sca-cpp/trunk/test/store-java/store.composite b/sca-cpp/trunk/test/store-java/store.composite index 15e778ca36..5024d79ee6 100644 --- a/sca-cpp/trunk/test/store-java/store.composite +++ b/sca-cpp/trunk/test/store-java/store.composite @@ -22,16 +22,6 @@ targetNamespace="http://store" name="store"> - <component name="Store"> - <implementation.java class="store.StoreImpl"/> - <service name="Widget"> - <t:binding.http uri="store"/> - </service> - <reference name="catalog" target="Catalog"/> - <reference name="shoppingCart" target="ShoppingCart/Cart"/> - <reference name="shoppingTotal" target="ShoppingCart/Total"/> - </component> - <component name="Catalog"> <implementation.java class="store.FruitsCatalogImpl"/> <property name="currencyCode">USD</property> diff --git a/sca-cpp/trunk/test/store-java/store/CurrencyConverter.java b/sca-cpp/trunk/test/store-java/store/CurrencyConverter.java new file mode 100644 index 0000000000..1ed15a670a --- /dev/null +++ b/sca-cpp/trunk/test/store-java/store/CurrencyConverter.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package store; + +public interface CurrencyConverter { + + Double convert(String from, String to, Double amount); + + String symbol(String currency); + +} diff --git a/sca-cpp/trunk/test/store-java/store/CurrencyConverterImpl.java b/sca-cpp/trunk/test/store-java/store/CurrencyConverterImpl.java new file mode 100644 index 0000000000..a6d0fd00b3 --- /dev/null +++ b/sca-cpp/trunk/test/store-java/store/CurrencyConverterImpl.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package store; + +/** + * Currency converter component implementation. + */ +public class CurrencyConverterImpl { + + /** + * Convert an amount from USD to a currency. + */ + public Double convert(String from, String to, Double amount) { + if ("EUR".equals(to)) + return amount * 0.70; + return amount; + } + + /** + * Return a currency symbol. + */ + public String symbol(String currency) { + if ("EUR".equals(currency)) + return "E"; + return "$"; + } + +} diff --git a/sca-cpp/trunk/test/store-java/store/FruitsCatalogImpl.java b/sca-cpp/trunk/test/store-java/store/FruitsCatalogImpl.java new file mode 100644 index 0000000000..3caa785416 --- /dev/null +++ b/sca-cpp/trunk/test/store-java/store/FruitsCatalogImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package store; + +import static org.apache.tuscany.IterableUtil.list; + +/** + * Catalog component implementation. + */ +public class FruitsCatalogImpl { + + /** + * Returns the catalog. + */ + public Iterable<?> get(final CurrencyConverter converter) { + class Converter { + Double convert(Double price) { + return converter.convert("USD", "USD", price); + } + }; + Converter c = new Converter(); + + String code = "USD"; + String symbol = converter.symbol(code); + + return list( + list(list("'javaClass", "services.Item"), list("'name", "Apple"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(2.99))), + list(list("'javaClass", "services.Item"), list("'name", "Orange"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(3.55))), + list(list("'javaClass", "services.Item"), list("'name", "Pear"), list("'currencyCode", code), list("'currencySymbol", symbol), list("'price", c.convert(1.55))) + ); + } + + /** + * TODO remove this JSON-RPC specific function. + */ + public Iterable<?> listMethods(final CurrencyConverter converter) { + return list("Service.get"); + } + +} diff --git a/sca-cpp/trunk/test/store-java/store/ShoppingCartImpl.java b/sca-cpp/trunk/test/store-java/store/ShoppingCartImpl.java new file mode 100644 index 0000000000..30ee59932a --- /dev/null +++ b/sca-cpp/trunk/test/store-java/store/ShoppingCartImpl.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package store; + +import org.apache.tuscany.Service; +import java.lang.System; +import java.util.UUID; +import static org.apache.tuscany.IterableUtil.*; + +/** + * Shopping cart component implementation. + */ +public class ShoppingCartImpl { + + static String cartId = "1234"; + + /** + * Get the shopping cart from the cache. Return an empty + * cart if not found. + */ + public Iterable<?> getcart(String id, Service cache) { + Iterable<?> cart = cache.get(id); + if (cart == null) + return list(); + return cart; + } + + /** + * Returns a UUID. + */ + String uuid() { + return UUID.randomUUID().toString(); + } + + /** + * Post a new item to the cart. Create a new cart if necessary. + */ + public String post(Iterable<?> item, Service cache) { + String id = uuid(); + Iterable<?> newItem = list(car(item), id, caddr(item)); + Iterable<?> cart = cons(newItem, getcart(cartId, cache)); + cache.put(cartId, cart); + return id; + } + + /** + * Return the contents of the cart. + */ + public Iterable<?> getall(Service cache) { + return cons("Your Cart", cons(cartId, getcart(cartId, cache))); + } + + /** + * Find an item in the cart. + */ + public Iterable<?> find(String id, Iterable<?> cart) { + if (isNil(cart)) + return cons("Item", list("0", list())); + if (id.equals(cadr(car(cart)))) + return car(cart); + return find(id, cdr(cart)); + } + + public Iterable<?> get(String id, Service cache) { + return find(id, getcart(cartId, cache)); + } + + /** + * Delete the whole cart. + */ + public Boolean deleteall(Service cache) { + return cache.delete(cartId); + } + + /** + * Delete an item from the cart. + */ + public Boolean delete(String id, Service cache) { + return true; + } + + /** + * Return the price of an item. + */ + Double price(Iterable<?> item) { + return Double.valueOf((String)cadr(assoc("'price", caddr(item)))); + } + + /** + * Sum the prices of a list of items. + */ + Double sum(Iterable<?> items) { + if (isNil(items)) + return 0.0; + return price((Iterable<?>)car(items)) + sum(cdr(items)); + } + + /** + * Return the total price of the items in the cart. + */ + public Double gettotal(Service cache) { + Iterable<?> cart = getcart(cartId, cache); + return sum(cart); + } + + /** + * TODO remove this JSON-RPC specific function. + */ + public Iterable<?> listMethods(final CurrencyConverter converter) { + return list("Service.gettotal"); + } + +} |