blob: 1c8b7267037e367212fc8a990cafa23b97664785 [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 org.omg.CORBA.ORB;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.OutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.rmi.Remote;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import javax.rmi.PortableRemoteObject;
abstract class RemoteDescriptor extends TypeDescriptor {
private java.util.Map method_map;
private java.util.Map refl_method_map;
private MethodDescriptor[] operations;
private Class[] remote_interfaces;
protected List super_descriptors;
@Override
protected abstract RemoteInterfaceDescriptor genRemoteInterface();
static final Class REMOTE_CLASS = Remote.class;
static final Class OBJECT_CLASS = java.lang.Object.class;
static final java.lang.Class REMOTE_EXCEPTION = java.rmi.RemoteException.class;
String[] _ids;
public String[] all_interfaces() {
if (_ids == null) {
Class[] ifaces = collect_remote_interfaces(type);
int len = ifaces.length;
String[] ids = new String[len];
for (int i = 0; i < len; i++) {
TypeDescriptor desc = repo.getDescriptor(ifaces[i]);
ids[i] = desc.getRepositoryID();
}
_ids = ids;
}
return _ids;
}
public MethodDescriptor getMethod(String idl_name) {
if (operations == null) {
init_methods();
}
if (method_map == null) {
method_map = new HashMap();
for (int i = 0; i < operations.length; i++) {
method_map.put(operations[i].getIDLName(), operations[i]);
}
}
return (MethodDescriptor) method_map.get(idl_name);
}
void debugMethodMap() {
if (logger.isLoggable(Level.FINER)) {
logger.finer("METHOD MAP FOR " + type.getName());
Iterator it = method_map.keySet().iterator();
while (it.hasNext()) {
String idl_name = (String) it.next();
MethodDescriptor desc = (MethodDescriptor) method_map.get(idl_name);
logger.finer("IDL " + idl_name + " -> "+ desc.reflected_method);
}
}
}
public MethodDescriptor getMethod(Method refl_method) {
if (operations == null) {
init_methods();
}
if (refl_method_map == null) {
refl_method_map = new HashMap();
for (int i = 0; i < operations.length; i++) {
refl_method_map.put(operations[i].getReflectedMethod(), operations[i]);
}
}
return (MethodDescriptor) refl_method_map.get(refl_method);
}
RemoteDescriptor(Class type, TypeRepository repository) {
super(type, repository);
}
public MethodDescriptor[] getMethods() {
if (operations == null) {
init_methods();
}
return operations;
}
public synchronized void init_methods() {
if (operations != null) {
return;
}
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
init_methods0();
return null;
}
});
}
private void init_methods0() {
ArrayList method_list = new ArrayList();
// first step is to build the helpers for any super classes
Class[] supers = type.getInterfaces();
super_descriptors = new ArrayList();
Map all_methods = new HashMap();
Map lower_case_names = new HashMap();
for (int i = 0; i < supers.length; i++) {
Class iface = supers[i];
if (!REMOTE_CLASS.equals(iface) && !OBJECT_CLASS.equals(iface)
&& REMOTE_CLASS.isAssignableFrom(iface)
&& iface.isInterface()) {
RemoteDescriptor superHelper = (RemoteDescriptor)repo.getDescriptor(iface);
super_descriptors.add(superHelper);
MethodDescriptor[] superOps = superHelper.getMethods();
for (int j = 0; j < superOps.length; j++) {
MethodDescriptor op = superOps[j];
method_list.add(op);
addMethodOverloading(all_methods, op.getReflectedMethod());
addMethodCaseSensitive(lower_case_names, op.getReflectedMethod());
}
}
}
// next, build the method helpers for this class
Method[] methods = getLocalMethods();
// register methods
for (int i = 0; i < methods.length; i++) {
addMethodOverloading(all_methods, methods[i]);
addMethodCaseSensitive(lower_case_names, methods[i]);
}
Set overloaded_names = new HashSet();
Iterator it = all_methods.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String mname = (String) entry.getKey();
Set s = (Set) entry.getValue();
if (s.size() > 1) {
overloaded_names.add(mname);
}
}
for (int i = 0; i < methods.length; i++) {
MethodDescriptor op = new MethodDescriptor(methods[i], repo);
String mname = op.java_name;
// is there another method that differs only in case?
Set same_case_names = (Set) lower_case_names.get(mname.toLowerCase());
if (same_case_names.size() > 1) {
op.setCaseSensitive(true);
}
// is this method overloaded?
Set overload_names = (Set) all_methods.get(mname);
if (overload_names.size() > 1) {
op.setOverloaded(true);
}
op.init();
method_list.add(op);
}
// init method map...
method_map = new HashMap();
for (int i = 0; i < method_list.size(); i++) {
MethodDescriptor desc = (MethodDescriptor) method_list.get(i);
logger.finer("Adding method " + desc.java_name + " to method map under " + desc.getIDLName());
method_map.put(desc.getIDLName(), desc);
}
//
// initialize "operations" from the values of the map, such
// that repeat methods are eliminated.
//
operations = (MethodDescriptor[]) method_map.values().toArray(
new MethodDescriptor[0]);
debugMethodMap();
}
private void addMethodOverloading(Map map, Method m) {
String mname = m.getName();
Set entry = (Set) map.get(mname);
if (entry == null) {
entry = new HashSet();
map.put(mname, entry);
}
entry.add(createMethodSelector(m));
}
Method[] getLocalMethods() {
ArrayList result = new ArrayList();
addNonRemoteInterfaceMethods(type, result);
Method[] out = new Method[result.size()];
result.toArray(out);
return out;
}
void addNonRemoteInterfaceMethods(Class clz, ArrayList result) {
Method[] methods;
try {
methods = clz.getDeclaredMethods();
} catch (NoClassDefFoundError e) {
ClassLoader clzClassLoader = clz.getClassLoader();
logger.log(Level.FINER, "cannot find class " + e.getMessage() + " from "
+ clz.getName() + " (classloader " + clzClassLoader + "): "
+ e.getMessage(), e);
throw e;
}
for (int j = 0; j < methods.length; j++) {
// since this is a remote interface, we need to add everything
result.add(methods[j]);
}
Class[] ifaces = clz.getInterfaces();
for (int i = 0; i < ifaces.length; i++) {
if (!REMOTE_CLASS.isAssignableFrom(ifaces[i])) {
addNonRemoteInterfaceMethods(ifaces[i], result);
}
}
}
boolean isRemoteMethod(Method m) {
Class[] ex = m.getExceptionTypes();
for (int i = 0; i < ex.length; i++) {
if (REMOTE_EXCEPTION.isAssignableFrom(ex[i]))
return true;
}
return false;
}
private static String createMethodSelector(java.lang.reflect.Method m) {
StringBuffer sb = new StringBuffer(m.getName());
sb.append('(');
Class[] parameterTypes = m.getParameterTypes();
for (int n = 0; n < parameterTypes.length; n++) {
sb.append(parameterTypes[n].getName());
if (n < parameterTypes.length - 1) {
sb.append(", ");
}
}
sb.append(')');
return sb.toString().intern();
}
private void addMethodCaseSensitive(Map map, Method m) {
String mname = m.getName();
String lowname = mname.toLowerCase();
Set entry = (Set) map.get(lowname);
if (entry == null) {
entry = new HashSet();
map.put(lowname, entry);
}
entry.add(mname);
}
private void collect_interfaces(Set s, Class c) {
if (c.isInterface() && !REMOTE_CLASS.equals(c))
s.add(c);
Class sup = c.getSuperclass();
if (sup != null && !OBJECT_CLASS.equals(sup)) {
collect_interfaces(s, sup);
}
Class[] supers = c.getInterfaces();
for (int i = 0; i < supers.length; i++) {
Class iface = supers[i];
if (!REMOTE_CLASS.equals(iface)
&& REMOTE_CLASS.isAssignableFrom(iface)) {
collect_interfaces(s, iface);
}
}
}
protected Class[] collect_remote_interfaces(Class c) {
if (remote_interfaces != null)
return remote_interfaces;
Set s = new TreeSet(new Comparator() {
public int compare(Object o1, Object o2) {
Class c1 = (Class) o1;
Class c2 = (Class) o2;
if (c1.equals(c2))
return 0;
if (c1.isAssignableFrom(c2)) {
// c2 is more specific (so it should come first)
return 1;
} else if (c2.isAssignableFrom(c1)) {
// c1 is more specific (so it should come first)
return -1;
} else // they are unrelated
{
// just define some consistent order...
return c1.getName().compareTo(c2.getName());
}
}
});
collect_interfaces(s, c);
remote_interfaces = new Class[s.size()];
s.toArray(remote_interfaces);
return remote_interfaces;
}
/** Read an instance of this value from a CDR stream */
@Override
public Object read(InputStream in) {
return PortableRemoteObject.narrow(in.read_Object(),
type);
}
/** Write an instance of this value to a CDR stream */
@Override
public void write(OutputStream out, Object val) {
javax.rmi.CORBA.Util.writeRemoteObject(out, val);
}
@Override
protected final TypeCode genTypeCode() {
ORB orb = ORB.init();
return orb.create_interface_tc(getRepositoryID(), type.getName());
}
@Override
void writeMarshalValue(PrintWriter pw, String outName,
String paramName) {
pw.print("javax.rmi.CORBA.Util.writeRemoteObject(");
pw.print(outName);
pw.print(',');
pw.print(paramName);
pw.print(')');
}
@Override
void writeUnmarshalValue(PrintWriter pw, String inName) {
pw.print('(');
pw.print(type.getName());
pw.print(')');
pw.print(PortableRemoteObject.class.getName());
pw.print(".narrow(");
pw.print(inName);
pw.print('.');
pw.print("read_Object(),");
pw.print(type.getName());
pw.print(".class)");
}
static String classNameFromStub(String name) {
if (name.startsWith("org.omg.stub."))
name = name.substring("org.omg.stub.".length());
// strip xx._X_Stub -> xx.X
int idx = name.lastIndexOf('.');
if (name.charAt(idx + 1) == '_' && name.endsWith("_Stub")) {
if (idx == -1) {
return name.substring(1, name.length() - 5);
} else {
return name.substring(0, idx + 1) /* package. */
+ name.substring(idx + 2, name.length() - 5);
}
}
return null;
}
static String stubClassName(Class c) {
String cname = c.getName();
String pkgname = null;
int idx = cname.lastIndexOf('.');
if (idx == -1) {
pkgname = "org.omg.stub";
} else {
pkgname = "org.omg.stub." + cname.substring(0, idx);
}
String cplain = cname.substring(idx + 1);
return pkgname + "._" + cplain + "_Stub";
}
void writeStubClass(PrintWriter pw) {
Class c = type;
String cname = c.getName();
String fullname = stubClassName(c);
//String stubname = fullname.substring(fullname.lastIndexOf('.') + 1);
String pkgname = fullname.substring(0, fullname.lastIndexOf('.'));
String cplain = cname.substring(cname.lastIndexOf('.') + 1);
pw.println("/** ");
pw.println(" * RMI/IIOP stub for " + cname);
pw.println(" * Generated using Apache Yoko stub generator.");
pw.println(" */");
pw.println("package " + pkgname + ";\n");
pw.println("public class _" + cplain + "_Stub");
pw.println("\textends javax.rmi.CORBA.Stub");
pw.println("\timplements " + cname);
pw.println("{");
//
// construct String[] _ids;
//
String[] all_interfaces = all_interfaces();
pw.println("\tprivate static final String[] _ids = {");
for (int i = 0; i < all_interfaces.length; i++) {
pw.println("\t\t\"" + all_interfaces[i] + "\",");
}
pw.println("\t};\n");
pw.println("\tpublic String[] _ids() {");
pw.println("\t\treturn _ids;");
pw.println("\t}");
//
// now, construct stub methods
//
MethodDescriptor[] meths = getMethods();
for (int i = 0; i < meths.length; i++) {
meths[i].writeStubMethod(pw);
}
pw.println("}");
}
String getStubClassName() {
Class c = type;
String cname = c.getName();
String pkgname = null;
int idx = cname.lastIndexOf('.');
if (idx == -1) {
pkgname = "org.omg.stub";
} else {
pkgname = "org.omg.stub." + cname.substring(0, idx);
}
String cplain = cname.substring(idx + 1);
return pkgname + "." + "_" + cplain + "_Stub";
}
@Override
void addDependencies(Set classes) {
Class c = type;
if (c == Remote.class || classes.contains(c))
return;
classes.add(c);
if (c.getSuperclass() != null) {
TypeDescriptor desc = repo.getDescriptor(c.getSuperclass());
desc.addDependencies(classes);
}
Class[] ifaces = c.getInterfaces();
for (int i = 0; i < ifaces.length; i++) {
TypeDescriptor desc = repo.getDescriptor(ifaces[i]);
desc.addDependencies(classes);
}
MethodDescriptor[] mths = getMethods();
for (int i = 0; i < mths.length; i++) {
mths[i].addDependencies(classes);
}
}
@Override
boolean copyInStub() {
return false;
}
}