All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ajax4jsf.framework.ajax.AjaxViewRoot Maven / Gradle / Ivy

Go to download

Ajax4jsf is an open source extension to the JavaServer Faces standard that adds AJAX capability to JSF applications without requiring the writing of any JavaScript.

The newest version!
/**
 * Licensed under the Common Development and Distribution License,
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.sun.com/cddl/
 *   
 * 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.
 */

package org.ajax4jsf.framework.ajax;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;

import org.ajax4jsf.framework.renderer.AjaxContainerRenderer;
import org.ajax4jsf.framework.renderer.AjaxRendererUtils;
import org.ajax4jsf.framework.util.message.Messages;
import org.apache.commons.collections.Buffer;
import org.apache.commons.collections.BufferUnderflowException;


/**
 * Custom ViewRoot for support render parts of tree for Ajax requests.
 * Main difference from default ViewRoot - store events queue and unique id counter in request-scope
 * variables. In common realisation, store request-scope variables in component produce errors in
 * case of concurrent requests to same view.
 * @author [email protected] (latest modification by $Author: ishabalov $)
 * @version $Revision: 1.15 $ $Date: 2006/11/16 21:16:11 $
 *
 */
public class AjaxViewRoot extends UIViewRoot implements AjaxContainer {
	
	public static final String SUBMITTED_REGION_PARAM = "org.ajax4jsf.framework.ajax.SubmittedRegion";
	
	private static final String SUBMITTED_REGION_ID_PARAM = "org.ajax4jsf.framework.ajax.SubmittedRegionId";

	public static final String ROOT_ID = "_viewRoot";
	
	private boolean havePage = false;
	private boolean havePageChecked = false;

	/**
	 * Store map of clientId - full JSF Id of {@link AjaxContainer}'s in tree.
	 */
	private Map _ajaxRegions = new HashMap();
	
	protected AjaxRegionBrige _brige;


	/**
	 * Key for stopre events buffers in faces request-scope parameters.
	 */
	private static final String EVENTS_PARAMETER = "org.ajax4jsf.framevork.FacesEvents";

	private static final String AJAX_EVENTS_PARAMETER = "org.ajax4jsf.framevork.AjaxFacesEvents";

	/**
	 * 
	 */
	public AjaxViewRoot() {
		super();
		_brige = new AjaxRegionBrige(this);
		setId(ROOT_ID);
	}

	
	/* (non-Javadoc)
	 * @see javax.faces.component.UIComponentBase#getId()
	 */
//	public String getId() {
//		return ROOT_ID;
//	}

    public String getRendererType() {
        return (COMPONENT_FAMILY);        
    }
	

	/**
	 * Append AjaxRegion to map of components.
	 * @param region
	 */
	public void addAjaxRegion(UIComponent region) {
		if (region instanceof AjaxContainer) {
//			AjaxContainer container = (AjaxContainer) region;
			_ajaxRegions.put(region.getClientId(getFacesContext()), AjaxRendererUtils.getAbsoluteId(region));
		} else {
			throw new IllegalArgumentException(Messages.getMessage(Messages.ARGUMENT_IS_NOT_AJAX_REGION_ERROR, region.getClientId(getFacesContext())));
		}
	}
	
	/**
	 * Create {@link Iterator} for loop on all registered ajax Regions.
	 * @param regionId TODO
	 * @return
	 */
	public String getAjaxRegionId(String regionId) {
		return (String) _ajaxRegions.get(regionId);
	}
	
	public void setSubmittedRegion(String regionId) {
		UIComponent region = findComponent(regionId);
		AjaxContext state = AjaxContext.getCurrentInstance();
		if (null != region ) {
			state.setSubmittedRegionId(regionId);
			state.setSubmittedRegion(region);
		}
	}
	
	public UIComponent getSubmittedRegion(FacesContext context) {
		AjaxContext state = AjaxContext.getCurrentInstance(context);
		UIComponent region = state.getSubmittedRegion();
		if( null == region ) {
			// Test for creating component at JSP processing - find new instance by name
			String regionId = state.getSubmittedRegionId();
			if(null != regionId) {
				region = findComponent(regionId);
				state.setSubmittedRegion(region);
			} 
		}
		return region;
	}
	
	/**
	 * Reset instance of AjaxRegion in context - since component can re-created at page
	 */
	public void resetSubmittedRegionInstance() {
		AjaxContext.getCurrentInstance().setSubmittedRegion(null);		
	}


	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#addAjaxArea(java.lang.String)
	 */
	public void addAjaxArea(String toRender) {
		_brige.addAjaxArea(toRender);
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#addAjaxAreas(java.util.Collection)
	 */
	public void addAjaxAreas(Collection collection) {
		_brige.addAjaxAreas(collection);
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#broadcast(javax.faces.event.FacesEvent)
	 */
	public void broadcast(FacesEvent event) throws AbortProcessingException {
		super.broadcast(event);
		_brige.broadcast(event);
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#getAjaxListener()
	 */
	public MethodBinding getAjaxListener() {
		return _brige.getAjaxListener();
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#getAjaxAreasToRender()
	 */
	public Set getAjaxAreasToRender() {
		return _brige.getAjaxAreasToRender();
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#getAjaxRenderedAreas()
	 */
	public Set getAjaxRenderedAreas() {
		return _brige.getAjaxRenderedAreas();
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isAjaxRequest()
	 */
	public boolean isAjaxRequest() {
		return _brige.isAjaxRequest();
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isImmediate()
	 */
	public boolean isImmediate() {
		return _brige.isImmediate();
	}

	/* (non-Javadoc)
	 * @see org.ajax4jsf.framework.ajax.AjaxViewBrige#isSubmitted()
	 */
	public boolean isSubmitted() {
		return _brige.isSubmitted();
	}

	
    /* (non-Javadoc)
     * @see javax.faces.component.UIComponent#queueEvent(javax.faces.event.FacesEvent)
     */
    public void queueEvent(FacesEvent event)
    {
        if (event == null)
			throw new NullPointerException(Messages.getMessage(Messages.NULL_EVENT_SUBMITTED_ERROR));
		if (  event.getPhaseId().compareTo(PhaseId.RENDER_RESPONSE) == 0 ) {
			// HACK - Special case - Ajax Events to RenderResponse phase queue.
			// in future, with JSF 1.2 it must be done by invokeOnComponent method.
			// In 1.1 , events to RENDER_RESPONSE phase not used.
			getAjaxEventsQueue(getFacesContext()).add(event);
		} else {
			getEventsQueue(getFacesContext(), event.getPhaseId()).add(event);
        }
    }

    /**
     * Broadcast events for specified Phase
     * @param context 
     * @param phaseId - phase, for wich events must be processed.
     */
    void broadcastEvents(FacesContext context, PhaseId phaseId)
    {
    	Buffer[] events = getEvents(context);
    	Buffer anyPhaseEvents = events[PhaseId.ANY_PHASE.getOrdinal()];
    	Buffer phaseEvents = events[ phaseId.getOrdinal()];
        if (phaseEvents.isEmpty() && anyPhaseEvents.isEmpty() ) return;
//        FacesEvent event = null;
        boolean haveAnyPhaseEvents = ! anyPhaseEvents.isEmpty();
		boolean havePhaseEvents = ! phaseEvents.isEmpty();
		do 
        {
        	// ANY_PHASE first			
			processEvents(anyPhaseEvents, haveAnyPhaseEvents);
			
			processEvents(phaseEvents, havePhaseEvents);
			// Events can queued in other events processing
	        haveAnyPhaseEvents = ! anyPhaseEvents.isEmpty();
			havePhaseEvents = ! phaseEvents.isEmpty();
        } while(haveAnyPhaseEvents || havePhaseEvents );
        if (context.getRenderResponse() || context.getResponseComplete())
        {
            clearEvents(context);
        }

    }


	/**
	 * @param phaseEventsQueue
	 * @param havePhaseEvents
	 */
	private void processEvents(Buffer phaseEventsQueue, boolean havePhaseEvents) {
		FacesEvent event;
		while(havePhaseEvents) {
		    try {
				event = (FacesEvent) phaseEventsQueue.remove();
				UIComponent source = event.getComponent();
				try {
					source.broadcast(event);
				} catch (AbortProcessingException e) {
					// abort event processing
					// Page 3-30 of JSF 1.1 spec: "Throw an AbortProcessingException, to tell the JSF implementation
					//  that no further broadcast of this event, or any further events, should take place."
					//clearEvents();
					// return;
				} 
			} catch (BufferUnderflowException e) {
				havePhaseEvents = false;
			} 
		}
	}

    public void broadcastAjaxEvents(FacesContext context){
    	Buffer queue = getAjaxEventsQueue(context);
    	processEvents(queue,!queue.isEmpty());
    }

    /**
     * Use FIFO buffers for hold Faces Events. Hold this buffers in Request scope parameters for
     * support any concurrent requests for same component tree ( since RI hold component tree in session ).
     * @param context
     * @param phase
     * @return
     */
    private Buffer getEventsQueue(FacesContext context,PhaseId phase){   	
//    	Buffer[] events = (Buffer[]) context.getExternalContext().getRequestMap().get(EVENTS_PARAMETER);
//    	if (null == events) {
//    		int len;
//    		events = new Buffer[len = PhaseId.VALUES.size()];
//    		for(int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy