Minor improvements to java component support, use one classloader per component, use Iterables instead of arrays to represent lists, added more tests and a working java version of the store integration test.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@902539 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2010-01-24 09:27:44 +00:00
parent aff8757990
commit 1c21d758af
27 changed files with 980 additions and 74 deletions

View file

@ -61,6 +61,7 @@ doxygen
*.pyc
*.class
*.stamp
*.jar
# Specific ignores
kernel-test

View file

@ -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

View file

@ -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);

View file

@ -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;
JNI_CreateJavaVM(&jvm, (void**)&env, &args);
args.nOptions = 0;
// 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);
// 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);
} 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);
@ -237,13 +284,20 @@ const jobjectArray valuesToJarray(const JavaRuntime& jr, const list<value>& v) {
return valuesToJarrayHelper(jr, a, v, 0);
}
/**
* 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;
}
@ -291,6 +345,23 @@ const list<value> jarrayToValues(const JavaRuntime& jr, jobjectArray o) {
return jarrayToValuesHelper(jr, o, 0, jr.env->GetArrayLength(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.
*/
@ -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(const jclass clazz, const jobject obj, const list<value> m) : clazz(clazz), obj(obj), m(m) {
JavaClass() : loader(NULL), clazz(NULL), obj(NULL) {
}
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;
}
}

View file

@ -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

View file

@ -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;

View file

@ -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));

View file

@ -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");
}
}

View file

@ -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));
}

View file

@ -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");
}
}

View file

@ -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);
/**
* Post a new item to a resource.
*/
String post(Iterable<?> item);
Object[] get(String id);
/**
* Return an item.
*/
Iterable<?> get(String id);
Object[] getall();
/**
* Return all items in the resource.
*/
Iterable<?> getall();
boolean put(String id, Object[] item);
/**
* 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);
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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

View file

@ -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")));
}

View file

@ -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

View file

@ -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"

View file

@ -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 }'`

View file

@ -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>

View file

@ -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);
}

View file

@ -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 "$";
}
}

View file

@ -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");
}
}

View file

@ -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");
}
}