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.pageflow.faces.internal;
020:
021: import org.apache.beehive.netui.pageflow.internal.InternalUtils;
022: import org.apache.beehive.netui.pageflow.internal.AnnotationReader;
023: import org.apache.beehive.netui.pageflow.internal.annotationreader.ProcessedAnnotation;
024: import org.apache.beehive.netui.util.logging.Logger;
025: import org.apache.beehive.netui.util.internal.cache.FieldCache;
026: import org.apache.beehive.netui.util.internal.cache.MethodCache;
027:
028: import javax.faces.el.MethodBinding;
029: import javax.faces.el.MethodNotFoundException;
030: import javax.faces.el.EvaluationException;
031: import javax.faces.context.FacesContext;
032: import javax.faces.context.ExternalContext;
033: import javax.faces.component.StateHolder;
034: import javax.faces.component.UIComponentBase;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.ServletContext;
037: import java.lang.reflect.Method;
038: import java.lang.reflect.Field;
039:
040: /**
041: * Internal class used in JSF/Page Flow integration. This exists to cause form beans to be submitted to Page Flow
042: * actions raised from JSF command event handlers.
043: * @see org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory
044: */
045: public class BackingClassMethodBinding extends MethodBinding implements
046: StateHolder {
047: private static final Logger _log = Logger
048: .getInstance(BackingClassMethodBinding.class);
049: private static final FieldCache _fieldCache = new FieldCache();
050: private static final MethodCache _methodCache = new MethodCache();
051:
052: private String _methodName;
053: private Class[] _params;
054: private MethodBinding _delegate;
055: private boolean _transient = false;
056:
057: public BackingClassMethodBinding() {
058: }
059:
060: public BackingClassMethodBinding(String methodName, Class[] params,
061: MethodBinding delegate) {
062: _methodName = methodName;
063: _params = params;
064: _delegate = delegate;
065: }
066:
067: public Class getType(FacesContext context)
068: throws MethodNotFoundException {
069: return _delegate.getType(context);
070: }
071:
072: public String getExpressionString() {
073: return _delegate.getExpressionString();
074: }
075:
076: /**
077: * Before returning the result from the base MethodBinding, see if the bound method is annotated with
078: * Jpf.CommandHandler. If it is, look through the "raiseActions" annotation array for a form bean member variable
079: * associated with the action being raised. If one is found, set it in the request so it gets passed to the action.
080: */
081: public Object invoke(FacesContext context, Object params[])
082: throws EvaluationException, MethodNotFoundException {
083: Object result = _delegate.invoke(context, params);
084:
085: if (result instanceof String) {
086: String action = (String) result;
087: ExternalContext externalContext = context
088: .getExternalContext();
089: Object request = externalContext.getRequest();
090: Object servletContextObject = externalContext.getContext();
091: assert request != null;
092:
093: if (request instanceof HttpServletRequest
094: && servletContextObject instanceof ServletContext) {
095: ServletContext servletContext = (ServletContext) servletContextObject;
096: HttpServletRequest httpRequest = (HttpServletRequest) request;
097: Object backingBean = InternalUtils.getFacesBackingBean(
098: httpRequest, servletContext);
099:
100: if (backingBean != null) {
101: Class backingClass = backingBean.getClass();
102: Method method = _methodCache.getMethod(
103: backingClass, _methodName, _params);
104:
105: if (method == null) {
106: throw new MethodNotFoundException(_methodName);
107: }
108: AnnotationReader annReader = AnnotationReader
109: .getAnnotationReader(backingClass,
110: servletContext);
111: ProcessedAnnotation ann = annReader
112: .getJpfAnnotation(method, "CommandHandler");
113:
114: if (ann != null) {
115: ProcessedAnnotation[] raiseActions = AnnotationReader
116: .getAnnotationArrayAttribute(ann,
117: "raiseActions");
118:
119: if (raiseActions != null) {
120: setOutputFormBeans(raiseActions,
121: backingClass, backingBean, action,
122: httpRequest);
123: }
124: }
125: }
126: }
127: }
128:
129: return result;
130: }
131:
132: private static void setOutputFormBeans(
133: ProcessedAnnotation[] raiseActions, Class backingClass,
134: Object backingBean, String action,
135: HttpServletRequest httpRequest) {
136: for (int i = 0; i < raiseActions.length; i++) {
137: ProcessedAnnotation raiseAction = raiseActions[i];
138: String actionAttr = AnnotationReader.getStringAttribute(
139: raiseAction, "action");
140:
141: if (actionAttr.equals(action)) {
142: String formBeanMember = AnnotationReader
143: .getStringAttribute(raiseAction,
144: "outputFormBean");
145:
146: if (formBeanMember != null
147: && formBeanMember.length() > 0) {
148: try {
149: Field field = _fieldCache.getDeclaredField(
150: backingClass, formBeanMember);
151: if (field == null) {
152: _log
153: .error("Could not find field "
154: + formBeanMember
155: + " specified as the outputFormBean "
156: + "for action " + action
157: + " raised by "
158: + backingClass.getName());
159: return;
160: }
161: Object value = field.get(backingBean);
162: InternalUtils.setForwardedFormBean(httpRequest,
163: InternalUtils.wrapFormBean(value));
164: } catch (IllegalAccessException e) {
165: _log.error("Could not access field "
166: + formBeanMember
167: + " specified as the outputFormBean "
168: + "for action " + action
169: + " raised by "
170: + backingClass.getName(), e);
171: }
172: }
173: }
174: }
175: }
176:
177: public Object saveState(FacesContext context) {
178: return new Object[] { _methodName, _params,
179: UIComponentBase.saveAttachedState(context, _delegate) };
180: }
181:
182: public void restoreState(FacesContext context, Object state) {
183: Object[] values = (Object[]) state;
184: _methodName = (String) values[0];
185: _params = (Class[]) values[1];
186: _delegate = (MethodBinding) UIComponentBase
187: .restoreAttachedState(context, values[2]);
188: }
189:
190: public boolean isTransient() {
191: return _transient;
192: }
193:
194: public void setTransient(boolean newTransientValue) {
195: _transient = newTransientValue;
196: }
197: }
|