001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.webadmin.clienttools;
017:
018: import java.io.ByteArrayOutputStream;
019: import java.io.IOException;
020: import java.io.PrintStream;
021: import java.io.PrintWriter;
022: import java.lang.reflect.InvocationTargetException;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.Modifier;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.Set;
028:
029: import org.apache.openejb.webadmin.HttpRequest;
030: import org.apache.openejb.webadmin.HttpResponse;
031: import org.apache.openejb.webadmin.HttpSession;
032: import org.apache.openejb.webadmin.WebAdminBean;
033: import org.apache.openejb.webadmin.HttpHome;
034:
035: import javax.ejb.Stateless;
036: import javax.ejb.RemoteHome;
037:
038: /**
039: * @author <a href="mailto:david.blevins@visi.com">David Blevins</a>
040: */
041: @Stateless(name="ClientTools/ViewJndi")
042: @RemoteHome(HttpHome.class)
043: public class InvokeObjectBean extends WebAdminBean implements Constants {
044:
045: private PrintWriter out;
046: private static String invLock = "lock";
047: private static int invCount;
048:
049: private HttpSession session;
050:
051: public void preProcess(HttpRequest request, HttpResponse response)
052: throws IOException {
053: }
054:
055: public void postProcess(HttpRequest request, HttpResponse response)
056: throws IOException {
057: }
058:
059: public void writeHtmlTitle(PrintWriter out) throws IOException {
060: out.write("Client Tools -- Object Invoker");
061: }
062:
063: public void writePageTitle(PrintWriter out) throws IOException {
064: out.write("Object Invoker");
065: }
066:
067: public void writeBody(PrintWriter out) throws IOException {
068: this .out = out;
069: try {
070: synchronized (this ) {
071: main(request.getSession(), out);
072: }
073: } catch (Exception e) {
074: out.println("FAIL");
075: //throw e;
076: return;
077: }
078: }
079:
080: class Invocation {
081:
082: protected String id = "inv";
083: protected String objID;
084: protected Class clazz;
085: protected Object target;
086: protected Method method;
087: protected Object[] args;
088: protected Object result;
089:
090: protected Invocation() {
091: synchronized (invLock) {
092: id += ++invCount;
093: }
094: }
095:
096: public Object invoke() throws Exception {
097: if (target == null || method == null || args == null) {
098: throw new Exception(
099: "This invocation contains null objects.");
100: }
101: return method.invoke(target, args);
102: }
103: }
104:
105: /**
106: * The main method of this JSP
107: */
108: public void main(HttpSession session, PrintWriter out)
109: throws Exception {
110: this .session = session;
111: this .out = out;
112:
113: printObjectSection();
114: }
115:
116: /**
117: * Print the list of objects with the focused object as
118: * selected in the box.
119: * If no object is selected, make an entry called "Pick an Object"
120: */
121: public void printObjectSection() throws Exception {
122: String removeID = request.getQueryParameter("remove");
123: if (removeID != null) {
124: removeObject(removeID);
125: }
126:
127: Invocation inv = null;
128: String invID = request.getQueryParameter("inv");
129:
130: if (invID == null) {
131: String objID = request.getQueryParameter("obj");
132: if (objID != null) {
133: inv = new Invocation();
134: inv.target = getObject(objID);
135: inv.objID = objID;
136: setInvocation(inv.id, inv);
137: }
138: } else {
139: inv = getInvocation(invID);
140: }
141:
142: if (inv == null || inv.target == null) {
143: // Pick from the list
144: printObjectList();
145:
146: } else {
147: out.print("<b>Object:</b><br>");
148: out.print(tab + inv.objID + " <a href='" + INVOKE_OBJ
149: + "'>[change]</a><br><br>");
150:
151: // Show the selected item and continue
152: printMethodSection(inv);
153: }
154: }
155:
156: /**
157: * Prints the list of objects that can be invoked
158: */
159: public void printObjectList() throws Exception {
160:
161: HashMap objects = getObjectMap();
162: if (objects.size() == 0) {
163: out.print("<b>No object have been created</b><br>");
164: out.print("<table>");
165: printRow(pepperImg, "<A HREF='" + VIEW_JNDI
166: + "'>Browse for an EJB</A>");
167: out.print("</table>");
168:
169: } else {
170: out.print("<b>Pick and object to invoke</b><br>");
171:
172: //out.print("<b>Objects:</b><br>");
173: Set keys = objects.keySet();
174: Iterator iterator = keys.iterator();
175: out.print("<table>");
176: while (iterator.hasNext()) {
177: String entry = (String) iterator.next();
178: printRow(tab + "<a href='" + INVOKE_OBJ + "?obj="
179: + entry + "'>" + entry + "</a>", "<a href='"
180: + INVOKE_OBJ + "?remove=" + entry
181: + "'>[remove]</a>");
182: }
183: out.print("</table>");
184: }
185: }
186:
187: /**
188: * Print the list of methods with the focused method as
189: * selected in the box.
190: * If no method is selected, make an entry called "Pick a Method"
191: */
192: public void printMethodSection(Invocation inv) throws Exception {
193: String methodID = request.getQueryParameter("m");
194:
195: if (methodID != null) {
196: int method = Integer.parseInt(methodID);
197: Method[] methods = inv.clazz.getMethods();
198: if (method > -1 && method < methods.length) {
199: inv.method = methods[method];
200: } else {
201: inv.method = null;
202: inv.args = null;
203: }
204: }
205:
206: if (inv.method == null) {
207: // Pick from the list
208: printMethodList(inv);
209:
210: } else {
211: out.print("<b>Method:</b><br>");
212: out.print(tab + formatMethod(inv.method) + " <a href='"
213: + INVOKE_OBJ + "?m=-1&inv=" + inv.id
214: + "'>[change]</a><br><br>");
215:
216: // Show the selected item and continue
217: printArgumentSection(inv);
218: }
219:
220: }
221:
222: /**
223: * Prints the list of methods that can be invoked
224: */
225: public void printMethodList(Invocation inv) throws Exception {
226: out.print("<b>Pick a method to invoke</b><br>");
227: //out.print("<b>Methods:</b><br>");
228:
229: Object obj = inv.target;
230: Class clazz = inv.target.getClass();
231: if (obj instanceof javax.ejb.EJBHome) {
232: clazz = obj.getClass().getInterfaces()[0];
233: } else if (obj instanceof javax.ejb.EJBObject) {
234: clazz = obj.getClass().getInterfaces()[0];
235: } else {
236: clazz = obj.getClass();
237: }
238: inv.clazz = clazz;
239:
240: out.print("<table>");
241: Method[] methods = clazz.getMethods();
242: for (int i = 0; i < methods.length; i++) {
243: Method m = methods[i];
244: if (Modifier.isPublic(m.getModifiers())) {
245: out.print("<tr><td><font size='2'>");
246: out.print(tab + "<a href='" + INVOKE_OBJ + "?inv="
247: + inv.id + "&m=" + i + "'>" + formatMethod(m)
248: + "</a><br>");
249: out.print("</font></td></tr>");
250: }
251: }
252: out.print("</table>");
253: }
254:
255: /**
256: * Print the list of arguments.
257: * If no arguments have been selected,
258: * show the argument entry form.
259: */
260: public void printArgumentSection(Invocation inv) throws Exception {
261: String args = request.getQueryParameter("args");
262:
263: if (args != null) {
264: parseArgs(inv);
265: }
266:
267: if (inv.method.getParameterTypes().length == 0) {
268: inv.args = new Object[] {};
269: }
270:
271: if (inv.args == null) {
272: printArgumentList(inv);
273: } else {
274: out.print("<b>Arguments:</b><br>");
275: if (inv.args.length == 0) {
276: out.print(tab + "none<br>");
277: }
278: for (int i = 0; i < inv.args.length; i++) {
279: String val = formatObject(inv.args[i]);
280: out.print(tab + "arg" + i + " <i>" + val
281: + "</i><br>");
282: }
283: out.print("<br>");
284: printInvokeSection(inv);
285: }
286: }
287:
288: public void parseArgs(Invocation inv) throws Exception {
289: Class[] pTypes = inv.method.getParameterTypes();
290: inv.args = new Object[pTypes.length];
291:
292: for (int i = 0; i < pTypes.length; i++) {
293: Class type = pTypes[i];
294: String unparsedArg = request.getQueryParameter("arg" + i);
295: inv.args[i] = getConverter(type).convert(type, unparsedArg);
296: }
297: }
298:
299: public void printArgumentList(Invocation inv) throws Exception {
300: out.print("<b>Fill in the arguments</b><br>");
301: Class[] pTypes = inv.method.getParameterTypes();
302: out.print("<FORM NAME='args' METHOD='GET' ACTION='"
303: + INVOKE_OBJ + "'>");
304: out.print("<INPUT type='HIDDEN' NAME='inv' VALUE='" + inv.id
305: + "'>");
306: out.print("<table>");
307: for (int i = 0; i < pTypes.length; i++) {
308: Converter con = getConverter(pTypes[i]);
309: out.print("<tr>");
310: out.print("<td align='right'><font size='2'>");
311: out.print(tab + getShortClassRef(pTypes[i]));
312: out.print("</font></td>");
313: out.print("<td><font size='2'>");
314: out.print(" arg" + i);
315: out.print("</font></td>");
316: out.print("<td><font size='2'>");
317: out.print(" "
318: + con.getInputControl(i, pTypes[i]));
319: out.print("</font></td>");
320: }
321: out.print("</table>");
322:
323: out.print("<br><br>");
324: out.print("<INPUT type='SUBMIT' NAME='args' value='Continue'>");
325: out.print("</form>");
326:
327: }
328:
329: /**
330: * Print the list of arguments.
331: * If no arguments have been selected,
332: * show the argument entry form.
333: */
334: public void printInvokeSection(Invocation inv) throws Exception {
335: String doInvoke = request.getQueryParameter("invoke");
336: if (doInvoke != null) {
337: invoke(inv);
338: } else {
339: out.print("<FORM NAME='invoke' METHOD='GET' ACTION='"
340: + INVOKE_OBJ + "'>");
341: out.print("<INPUT type='HIDDEN' NAME='inv' VALUE='"
342: + inv.id + "'>");
343: out
344: .print("<INPUT type='SUBMIT' NAME='invoke' value='Invoke'>");
345: out.print("</FORM>");
346: }
347:
348: }
349:
350: String pepperImg = "<img src='/images/pepper.gif' border='0'>";
351:
352: public void invoke(Invocation inv) throws Exception {
353:
354: try {
355: inv.result = inv.invoke();
356:
357: out.print("<b>Result:</b><br>");
358: if (inv.method.getReturnType() == java.lang.Void.TYPE) {
359: out.print(tab + "Done");
360: } else if (inv.result == null) {
361: out.print(tab + "<i>null</i>");
362: } else {
363: String clazz = inv.result.getClass().getName();
364: String objID = getObjectID(inv.result);
365: setObject(objID, inv.result);
366:
367: out.print("<table>");
368: printRow("<i>id</i>", objID);
369: printRow("<i>class</i>", "<a href='" + VIEW_CLASS
370: + "?class=" + clazz + "'>" + clazz + "</a>");
371: printRow("<i>toString</i>", formatObject(inv.result));
372: out.print("</table>");
373:
374: out.print("<br><br><b>Actions:</b><br>");
375: out.print("<table>");
376: String invokerURL = "<a href='" + INVOKE_OBJ + "?obj="
377: + objID + "'>Invoke a method on the object</a>";
378: printRow(pepperImg, invokerURL);
379: String discardURL = "<a href='" + INVOKE_OBJ
380: + "?remove=" + objID
381: + "'>Discard the object</a>";
382: printRow(pepperImg, discardURL);
383: out.print("</table>");
384: }
385: } catch (InvocationTargetException e) {
386: out.print("<b>Exception:</b><br><br>");
387: Throwable t = e.getTargetException();
388: out.print("Received a " + t.getClass().getName());
389: //out.print(inv.method+"<br><br>");
390: if (t instanceof java.rmi.RemoteException) {
391: out.print(" <a href='re-help.html'>[Tip]</a><br><br>");
392: java.rmi.RemoteException re = (java.rmi.RemoteException) t;
393: out.print("<i>RemoteException message:</i><br>");
394: out.print(t.getMessage() + "<br><br>");
395: out.print("<i>Nested exception's stack trace:</i><br>");
396:
397: while (t instanceof java.rmi.RemoteException) {
398: t = ((java.rmi.RemoteException) t).detail;
399: }
400: out.print(formatThrowable(t));
401: } else {
402: out.print("<br><br>" + formatThrowable(t));
403: }
404:
405: } catch (Throwable e) {
406: out.print("<b>Exception:</b><br><br>");
407: out.print(formatObject(e));
408: }
409: }
410:
411: public String formatThrowable(Throwable err) throws Exception {
412: ByteArrayOutputStream baos = new ByteArrayOutputStream();
413: err.printStackTrace(new PrintStream(baos));
414: byte[] bytes = baos.toByteArray();
415: StringBuffer sb = new StringBuffer(bytes.length);
416: for (int i = 0; i < bytes.length; i++) {
417: char c = (char) bytes[i];
418: switch (c) {
419: case ' ':
420: sb.append(" ");
421: break;
422: case '\n':
423: sb.append("<br>");
424: break;
425: case '\r':
426: break;
427: default:
428: sb.append(c);
429: }
430: }
431: return sb.toString();
432: }
433:
434: public String formatObject(Object obj) throws Exception {
435: int max = 75;
436: String val = obj.toString();
437: val = (val.length() > max) ? val.substring(0, max - 3) + "..."
438: : val;
439: char[] chars = new char[val.length()];
440: val.getChars(0, chars.length, chars, 0);
441:
442: StringBuffer sb = new StringBuffer(chars.length);
443: for (int j = 0; j < chars.length; j++) {
444: char c = chars[j];
445: switch (c) {
446: case '<':
447: sb.append("<");
448: break;
449: case '>':
450: sb.append(">");
451: break;
452: case '&':
453: sb.append("&");
454: break;
455: default:
456: sb.append(c);
457: }
458: }
459: return sb.toString();
460: }
461:
462: /*-----------------------------------------------------------*/
463: // Method name formatting
464: /*-----------------------------------------------------------*/
465: public String formatMethod(Method m) throws Exception {
466: StringBuffer sb = new StringBuffer();
467:
468: sb
469: .append(getShortClassName(m.getReturnType())
470: + " ");
471: sb.append(m.getName());
472:
473: Class[] params = m.getParameterTypes();
474: sb.append("(");
475: for (int j = 0; j < params.length; j++) {
476: sb.append(getShortClassName(params[j]));
477: if (j != params.length - 1) {
478: sb.append(", ");
479: }
480: }
481: sb.append(")");
482:
483: Class[] excp = m.getExceptionTypes();
484: if (excp.length > 0) {
485: sb.append(" throws ");
486: for (int j = 0; j < excp.length; j++) {
487: sb.append(getShortClassName(excp[j]));
488: if (j != excp.length - 1) {
489: sb.append(", ");
490: }
491: }
492: }
493: return sb.toString();
494: }
495:
496: /*-----------------------------------------------------------*/
497: // Class name formatting
498: /*-----------------------------------------------------------*/
499: public String getShortClassName(Class clazz) throws Exception {
500: if (clazz.isPrimitive()) {
501: return clazz.getName();
502: } else if (clazz.isArray()
503: && clazz.getComponentType().isPrimitive()) {
504: return clazz.getComponentType() + "[]";
505: } else if (clazz.isArray()) {
506: String name = clazz.getComponentType().getName();
507: int dot = name.lastIndexOf(".") + 1;
508: String shortName = name.substring(dot, name.length());
509: return shortName + "[]";
510: } else {
511: String name = clazz.getName();
512: int dot = name.lastIndexOf(".") + 1;
513: String shortName = name.substring(dot, name.length());
514: return shortName;
515: }
516: }
517:
518: public String getShortClassRef(Class clazz) throws Exception {
519: if (clazz.isPrimitive()) {
520: return "<font color='gray'>" + clazz.getName() + "</font>";
521: } else if (clazz.isArray()
522: && clazz.getComponentType().isPrimitive()) {
523: return "<font color='gray'>" + clazz.getComponentType()
524: + "[]</font>";
525: } else if (clazz.isArray()) {
526: String name = clazz.getComponentType().getName();
527: int dot = name.lastIndexOf(".") + 1;
528: String shortName = name.substring(dot, name.length());
529: return "<a href='" + VIEW_CLASS + "?class=" + name + "'>"
530: + shortName + "[]</a>";
531: } else {
532: String name = clazz.getName();
533: int dot = name.lastIndexOf(".") + 1;
534: String shortName = name.substring(dot, name.length());
535: return "<a href='" + VIEW_CLASS + "?class=" + name + "'>"
536: + shortName + "</a>";
537: }
538: }
539:
540: protected void printRow(String col1, String col2) throws Exception {
541: out.print("<tr><td><font size='2'>");
542: out.print(col1);
543: out.print("</font></td><td><font size='2'>");
544: out.print(col2);
545: out.print("</font></td></tr>");
546: }
547:
548: /*-----------------------------------------------------------*/
549: // Object list support
550: /*-----------------------------------------------------------*/
551: public String getObjectID(Object obj) {
552: Class clazz = obj.getClass();
553: if (obj instanceof javax.ejb.EJBHome) {
554: clazz = obj.getClass().getInterfaces()[0];
555: } else if (obj instanceof javax.ejb.EJBObject) {
556: clazz = obj.getClass().getInterfaces()[0];
557: }
558: return clazz.getName() + "@" + obj.hashCode();
559: }
560:
561: public Object getObject(String objID) {
562: return getObjectMap().get(objID);
563: }
564:
565: public void setObject(String objID, Object obj) {
566: getObjectMap().put(objID, obj);
567: }
568:
569: public void removeObject(String objID) {
570: getObjectMap().remove(objID);
571: }
572:
573: public HashMap getObjectMap() {
574: HashMap objects = (HashMap) session.getAttribute("objects");
575: if (objects == null) {
576: objects = new HashMap();
577: session.setAttribute("objects", objects);
578: }
579: return objects;
580: }
581:
582: /*-----------------------------------------------------------*/
583: // Invocation list support
584: /*-----------------------------------------------------------*/
585: public Invocation getInvocation(String invID) {
586: return (Invocation) getInvocationMap().get(invID);
587: }
588:
589: public void setInvocation(String invID, Invocation obj) {
590: getInvocationMap().put(invID, obj);
591: }
592:
593: public HashMap getInvocationMap() {
594: HttpSession session = request.getSession();
595: HashMap invocations = (HashMap) session
596: .getAttribute("invocations");
597: if (invocations == null) {
598: invocations = new HashMap();
599: session.setAttribute("invocations", invocations);
600: }
601: return invocations;
602: }
603:
604: /*-----------------------------------------------------------*/
605: // String conversion support
606: /*-----------------------------------------------------------*/
607: final HashMap converters = initConverters();
608:
609: public Converter getConverter(Class type) {
610: Converter con = (Converter) converters.get(type);
611: if (con == null) {
612: con = defaultConverter;
613: }
614: return con;
615: }
616:
617: final Converter defaultConverter = new ObjectConverter();
618:
619: private HashMap initConverters() {
620: HashMap map = new HashMap();
621:
622: map.put(String.class, new StringConverter());
623: map.put(Character.class, new CharacterConverter());
624: map.put(Boolean.class, new BooleanConverter());
625: map.put(Byte.class, new ByteConverter());
626: map.put(Short.class, new ShortConverter());
627: map.put(Integer.class, new IntegerConverter());
628: map.put(Long.class, new LongConverter());
629: map.put(Float.class, new FloatConverter());
630: map.put(Double.class, new DoubleConverter());
631: map.put(Object.class, new ObjectConverter());
632: map.put(Character.TYPE, map.get(Character.class));
633: map.put(Boolean.TYPE, map.get(Boolean.class));
634: map.put(Byte.TYPE, map.get(Byte.class));
635: map.put(Short.TYPE, map.get(Short.class));
636: map.put(Integer.TYPE, map.get(Integer.class));
637: map.put(Long.TYPE, map.get(Long.class));
638: map.put(Float.TYPE, map.get(Float.class));
639: map.put(Double.TYPE, map.get(Double.class));
640:
641: return map;
642: }
643:
644: abstract class Converter {
645: public abstract Object convert(Class type, String raw)
646: throws Exception;
647:
648: public String getInputControl(int argNumber, Class type)
649: throws Exception {
650: return "<INPUT type='text' NAME='arg" + argNumber + "'>";
651: }
652: }
653:
654: class StringConverter extends Converter {
655: public Object convert(Class type, String raw) throws Exception {
656: return raw;
657: }
658: }
659:
660: class CharacterConverter extends Converter {
661: public Object convert(Class type, String raw) throws Exception {
662: return new Character(raw.charAt(0));
663: }
664: }
665:
666: class BooleanConverter extends Converter {
667: public Object convert(Class type, String raw) throws Exception {
668: return new Boolean(raw);
669: }
670: }
671:
672: class ByteConverter extends Converter {
673: public Object convert(Class type, String raw) throws Exception {
674: return new Byte(raw);
675: }
676: }
677:
678: class ShortConverter extends Converter {
679: public Object convert(Class type, String raw) throws Exception {
680: return new Short(raw);
681: }
682: }
683:
684: class IntegerConverter extends Converter {
685: public Object convert(Class type, String raw) throws Exception {
686: return new Integer(raw);
687: }
688: }
689:
690: class LongConverter extends Converter {
691: public Object convert(Class type, String raw) throws Exception {
692: return new Long(raw);
693: }
694: }
695:
696: class FloatConverter extends Converter {
697: public Object convert(Class type, String raw) throws Exception {
698: return new Float(raw);
699: }
700: }
701:
702: class DoubleConverter extends Converter {
703: public Object convert(Class type, String raw) throws Exception {
704: return new Double(raw);
705: }
706: }
707:
708: class ObjectConverter extends Converter {
709: public Object convert(Class type, String raw) throws Exception {
710: return raw;
711: }
712: }
713: }
|