0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: *
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: */
0018:
0019: /**
0020: * @author Vasily Zakharov
0021: * @version $Revision: 1.1.2.3 $
0022: */package org.apache.harmony.rmi.compiler;
0023:
0024: import java.lang.reflect.Method;
0025:
0026: import java.rmi.Remote;
0027: import java.rmi.RemoteException;
0028:
0029: import java.util.Arrays;
0030: import java.util.Iterator;
0031: import java.util.TreeMap;
0032: import java.util.Vector;
0033:
0034: import org.apache.harmony.rmi.common.ClassList;
0035: import org.apache.harmony.rmi.common.RMIHash;
0036: import org.apache.harmony.rmi.common.RMIHashException;
0037: import org.apache.harmony.rmi.common.RMIUtil;
0038: import org.apache.harmony.rmi.internal.nls.Messages;
0039:
0040: /**
0041: * Generates RMI stub code for a particular class.
0042: *
0043: * @author Vasily Zakharov
0044: * @version $Revision: 1.1.2.3 $
0045: */
0046: final class ClassStub implements RmicConstants {
0047:
0048: /**
0049: * Should the stub support v1.1.
0050: */
0051: final boolean v11;
0052:
0053: /**
0054: * Should the stub support v1.2.
0055: */
0056: final boolean v12;
0057:
0058: /**
0059: * Should the stub support both v1.1 and v1.2.
0060: */
0061: final boolean vCompat;
0062:
0063: /**
0064: * Indenter to write source files.
0065: */
0066: Indenter indenter;
0067:
0068: /**
0069: * Name of the class to generate stub for.
0070: */
0071: private final String className;
0072:
0073: /**
0074: * Package of the class to generate stub for.
0075: */
0076: private final String packageName;
0077:
0078: /**
0079: * Stub class name.
0080: */
0081: private final String stubName;
0082:
0083: /**
0084: * Skeleton class name.
0085: */
0086: private final String skelName;
0087:
0088: /**
0089: * List of remote interfaces for the class.
0090: */
0091: private final Class[] interfaces;
0092:
0093: /**
0094: * List of remote interfaces methods for the class.
0095: */
0096: private final Vector methods;
0097:
0098: /**
0099: * <code>true</code> if methods exist in {@link #methods} vector.
0100: */
0101: private final boolean methodsExist;
0102:
0103: /**
0104: * Class interface hash.
0105: */
0106: private final long interfaceHash;
0107:
0108: /**
0109: * Creates <code>ClassStub</code> instance for specified version and class.
0110: *
0111: * @param version
0112: * Version of the stub to create.
0113: *
0114: * @param className
0115: * Name of the class to load.
0116: *
0117: * @throws RMICompilerException
0118: * If version number is incorrect or some other error occurs.
0119: */
0120: ClassStub(int version, String className)
0121: throws RMICompilerException {
0122: this (version, getClass(className));
0123: }
0124:
0125: /**
0126: * Creates <code>ClassStub</code> instance for specified version and class.
0127: *
0128: * @param version
0129: * Version of the stub to create.
0130: *
0131: * @param cls
0132: * Class to load.
0133: *
0134: * @throws RMICompilerException
0135: * If version number is incorrect or some other error occurs.
0136: */
0137: ClassStub(int version, Class cls) throws RMICompilerException {
0138: // Check version.
0139: if ((version < MIN_VERSION) || (version > MAX_VERSION)) {
0140: // rmi.50=Incorrect version specified.
0141: throw new RMICompilerException(Messages.getString("rmi.50")); //$NON-NLS-1$
0142: }
0143:
0144: // Set appropriate version flags.
0145: switch (version) {
0146: case VERSION_V11:
0147: v11 = true;
0148: v12 = false;
0149: vCompat = false;
0150: break;
0151: case VERSION_V12:
0152: v11 = false;
0153: v12 = true;
0154: vCompat = false;
0155: break;
0156: case VERSION_VCOMPAT:
0157: v11 = true;
0158: v12 = true;
0159: vCompat = true;
0160: break;
0161: default:
0162: // rmi.51=Version currently unsupported.
0163: throw new RMICompilerException(Messages.getString("rmi.51")); //$NON-NLS-1$
0164: }
0165:
0166: className = RMIUtil.getCanonicalName(cls);
0167:
0168: // Check if the specified class is interface.
0169: if (cls.isInterface()) {
0170: // rmi.52=Class {0} is interface, and so does not need an RMI stub.
0171: throw new RMICompilerException(Messages.getString(
0172: "rmi.52", className)); //$NON-NLS-1$
0173: }
0174:
0175: // Check if the specified class is remote.
0176: if (!Remote.class.isAssignableFrom(cls)) {
0177: // rmi.53=Class {0} does not implement a remote interface, and so does not need an RMI stub.
0178: throw new RMICompilerException(Messages.getString(
0179: "rmi.53", className)); //$NON-NLS-1$
0180: }
0181:
0182: // Check if the specified class implements any remote interfaces.
0183: if (!new ClassList(cls.getInterfaces()).contains(Remote.class)) {
0184: // rmi.54=Class {0} does not directly implement a remote interface, and so does not need an RMI stub.
0185: throw new RMICompilerException(Messages.getString(
0186: "rmi.54", className)); //$NON-NLS-1$
0187: }
0188:
0189: // Initialize class variables.
0190: packageName = RMIUtil.getPackageName(cls);
0191:
0192: String shortClassName = RMIUtil.getShortName(cls);
0193: stubName = shortClassName + stubSuffix;
0194: skelName = shortClassName + skelSuffix;
0195:
0196: try {
0197: interfaces = RMIUtil.getRemoteInterfaces(cls);
0198: } catch (IllegalArgumentException e) {
0199: throw new RMICompilerException(e);
0200: }
0201:
0202: methods = new Vector();
0203:
0204: // Create temporal method stubs table (sorted, no duplicates).
0205: TreeMap methodMap = new TreeMap();
0206:
0207: // Extract remote methods from remote interfaces of cls and ancestors.
0208: for (int i = 0; i < interfaces.length; i++) {
0209: // Add public methods from this interface to the map.
0210: RMIHash.getSortedMethodMap(methodMap, interfaces[i]
0211: .getMethods());
0212: }
0213:
0214: if (v11) {
0215: try {
0216: // Calculate interface hash value for the set of methods found.
0217: interfaceHash = RMIHash.getInterfaceHash(methodMap);
0218: } catch (RMIHashException e) {
0219: throw new RMICompilerException(e.getMessage(), e
0220: .getCause());
0221: }
0222: } else {
0223: interfaceHash = (-1L);
0224: }
0225:
0226: // Put the complete MethodStub objects to methods list.
0227: int n = 0;
0228: for (Iterator i = methodMap.values().iterator(); i.hasNext();) {
0229: methods.add(new MethodStub((Method) i.next(), n++));
0230: }
0231:
0232: methodsExist = (n > 0);
0233: }
0234:
0235: /**
0236: * Returns the class object for the specified class name.
0237: *
0238: * @param className
0239: * Class name.
0240: *
0241: * @return Class object for the specified class name.
0242: *
0243: * @throws RMICompilerException
0244: * If class is not found.
0245: */
0246: private static Class getClass(String className)
0247: throws RMICompilerException {
0248: try {
0249: return Class.forName(className);
0250: } catch (ClassNotFoundException e) {
0251: // rmi.55=Class not found: {0}
0252: throw new RMICompilerException(Messages.getString(
0253: "rmi.55", className)); //$NON-NLS-1$
0254: }
0255: }
0256:
0257: /**
0258: * Returns stub class name for loaded class.
0259: *
0260: * @return Stub class name.
0261: */
0262: String getStubClassName() {
0263: return stubName;
0264: }
0265:
0266: /**
0267: * Returns skeleton class name for loaded class.
0268: *
0269: * @return Skeleton class name.
0270: */
0271: String getSkeletonClassName() {
0272: return skelName;
0273: }
0274:
0275: /**
0276: * Returns stub source code for the loaded class (v1.1/v1.2).
0277: *
0278: * @return String containing the stub source code for loaded class.
0279: */
0280: String getStubSource() {
0281: indenter = new Indenter();
0282:
0283: return (getStubHeader("stub") + getPackageStatement() + EOLN //$NON-NLS-1$
0284: + getStubClassDeclaration()
0285: + indenter.hIncrease()
0286: + (v12 ? (EOLN + getSerialVersionUID()) : "") //$NON-NLS-1$
0287: + (v11 ? (EOLN + getInterfaceHash() + (methodsExist ? ((vCompat ? EOLN
0288: + getNewInvoke()
0289: : "") //$NON-NLS-1$
0290: + EOLN + getOperationsArrayDeclaration())
0291: : "")) : "") //$NON-NLS-1$ //$NON-NLS-2$
0292: + ((v12 && methodsExist) ? (EOLN
0293: + getMethodVariablesDeclaration() + EOLN + getStaticInitializationBlock())
0294: : "") + EOLN //$NON-NLS-1$
0295: + getStubConstructors()
0296: + (methodsExist ? getMethodImplementations() : "") //$NON-NLS-1$
0297: + indenter.decrease() + '}' + EOLN + indenter
0298: .assertEmpty());
0299: }
0300:
0301: /**
0302: * Returns skeleton source code for the loaded class (v1.1).
0303: *
0304: * @return String containing the skeleton source code for loaded class.
0305: */
0306: String getSkeletonSource() {
0307: indenter = new Indenter();
0308:
0309: return (getStubHeader("skeleton") + getPackageStatement() + EOLN //$NON-NLS-1$
0310: + getSkeletonClassDeclaration() + indenter.hIncrease()
0311: + EOLN + getInterfaceHash() + EOLN
0312: + getOperationsArrayDeclaration() + EOLN
0313: + getOperationsMethod() + EOLN + getDispatchMethod()
0314: + indenter.decrease() + '}' + EOLN + indenter
0315: .assertEmpty());
0316: }
0317:
0318: /**
0319: * Returns stub source code header
0320: * (Stub/Skeleton v1.1/v1.2/vCompat).
0321: *
0322: * @param type
0323: * Header type, <code>"stub"</code> or <code>"skeleton"</code>.
0324: *
0325: * @return Stub/skeleton header.
0326: */
0327: private String getStubHeader(String type) {
0328: return ("/*" + EOLN + " * RMI " + type + " class" + EOLN //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0329: + " * for class " + className + EOLN //$NON-NLS-1$
0330: + " * Compatible with stub protocol version " //$NON-NLS-1$
0331: + (v11 ? "1.1" : "") + (vCompat ? "/" : "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
0332: + (v12 ? "1.2" : "") + EOLN + " *" + EOLN //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0333: + " * Generated by DRL RMI Compiler (rmic)." + EOLN //$NON-NLS-1$
0334: + " *" + EOLN + " * DO NOT EDIT!!!" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
0335: + " * Contents subject to change without notice!" + EOLN //$NON-NLS-1$
0336: + " */" + EOLN); //$NON-NLS-1$
0337: }
0338:
0339: /**
0340: * Returns <code>package</code> statement
0341: * (Stub/Skeleton v1.1/v1.2/vCompat).
0342: *
0343: * @return <code>package</code> statement for stub/skeleton class.
0344: */
0345: private String getPackageStatement() {
0346: return ((packageName == null) ? "" //$NON-NLS-1$
0347: : ("package " + packageName + ';' + EOLN + EOLN)); //$NON-NLS-1$
0348: }
0349:
0350: /**
0351: * Returns stub class declaration
0352: * (Stub v1.1/v1.2/vCompat).
0353: *
0354: * @return Stub class declaration statement.
0355: */
0356: private String getStubClassDeclaration() {
0357: StringBuffer buffer = new StringBuffer("public final class " //$NON-NLS-1$
0358: + stubName
0359: + " extends java.rmi.server.RemoteStub" + EOLN //$NON-NLS-1$
0360: + indenter.tIncrease(2) + "implements "); //$NON-NLS-1$
0361:
0362: // Add implemented interfaces list.
0363: for (int i = 0; i < interfaces.length; i++) {
0364: buffer
0365: .append(((i > 0) ? ", " : "") + interfaces[i].getName()); //$NON-NLS-1$ //$NON-NLS-2$
0366: }
0367:
0368: buffer.append(" {" + EOLN); //$NON-NLS-1$
0369:
0370: return buffer.toString();
0371: }
0372:
0373: /**
0374: * Returns skeleton class declaration
0375: * (Skeleton v1.1/vCompat).
0376: *
0377: * @return Skeleton class declaration statement.
0378: */
0379: private String getSkeletonClassDeclaration() {
0380: return ("public final class " + skelName //$NON-NLS-1$
0381: + " implements java.rmi.server.Skeleton {" + EOLN); //$NON-NLS-1$
0382: }
0383:
0384: /**
0385: * Returns <code>serialVersionUID</code> declaration
0386: * (Stub v1.2/vCompat).
0387: *
0388: * @return <code>serialVersionUID</code> declaration statement.
0389: */
0390: private String getSerialVersionUID() {
0391: return (indenter.indent()
0392: + "private static final long serialVersionUID = 2;" + EOLN); //$NON-NLS-1$
0393: }
0394:
0395: /**
0396: * Returns <code>interfaceHash</code> declaration
0397: * (Stub/Skeleton v1.1/vCompat).
0398: *
0399: * @return <code>interfaceHash</code> declaration statement.
0400: */
0401: private String getInterfaceHash() {
0402: return (indenter.indent() + "private static final long " //$NON-NLS-1$
0403: + interfaceHashVarName + " = " + interfaceHash + "L;" + EOLN); //$NON-NLS-1$ //$NON-NLS-2$
0404: }
0405:
0406: /**
0407: * Returns <code>useNewInvoke</code> declaration
0408: * (Stub vCompat).
0409: *
0410: * @return <code>useNewInvoke</code> declaration statement.
0411: */
0412: private String getNewInvoke() {
0413: return (indenter.indent()
0414: + "private static boolean " + useNewInvoke + ';' + EOLN); //$NON-NLS-1$
0415: }
0416:
0417: /**
0418: * Returns <code>operations</code> array declaration
0419: * (Stub/Skeleton v1.1/vCompat).
0420: *
0421: * @return <code>operations</code> array declaration statement.
0422: */
0423: private String getOperationsArrayDeclaration() {
0424: StringBuffer buffer = new StringBuffer(indenter.indent()
0425: + "private static final java.rmi.server.Operation[]" //$NON-NLS-1$
0426: + " operations = {"); //$NON-NLS-1$
0427:
0428: if (methodsExist) {
0429: buffer.append(EOLN + indenter.hIncrease());
0430:
0431: for (Iterator i = methods.iterator(); i.hasNext();) {
0432: buffer.append(((MethodStub) i.next())
0433: .getOpsArrayElement()
0434: + (i.hasNext() ? "," : "") + EOLN); //$NON-NLS-1$ //$NON-NLS-2$
0435: }
0436:
0437: buffer.append(indenter.decrease());
0438: }
0439:
0440: buffer.append("};" + EOLN); //$NON-NLS-1$
0441:
0442: return buffer.toString();
0443: }
0444:
0445: /**
0446: * Returns <code>getOperations()</code> method declaration
0447: * (Skeleton v1.1/vCompat).
0448: *
0449: * @return <code>getOperations()</code> declaration statement.
0450: */
0451: private String getOperationsMethod() {
0452: return (indenter.indent()
0453: + "public java.rmi.server.Operation[] getOperations() {" + EOLN //$NON-NLS-1$
0454: + indenter.tIncrease()
0455: + "return (java.rmi.server.Operation[]) operations.clone();" //$NON-NLS-1$
0456: + EOLN + indenter.indent() + '}' + EOLN);
0457: }
0458:
0459: /**
0460: * Returns <code>dispatch()</code> method declaration
0461: * (Skeleton v1.1/vCompat).
0462: *
0463: * @return <code>dispatch()</code> method declaration statement.
0464: */
0465: private String getDispatchMethod() {
0466: StringBuffer buffer = new StringBuffer(
0467: indenter.indent()
0468: + "public void dispatch(java.rmi.Remote obj, " //$NON-NLS-1$
0469: + "java.rmi.server.RemoteCall call, int opnum, long hash) " //$NON-NLS-1$
0470: + "throws java.lang.Exception {" + EOLN + indenter.hIncrease()); //$NON-NLS-1$
0471:
0472: if (vCompat) {
0473: buffer.append(indenter.indent() + "if (opnum < 0) {" + EOLN //$NON-NLS-1$
0474: + indenter.increase());
0475:
0476: if (methodsExist) {
0477: for (Iterator i = methods.iterator(); i.hasNext();) {
0478: buffer.append(((MethodStub) i.next())
0479: .getHashCheck());
0480: }
0481: buffer.append('{' + EOLN + indenter.increase());
0482: }
0483:
0484: buffer
0485: .append("throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
0486: + "\"Invalid method hash: \" + hash);" + EOLN //$NON-NLS-1$
0487: + indenter.decrease()
0488: + '}'
0489: + EOLN
0490: + (methodsExist ? (indenter.tDecrease() + "} else {") : "") //$NON-NLS-1$ //$NON-NLS-2$
0491: + EOLN);
0492: }
0493:
0494: buffer
0495: .append(indenter.indent()
0496: + "if (hash != interfaceHash) {" + EOLN //$NON-NLS-1$
0497: + indenter.increase()
0498: + "throw new java.rmi.server.SkeletonMismatchException(" + EOLN //$NON-NLS-1$
0499: + indenter.tIncrease(2)
0500: + "\"Interface hash mismatch, expected: \" + interfaceHash" //$NON-NLS-1$
0501: + " + \", received: \" + hash);" + EOLN //$NON-NLS-1$
0502: + indenter.decrease()
0503: + '}'
0504: + EOLN
0505: + ((vCompat && methodsExist) ? (indenter
0506: .decrease() + '}' + EOLN) : "") + EOLN //$NON-NLS-1$
0507: + indenter.indent() + className + " server = " //$NON-NLS-1$
0508: + '(' + className + ") obj;" + EOLN + EOLN); //$NON-NLS-1$
0509:
0510: if (methodsExist) {
0511: buffer
0512: .append(indenter.indent()
0513: + "switch (opnum) {" + EOLN); //$NON-NLS-1$
0514:
0515: for (Iterator i = methods.iterator(); i.hasNext();) {
0516: buffer.append(EOLN
0517: + ((MethodStub) i.next()).getDispatchCase());
0518: }
0519:
0520: buffer.append(EOLN + indenter.indent() + "default:" + EOLN); //$NON-NLS-1$
0521:
0522: indenter.increase();
0523: }
0524:
0525: buffer.append(indenter.indent()
0526: + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
0527: + "\"Invalid method number: \" + opnum);" + EOLN //$NON-NLS-1$
0528: + (methodsExist ? (indenter.decrease() + '}' + EOLN)
0529: : "") //$NON-NLS-1$
0530: + indenter.decrease() + '}' + EOLN);
0531:
0532: return buffer.toString();
0533: }
0534:
0535: /**
0536: * Returns method variables declaration block
0537: * (Stub v1.2/vCompat).
0538: *
0539: * @return Variables declaration block.
0540: */
0541: private String getMethodVariablesDeclaration() {
0542: StringBuffer buffer = new StringBuffer();
0543:
0544: for (Iterator i = methods.iterator(); i.hasNext();) {
0545: buffer.append(((MethodStub) i.next()).getVariableDecl());
0546: }
0547:
0548: return buffer.toString();
0549: }
0550:
0551: /**
0552: * Creates static initialization block
0553: * (Stub v1.2/vCompat).
0554: *
0555: * @return Static initialization declaration block.
0556: */
0557: private String getStaticInitializationBlock() {
0558: StringBuffer buffer = new StringBuffer(
0559: indenter.indent()
0560: + "static {" + EOLN + indenter.increase() + "try {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
0561: + indenter.hIncrease());
0562:
0563: if (vCompat) {
0564: buffer
0565: .append(indenter.indent()
0566: + "java.rmi.server.RemoteRef.class.getMethod(\"invoke\", " //$NON-NLS-1$
0567: + "new java.lang.Class[] {java.rmi.Remote.class, " //$NON-NLS-1$
0568: + "java.lang.reflect.Method.class, java.lang.Object[].class" //$NON-NLS-1$
0569: + ", long.class});" + EOLN + EOLN); //$NON-NLS-1$
0570: }
0571:
0572: for (Iterator i = methods.iterator(); i.hasNext();) {
0573: buffer.append(((MethodStub) i.next()).getVariableInit());
0574: }
0575:
0576: buffer
0577: .append((vCompat ? (EOLN + indenter.indent()
0578: + useNewInvoke + " = true;" + EOLN) : "") + indenter.decrease() //$NON-NLS-1$ //$NON-NLS-2$
0579: + "} catch (java.lang.NoSuchMethodException e) {" + EOLN //$NON-NLS-1$
0580: + indenter.increase()
0581: + (vCompat ? (useNewInvoke + " = false;") //$NON-NLS-1$
0582: : ("throw new java.lang.NoSuchMethodError(" + EOLN //$NON-NLS-1$
0583: + indenter.tIncrease(2)
0584: + "\"Stub class initialization failed: " //$NON-NLS-1$
0585: + ((packageName != null) ? (packageName + '.')
0586: : "") //$NON-NLS-1$
0587: + stubName + "\");")) + EOLN //$NON-NLS-1$
0588: + indenter.decrease()
0589: + '}'
0590: + EOLN
0591: + indenter.decrease() + '}' + EOLN);
0592:
0593: return buffer.toString();
0594: }
0595:
0596: /**
0597: * Returns stub constructors
0598: * (Stub v1.1/v1.2/vCompat).
0599: *
0600: * @return Stub constructors code.
0601: */
0602: private String getStubConstructors() {
0603: StringBuffer buffer = new StringBuffer();
0604:
0605: if (v11) {
0606: buffer
0607: .append(indenter.indent()
0608: + "public " + stubName //$NON-NLS-1$
0609: + "() {" + EOLN + indenter.tIncrease() + "super();" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
0610: + indenter.indent() + '}' + EOLN + EOLN);
0611: }
0612:
0613: buffer.append(indenter.indent() + "public " + stubName //$NON-NLS-1$
0614: + "(java.rmi.server.RemoteRef ref) {" + EOLN //$NON-NLS-1$
0615: + indenter.tIncrease() + "super(ref);" + EOLN //$NON-NLS-1$
0616: + indenter.indent() + '}' + EOLN);
0617:
0618: return buffer.toString();
0619: }
0620:
0621: /**
0622: * Returns remote methods implementation
0623: * (Stub v1.1/v1.2/vCompat).
0624: *
0625: * @return Stub method implementations code.
0626: */
0627: private String getMethodImplementations() {
0628: StringBuffer buffer = new StringBuffer();
0629:
0630: for (Iterator i = methods.iterator(); i.hasNext();) {
0631: buffer.append(EOLN + ((MethodStub) i.next()).getStubImpl());
0632: }
0633:
0634: return buffer.toString();
0635: }
0636:
0637: /**
0638: * Generates RMI stub code for a particular method.
0639: */
0640: private final class MethodStub {
0641:
0642: /**
0643: * The method name (via {@link Method#getName()}).
0644: */
0645: private final String name;
0646:
0647: /**
0648: * The name of the interface declaring this method.
0649: */
0650: private final String interfaceName;
0651:
0652: /**
0653: * The method parameters (via {@link Method#getParameterTypes()}).
0654: */
0655: private final Class[] parameters;
0656:
0657: /**
0658: * The method parameters class names.
0659: */
0660: private final String[] paramClassNames;
0661:
0662: /**
0663: * The method parameters names.
0664: */
0665: private final String[] paramNames;
0666:
0667: /**
0668: * Number of parameters for this method.
0669: */
0670: private final int numParams;
0671:
0672: /**
0673: * The method return type (via {@link Method#getReturnType()}).
0674: */
0675: private final Class retType;
0676:
0677: /**
0678: * The method return type name.
0679: */
0680: private final String retTypeName;
0681:
0682: /**
0683: * Exceptions that this method throws.
0684: */
0685: private final Vector exceptions;
0686:
0687: /**
0688: * Exceptions that must be caught in method stub.
0689: */
0690: private final ClassList catches;
0691:
0692: /**
0693: * The method long signature
0694: * (via {@link RMIUtil#getLongMethodSignature(Method)
0695: * getLongMethodSignature()}).
0696: */
0697: private final String longSign;
0698:
0699: /**
0700: * The method short signature
0701: * (via {@link RMIUtil#getShortMethodSignature(Method)
0702: * getShortMethodSignature()}).
0703: */
0704: private final String shortSign;
0705:
0706: /**
0707: * The method hash (via {@link RMIHash#getMethodHash(Method)
0708: * getMethodHash()}).
0709: */
0710: private final long hash;
0711:
0712: /**
0713: * The method number in the stub.
0714: */
0715: private final int number;
0716:
0717: /**
0718: * Name of the variable containing this method in the stub
0719: * (<code>$method_<em>name</em>_<em>number</em></code>).
0720: */
0721: private final String varName;
0722:
0723: /**
0724: * Whether this method throws {@link Exception}.
0725: */
0726: private final boolean throwsException;
0727:
0728: /**
0729: * Creates method stub instance.
0730: *
0731: * @param method
0732: * Method to process.
0733: *
0734: * @param number
0735: * Method number in sorted methods table.
0736: *
0737: * @throws RMICompilerException
0738: * If some error occurs.
0739: */
0740: MethodStub(Method method, int number)
0741: throws RMICompilerException {
0742: this .name = method.getName();
0743: this .interfaceName = method.getDeclaringClass().getName();
0744: this .parameters = method.getParameterTypes();
0745: this .numParams = parameters.length;
0746: this .retType = method.getReturnType();
0747: this .retTypeName = RMIUtil.getCanonicalName(retType);
0748: this .longSign = RMIUtil.getLongMethodSignature(method);
0749: this .shortSign = RMIUtil.getShortMethodSignature(method);
0750: this .number = number;
0751: this .varName = (methodVarPrefix + name + '_' + number);
0752:
0753: try {
0754: this .hash = RMIHash.getMethodHash(method);
0755: } catch (RMIHashException e) {
0756: throw new RMICompilerException(e.getMessage(), e);
0757: }
0758:
0759: // Create parameter names array.
0760: paramClassNames = new String[numParams];
0761: paramNames = new String[numParams];
0762: for (int i = 0; i < numParams; i++) {
0763: Class parameter = parameters[i];
0764: paramClassNames[i] = RMIUtil
0765: .getCanonicalName(parameter);
0766: paramNames[i] = RmicUtil.getParameterName(parameter,
0767: i + 1);
0768: }
0769:
0770: // Create list of exceptions declared thrown.
0771: Class[] exceptionsArray = method.getExceptionTypes();
0772: exceptions = new Vector(exceptionsArray.length);
0773: exceptions.addAll(Arrays.asList(exceptionsArray));
0774:
0775: // Create list of exceptions to be caught.
0776: catches = new ClassList(true);
0777:
0778: // Add standard exceptions to make sure they are first in the list.
0779: catches.add(RuntimeException.class);
0780: catches.add(RemoteException.class);
0781:
0782: // Add declared thrown exceptions.
0783: catches.addAll(exceptions);
0784:
0785: throwsException = catches.contains(Exception.class);
0786: }
0787:
0788: /**
0789: * Returns <code>operations</code> array element for this method
0790: * (Stub/Skeleton v1.1/vCompat)
0791: *
0792: * @return <code>operations</code> array element for this method.
0793: */
0794: String getOpsArrayElement() {
0795: return (indenter.indent()
0796: + "new java.rmi.server.Operation(\"" + longSign + "\")"); //$NON-NLS-1$ //$NON-NLS-2$
0797: }
0798:
0799: /**
0800: * Returns hash checking code for this method
0801: * (Skeleton vCompat).
0802: *
0803: * @return Hash checking code for this method..
0804: */
0805: String getHashCheck() {
0806: return ("if (hash == " + hash + "L) {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
0807: + indenter.tIncrease()
0808: + "opnum = " + number + ';' + EOLN //$NON-NLS-1$
0809: + indenter.indent() + "} else "); //$NON-NLS-1$
0810: }
0811:
0812: /**
0813: * Returns <code>dispatch()</code> method case for this method
0814: * (Skeleton v1.1/vCompat).
0815: *
0816: * @return <code>dispatch()</code> method case for this method.
0817: */
0818: String getDispatchCase() {
0819: StringBuffer buffer = new StringBuffer(
0820: indenter.indent()
0821: + "case " + number + ": { // " + shortSign + EOLN + EOLN //$NON-NLS-1$ //$NON-NLS-2$
0822: + indenter.hIncrease());
0823:
0824: if (numParams > 0) {
0825: // Add parameters declaration.
0826: for (int i = 0; i < numParams; i++) {
0827: buffer.append(indenter.indent()
0828: + paramClassNames[i] + ' ' + paramNames[i]
0829: + ';' + EOLN);
0830: }
0831:
0832: // Access input stream.
0833: buffer.append(EOLN + indenter.indent()
0834: + "try {" + EOLN //$NON-NLS-1$
0835: + indenter.increase()
0836: + "java.io.ObjectInput " //$NON-NLS-1$
0837: + inputStreamName
0838: + " = call.getInputStream();" + EOLN); //$NON-NLS-1$
0839:
0840: boolean objectParametersExist = false;
0841:
0842: // Add parameters initialization, read them from the stream.
0843: for (int i = 0; i < numParams; i++) {
0844: buffer.append(indenter.indent()
0845: + paramNames[i]
0846: + " = " //$NON-NLS-1$
0847: + RmicUtil.getReadObjectString(
0848: parameters[i], inputStreamName)
0849: + ';' + EOLN);
0850:
0851: if (!parameters[i].isPrimitive()) {
0852: objectParametersExist = true;
0853: }
0854: }
0855:
0856: // Add catch block.
0857: buffer
0858: .append(indenter.tDecrease()
0859: + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
0860: + indenter.indent()
0861: + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
0862: + "\"Error unmarshalling arguments\", e);" + EOLN //$NON-NLS-1$
0863: + (objectParametersExist ? (indenter
0864: .tDecrease()
0865: + "} catch (java.lang.ClassNotFoundException e) {" //$NON-NLS-1$
0866: + EOLN
0867: + indenter.indent()
0868: + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
0869: + "\"Error unmarshalling arguments\", e);" + EOLN) : "") //$NON-NLS-1$ //$NON-NLS-2$
0870: + indenter.tDecrease()
0871: + "} finally {" + EOLN); //$NON-NLS-1$
0872: }
0873: // Release input stream.
0874: buffer.append(indenter.indent()
0875: + "call.releaseInputStream();" + EOLN); //$NON-NLS-1$
0876:
0877: if (numParams > 0) {
0878: buffer.append(indenter.decrease() + '}' + EOLN);
0879: }
0880:
0881: buffer.append(EOLN
0882: + indenter.indent()
0883: + ((retType != void.class) ? (retTypeName + ' '
0884: + retVarName + " = ") : "") //$NON-NLS-1$ //$NON-NLS-2$
0885: + "server." + name + '('); //$NON-NLS-1$
0886:
0887: for (int i = 0; i < numParams; i++) {
0888: buffer.append(((i > 0) ? ", " : "") + paramNames[i]); //$NON-NLS-1$ //$NON-NLS-2$
0889: }
0890:
0891: buffer
0892: .append(");" + EOLN + EOLN + indenter.indent() + "try {" //$NON-NLS-1$ //$NON-NLS-2$
0893: + EOLN
0894: + indenter.increase()
0895: + ((retType != void.class) ? ("java.io.ObjectOutput " + outputStreamName + " = ") : "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0896: + "call.getResultStream(true);" + EOLN //$NON-NLS-1$
0897: + ((retType != void.class) ? (indenter
0898: .indent()
0899: + RmicUtil.getWriteObjectString(
0900: retType, retVarName,
0901: outputStreamName) + ';' + EOLN)
0902: : "") //$NON-NLS-1$
0903: + indenter.decrease()
0904: + "} catch (java.io.IOException e) {" //$NON-NLS-1$
0905: + EOLN
0906: + indenter.tIncrease()
0907: + "throw new java.rmi.MarshalException(" //$NON-NLS-1$
0908: + "\"Error marshalling return\", e);" + EOLN //$NON-NLS-1$
0909: + indenter.indent() + '}' + EOLN + EOLN
0910: + indenter.indent() + "break;" + EOLN //$NON-NLS-1$
0911: + indenter.decrease() + '}' + EOLN);
0912:
0913: return buffer.toString();
0914: }
0915:
0916: /**
0917: * Returns source code for the method variable declaration
0918: * (Stub v1.2/vCompat).
0919: *
0920: * @return Method variable declaration.
0921: */
0922: String getVariableDecl() {
0923: return (indenter.indent()
0924: + "private static java.lang.reflect.Method" //$NON-NLS-1$
0925: + ' ' + varName + ';' + EOLN);
0926: }
0927:
0928: /**
0929: * Returns source code for the method variable initialization
0930: * (Stub v1.2/vCompat).
0931: *
0932: * @return Method variable initialization.
0933: */
0934: String getVariableInit() {
0935: StringBuffer buffer = new StringBuffer(indenter.indent()
0936: + varName
0937: + " = " + interfaceName + ".class.getMethod(\"" //$NON-NLS-1$ //$NON-NLS-2$
0938: + name + "\", new java.lang.Class[] {"); //$NON-NLS-1$
0939:
0940: if (numParams > 0) {
0941: // Write method parameters.
0942: for (int i = 0; i < numParams; i++) {
0943: buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
0944: + paramClassNames[i] + ".class"); //$NON-NLS-1$
0945: }
0946: }
0947:
0948: buffer.append("});" + EOLN); //$NON-NLS-1$
0949:
0950: return buffer.toString();
0951: }
0952:
0953: /**
0954: * Returns stub implementation for this method
0955: * (Stub v1.1/v1.2/vCompat).
0956: *
0957: * @return Stub implementation for this method.
0958: */
0959: String getStubImpl() {
0960: return (getStubImplHeader()
0961: + (vCompat ? (indenter.indent()
0962: + "if (" + useNewInvoke //$NON-NLS-1$
0963: + ") {" + EOLN + indenter.hIncrease()) : "") //$NON-NLS-1$ //$NON-NLS-2$
0964: + (v12 ? getStubImplCodeV12() : "") + (vCompat //$NON-NLS-1$
0965: ? (indenter.tDecrease() + "} else {" + EOLN) : "") //$NON-NLS-1$ //$NON-NLS-2$
0966: + (v11 ? getStubImplCodeV11() : "") //$NON-NLS-1$
0967: + (vCompat ? (indenter.decrease() + '}' + EOLN)
0968: : "") //$NON-NLS-1$
0969: + (throwsException ? "" : (indenter.hDecrease() //$NON-NLS-1$
0970: + getStubImplCatchBlock()))
0971: + indenter.decrease() + '}' + EOLN);
0972: }
0973:
0974: /**
0975: * Returns header for the stub implementation for this method
0976: * (Stub v1.1/v1.2/vCompat).
0977: *
0978: * @return Stub implementation header for this method.
0979: */
0980: private String getStubImplHeader() {
0981: StringBuffer buffer = new StringBuffer(indenter.indent()
0982: + "// Implementation of " + shortSign + EOLN //$NON-NLS-1$
0983: + indenter.indent() + "public " + retTypeName //$NON-NLS-1$
0984: + ' ' + name + '(');
0985:
0986: // Write method parameters.
0987: for (int i = 0; i < numParams; i++) {
0988: buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
0989: + paramClassNames[i] + ' ' + paramNames[i]);
0990: }
0991:
0992: buffer.append(')' + EOLN + indenter.tIncrease(2)
0993: + "throws "); //$NON-NLS-1$
0994:
0995: // Write exceptions declared thrown.
0996: for (Iterator i = exceptions.iterator(); i.hasNext();) {
0997: buffer.append(((Class) i.next()).getName()
0998: + (i.hasNext() ? ", " : "")); //$NON-NLS-1$ //$NON-NLS-2$
0999: }
1000:
1001: buffer.append(" {" + EOLN + indenter.hIncrease() //$NON-NLS-1$
1002: + (throwsException ? "" : (indenter.indent() //$NON-NLS-1$
1003: + "try {" + EOLN + indenter.hIncrease()))); //$NON-NLS-1$
1004:
1005: return buffer.toString();
1006: }
1007:
1008: /**
1009: * Returns the stub implementation code section source for this method
1010: * (Stub v1.1/vCompat).
1011: *
1012: * @return Stub implementation code for this method.
1013: */
1014: private String getStubImplCodeV11() {
1015: StringBuffer buffer = new StringBuffer(
1016: indenter.indent()
1017: + "java.rmi.server.RemoteCall call = " //$NON-NLS-1$
1018: + "ref.newCall((java.rmi.server.RemoteObject) this, " //$NON-NLS-1$
1019: + "operations, " + number + ", " + interfaceHashVarName //$NON-NLS-1$ //$NON-NLS-2$
1020: + ");" + EOLN); //$NON-NLS-1$
1021:
1022: if (numParams > 0) {
1023: buffer.append(EOLN + indenter.indent() + "try {" + EOLN //$NON-NLS-1$
1024: + indenter.increase()
1025: + "java.io.ObjectOutput " //$NON-NLS-1$
1026: + outputStreamName
1027: + " = call.getOutputStream();" + EOLN); //$NON-NLS-1$
1028:
1029: for (int i = 0; i < numParams; i++) {
1030: buffer.append(indenter.indent()
1031: + RmicUtil.getWriteObjectString(
1032: parameters[i], paramNames[i],
1033: outputStreamName) + ';' + EOLN);
1034: }
1035:
1036: buffer.append(indenter.decrease()
1037: + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
1038: + indenter.tIncrease()
1039: + "throw new java.rmi.MarshalException(" //$NON-NLS-1$
1040: + "\"Error marshalling arguments\", e);" + EOLN //$NON-NLS-1$
1041: + indenter.indent() + '}' + EOLN);
1042: }
1043:
1044: buffer.append(EOLN + indenter.indent()
1045: + "ref.invoke(call);" + EOLN); //$NON-NLS-1$
1046:
1047: if (retType != void.class) {
1048: buffer
1049: .append(EOLN
1050: + indenter.indent()
1051: + retTypeName
1052: + ' '
1053: + retVarName
1054: + ';'
1055: + EOLN
1056: + EOLN
1057: + indenter.indent()
1058: + "try {" + EOLN //$NON-NLS-1$
1059: + indenter.increase()
1060: + "java.io.ObjectInput " //$NON-NLS-1$
1061: + inputStreamName
1062: + " = call.getInputStream();" + EOLN //$NON-NLS-1$
1063: + indenter.indent()
1064: + retVarName
1065: + " = " //$NON-NLS-1$
1066: + RmicUtil.getReadObjectString(retType,
1067: inputStreamName)
1068: + ';'
1069: + EOLN
1070: + indenter.decrease()
1071: + "} catch (java.io.IOException e) {" + EOLN //$NON-NLS-1$
1072: + indenter.tIncrease()
1073: + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
1074: + "\"Error unmarshalling return value\", e);" + EOLN //$NON-NLS-1$
1075: + (!retType.isPrimitive() ? (indenter
1076: .indent()
1077: + "} catch (java.lang.ClassNotFoundException e) {" //$NON-NLS-1$
1078: + EOLN
1079: + indenter.tIncrease()
1080: + "throw new java.rmi.UnmarshalException(" //$NON-NLS-1$
1081: + "\"Error unmarshalling return value\", e);" + EOLN) //$NON-NLS-1$
1082: : "") + indenter.indent() + "} finally {" + EOLN //$NON-NLS-1$ //$NON-NLS-2$
1083: + indenter.tIncrease()
1084: + "ref.done(call);" + EOLN //$NON-NLS-1$
1085: + indenter.indent() + '}' + EOLN + EOLN
1086: + indenter.indent()
1087: + "return " + retVarName + ';' //$NON-NLS-1$
1088: + EOLN);
1089: } else {
1090: buffer.append(EOLN + indenter.indent()
1091: + "ref.done(call);" + EOLN); //$NON-NLS-1$
1092: }
1093:
1094: return buffer.toString();
1095: }
1096:
1097: /**
1098: * Returns the stub implementation code section source for this method
1099: * (Stub v1.2/vCompat).
1100: *
1101: * @return Stub implementation code for this method.
1102: */
1103: private String getStubImplCodeV12() {
1104: StringBuffer buffer = new StringBuffer(indenter.indent());
1105:
1106: if (retType != void.class) {
1107: buffer.append("java.lang.Object " + retVarName + " = "); //$NON-NLS-1$ //$NON-NLS-2$
1108: }
1109:
1110: buffer.append("ref.invoke(this, " + varName + ", "); //$NON-NLS-1$ //$NON-NLS-2$
1111:
1112: if (numParams > 0) {
1113: buffer.append("new java.lang.Object[] {"); //$NON-NLS-1$
1114:
1115: // Write invocation parameters.
1116: for (int i = 0; i < numParams; i++) {
1117: buffer.append(((i > 0) ? ", " : "") //$NON-NLS-1$ //$NON-NLS-2$
1118: + RmicUtil.getObjectParameterString(
1119: parameters[i], paramNames[i]));
1120: }
1121: buffer.append('}');
1122: } else {
1123: buffer.append("null"); //$NON-NLS-1$
1124: }
1125:
1126: buffer.append(", " + hash + "L);" + EOLN); //$NON-NLS-1$ //$NON-NLS-2$
1127:
1128: // Write return statement.
1129: if (retType != void.class) {
1130: buffer.append(indenter.indent()
1131: + "return " //$NON-NLS-1$
1132: + RmicUtil.getReturnObjectString(retType,
1133: retVarName) + ';' + EOLN);
1134: }
1135:
1136: return buffer.toString();
1137: }
1138:
1139: /**
1140: * Returns the stub implementation catch block for this method
1141: * (Stub v1.1/v1.2/vCompat).
1142: *
1143: * @return Stub implementation catch block for this method.
1144: */
1145: private String getStubImplCatchBlock() {
1146: StringBuffer buffer = new StringBuffer();
1147:
1148: for (Iterator i = catches.iterator(); i.hasNext();) {
1149: buffer.append(indenter.indent() + "} catch (" //$NON-NLS-1$
1150: + ((Class) i.next()).getName() + " e) {" + EOLN //$NON-NLS-1$
1151: + indenter.tIncrease() + "throw e;" + EOLN); //$NON-NLS-1$
1152: }
1153:
1154: buffer.append(indenter.indent()
1155: + "} catch (java.lang.Exception e) {" + EOLN //$NON-NLS-1$
1156: + indenter.tIncrease()
1157: + "throw new java.rmi.UnexpectedException(" //$NON-NLS-1$
1158: + "\"Undeclared checked exception\", e);" + EOLN //$NON-NLS-1$
1159: + indenter.indent() + '}' + EOLN);
1160:
1161: return buffer.toString();
1162: }
1163: }
1164: }
|