Source Code Cross Referenced for AbstractCallMethod.java in  » Library » Apache-beehive-1.0.2-src » org » apache » beehive » netui » tags » databinding » invoke » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache beehive 1.0.2 src » org.apache.beehive.netui.tags.databinding.invoke 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:         *
017:         * $Header:$
018:         */
019:        package org.apache.beehive.netui.tags.databinding.invoke;
020:
021:        import java.lang.reflect.InvocationTargetException;
022:        import java.lang.reflect.Method;
023:        import java.util.ArrayList;
024:        import java.util.List;
025:        import java.util.Collections;
026:        import javax.servlet.jsp.JspException;
027:
028:        import org.apache.beehive.netui.tags.AbstractClassicTag;
029:        import org.apache.beehive.netui.util.Bundle;
030:        import org.apache.beehive.netui.util.internal.InternalStringBuilder;
031:        import org.apache.beehive.netui.util.logging.Logger;
032:        import org.apache.beehive.netui.util.type.TypeUtils;
033:
034:        /**
035:         * <p>
036:         * An abstract base class for tags that are capable of reflectively invoking methods.  Specializations of this
037:         * tag provide method implementations that locate the object on which to invoke the method and that handle
038:         * any return value from the invoked method.
039:         * <p/>
040:         * <p>
041:         * The <code>CallMethod</code> tag can have child tags of type {@link MethodParameter}; these tags must be in the same
042:         * order as the parameter list in the method signature of the method that will be invoked.  To invoke an overloaded
043:         * method, the {@link MethodParameter#setType(String)} property must be set to the String name of the type to pass
044:         * to the method.  If the type attribute values on nested {@link MethodParameter} tags do not match any method
045:         * signature, an error will be reported in the page.
046:         * </p>
047:         */
048:        public abstract class AbstractCallMethod extends AbstractClassicTag {
049:
050:            private static final Logger LOGGER = Logger
051:                    .getInstance(AbstractCallMethod.class);
052:
053:            private static final Object[] EMPTY_ARGS = new Object[0];
054:            private static final String EMPTY_STRING = "";
055:
056:            private List _parameters = null;
057:            private String _method = null;
058:            private boolean _failOnError = true;
059:            private String _resultId = null;
060:            private boolean _verifyTypes = false;
061:
062:            /**
063:             * Sets the identifier at which the result of invoking the method will stored.  Once stored, the
064:             * result of the reflective invocation will be available via the JSP EL implicit object
065:             * <code>${pageScope}</code> with the attribute name set via this property.
066:             *
067:             * @param resultId a String that names an attribute in the PageContext's
068:             *                 attribute map where any resulting object will be stored.
069:             * @jsptagref.attributedescription
070:             * Sets the identifier at which the result of invoking the method will stored.  Once stored, the
071:             * result of the reflective invocation will be available via the JSP EL implicit object
072:             * <code>${pageScope}</code> with the attribute name set via this property.
073:             * @netui:attribute required="false"
074:             */
075:            public void setResultId(String resultId) {
076:                _resultId = resultId;
077:            }
078:
079:            /**
080:             * Sets whether or not to report exceptions to the page when errors occur invoking a method on an object.
081:             *
082:             * @param failOnError a boolean that defines whether or not exceptions should be thrown when invocation fails.
083:             * @jsptagref.attributedescription
084:             * Sets whether or not to report exceptions to the page when errors occur invoking a method on an object.
085:             * @netui:attribute required="false"
086:             */
087:            public void setFailOnError(boolean failOnError) {
088:                _failOnError = failOnError;
089:            }
090:
091:            /**
092:             * Sets the name of a method to invoke on the target object.
093:             *
094:             * @param method the name of the method to invoke
095:             * @jsptagref.attributedescription
096:             * Sets the name of a method to invoke on the target object.
097:             * @netui:attribute required="true"
098:             */
099:            public void setMethod(String method) {
100:                _method = method;
101:            }
102:
103:            /**
104:             * Add a paramter that will be passed as an argument to the method that will be invoked.  This method
105:             * is implemented to allow the the {@link MethodParameter} tags to register their parameters.  This
106:             * object is passed in the position that it appeared in the set of child {@link MethodParameter} tags.
107:             *
108:             * @param type      a String of the type or class name of this parameter
109:             * @param parameter an object that should be passed as an argument to the invoked method
110:             * @see MethodParameter
111:             */
112:            public void addParameter(String type, Object parameter) {
113:                if (_parameters == null)
114:                    _parameters = new ArrayList();
115:
116:                // only check the types if necessary
117:                if (type != null)
118:                    _verifyTypes = true;
119:
120:                ParamNode pn = new ParamNode();
121:                pn.typeName = type;
122:                pn.paramValue = parameter;
123:
124:                _parameters.add(pn);
125:            }
126:
127:            /**
128:             * Causes the body of this tag to be rendered; only {@link MethodParameter} tags are allowed to be
129:             * contained inside of this tag.  The output of rendering the body is never written into the
130:             * output stream of the servlet.
131:             *
132:             * @return {@link #EVAL_BODY_BUFFERED}
133:             */
134:            public int doStartTag() throws JspException {
135:                return EVAL_BODY_BUFFERED;
136:            }
137:
138:            /**
139:             * Reflectively invokes the method specified by the <code>method</code> attribute,
140:             * {@link #findMethod(Object, String, boolean)}.  The arguments passed to the method are taken from any nested
141:             * {@link MethodParameter} tags.  When the parameters which are added by the
142:             * {@link MethodParameter} tags are {@link java.lang.String} types, an attempt is made to convert each of
143:             * these parameters into the type expected by the method.  This conversion is done using the
144:             * {@link TypeUtils#convertToObject(java.lang.String, java.lang.Class)} method.  If a String can not
145:             * be converted do the type expected by the method, an exception is thrown and the error is reported
146:             * in the tag.  Any return value that results from invoking the given method is passed to the
147:             * subclass implementation of the method {@link #handleReturnValue(java.lang.Object)}.
148:             *
149:             * @return {@link #EVAL_PAGE} to continue evaluating the page
150:             * @throws JspException if there are errors.  All exceptions that may be thrown
151:             *                      in the process of reflectively invoking the method and performing type
152:             *                      conversion are reported as {@link JspException}
153:             * @see #findMethod(Object, String, boolean)
154:             * @see #handleReturnValue(java.lang.Object)
155:             * @see MethodParameter
156:             * @see ObjectNotFoundException
157:             * @see TypeUtils#convertToObject(java.lang.String, java.lang.Class)
158:             * @see java.lang.String
159:             */
160:            public int doEndTag() throws JspException {
161:
162:                // find the object on which to invoke the method
163:                Object object = null;
164:                try {
165:                    object = resolveObject();
166:                } catch (ObjectNotFoundException onf) {
167:                    Throwable cause = (onf.getCause() != null ? onf.getCause()
168:                            : onf);
169:                    String msg = Bundle.getErrorString(
170:                            "Tags_AbstractCallMethod_noSuchObject",
171:                            new Object[] { getObjectName(), _method, cause });
172:                    registerTagError(msg, null);
173:                }
174:
175:                // if this tag can accept null invocation targets, 
176:                if (object == null) {
177:                    if (allowNullInvocationTarget()) {
178:                        // each implementation does this on their own
179:                        handleReturnValue(null);
180:                        localRelease();
181:                        return EVAL_PAGE;
182:                    } else {
183:                        String msg = Bundle.getErrorString(
184:                                "Tags_AbstractCallMethod_objectIsNull",
185:                                new Object[] { getObjectName(), _method });
186:                        registerTagError(msg, null);
187:                    }
188:                }
189:
190:                if (hasErrors()) {
191:                    reportErrors();
192:                    localRelease();
193:                    return EVAL_PAGE;
194:                }
195:
196:                Method m = findMethod(object, _method, _verifyTypes);
197:
198:                if (m == null) {
199:                    String msg = null;
200:                    if (_verifyTypes) {
201:                        String paramString = prettyPrintParameterTypes(_parameters);
202:                        msg = Bundle
203:                                .getErrorString(
204:                                        "Tags_AbstractCallMethod_noSuchMethodWithTypes",
205:                                        new Object[] {
206:                                                _method,
207:                                                (_parameters != null ? new Integer(
208:                                                        _parameters.size())
209:                                                        : new Integer(0)),
210:                                                paramString, getObjectName() });
211:                    } else
212:                        msg = Bundle.getErrorString(
213:                                "Tags_AbstractCallMethod_noSuchMethod",
214:                                new Object[] {
215:                                        _method,
216:                                        (_parameters != null ? new Integer(
217:                                                _parameters.size())
218:                                                : new Integer(0)),
219:                                        getObjectName() });
220:
221:                    registerTagError(msg, null);
222:                    reportErrors();
223:                    localRelease();
224:                    return EVAL_PAGE;
225:                }
226:
227:                Object[] args = null;
228:                try {
229:                    args = getArguments(m.getParameterTypes());
230:                } catch (IllegalArgumentException iae) {
231:                    registerTagError(iae.getMessage(), null);
232:                    reportErrors();
233:                    localRelease();
234:                    return EVAL_PAGE;
235:                }
236:
237:                // invoke method
238:                Object result = null;
239:                try {
240:                    if (LOGGER.isDebugEnabled()) {
241:                        LOGGER.debug("method: " + m.toString());
242:                        for (int i = 0; i < args.length; i++)
243:                            LOGGER.debug("arg["
244:                                    + i
245:                                    + "]: "
246:                                    + (args[i] != null ? args[i].getClass()
247:                                            .getName() : "null"));
248:                    }
249:
250:                    result = m.invoke(object, args);
251:                } catch (Exception e) {
252:                    assert e instanceof  IllegalAccessException
253:                            || e instanceof  InvocationTargetException
254:                            || e instanceof  IllegalArgumentException;
255:
256:                    if (LOGGER.isErrorEnabled())
257:                        LOGGER.error("Could not invoke method \"" + _method
258:                                + "\" on the object named \"" + getObjectName()
259:                                + "\" because: " + e, e);
260:
261:                    if (_failOnError) {
262:                        String msg = Bundle.getErrorString(
263:                                "Tags_AbstractCallMethod_invocationError",
264:                                new Object[] { _method, getObjectName(), e });
265:                        registerTagError(msg, null);
266:                        reportErrors();
267:                        localRelease();
268:                        return EVAL_PAGE;
269:                    }
270:                }
271:
272:                if (LOGGER.isDebugEnabled()) {
273:                    LOGGER
274:                            .debug((result != null ? "return value is non-null and is of type \""
275:                                    + result.getClass().getName() + "\""
276:                                    : "return value is null."));
277:                }
278:
279:                /* allow the tag to handle the return value */
280:                handleReturnValue(result);
281:
282:                localRelease();
283:
284:                return EVAL_PAGE;
285:            }
286:
287:            /**
288:             * Reset all of the fields of this tag.
289:             */
290:            protected void localRelease() {
291:                super .localRelease();
292:                _parameters = null;
293:                _method = null;
294:                _failOnError = true;
295:                _resultId = null;
296:                _verifyTypes = false;
297:            }
298:
299:            /**
300:             * <p/>
301:             * Resolve the object on which the method should be invoked.  If there are errors resolving this object,
302:             * this method will throw an {@link ObjectNotFoundException}.
303:             * </p>
304:             * <p>
305:             * If the object is not found but no exception occurred, this method returns <code>null</code>.
306:             * </p>
307:             *
308:             * @return the object on which to reflectively invoke the method or <code>null</code> if the
309:             *         object was not found and no exception occurred.
310:             * @throws ObjectNotFoundException if an exception occurred attempting to resolve an object
311:             */
312:            protected abstract Object resolveObject()
313:                    throws ObjectNotFoundException, JspException;
314:
315:            /**
316:             * The default findMethod implementation is an uncached search of all
317:             * of the methods available on the Class of the <code>target</code>
318:             *
319:             * @param target      the object from which to find the method
320:             * @param methodName  the name of the method to find
321:             * @param verifyTypes a boolean that if true will match the type names in addition to the String method name
322:             * @return a Method object matching the methodName and types, if <code>verifyTypes</code> is true.
323:             *         <code>null</code> otherwise.
324:             */
325:            protected abstract Method findMethod(Object target,
326:                    String methodName, boolean verifyTypes);
327:
328:            /**
329:             * Get the name of the object that is the target of the invocation.  This is a generic method for this
330:             * tag that enables more specific error reporting.
331:             *
332:             * @return a name for the object on which the method will be invoked.
333:             */
334:            protected abstract String getObjectName();
335:
336:            /**
337:             * When implemented to return true, this method allows a tag invoking a method to
338:             * accept a null invocation target and simply return null.  The default
339:             * implementation returns false.
340:             *
341:             * @return true if the object on which to invoke the method can be null; false otherwise.
342:             */
343:            protected boolean allowNullInvocationTarget() {
344:                return false;
345:            }
346:
347:            /**
348:             * <p/>
349:             * A method that allows concrete classes to handle the result of the
350:             * reflective invocation in an implementation specific way.
351:             * </p>
352:             * <p/>
353:             * The default beahavior is to set the return value resulting from invoking the method
354:             * in the {@link javax.servlet.jsp.PageContext} attribute map of the current JSP page.
355:             * The result is set as an attribute if the <code>result</code> is not null and the
356:             * {@link CallMethod#setResultId(java.lang.String)} String is not null.  If the value returned
357:             * from calling a method is null and the {@link CallMethod#setResultId(java.lang.String)} is non-null,
358:             * the {@link javax.servlet.jsp.PageContext#removeAttribute(java.lang.String)}
359:             * is called to remove the attribute from the attribute map.
360:             * </p>
361:             *
362:             * @param result the object that was returned by calling the method on the object
363:             */
364:            protected void handleReturnValue(Object result) {
365:                if (_resultId != null) {
366:                    if (result != null) {
367:                        if (LOGGER.isInfoEnabled()
368:                                && pageContext.getAttribute(_resultId) != null)
369:                            LOGGER
370:                                    .info("Overwriting attribute named \""
371:                                            + _resultId
372:                                            + "\" in the PageContext with a new attribute of type \""
373:                                            + result.getClass().getName()
374:                                            + "\" returned from calling the method \""
375:                                            + _method
376:                                            + "\" on an object named \""
377:                                            + getObjectName() + "\".");
378:
379:                        pageContext.setAttribute(_resultId, result);
380:                    } else {
381:                        if (LOGGER.isInfoEnabled())
382:                            LOGGER
383:                                    .info("Removing attribute named \""
384:                                            + _resultId
385:                                            + "\" from the PageContext.  "
386:                                            + "The value returned from calling the method \""
387:                                            + _method
388:                                            + "\" on an object named \""
389:                                            + getObjectName() + "\" is null.");
390:
391:                        pageContext.removeAttribute(_resultId);
392:                    }
393:                }
394:            }
395:
396:            /**
397:             * Internal, read-only property used by subclasses to get
398:             * the list of parameters to be used when reflectively
399:             * invoking a method.  If the method takes no parameters, this
400:             * list will be of size zero.
401:             *
402:             * @return the list of parameters
403:             */
404:            protected List getParameterNodes() {
405:                return _parameters != null ? _parameters
406:                        : Collections.EMPTY_LIST;
407:            }
408:
409:            /**
410:             * Convert the arguments for a method from Strings set as attributes
411:             * on JSP tags to the types represented by teh list of Class[] objects
412:             * provided here.
413:             *
414:             * @return an Object[] that contains the parameters to pass to the method
415:             * @throws IllegalArgumentException if an error occurs converting an
416:             *                                  argument to a specific type.
417:             */
418:            private Object[] getArguments(Class[] paramTypes) {
419:                if (_parameters == null)
420:                    return EMPTY_ARGS;
421:
422:                Object[] args = new Object[paramTypes.length];
423:
424:                for (int i = 0; i < _parameters.size(); i++) {
425:                    ParamNode pn = (ParamNode) _parameters.get(i);
426:
427:                    if (LOGGER.isDebugEnabled())
428:                        LOGGER.debug("argTypes[" + i + "]: " + paramTypes[i]);
429:
430:                    /* if the parameter should have been null, leave it null */
431:                    if (pn.paramValue == MethodParameter.NULL_ARG)
432:                        continue;
433:
434:                    Object value = pn.paramValue;
435:                    try {
436:                        /* if the value wasn't a String, assume it was referenced via an expression language
437:                           and is already of the correct type */
438:                        if (!(value instanceof  String) || value == null)
439:                            args[i] = value;
440:                        /* convert a non-null String value using the registered type converters */
441:                        else
442:                            args[i] = TypeUtils.convertToObject((String) value,
443:                                    paramTypes[i]);
444:                    }
445:                    /* catch Exception here because almost anything can be thrown by TypeUtils.convertToObject(). */
446:                    catch (Exception e) {
447:                        String msg = Bundle.getErrorString(
448:                                "Tags_AbstractCallMethod_parameterError",
449:                                new Object[] { paramTypes[i], new Integer(i),
450:                                        value, e.toString() });
451:                        throw new IllegalArgumentException(msg);
452:                    }
453:                }
454:
455:                return args;
456:            }
457:
458:            /**
459:             * Utility method that pretty-prints the types of the parameters
460:             * passed to a method; this is used in debugging.
461:             *
462:             * @param parameters the list of parameters
463:             * @return a String that represents the types of each of these paramters in order
464:             */
465:            private static String prettyPrintParameterTypes(List parameters) {
466:                InternalStringBuilder paramString;
467:                if (parameters != null && parameters.size() > 0) {
468:                    paramString = new InternalStringBuilder(128);
469:                    paramString.append("(");
470:                    for (int i = 0; i < parameters.size(); i++) {
471:                        if (i > 0)
472:                            paramString.append(", ");
473:                        paramString
474:                                .append(((ParamNode) parameters.get(i)).typeName);
475:                    }
476:                    paramString.append(")");
477:
478:                    return paramString.toString();
479:                } else
480:                    return "";
481:            }
482:
483:            /**
484:             * An internal struct that represents a parameter that will be passed to a
485:             * reflective method invocation call.  Instances of <code>ParamNode</code>
486:             * map 1:1 to the methodParameter tags that appear within the body of
487:             * an AbstrctCallMethod tag.
488:             *
489:             * @exclude
490:             */
491:            protected class ParamNode {
492:                /**
493:                 * The fully qualified class name of the parameter type.  This value
494:                 * can be null if parameter type checking does not need to occur.
495:                 */
496:                String typeName = null;
497:
498:                /**
499:                 * The value of the parameter.  Often, this is a String expression
500:                 * which is evaluated later and converted into some Object
501:                 * type such as Integer or Foobar.
502:                 */
503:                Object paramValue = null;
504:            }
505:        }
w___ww___.__j__a_v_a__2___s___.___c_o___m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.