2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.tiger.view.faces;
19  
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.util.HashMap;
23  import java.util.Map;
24  import javax.faces.context.FacesContext;
25  import org.apache.shale.tiger.view.Preprocess;
26  import org.apache.shale.tiger.view.Prerender;
27  import org.apache.shale.tiger.view.View;
28  import org.apache.shale.view.ViewController;
29  import org.apache.shale.view.faces.ViewControllerCallbacks;
30  
31  /***
32   * <p>Utility class to perform the event callbacks specified by the
33   * {@link ViewController} interface.  This version will call through
34   * to ViewController methods if the bean class actually implements this
35   * interface, or ituses annotations to identify the relevant methods.</p>
36   *
37   * <p><strong>NOTE</strong> - The annotated callback methods must be
38   * public, and take no arguments.  They may exist on the class of the
39   * instance being passed in, or be inherited from a superclass.</p>
40   *
41   * $Id: ViewControllerCallbacks2.java 465074 2006-10-17 22:05:53Z rahul $
42   *
43   * @since 1.0.1
44   */
45  public class ViewControllerCallbacks2 extends ViewControllerCallbacks {
46  
47  
48      // ------------------------------------------------------------ Constructors
49  
50  
51      // ------------------------------------------------------ Instance Variables
52  
53  
54      // ---------------------------------------------------------- Public Methods
55  
56  
57      /***
58       * <p>Perform the <code>preprocess</code> callback on the specified
59       * instance.</p>
60       *
61       * @param instance Bean instance on which to perform this callback
62       */
63      public void preprocess(Object instance) {
64  
65          if (instance instanceof ViewController) {
66              try {
67                  ((ViewController) instance).preprocess();
68              } catch (Exception e) {
69                  handleException(FacesContext.getCurrentInstance(), e);
70              }
71              return;
72          }
73  
74          Method method = method(instance, Preprocess.class);
75          if (method != null) {
76              try {
77                  method.invoke(instance, new Object[0]);
78              } catch (IllegalAccessException e) {
79                  handleException(FacesContext.getCurrentInstance(), e);
80              } catch (InvocationTargetException e) {
81                  handleException(FacesContext.getCurrentInstance(), (Exception) e.getCause());
82              }
83          }
84  
85      }
86  
87  
88      /***
89       * <p>Perform the <code>prerender</code> callback on the specified
90       * instance.</p>
91       *
92       * @param instance Bean instance on which to perform this callback
93       */
94      public void prerender(Object instance) {
95  
96          if (instance instanceof ViewController) {
97              try {
98                  ((ViewController) instance).prerender();
99              } catch (Exception e) {
100                 handleException(FacesContext.getCurrentInstance(), e);
101             }
102             return;
103         }
104 
105         Method method = method(instance, Prerender.class);
106         if (method != null) {
107             try {
108                 method.invoke(instance, new Object[0]);
109             } catch (IllegalAccessException e) {
110                 handleException(FacesContext.getCurrentInstance(), e);
111             } catch (InvocationTargetException e) {
112                 handleException(FacesContext.getCurrentInstance(), (Exception) e.getCause());
113             }
114         }
115 
116     }
117 
118 
119     // --------------------------------------------------------- Private Methods
120 
121 
122     /***
123      * <p>The set of method annotations for callbacks of interest.</p>
124      */
125     private static final Class[] annotations =
126     { Preprocess.class, Prerender.class };
127 
128 
129 
130     /***
131      * <p>Data structure to maintain information about annotated
132      * methods.  In this map, the key is the Class being analyzed,
133      * and the value is an inner map.  In the inner map, the key
134      * is an Annotation class, and the value is the corresponding
135      * Method instance.</p>
136      */
137     private transient Map<Class,Map<Class,Method>> maps =
138       new HashMap<Class,Map<Class,Method>>();
139 
140 
141     /***
142      * <p>Return the <code>Method</code> to be called for the specified
143      * annotation on the specified instance, if any.  If there is no such
144      * method, return <code>null</code>.</p>
145      *
146      * @param instance Instance on which callbacks will be performed
147      * @param annotation Annotation for which to return a method
148      */
149     private Method method(Object instance, Class annotation) {
150 
151         // Does the underlying class implement the View annotation?
152         // If not, exit early
153         Class clazz = instance.getClass();
154         if (clazz.getAnnotation(View.class) == null) {
155             return null;
156         }
157 
158         synchronized (maps) {
159 
160             // If we have seen this Class already, simply return the
161             // previously located Method (if any)
162             Map<Class,Method> map = maps.get(clazz);
163             if (map != null) {
164                 return map.get(annotation);
165             }
166 
167             // Construct and cache a new Map identifying the
168             // methods of interest for these callbacks
169             map = new HashMap<Class,Method>();
170             Method[] methods = clazz.getMethods();
171             for (int i = 0; i < methods.length; i++) {
172                 if (methods[i].getParameterTypes().length > 0) {
173                     continue;
174                 }
175                 for (int j = 0; j < annotations.length; j++) {
176                     if (methods[i].getAnnotation(annotations[j]) != null) {
177                         map.put(annotations[j], methods[i]);
178                     }
179                 }
180             }
181             maps.put(clazz, map);
182             return map.get(annotation);
183 
184         }
185 
186     }
187 
188 
189 }