blob: 81a049bed90655c13245a9cb976ae84188f2bb1b [file] [log] [blame]
/**
*
* 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.yoko.rmi.impl;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.rmi.MarshalException;
import java.rmi.RemoteException;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.rmi.CORBA.Util;
import org.omg.CORBA.ORB;
public final class MethodDescriptor extends ModelElement {
static final Logger logger = Logger.getLogger(MethodDescriptor.class.getName());
/** The refleced method object for this method */
final java.lang.reflect.Method reflected_method;
java.lang.Object invocation_block_selector;
boolean onewayInitialized = false;
boolean oneway = false;
public boolean responseExpected() {
if (!onewayInitialized) {
if (!reflected_method.getReturnType().equals(Void.TYPE)) {
onewayInitialized = true;
oneway = false;
return true;
}
Class[] exceptions = reflected_method.getExceptionTypes();
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i] == org.apache.yoko.rmi.api.RemoteOnewayException.class) {
oneway = true;
break;
}
}
onewayInitialized = true;
}
return !oneway;
}
public java.lang.reflect.Method getReflectedMethod() {
return reflected_method;
}
MethodDescriptor(java.lang.reflect.Method method, TypeRepository repository) {
super(repository, method.getName());
reflected_method = method;
}
/** The number of arguments */
int parameter_count;
/** The argument's type descriptors */
TypeDescriptor[] parameter_types;
/** The return value's type descriptor */
TypeDescriptor return_type;
/** The declared exception's type descriptors */
ExceptionDescriptor[] exception_types;
boolean copyWithinState;
/**
* Copy a set of arguments. If sameState=true, then we're invoking on the
* same RMIState, i.e. an environment with the same context class loader.
*/
Object[] copyArguments(Object[] args, boolean sameState, ORB orb)
throws RemoteException {
if (!sameState) {
try {
org.omg.CORBA_2_3.portable.OutputStream out = (org.omg.CORBA_2_3.portable.OutputStream) orb
.create_output_stream();
for (int i = 0; i < args.length; i++) {
if (parameter_types[i].copyBetweenStates()) {
parameter_types[i].write(out, args[i]);
}
}
org.omg.CORBA_2_3.portable.InputStream in = (org.omg.CORBA_2_3.portable.InputStream) out
.create_input_stream();
for (int i = 0; i < args.length; i++) {
if (parameter_types[i].copyBetweenStates()) {
args[i] = parameter_types[i].read(in);
}
}
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Exception occurred copying arguments", ex);
throw Util.mapSystemException(ex);
}
} else if (copyWithinState) {
CopyState state = new CopyState(repo);
for (int i = 0; i < args.length; i++) {
if (parameter_types[i].copyWithinState()) {
try {
args[i] = state.copy(args[i]);
} catch (CopyRecursionException e) {
final int idx = i;
final Object[] args_arr = args;
state.registerRecursion(new CopyRecursionResolver(
args[i]) {
public void resolve(Object value) {
args_arr[idx] = value;
}
});
}
}
}
}
return args;
}
Object copyResult(Object result, boolean sameState, ORB orb)
throws RemoteException {
if (result == null) {
return null;
}
if (!sameState) {
if (return_type.copyBetweenStates()) {
try {
org.omg.CORBA_2_3.portable.OutputStream out = (org.omg.CORBA_2_3.portable.OutputStream) orb
.create_output_stream();
return_type.write(out, result);
org.omg.CORBA_2_3.portable.InputStream in = (org.omg.CORBA_2_3.portable.InputStream) out
.create_input_stream();
return return_type.read(in);
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Exception occurred copying result", ex);
throw Util.mapSystemException(ex);
}
}
} else if (copyWithinState) {
CopyState state = new CopyState(repo);
try {
return state.copy(result);
} catch (CopyRecursionException e) {
throw new MarshalException("cannot copy recursive value?");
}
}
return result;
}
/**
* read the arguments to this method, and return them as an array of objects
*/
public Object[] readArguments(org.omg.CORBA.portable.InputStream in) {
Object[] args = new Object[parameter_count];
for (int i = 0; i < parameter_count; i++) {
args[i] = parameter_types[i].read(in);
}
return args;
}
public void writeArguments(org.omg.CORBA.portable.OutputStream out,
Object[] args) {
/*
* if (log.isDebugEnabled ()) { java.util.Map recurse = new
* org.apache.yoko.rmi.util.IdentityHashMap (); java.io.CharArrayWriter cw = new
* java.io.CharArrayWriter (); java.io.PrintWriter pw = new
* java.io.PrintWriter (cw);
*
* pw.print ("invoking "); pw.print (reflected_method.toString ());
*
* for (int i = 0; i < parameter_count; i++) { pw.print (" arg["+i+"] =
* "); if (args[i] == null) { pw.write ("null"); } else { TypeDescriptor
* desc;
*
* try { desc = getTypeRepository ().getDescriptor (args[i].getClass
* ()); } catch (RuntimeException ex) { desc = parameter_types[i]; }
*
* desc.print (pw, recurse, args[i]); } }
*
* pw.close (); log.debug (cw.toString ()); }
*/
for (int i = 0; i < parameter_count; i++) {
parameter_types[i].write(out, args[i]);
}
}
/** write the result of this method */
public void writeResult(org.omg.CORBA.portable.OutputStream out,
Object value) {
return_type.write(out, value);
}
static final String UNKNOWN_EXCEPTION_ID = "IDL:omg.org/CORBA/portable/UnknownException:1.0";
public org.omg.CORBA.portable.OutputStream writeException(
org.omg.CORBA.portable.ResponseHandler response, Throwable ex) {
for (int i = 0; i < exception_types.length; i++) {
if (exception_types[i].type.isInstance(ex)) {
org.omg.CORBA.portable.OutputStream out = response
.createExceptionReply();
org.omg.CORBA_2_3.portable.OutputStream out2 = (org.omg.CORBA_2_3.portable.OutputStream) out;
out2
.write_string(exception_types[i]
.getExceptionRepositoryID());
out2.write_value((java.io.Serializable) ex);
return out;
}
}
logger.log(Level.WARNING, "unhandled exception: " + ex.getMessage(), ex);
throw new org.omg.CORBA.portable.UnknownException(ex);
}
public void readException(org.omg.CORBA.portable.InputStream in)
throws Throwable {
org.omg.CORBA_2_3.portable.InputStream in2 = (org.omg.CORBA_2_3.portable.InputStream) in;
String ex_id = in.read_string();
Throwable ex = null;
for (int i = 0; i < exception_types.length; i++) {
if (ex_id.equals(exception_types[i].getExceptionRepositoryID())) {
ex = (Throwable) in2.read_value();
throw ex;
}
}
ex = (Throwable) in2.read_value();
if (ex instanceof Exception) {
throw new java.rmi.UnexpectedException(ex.getMessage(),
(Exception) ex);
} else if (ex instanceof Error) {
throw ex;
}
}
public Object readResult(org.omg.CORBA.portable.InputStream in) {
Object result = return_type.read(in);
/*
* if (log.isDebugEnabled ()) { java.util.Map recurse = new
* org.apache.yoko.rmi.util.IdentityHashMap (); java.io.CharArrayWriter cw = new
* java.io.CharArrayWriter (); java.io.PrintWriter pw = new
* java.io.PrintWriter (cw);
*
* pw.print ("returning from "); pw.println (reflected_method.toString
* ()); pw.print (" => ");
*
* if (result == null) { pw.write ("null"); } else {
*
* TypeDescriptor desc;
*
* try { desc = getTypeRepository ().getDescriptor (result.getClass ()); }
* catch (RuntimeException ex) { desc = return_type; }
*
* desc.print (pw, recurse, result); }
*
* pw.close (); log.debug (cw.toString ()); }
*/
return result;
}
String transformOverloading(String mname) {
StringBuffer buf = new StringBuffer(mname);
if (parameter_types.length == 0) {
buf.append("__");
} else {
for (int i = 0; i < parameter_types.length; i++) {
buf.append("__");
buf.append(parameter_types[i].getIDLName());
}
}
return buf.toString();
}
boolean isOverloaded = false;
boolean isCaseSensitive = false;
protected void setOverloaded(boolean val) {
isOverloaded = val;
}
protected void setCaseSensitive(boolean val) {
isCaseSensitive = val;
}
public void init() {
Class[] param_types = reflected_method.getParameterTypes();
parameter_types = new TypeDescriptor[param_types.length];
for (int i = 0; i < param_types.length; i++) {
try {
parameter_types[i] = repo.getDescriptor(param_types[i]);
copyWithinState |= parameter_types[i].copyWithinState();
} catch (RuntimeException ex) {
throw ex;
}
}
Class result_type = reflected_method.getReturnType();
return_type = repo.getDescriptor(result_type);
Class[] exc_types = reflected_method.getExceptionTypes();
exception_types = new ExceptionDescriptor[exc_types.length];
for (int i = 0; i < exc_types.length; i++) {
exception_types[i] = (ExceptionDescriptor) repo.getDescriptor(exc_types[i]);
}
parameter_count = param_types.length;
super.init();
}
@Override
protected String genIDLName() {
String idl_name = null;
if (isSetterMethod()) {
idl_name = "_set_" + transformIdentifier(attributeName());
} else if (isGetterMethod()) {
idl_name = "_get_" + transformIdentifier(attributeName());
} else {
idl_name = transformIdentifier(java_name);
}
if (isCaseSensitive) {
idl_name = transformCaseSensitive(idl_name);
}
if (isOverloaded) {
idl_name = transformOverloading(idl_name);
}
return idl_name;
}
private String attributeName() {
String methodName = java_name;
StringBuffer buf = new StringBuffer();
int pfxLen;
if (methodName.startsWith("get"))
pfxLen = 3;
else if (methodName.startsWith("is"))
pfxLen = 2;
else if (methodName.startsWith("set"))
pfxLen = 3;
else
throw new RuntimeException("methodName " + methodName
+ " is not attribute");
if (methodName.length() >= (pfxLen + 2)
&& Character.isUpperCase(methodName.charAt(pfxLen))
&& Character.isUpperCase(methodName.charAt(pfxLen + 1))) {
return methodName.substring(pfxLen);
}
buf.append(Character.toLowerCase(methodName.charAt(pfxLen)));
buf.append(methodName.substring(pfxLen + 1));
return buf.toString();
}
private boolean isSetterMethod() {
Method m = getReflectedMethod();
String name = m.getName();
if (!name.startsWith("set"))
return false;
if (name.length() == 3)
return false;
if (!Character.isUpperCase(name.charAt(3)))
return false;
if (!m.getReturnType().equals(Void.TYPE))
return false;
if (m.getParameterTypes().length == 1)
return true;
else
return false;
}
private boolean isGetterMethod() {
Method m = getReflectedMethod();
String name = m.getName();
int pfxLen;
if (name.startsWith("get"))
pfxLen = 3;
else if (name.startsWith("is")
&& m.getReturnType().equals(Boolean.TYPE))
pfxLen = 2;
else
return false;
if (name.length() == pfxLen)
return false;
if (!Character.isUpperCase(name.charAt(pfxLen)))
return false;
if (m.getReturnType().equals(Void.TYPE))
return false;
if (m.getParameterTypes().length == 0)
return true;
else
return false;
}
static String transformIdentifier(String name) {
StringBuffer buf = new StringBuffer();
// it cannot start with underscore; prepend a 'J'
if (name.charAt(0) == '_')
buf.append('J');
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
// basic identifier elements
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || (ch == '_')) {
buf.append(ch);
}
// dot becomes underscore
else if (ch == '.') {
buf.append('_');
}
// else, use translate to UXXXX unicode
else {
buf.append('U');
String hex = Integer.toHexString((int) ch);
switch (hex.length()) {
case 1:
buf.append('0');
case 2:
buf.append('0');
case 3:
buf.append('0');
}
buf.append(hex);
}
}
return buf.toString();
}
private static String transformCaseSensitive(String name) {
StringBuffer buf = new StringBuffer(name);
buf.append('_');
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
// basic identifier elements
if (Character.isUpperCase(ch)) {
buf.append('_');
buf.append(i);
}
}
return buf.toString();
}
void writeStubMethod(PrintWriter pw) {
pw.println("\t/**");
pw.println("\t *");
pw.println("\t */");
writeMethodHead(pw);
pw.println("\t{");
pw.println("\t\tboolean marshal = !" + UTIL + ".isLocal (this);");
pw.println("\t\tmarshal: while(true) {");
pw.println("\t\tif(marshal) {");
writeMarshalCall(pw);
pw.println("\t\t} else {");
writeLocalCall(pw);
pw.println("\t\t}}");
// pw.println ("throw new org.omg.CORBA.NO_IMPLEMENT(\"local
// invocation\")");
pw.println("\t}\n");
}
void writeMethodHead(PrintWriter pw) {
pw.print("\tpublic ");
writeJavaType(pw, reflected_method.getReturnType());
pw.print(' ');
pw.print(java_name);
pw.print(" (");
Class[] args = reflected_method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
if (i != 0) {
pw.print(", ");
}
writeJavaType(pw, args[i]);
pw.print(" arg");
pw.print(i);
}
pw.println(")");
Class[] ex = reflected_method.getExceptionTypes();
pw.print("\t\tthrows ");
for (int i = 0; i < ex.length; i++) {
if (i != 0) {
pw.print(", ");
}
writeJavaType(pw, ex[i]);
}
pw.println();
}
static void writeJavaType(PrintWriter pw, Class type) {
if (type.isArray()) {
writeJavaType(pw, type.getComponentType());
pw.print("[]");
} else {
pw.print(type.getName());
}
}
static final String SERVANT = "org.omg.CORBA.portable.ServantObject";
static final String INPUT = "org.omg.CORBA_2_3.portable.InputStream";
static final String OUTPUT = "org.omg.CORBA_2_3.portable.OutputStream";
static final String UTIL = "javax.rmi.CORBA.Util";
void writeMarshalCall(PrintWriter pw) {
pw.println("\t\t" + INPUT + " in = null;");
pw.println("\t\ttry {");
pw.println("\t\t\t" + OUTPUT + " out " + "= (" + OUTPUT
+ ")_request (\"" + getIDLName() + "\", true);");
pw.println("\t\t\ttry{");
Class[] args = reflected_method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
TypeDescriptor desc = repo.getDescriptor(args[i]);
pw.print("\t\t\t");
desc.writeMarshalValue(pw, "out", "arg" + i);
pw.println(";");
}
pw.println("\t\t\tin = (" + INPUT + ")_invoke(out);");
Class rtype = reflected_method.getReturnType();
if (rtype == Void.TYPE) {
pw.println("\t\t\treturn;");
} else {
pw.print("\t\t\treturn (");
writeJavaType(pw, rtype);
pw.print(")");
TypeDescriptor desc = repo.getDescriptor(rtype);
desc.writeUnmarshalValue(pw, "in");
pw.println(";");
}
pw
.println("\t\t} catch (org.omg.CORBA.portable.ApplicationException ex) {");
pw.println("\t\t\t" + INPUT + " exin = (" + INPUT
+ ")ex.getInputStream();");
pw.println("\t\t\tString exname = exin.read_string();");
Class[] ex = reflected_method.getExceptionTypes();
for (int i = 0; i < ex.length; i++) {
if (java.rmi.RemoteException.class.isAssignableFrom(ex[i])) {
continue;
}
ExceptionDescriptor exd = (ExceptionDescriptor) repo.getDescriptor(ex[i]);
pw.println("\t\t\tif (exname.equals(\""
+ exd.getExceptionRepositoryID() + "\"))");
pw.print("\t\t\t\tthrow (");
writeJavaType(pw, ex[i]);
pw.print(")exin.read_value(");
writeJavaType(pw, ex[i]);
pw.println(".class);");
}
pw.println("\t\t\tthrow new java.rmi.UnexpectedException(exname,ex);");
pw
.println("\t\t} catch (org.omg.CORBA.portable.RemarshalException ex) {");
pw.println("\t\t\tcontinue marshal;");
pw.println("\t\t} finally {");
pw.println("\t\t\t if(in != null) _releaseReply(in);");
pw.println("\t\t}");
pw.println("\t\t} catch (org.omg.CORBA.SystemException ex) {");
pw.println("\t\t\t throw " + UTIL + ".mapSystemException(ex);");
pw.println("\t\t}");
}
void writeLocalCall(PrintWriter pw) {
Class thisClass = reflected_method.getDeclaringClass();
pw.println("\t\t\t" + SERVANT + " so = _servant_preinvoke (");
pw.println("\t\t\t\t\"" + getIDLName() + "\",");
pw.print("\t\t\t\t");
writeJavaType(pw, thisClass);
pw.println(".class);");
pw
.print("\t\t\tif (so==null || so.servant==null || !(so.servant instanceof ");
writeJavaType(pw, thisClass);
pw.print("))");
pw.println(" { marshal=true; continue marshal; }");
pw.println("\t\t\ttry {");
// copy arguments
Class[] args = reflected_method.getParameterTypes();
if (args.length == 1) {
if (repo.getDescriptor(args[0]).copyInStub()) {
pw.print("\t\t\t\targ0 = (");
writeJavaType(pw, args[0]);
pw.println(")" + UTIL + ".copyObject(arg0, _orb());");
}
} else if (args.length > 1) {
boolean[] copy = new boolean[args.length];
int copyCount = 0;
for (int i = 0; i < args.length; i++) {
TypeDescriptor td = repo.getDescriptor(args[i]);
copy[i] = td.copyInStub();
if (copy[i]) {
copyCount += 1;
}
}
if (copyCount > 0) {
pw.println("\t\t\t\tObject[] args = new Object[" + copyCount
+ "];");
int pos = 0;
for (int i = 0; i < args.length; i++) {
if (copy[i]) {
pw.println("\t\t\t\targs[" + (pos++) + "] = arg" + i
+ ";");
}
}
pw.println("\t\t\t\targs=" + UTIL
+ ".copyObjects(args,_orb());");
pos = 0;
for (int i = 0; i < args.length; i++) {
if (copy[i]) {
pw.print("\t\t\t\targ" + i + "=(");
writeJavaType(pw, args[i]);
pw.println(")args[" + (pos++) + "];");
}
}
}
}
// now, invoke!
Class out = reflected_method.getReturnType();
pw.print("\t\t\t\t");
if (out != Void.TYPE) {
writeJavaType(pw, out);
pw.print(" result = ");
}
pw.print("((");
writeJavaType(pw, thisClass);
pw.print(")so.servant).");
pw.print(java_name);
pw.print("(");
for (int i = 0; i < args.length; i++) {
if (i != 0) {
pw.print(',');
}
pw.print("arg" + i);
}
pw.println(");");
pw.print("\t\t\t\treturn ");
if (out != Void.TYPE) {
TypeDescriptor td = repo.getDescriptor(out);
if (td.copyInStub()) {
pw.print('(');
writeJavaType(pw, out);
pw.print(')');
pw.println(UTIL + ".copyObject (result, _orb());");
} else {
pw.println("result;");
}
} else {
pw.println(";");
}
pw.println("\t\t\t} finally {");
pw.println("\t\t\t\t_servant_postinvoke (so);");
pw.println("\t\t\t}");
}
void addDependencies(java.util.Set classes) {
TypeDescriptor desc = null;
desc = repo.getDescriptor(reflected_method.getReturnType());
desc.addDependencies(classes);
Class[] param = reflected_method.getParameterTypes();
for (int i = 0; i < param.length; i++) {
desc = repo.getDescriptor(param[i]);
desc.addDependencies(classes);
}
Class[] ex = reflected_method.getExceptionTypes();
for (int i = 0; i < ex.length; i++) {
desc = repo.getDescriptor(ex[i]);
desc.addDependencies(classes);
}
}
static final java.lang.Class REMOTE_EXCEPTION = java.rmi.RemoteException.class;
boolean isRemoteOperation() {
Class[] ex = reflected_method.getExceptionTypes();
for (int i = 0; i < ex.length; i++) {
if (REMOTE_EXCEPTION.isAssignableFrom(ex[i]))
return true;
}
return false;
}
}