/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Header:$
*/
package org.apache.beehive.netui.pageflow.faces.internal;
import org.apache.beehive.netui.pageflow.internal.InternalUtils;
import org.apache.beehive.netui.pageflow.internal.AnnotationReader;
import org.apache.beehive.netui.pageflow.internal.annotationreader.ProcessedAnnotation;
import org.apache.beehive.netui.util.logging.Logger;
import org.apache.beehive.netui.util.internal.cache.FieldCache;
import org.apache.beehive.netui.util.internal.cache.MethodCache;
import javax.faces.el.MethodBinding;
import javax.faces.el.MethodNotFoundException;
import javax.faces.el.EvaluationException;
import javax.faces.context.FacesContext;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponentBase;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletContext;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
/**
* Internal class used in JSF/Page Flow integration. This exists to cause form beans to be submitted to Page Flow
* actions raised from JSF command event handlers.
* @see org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory
*/
public class BackingClassMethodBinding
extends MethodBinding
implements StateHolder
{
private static final Logger _log = Logger.getInstance( BackingClassMethodBinding.class );
private static final FieldCache _fieldCache = new FieldCache();
private static final MethodCache _methodCache = new MethodCache();
private String _methodName;
private Class[] _params;
private MethodBinding _delegate;
private boolean _transient = false;
public BackingClassMethodBinding()
{
}
public BackingClassMethodBinding( String methodName, Class[] params, MethodBinding delegate )
{
_methodName = methodName;
_params = params;
_delegate = delegate;
}
public Class getType( FacesContext context )
throws MethodNotFoundException
{
return _delegate.getType( context );
}
public String getExpressionString() {
return _delegate.getExpressionString();
}
/**
* Before returning the result from the base MethodBinding, see if the bound method is annotated with
* Jpf.CommandHandler. If it is, look through the "raiseActions" annotation array for a form bean member variable
* associated with the action being raised. If one is found, set it in the request so it gets passed to the action.
*/
public Object invoke( FacesContext context, Object params[] )
throws EvaluationException, MethodNotFoundException
{
Object result = _delegate.invoke( context, params );
if ( result instanceof String )
{
String action = ( String ) result;
Object request = context.getExternalContext().getRequest();
assert request != null;
assert request instanceof HttpServletRequest : request.getClass().getName();
Object servletContextObject = context.getExternalContext().getContext();
assert servletContextObject instanceof ServletContext : servletContextObject.getClass().getName();
ServletContext servletContext = ( ServletContext ) servletContextObject;
HttpServletRequest httpRequest = ( HttpServletRequest ) request;
Object backingBean = InternalUtils.getFacesBackingBean( httpRequest, servletContext );
if ( backingBean != null )
{
Class backingClass = backingBean.getClass();
Method method = _methodCache.getMethod( backingClass, _methodName, _params );
if ( method == null ) throw new MethodNotFoundException( _methodName );
AnnotationReader annReader = AnnotationReader.getAnnotationReader( backingClass, servletContext );
ProcessedAnnotation ann = annReader.getJpfAnnotation( method, "CommandHandler" );
if ( ann != null )
{
ProcessedAnnotation[] raiseActions =
AnnotationReader.getAnnotationArrayAttribute( ann, "raiseActions" );
if ( raiseActions != null )
{
setOutputFormBeans( raiseActions, backingClass, backingBean, action, httpRequest );
}
}
}
}
return result;
}
private static void setOutputFormBeans( ProcessedAnnotation[] raiseActions, Class backingClass, Object backingBean,
String action, HttpServletRequest httpRequest )
{
for ( int i = 0; i < raiseActions.length; i++ )
{
ProcessedAnnotation raiseAction = raiseActions[i];
String actionAttr = AnnotationReader.getStringAttribute( raiseAction, "action" );
if ( actionAttr.equals( action ) )
{
String formBeanMember =
AnnotationReader.getStringAttribute( raiseAction, "outputFormBean" );
if ( formBeanMember != null && formBeanMember.length() > 0 )
{
try
{
Field field = _fieldCache.getDeclaredField( backingClass, formBeanMember );
if ( field == null )
{
_log.error( "Could not find field " + formBeanMember + " specified as the outputFormBean "
+ "for action " + action + " raised by " + backingClass.getName() );
return;
}
Object value = field.get( backingBean );
InternalUtils.setForwardedFormBean( httpRequest, InternalUtils.wrapFormBean( value ) );
}
catch ( IllegalAccessException e )
{
_log.error( "Could not access field " + formBeanMember + " specified as the outputFormBean "
+ "for action " + action + " raised by " + backingClass.getName(), e );
}
}
}
}
}
public Object saveState( FacesContext context )
{
return new Object[]{ _methodName, _params, UIComponentBase.saveAttachedState( context, _delegate ) };
}
public void restoreState( FacesContext context, Object state )
{
Object[] values = ( Object[] ) state;
_methodName = ( String ) values[0];
_params = ( Class[] ) values[1];
_delegate = ( MethodBinding ) UIComponentBase.restoreAttachedState( context, values[2] );
}
public boolean isTransient()
{
return _transient;
}
public void setTransient( boolean newTransientValue )
{
_transient = newTransientValue;
}
}