001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.satsa.jcrmic;
028:
029: import java.util.*;
030: import java.io.*;
031:
032: import com.sun.satsa.jcrmic.classfile.*;
033: import com.sun.satsa.jcrmic.utils.IndentingWriter;
034:
035: /**
036: * This class represents remote method.
037: */
038:
039: public class RemoteMethod {
040:
041: /**
042: * Method name.
043: */
044: private String name;
045:
046: /**
047: * Method descriptor.
048: */
049: private String descriptor;
050:
051: /**
052: * Exceptions thrown by method.
053: */
054: private Vector exceptions;
055:
056: /**
057: * Class loader.
058: */
059: private Loader loader;
060:
061: /**
062: * Constructor.
063: * @param name method name
064: * @param descriptor method descriptor
065: * @param loader class loader
066: */
067: public RemoteMethod(String name, String descriptor, Loader loader) {
068:
069: this .name = name;
070: this .descriptor = descriptor;
071: this .loader = loader;
072: exceptions = new Vector();
073: }
074:
075: /**
076: * Add an exception type to the exceptions list.
077: * @param ex exception class descriptor
078: */
079: public void addException(JClass ex) {
080:
081: exceptions.add(ex);
082: }
083:
084: /**
085: * Returns the list of exceptions thrown by method.
086: * @return the list of exceptions thrown by method
087: */
088: public Vector getExceptions() {
089: return exceptions;
090: }
091:
092: /**
093: * Merge the lists of exceptions thrown by this and specfied remote methods.
094: * @param m remote method descriptor
095: */
096: public void merge(RemoteMethod m) {
097:
098: Vector list1 = exceptions;
099: Vector list2 = m.getExceptions();
100: exceptions = new Vector();
101: mergeLists(list1, list2, exceptions);
102: mergeLists(list2, list1, exceptions);
103: }
104:
105: /**
106: * Places into the third list all exceptions from the first list that are
107: * subclasses of exceptions in the second list.
108: * @param list1 exceptions list
109: * @param list2 exceptions list
110: * @param exceptions exceptions list
111: */
112: private static void mergeLists(Vector list1, Vector list2,
113: Vector exceptions) {
114:
115: for (int i = 0; i < list1.size(); i++) {
116:
117: JClass c1 = (JClass) list1.elementAt(i);
118:
119: if (exceptions.contains(c1)) {
120: continue;
121: }
122:
123: for (int j = 0; j < list2.size(); j++) {
124:
125: JClass c2 = (JClass) list2.elementAt(j);
126:
127: if (c1.isSubclass(c2)) {
128: exceptions.add(c1);
129: break;
130: }
131: }
132: }
133: }
134:
135: /**
136: * Write stub method for this method into the output stream.
137: * @param p output stream
138: * @throws IOException if I/O error occurs
139: */
140: public void write(IndentingWriter p) throws IOException {
141:
142: Vector v = parseDescriptor(descriptor);
143: String param = (String) v.elementAt(v.size() - 1);
144:
145: String s = "public " + getType(param) + " " + name + "(";
146:
147: for (int i = 0; i < v.size() - 1; i++) {
148:
149: s = s + getType((String) v.elementAt(i)) + " param" + (i + 1);
150:
151: if (i < v.size() - 2) {
152: s = s + ", ";
153: }
154: }
155:
156: s = s + ") ";
157:
158: if (exceptions.size() > 0) {
159:
160: s = s + "throws ";
161:
162: for (int i = 0; i < exceptions.size(); i++) {
163:
164: JClass ex = (JClass) exceptions.elementAt(i);
165: s = s + ex.getClassName().replace('/', '.');
166:
167: if (i < exceptions.size() - 1) {
168: s = s + ", ";
169: }
170: }
171: }
172:
173: p.pln("");
174: p.plnI(s + " {");
175: p.pln("");
176:
177: computeUniqueCatchList();
178:
179: if (exceptions.size() > 0) {
180: p.plnI("try {");
181: }
182:
183:
184: p.pln("");
185:
186: if (!((String) v.elementAt(v.size() - 1)).equals("V")) {
187: p.p("Object result = ");
188: }
189:
190: p.p("ref.invoke(\"" + name + descriptor + "\", ");
191:
192: if (v.size() == 1) {
193: p.p("null");
194: } else {
195: p.p("new java.lang.Object[] {");
196:
197: for (int i = 0; i < v.size() - 1; i++) {
198: p.p(getParameter((String) v.elementAt(i), i));
199: if (i < v.size() - 2) {
200: p.p(", ");
201: }
202: }
203: p.p("}");
204: }
205:
206: p.pln(");");
207: s = (String) v.elementAt(v.size() - 1);
208:
209: if (!s.equals("V")) {
210: p.pln("return " + getReturnFunction(s));
211: }
212:
213: p.pln("");
214:
215:
216: /*
217: * If we need to catch any particular exceptions, finally
218: * write the catch blocks for them, rethrow any other
219: * Exceptions with an UnexpectedException, and end the try
220: * block.
221: */
222: if (exceptions.size() > 0) {
223: for (Enumeration enum = exceptions.elements();
224: enum.hasMoreElements();) {
225: JClass def = (JClass) enum.nextElement();
226: p.pOlnI("} catch (" + def.getClassName().replace('/', '.') +
227: " e) {");
228: p.pln("throw e;");
229: }
230: p.pOlnI("} catch (java.lang.Exception e) {");
231: p.pln("throw new java.rmi.RemoteException" +
232: "(\"undeclared checked exception\", e);");
233: p.pOln("}"); // end try/catch block
234: }
235:
236: p.pOln("}");
237: }
238:
239: /**
240: * Returns parameter initialization expression for stub method.
241: * @param param parameter descriptor
242: * @param index parameter index
243: * @return parameter initialization expression
244: */
245: private String getParameter(String param, int index) {
246:
247: if (param.length() == 1) {
248:
249: switch (JCReturnTypes.indexOf(param)) {
250:
251: case 0:
252: return "new Boolean(param" + (index + 1) + ")";
253: case 1:
254: return "new Byte(param" + (index + 1) + ")";
255: case 2:
256: return "new Short(param" + (index + 1) + ")";
257: case 3:
258: return "new Integer(param" + (index + 1) + ")";
259: }
260: }
261:
262: return "param" + (index + 1);
263: }
264:
265: /**
266: * Java Card type descriptor string.
267: */
268: private static final String JCTypes = "ZBSI";
269: /**
270: * Java Card type descriptor string.
271: */
272: private static final String JCArrays = "[Z[B[S[I";
273: /**
274: * Java Card type descriptor string.
275: */
276: private static final String JCReturnTypes = "ZBSIV";
277:
278: /**
279: * Returns return type expression for stub method.
280: * @param param return type descriptor
281: * @return return type expression
282: */
283: private static String getType(String param) {
284:
285: if (param.length() == 1) {
286:
287: switch (JCReturnTypes.indexOf(param)) {
288:
289: case 0:
290: return "boolean";
291: case 1:
292: return "byte";
293: case 2:
294: return "short";
295: case 3:
296: return "int";
297: case 4:
298: return "void";
299: }
300: }
301:
302: if (param.length() == 2) {
303:
304: switch (JCArrays.indexOf(param)) {
305:
306: case 0:
307: return "boolean[]";
308: case 2:
309: return "byte[]";
310: case 4:
311: return "short[]";
312: case 6:
313: return "int[]";
314: }
315: }
316:
317: return param.substring(1, param.length() - 1).replace('/', '.');
318: }
319:
320: /**
321: * Returns expression for stub method return value.
322: * @param param return type descriptor
323: * @return expression for stub method return value
324: */
325: private static String getReturnFunction(String param) {
326:
327: if (param.length() == 1) {
328:
329: switch (JCReturnTypes.indexOf(param)) {
330:
331: case 0:
332: return "((Boolean) result).booleanValue();";
333: case 1:
334: return "((Byte) result).byteValue();";
335: case 2:
336: return "((Short) result).shortValue();";
337: case 3:
338: return "((Integer) result).intValue();";
339: }
340: }
341:
342: if (param.length() == 2) {
343:
344: switch (JCArrays.indexOf(param)) {
345:
346: case 0:
347: return "(boolean[]) result;";
348: case 2:
349: return "(byte[]) result;";
350: case 4:
351: return "(short[]) result;";
352: case 6:
353: return "(int[]) result;";
354: }
355: }
356:
357: param = param.substring(1, param.length() - 1)
358: .replace('/', '.');
359: return "(" + param + ") result;";
360: }
361:
362: /**
363: * Compute the exceptions which need to be caught and rethrown in a
364: * stub method before wrapping Exceptions in RemoteException.
365: */
366: private void computeUniqueCatchList() {
367:
368: Vector uniqueList = new Vector();
369:
370: uniqueList.addElement(loader
371: .getClass("java/lang/RuntimeException"));
372: uniqueList.addElement(loader
373: .getClass("java/rmi/RemoteException"));
374:
375: JClass defException = loader.getClass("java/lang/Exception");
376:
377: /* For each exception declared by the stub method's throws clause: */
378: nextException: for (int i = 0; i < exceptions.size(); i++) {
379:
380: JClass decl = (JClass) exceptions.elementAt(i);
381:
382: if (defException.isSubclass(decl)) {
383: /*
384: * If java.lang.Exception (or a superclass) was
385: * declared in the throws clause of this stub method,
386: * then we don't have to bother catching anything;
387: * clear the list and return.
388: */
389: uniqueList.removeAllElements();
390: break;
391: } else if (!decl.isSubclass(defException)) {
392: /*
393: * Ignore other Throwables that do not extend Exception,
394: * since they do not need to be caught anyway.
395: */
396: continue;
397: }
398: /*
399: * Compare this exception against the current list of
400: * exceptions that need to be caught:
401: */
402: for (int j = 0; j < uniqueList.size();) {
403: JClass def = (JClass) uniqueList.elementAt(j);
404: if (decl.isSubclass(def)) {
405: /*
406: * If a superclass of this exception is already on
407: * the list to catch, then ignore and continue;
408: */
409: continue nextException;
410: } else if (def.isSubclass(decl)) {
411: /*
412: * If a subclass of this exception is on the list
413: * to catch, then remove it.
414: */
415: uniqueList.removeElementAt(j);
416: } else {
417: j++; // else continue comparing
418: }
419: }
420: /* This exception is unique: add it to the list to catch. */
421: uniqueList.addElement(decl);
422: }
423: exceptions = uniqueList;
424: }
425:
426: /**
427: * Parses remote method descriptor.
428: * @param descriptor remote method descriptor
429: * @return vector that contais string descriptor for every parameter
430: * and return value.
431: */
432: public static Vector parseDescriptor(String descriptor) {
433:
434: Vector v = new Vector();
435:
436: int index = descriptor.indexOf(")");
437:
438: String parameters = descriptor.substring(1, index);
439:
440: int j = 0;
441: while (j < parameters.length()) {
442:
443: String c = parameters.substring(j, j + 1);
444: j++;
445:
446: if (JCTypes.indexOf(c) != -1) {
447: v.add(c);
448: continue;
449: }
450:
451: if (j == parameters.length()) {
452: return null;
453: }
454:
455: c = c + parameters.substring(j, j + 1);
456: j++;
457:
458: if (JCArrays.indexOf(c) != -1) {
459: v.add(c);
460: continue;
461: }
462:
463: return null;
464: }
465:
466: parameters = descriptor.substring(index + 1);
467:
468: if ((parameters.length() == 1)
469: && (JCReturnTypes.indexOf(parameters) == -1)) {
470: return null;
471: }
472: if (parameters.length() == 2
473: && JCArrays.indexOf(parameters) == -1) {
474: return null;
475: }
476: if (parameters.length() > 2
477: && !(parameters.startsWith("L") && parameters
478: .endsWith(";"))) {
479: return null;
480: }
481: v.add(parameters);
482:
483: return v;
484: }
485: }
|