From ca64a758cac9b5bd066eda16d569f1a0e3952c9e Mon Sep 17 00:00:00 2001 From: wjaniszewski Date: Thu, 16 Apr 2009 18:01:41 +0000 Subject: Added support for Erlang Atoms git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@765708 13f79535-47bb-0310-9956-ffa450edef68 --- .../sca/binding/erlang/impl/ErlangInvoker.java | 23 +++++-- .../sca/binding/erlang/impl/ServiceExecutor.java | 62 ++++++++++++++---- .../erlang/impl/types/AnnotatedListTypeHelper.java | 71 +++++++++++++++++++++ .../binding/erlang/impl/types/AtomTypeHelper.java | 39 ++++++++++++ .../binding/erlang/impl/types/ListTypeHelper.java | 9 +-- .../binding/erlang/impl/types/TupleTypeHelper.java | 9 ++- .../erlang/impl/types/TypeHelpersProxy.java | 73 +++++++++++++++++----- .../sca/binding/erlang/meta/ErlangAtom.java | 28 +++++++++ .../sca/binding/erlang/testing/AtomTuple.java | 30 +++++++++ .../sca/binding/erlang/testing/MboxInterface.java | 14 ++++- .../sca/binding/erlang/testing/MboxListener.java | 18 +++--- .../erlang/testing/ReferenceServiceTestCase.java | 69 +++++++++++++++++++- 12 files changed, 393 insertions(+), 52 deletions(-) create mode 100644 branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AnnotatedListTypeHelper.java create mode 100644 branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AtomTypeHelper.java create mode 100644 branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/meta/ErlangAtom.java create mode 100644 branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/AtomTuple.java (limited to 'branches/sca-java-1.x/modules/binding-erlang-runtime') diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ErlangInvoker.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ErlangInvoker.java index 6750e292d9..2fe9ae38b9 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ErlangInvoker.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ErlangInvoker.java @@ -19,12 +19,14 @@ package org.apache.tuscany.sca.binding.erlang.impl; +import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.tuscany.sca.binding.erlang.ErlangBinding; import org.apache.tuscany.sca.binding.erlang.impl.exceptions.ErlangException; import org.apache.tuscany.sca.binding.erlang.impl.types.TypeHelpersProxy; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Message; @@ -81,9 +83,13 @@ public class ErlangInvoker implements Invoker { } tmpMbox = node.createMbox(); Object[] args = msg.getBody(); + Method jmethod = ((JavaOperation) msg.getOperation()) + .getJavaMethod(); // create and send msg with self pid in the beginning - OtpErlangObject[] argsArray = { tmpMbox.self(), - TypeHelpersProxy.toErlang(args) }; + OtpErlangObject[] argsArray = { + tmpMbox.self(), + TypeHelpersProxy.toErlang(args, jmethod + .getParameterAnnotations()) }; OtpErlangObject otpArgs = new OtpErlangTuple(argsArray); tmpMbox.send(msg.getOperation().getName(), binding.getNode(), otpArgs); @@ -96,7 +102,8 @@ public class ErlangInvoker implements Invoker { } OtpErlangObject result = resultMsg.getMsg(); msg.setBody(TypeHelpersProxy.toJava(result, msg.getOperation() - .getOutputType().getPhysical())); + .getOutputType().getPhysical(), jmethod + .getAnnotations())); } } catch (InterruptedException e) { // TODO: externalize message? @@ -129,8 +136,10 @@ public class ErlangInvoker implements Invoker { } other = new OtpPeer(binding.getNode()); connection = self.connect(other); - OtpErlangList params = TypeHelpersProxy - .toErlangAsList((Object[]) msg.getBody()); + Method jmethod = ((JavaOperation) msg.getOperation()) + .getJavaMethod(); + OtpErlangList params = TypeHelpersProxy.toErlangAsList(msg + .getBody(), jmethod.getParameterAnnotations()); OtpErlangTuple message = MessageHelper.rpcMessage(self.pid(), self .createRef(), binding.getModule(), msg.getOperation() .getName(), params); @@ -152,8 +161,10 @@ public class ErlangInvoker implements Invoker { reportProblem(msg, e); msg.setBody(null); } else if (msg.getOperation().getOutputType() != null) { + jmethod.getAnnotations(); msg.setBody(TypeHelpersProxy.toJava(result, msg.getOperation() - .getOutputType().getPhysical())); + .getOutputType().getPhysical(), jmethod + .getAnnotations())); } } catch (OtpAuthException e) { // TODO: externalize message? diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ServiceExecutor.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ServiceExecutor.java index e42b93c313..26b772f5e3 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ServiceExecutor.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/ServiceExecutor.java @@ -20,7 +20,9 @@ package org.apache.tuscany.sca.binding.erlang.impl; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -30,6 +32,7 @@ import org.apache.tuscany.sca.binding.erlang.ErlangBinding; import org.apache.tuscany.sca.binding.erlang.impl.types.TypeHelpersProxy; import org.apache.tuscany.sca.interfacedef.DataType; import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; import org.apache.tuscany.sca.runtime.RuntimeComponentService; import com.ericsson.otp.erlang.OtpAuthException; @@ -104,6 +107,7 @@ public class ServiceExecutor implements Runnable { argsList = new OtpErlangList(args); } if (!nodeElement.getBinding().getModule().equals(module)) { + // module not found // TODO: externalize message? OtpErlangObject errorMsg = MessageHelper.functionUndefMessage( module, function, argsList, @@ -111,6 +115,7 @@ public class ServiceExecutor implements Runnable { sendMessage(connection, senderPid, senderRef, MessageHelper.ATOM_BADRPC, errorMsg); } else { + // module found, looking for operation RuntimeComponentService service = nodeElement.getService(); ErlangBinding binding = nodeElement.getBinding(); List operations = service.getInterfaceContract() @@ -123,6 +128,7 @@ public class ServiceExecutor implements Runnable { } } if (operation != null) { + // operation found List iTypes = operation.getInputType() .getLogical(); Class[] forClasses = new Class[iTypes.size()]; @@ -130,22 +136,35 @@ public class ServiceExecutor implements Runnable { forClasses[i] = iTypes.get(i).getPhysical(); } try { + // invoke operation + Method jmethod = ((JavaOperation) operation) + .getJavaMethod(); Object result = service.getRuntimeWire(binding, service.getInterfaceContract()).invoke( operation, TypeHelpersProxy.toJavaFromList(argsList, - forClasses)); + forClasses, jmethod + .getParameterAnnotations())); OtpErlangObject response = null; + + // send reply if (operation.getOutputType() != null && operation.getOutputType().getPhysical() .isArray()) { - response = TypeHelpersProxy.toErlangAsList(result); + // output type is array + Annotation[][] outNotes = new Annotation[][] { jmethod + .getAnnotations() }; + response = TypeHelpersProxy.toErlangAsList(result, + outNotes); } else if (operation.getOutputType() == null) { + // output type is void, create empty reply Object[] arrArg = new Object[] {}; - response = TypeHelpersProxy.toErlang(arrArg); + response = TypeHelpersProxy.toErlang(arrArg, + new Annotation[0][0]); } else { - Object[] arrArg = new Object[] { result }; - response = TypeHelpersProxy.toErlang(arrArg); + // output type is not void and not array + response = TypeHelpersProxy.toErlang(result, + jmethod.getAnnotations()); } sendMessage(connection, senderPid, senderRef, null, response); @@ -156,6 +175,7 @@ public class ServiceExecutor implements Runnable { IllegalArgumentException.class)) || e.getClass().equals( TypeMismatchException.class)) { + // wrong params // TODO: externalize message? OtpErlangObject errorMsg = MessageHelper .functionUndefMessage(module, function, @@ -164,10 +184,12 @@ public class ServiceExecutor implements Runnable { sendMessage(connection, senderPid, senderRef, MessageHelper.ATOM_BADRPC, errorMsg); } else { + // unexpected error throw e; } } } else { + // operation not found // TODO: externalize message? OtpErlangObject errorMsg = MessageHelper .functionUndefMessage(module, function, argsList, @@ -177,6 +199,7 @@ public class ServiceExecutor implements Runnable { } } } catch (ClassCastException e) { + // invalid request // TODO: externalize message? try { logger @@ -189,6 +212,7 @@ public class ServiceExecutor implements Runnable { } catch (OtpErlangDecodeException e1) { } } catch (Exception e) { + // unknown error try { sendMessage(connection, senderPid, senderRef, MessageHelper.ATOM_ERROR, new OtpErlangString( @@ -224,10 +248,12 @@ public class ServiceExecutor implements Runnable { msgNoSender = msg.getMsg(); } } catch (Exception e) { + // TODO: check when this exception can occur e.printStackTrace(); } if (operations == null) { + // operation name not found // TODO: externalize message? // NOTE: I assume in Erlang sender doesn't get confirmation so // no message will be send @@ -235,7 +261,9 @@ public class ServiceExecutor implements Runnable { + "' received message addressed to non exising mbox: " + msg.getRecipientName()); } else { + // find proper operation for received parameters for (Operation operation : operations) { + Method method = ((JavaOperation) operation).getJavaMethod(); List iTypes = operation.getInputType().getLogical(); Class[] forClasses = new Class[iTypes.size()]; for (int i = 0; i < iTypes.size(); i++) { @@ -243,7 +271,7 @@ public class ServiceExecutor implements Runnable { } try { args = TypeHelpersProxy.toJavaAsArgs(msgNoSender, - forClasses); + forClasses, method.getParameterAnnotations()); matchedOperation = operation; break; } catch (Exception e) { @@ -252,22 +280,33 @@ public class ServiceExecutor implements Runnable { } } if (matchedOperation != null) { + // operation found, invoke it try { + Method jmethod = ((JavaOperation) matchedOperation) + .getJavaMethod(); Object result = nodeElement.getService().getRuntimeWire( nodeElement.getBinding()).invoke(matchedOperation, args); OtpErlangObject response = null; + + // create and send send reply if (matchedOperation.getOutputType() != null && matchedOperation.getOutputType().getPhysical() .isArray()) { - response = TypeHelpersProxy.toErlangAsList(result); + // result type is array + Annotation[][] outNotes = new Annotation[][] { jmethod + .getAnnotations() }; + response = TypeHelpersProxy.toErlangAsList(result, + outNotes); } else if (matchedOperation.getOutputType() != null) { - Object[] arrArg = new Object[] { result }; - response = TypeHelpersProxy.toErlang(arrArg); + // result type is not array and not void + response = TypeHelpersProxy.toErlang(result, jmethod + .getAnnotations()); } if (response != null && senderPid != null) { connection.send(senderPid, response); } else if (response != null && senderPid == null) { + // couldn't send reply - sender pid unavailable // TODO: externalize message? // TODO: do we need to send this reply? logger @@ -288,13 +327,13 @@ public class ServiceExecutor implements Runnable { new OtpErlangString( "Operation name found in SCA component, but parameters types didn't match.")); } catch (IOException e1) { - // TODO Auto-generated catch block e1.printStackTrace(); } } else { + // unknown/unhandled error + // TODO: decide what to do with this exception e.printStackTrace(); } - // } catch (IOException e) { } catch (Exception e) { // FIXME: log this problem? use linking feature? send error? e.printStackTrace(); @@ -319,6 +358,7 @@ public class ServiceExecutor implements Runnable { } else { msg = connection.receiveMsg(); } + // check if request is message or RPC if (msg.getRecipientName().equals(MessageHelper.RPC_MBOX) && !nodeElement.getBinding().isMbox()) { handleRpc(msg); diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AnnotatedListTypeHelper.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AnnotatedListTypeHelper.java new file mode 100644 index 0000000000..154f0c27fc --- /dev/null +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AnnotatedListTypeHelper.java @@ -0,0 +1,71 @@ +/* + * 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.sca.binding.erlang.impl.types; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +import com.ericsson.otp.erlang.OtpErlangList; +import com.ericsson.otp.erlang.OtpErlangObject; + +/** + * @version $Rev$ $Date$ + */ +public class AnnotatedListTypeHelper implements TypeHelper { + + private Annotation[] notes; + + public AnnotatedListTypeHelper(Annotation[] notes) { + this.notes = notes; + } + + public OtpErlangObject toErlang(Object object) { + int i = 0; + List elements = new ArrayList(); + while (true) { + try { + elements.add(TypeHelpersProxy.toErlang(Array.get(object, i), + notes)); + i++; + } catch (ArrayIndexOutOfBoundsException e) { + // expected + break; + } + } + return new OtpErlangList(elements.toArray(new OtpErlangObject[elements + .size()])); + } + + public Object toJava(OtpErlangObject object, Class forClass) + throws Exception { + OtpErlangList erlangList = (OtpErlangList) object; + Object result = Array.newInstance(forClass.getComponentType(), + erlangList.arity()); + for (int i = 0; i < erlangList.arity(); i++) { + Array.set(result, i, TypeHelpersProxy.toJava(erlangList + .elementAt(i), forClass.getComponentType(), + new Annotation[0])); + } + return result; + } + +} diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AtomTypeHelper.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AtomTypeHelper.java new file mode 100644 index 0000000000..94285c66bf --- /dev/null +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/AtomTypeHelper.java @@ -0,0 +1,39 @@ +/* + * 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.sca.binding.erlang.impl.types; + +import com.ericsson.otp.erlang.OtpErlangAtom; +import com.ericsson.otp.erlang.OtpErlangObject; + +/** + * @version $Rev$ $Date$ + */ +public class AtomTypeHelper implements TypeHelper { + + public OtpErlangObject toErlang(Object object) { + return new OtpErlangAtom((String) object); + } + + public Object toJava(OtpErlangObject object, Class forClass) + throws Exception { + return ((OtpErlangAtom) object).atomValue(); + } + +} diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/ListTypeHelper.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/ListTypeHelper.java index adac10bcef..7bb62d4cf8 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/ListTypeHelper.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/ListTypeHelper.java @@ -19,6 +19,7 @@ package org.apache.tuscany.sca.binding.erlang.impl.types; +import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; @@ -36,9 +37,8 @@ public class ListTypeHelper implements TypeHelper { List elements = new ArrayList(); while (true) { try { - Object arrElement = Array.get(object, i); - Object[] args = new Object[] { arrElement }; - elements.add(TypeHelpersProxy.toErlang(args)); + elements.add(TypeHelpersProxy.toErlang(Array.get(object, i), + new Annotation[0])); i++; } catch (ArrayIndexOutOfBoundsException e) { // expected @@ -56,7 +56,8 @@ public class ListTypeHelper implements TypeHelper { erlangList.arity()); for (int i = 0; i < erlangList.arity(); i++) { Array.set(result, i, TypeHelpersProxy.toJava(erlangList - .elementAt(i), forClass.getComponentType())); + .elementAt(i), forClass.getComponentType(), + new Annotation[0])); } return result; } diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TupleTypeHelper.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TupleTypeHelper.java index 474459b9dc..64ea57f836 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TupleTypeHelper.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TupleTypeHelper.java @@ -36,16 +36,15 @@ public class TupleTypeHelper implements TypeHelper { List tupleMembers = new ArrayList(); Field[] fields = forClass.getFields(); for (int i = 0; i < fields.length; i++) { - Object[] args = null; try { - args = new Object[] { fields[i].get(object) }; + OtpErlangObject member = TypeHelpersProxy.toErlang(fields[i] + .get(object), fields[i].getAnnotations()); + tupleMembers.add(member); } catch (IllegalArgumentException e) { // no problem should occur here } catch (IllegalAccessException e) { // and here } - OtpErlangObject member = TypeHelpersProxy.toErlang(args); - tupleMembers.add(member); } OtpErlangObject result = new OtpErlangTuple(tupleMembers .toArray(new OtpErlangObject[tupleMembers.size()])); @@ -61,7 +60,7 @@ public class TupleTypeHelper implements TypeHelper { for (int i = 0; i < tuple.arity(); i++) { OtpErlangObject tupleMember = tuple.elementAt(i); Object javaMember = TypeHelpersProxy.toJava(tupleMember, fields[i] - .getType()); + .getType(), fields[i].getAnnotations()); fields[i].setAccessible(true); fields[i].set(result, javaMember); } diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TypeHelpersProxy.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TypeHelpersProxy.java index cbfd93796f..380abb852b 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TypeHelpersProxy.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/impl/types/TypeHelpersProxy.java @@ -19,6 +19,7 @@ package org.apache.tuscany.sca.binding.erlang.impl.types; +import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.HashMap; @@ -26,6 +27,7 @@ import java.util.List; import java.util.Map; import org.apache.tuscany.sca.binding.erlang.impl.TypeMismatchException; +import org.apache.tuscany.sca.binding.erlang.meta.ErlangAtom; import com.ericsson.otp.erlang.OtpErlangList; import com.ericsson.otp.erlang.OtpErlangObject; @@ -60,19 +62,52 @@ public class TypeHelpersProxy { primitiveTypes.put(Float.class, primitiveTypes.get(float.class)); primitiveTypes.put(Double.class, primitiveTypes.get(double.class)); primitiveTypes.put(byte[].class, new BinaryTypeHelper()); + primitiveTypes.put(ErlangAtom.class, new AtomTypeHelper()); } - private static TypeHelper getTypeHelper(Class forClass) { - TypeHelper typeHelper = primitiveTypes.get(forClass); + private static TypeHelper getTypeHelper(Class forClass, + Annotation[] notes) { + TypeHelper typeHelper = null; + // check for special types marked by annotations + for (int i = 0; i < notes.length; i++) { + typeHelper = primitiveTypes.get(notes[i].annotationType()); + if (typeHelper != null) { + // annotation found, check if it points to array + // FIXME: check if annotation points to proper type + // ie. ErlangAtom -> String. If not, then log? exception? + if (forClass.isArray()) { + typeHelper = new AnnotatedListTypeHelper(notes); + } + break; + } + } + // check for standard types + if (typeHelper == null) { + typeHelper = primitiveTypes.get(forClass); + } + // check for arrays if (typeHelper == null && forClass.isArray()) { typeHelper = new ListTypeHelper(); } + // others would be tuples if (typeHelper == null) { typeHelper = new TupleTypeHelper(); } return typeHelper; } + /** + * Converts single Java object into Erlang + * + * @param object + * @param notes + * @return + */ + public static OtpErlangObject toErlang(Object object, Annotation[] notes) { + TypeHelper helper = getTypeHelper(object.getClass(), notes); + return helper.toErlang(object); + } + /** * Converts Java objects arrays to Erlang: 1. single object (if array arity * == 1) or 2. tuple (if array arity > 1) @@ -80,7 +115,8 @@ public class TypeHelpersProxy { * @param objects * @return */ - public static OtpErlangObject toErlang(Object[] objects) { + public static OtpErlangObject toErlang(Object[] objects, + Annotation[][] notes) { OtpErlangObject result = null; if (objects != null) { TypeHelper helper = null; @@ -89,13 +125,13 @@ public class TypeHelpersProxy { result = new OtpErlangList(); break; case 1: - helper = getTypeHelper(objects[0].getClass()); + helper = getTypeHelper(objects[0].getClass(), notes[0]); result = helper.toErlang(objects[0]); break; default: OtpErlangObject[] erlObjects = new OtpErlangObject[objects.length]; for (int i = 0; i < objects.length; i++) { - helper = getTypeHelper(objects[i].getClass()); + helper = getTypeHelper(objects[i].getClass(), notes[i]); erlObjects[i] = helper.toErlang(objects[i]); } result = new OtpErlangTuple(erlObjects); @@ -111,15 +147,24 @@ public class TypeHelpersProxy { * @param array * @return */ - public static OtpErlangList toErlangAsList(Object array) { + public static OtpErlangList toErlangAsList(Object array, + Annotation[][] notes) { OtpErlangList result = null; if (array != null) { List attrsList = new ArrayList(); int i = 0; while (true) { try { + // FIXME: if notes.length == 1 then its used to annotate + // array. Clean up. + Annotation[] currNotes = null; + if (notes.length == 1) { + currNotes = notes[0]; + } else { + currNotes = notes[i]; + } TypeHelper helper = getTypeHelper(Array.get(array, i) - .getClass()); + .getClass(), currNotes); attrsList.add(helper.toErlang(Array.get(array, i))); i++; } catch (ArrayIndexOutOfBoundsException e) { @@ -142,10 +187,10 @@ public class TypeHelpersProxy { * @return * @throws Exception */ - public static Object toJava(OtpErlangObject object, Class forClass) - throws Exception { + public static Object toJava(OtpErlangObject object, Class forClass, + Annotation[] notes) throws Exception { try { - TypeHelper helper = getTypeHelper(forClass); + TypeHelper helper = getTypeHelper(forClass, notes); return helper.toJava(object, forClass); } catch (ClassCastException e) { throw new TypeMismatchException(forClass, object.getClass()); @@ -161,11 +206,11 @@ public class TypeHelpersProxy { * @throws Exception */ public static Object[] toJavaFromList(OtpErlangList objects, - Class[] forClass) throws Exception { + Class[] forClass, Annotation[][] notes) throws Exception { Object[] result = new Object[objects.arity()]; try { for (int i = 0; i < objects.arity(); i++) { - TypeHelper helper = getTypeHelper(forClass[i]); + TypeHelper helper = getTypeHelper(forClass[i], notes[i]); result[i] = helper.toJava(objects.elementAt(i), forClass[i]); } } catch (Exception e) { @@ -187,7 +232,7 @@ public class TypeHelpersProxy { * @throws Exception */ public static Object[] toJavaAsArgs(OtpErlangObject objects, - Class[] forClass) throws Exception { + Class[] forClass, Annotation[][] notes) throws Exception { OtpErlangObject[] args = null; // normalize input if (objects.getClass().equals(OtpErlangTuple.class)) { @@ -202,7 +247,7 @@ public class TypeHelpersProxy { Object[] result = new Object[args.length]; try { for (int i = 0; i < args.length; i++) { - TypeHelper helper = getTypeHelper(forClass[i]); + TypeHelper helper = getTypeHelper(forClass[i], notes[i]); result[i] = helper.toJava(args[i], forClass[i]); } } catch (Exception e) { diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/meta/ErlangAtom.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/meta/ErlangAtom.java new file mode 100644 index 0000000000..48037eaa1c --- /dev/null +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/main/java/org/apache/tuscany/sca/binding/erlang/meta/ErlangAtom.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 org.apache.tuscany.sca.binding.erlang.meta; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ErlangAtom { + +} diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/AtomTuple.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/AtomTuple.java new file mode 100644 index 0000000000..f0930295a7 --- /dev/null +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/AtomTuple.java @@ -0,0 +1,30 @@ +/* + * 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.sca.binding.erlang.testing; + +import org.apache.tuscany.sca.binding.erlang.meta.ErlangAtom; + +public class AtomTuple { + + @ErlangAtom + public String field1; + public int field2; + +} diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxInterface.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxInterface.java index 74ec613018..8f950d54f7 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxInterface.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxInterface.java @@ -19,6 +19,8 @@ package org.apache.tuscany.sca.binding.erlang.testing; +import org.apache.tuscany.sca.binding.erlang.meta.ErlangAtom; + /** * @version $Rev$ $Date$ */ @@ -49,7 +51,15 @@ public interface MboxInterface { String[] sendArgs(String[] arg) throws Exception; String[][] sendArgs(String[][] arg); - + byte[] sendArgs(byte[] arg); - + + @ErlangAtom + String[] sendArgs(@ErlangAtom String arg1, AtomTuple arg2); + + @ErlangAtom + String[][] sendArgs(@ErlangAtom String[][] arg1, int arg2); + + void sendArgs(); + } diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxListener.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxListener.java index fe643fcff6..0cab5c0b0e 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxListener.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/MboxListener.java @@ -19,6 +19,8 @@ package org.apache.tuscany.sca.binding.erlang.testing; +import java.lang.annotation.Annotation; + import org.apache.tuscany.sca.binding.erlang.impl.types.TypeHelpersProxy; import com.ericsson.otp.erlang.OtpErlangObject; @@ -53,14 +55,16 @@ public class MboxListener implements Runnable { Thread.sleep(duration); OtpErlangPid senderPid = null; if (response != null) { - Object[] args = new Object[1]; - args[0] = response; - if (msg.getMsg().getClass().equals(OtpErlangTuple.class) && ((OtpErlangTuple) msg.getMsg()).elementAt(0).getClass().equals(OtpErlangPid.class)) { - senderPid = (OtpErlangPid) ((OtpErlangTuple) msg.getMsg()).elementAt(0); + if (msg.getMsg().getClass().equals(OtpErlangTuple.class) + && ((OtpErlangTuple) msg.getMsg()).elementAt(0) + .getClass().equals(OtpErlangPid.class)) { + senderPid = (OtpErlangPid) ((OtpErlangTuple) msg.getMsg()) + .elementAt(0); } else { senderPid = msg.getSenderPid(); } - mbox.send(senderPid, TypeHelpersProxy.toErlang(args)); + mbox.send(senderPid, TypeHelpersProxy.toErlang(response, + new Annotation[0])); } } catch (Exception e) { e.printStackTrace(); @@ -84,9 +88,9 @@ public class MboxListener implements Runnable { } } } - return msg.getMsg(); + return ((OtpErlangTuple) msg.getMsg()).elementAt(1); } catch (Exception e) { - + e.printStackTrace(); } return null; } diff --git a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/ReferenceServiceTestCase.java b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/ReferenceServiceTestCase.java index 3e0a60725e..0c80df7a04 100644 --- a/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/ReferenceServiceTestCase.java +++ b/branches/sca-java-1.x/modules/binding-erlang-runtime/src/test/java/org/apache/tuscany/sca/binding/erlang/testing/ReferenceServiceTestCase.java @@ -32,6 +32,7 @@ import org.apache.tuscany.sca.host.embedded.SCADomain; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -292,6 +293,11 @@ public class ReferenceServiceTestCase { String testString = "TupleString"; int testInt = 10; mboxReference.sendArgs(testInt, testString); + // FIXME: + // without following sleep an exception occurs: + // com.ericsson.otp.erlang.OtpErlangDecodeException: Cannot read from + // input stream + Thread.sleep(100); assertEquals(testInt, ((OtpErlangLong) ((OtpErlangTuple) mboxListener .getMsg()).elementAt(0)).longValue()); assertEquals(testString, @@ -411,6 +417,52 @@ public class ReferenceServiceTestCase { } } + /** + * Tests passing Erlang atoms. It provides cases for annotating result + * types, parameters and fields in java classes - tuples. + * + * @throws Exception + */ + @Test(timeout = 1000) + public void testAtoms() throws Exception { + AtomTuple arg2 = new AtomTuple(); + arg2.field1 = "test"; + String arg1 = "First arg"; + String[] strResult = { "Hello", "World" }; + MboxListener mboxListener = new MboxListener(serMbox, strResult); + Thread mboxThread = new Thread(mboxListener); + mboxThread.start(); + String[] testResult = mboxReference.sendArgs(arg1, arg2); + assertEquals(strResult[0], testResult[0]); + assertEquals(strResult[1], testResult[1]); + + assertEquals(arg1, ((OtpErlangAtom) ((OtpErlangTuple) mboxListener + .getMsg()).elementAt(0)).atomValue()); + + assertEquals( + arg2.field1, + ((OtpErlangAtom) ((OtpErlangTuple) ((OtpErlangTuple) mboxListener + .getMsg()).elementAt(1)).elementAt(0)).atomValue()); + + // test multi dimensional arrays + String[][] arg = { { "this", "is" }, { "a" }, { "test" } }; + mboxListener = new MboxListener(serMbox, arg); + mboxThread = new Thread(mboxListener); + mboxThread.start(); + String[][] multiDimRes = mboxReference.sendArgs(arg, 1); + for (int i = 0; i < arg.length; i++) { + for (int j = 0; j < arg[i].length; j++) { + assertEquals(arg[i][j], multiDimRes[i][j]); + assertEquals( + arg[i][j], + ((OtpErlangAtom) ((OtpErlangList) ((OtpErlangList) ((OtpErlangTuple) mboxListener + .getMsg()).elementAt(0)).elementAt(i)) + .elementAt(j)).atomValue()); + } + } + + } + /** * Tests mismatched interface * @@ -644,14 +696,16 @@ public class ReferenceServiceTestCase { OtpErlangObject[] argsWithSender = new OtpErlangObject[2]; argsWithSender[0] = refMbox.self(); argsWithSender[1] = tuple; - refMbox.send("sayHello", "RPCServerMbox", new OtpErlangTuple(argsWithSender)); + refMbox.send("sayHello", "RPCServerMbox", new OtpErlangTuple( + argsWithSender)); OtpErlangString result = (OtpErlangString) refMbox.receiveMsg() .getMsg(); assertEquals("Hello world !", result.stringValue()); } - + /** * Tests receiving reply without sending self PID + * * @throws Exception */ @Test(timeout = 1000) @@ -698,7 +752,8 @@ public class ReferenceServiceTestCase { OtpErlangObject[] withSender = new OtpErlangObject[2]; withSender[0] = refMbox.self(); withSender[1] = args; - refMbox.send("passComplexArgs", "RPCServerMbox", new OtpErlangTuple(withSender)); + refMbox.send("passComplexArgs", "RPCServerMbox", new OtpErlangTuple( + withSender)); OtpErlangObject result = refMbox.receiveMsg().getMsg(); assertEquals(arg1, ((OtpErlangLong) ((OtpErlangTuple) ((OtpErlangTuple) result) @@ -831,4 +886,12 @@ public class ReferenceServiceTestCase { cookieModuleReference.sayHellos(); } + @Test(timeout = 1000) + @Ignore("Nothing to test yet") + public void testMboxNoArgs() throws Exception { + // FIXME: decide what to do while invoking mbox reference with no params + // exception? log? + mboxReference.sendArgs(); + } + } -- cgit v1.2.3