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

nextapp.echo.webcontainer.ComponentInputProcessor Maven / Gradle / Ivy

/* 
 * This file is part of the Echo Web Application Framework (hereinafter "Echo").
 * Copyright (C) 2002-2009 NextApp, Inc.
 *
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 */

package nextapp.echo.webcontainer;

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

import nextapp.echo.app.Component;
import nextapp.echo.app.serial.PropertyPeerFactory;
import nextapp.echo.app.serial.SerialException;
import nextapp.echo.app.serial.SerialPropertyPeer;
import nextapp.echo.app.update.UpdateManager;
import nextapp.echo.app.util.Context;
import nextapp.echo.app.util.DomUtil;
import nextapp.echo.app.util.Log;

import org.w3c.dom.Element;

/**
 * ClientMessage.Processor which de-serializes
 * changed properties and fired events generated by the
 * client-side component hierarchy and passes them
 * to appropriate ComponentSynchronizePeers
 * for processing.
 */
public class ComponentInputProcessor
implements ClientMessage.Processor {
    
    private Map componentUpdateMap = new HashMap();
    private String eventComponentId;
    private Element eventElement;
    private String eventType;
    
    /**
     * Returns the event element of the event that resulted in the client-server interaction.
     * 
     * @return the event element
     */
    private Element getEvent() {
        return eventElement;
    }
    
    /**
     * Returns the id of the component that fired the event that resulted in the client-server interaction.
     * 
     * @return the event component id
     */
    private String getEventComponentId() {
        return eventComponentId;
    }

    /**
     * Returns the event type.
     * 
     * @return the event type
     */
    private String getEventType() {
        return eventType;
    }
    
    /**
     * Returns the ids of all updated components.
     * 
     * @return the ids of all updated components.
     */
    private Iterator getUpdatedComponentIds() {
        return componentUpdateMap.keySet().iterator(); 
    }
    
    /**
     * Returns the "p" element of a specific updated property of a specific component
     * 
     * @param componentId the id of the component
     * @param propertyName the name of the property
     * @return the property element
     */
    private Element getUpdatedProperty(String componentId, String propertyName) {
        Map propertyMap = (Map) componentUpdateMap.get(componentId);
        return (Element) propertyMap.get(propertyName);
    }
    
    /**
     * Returns the names of updated properties for a specific component.
     * 
     * @param componentId the id of the component
     * @return the updated property names
     */
    private Iterator getUpdatedPropertyNames(String componentId) {
        Map propertyMap = (Map) componentUpdateMap.get(componentId);
        return propertyMap.keySet().iterator();
    }
    
    /**
     * Parses the component synchronize directive element, storing
     * necessary values in instance variables for later processing.
     * 
     * @param dirElement the "dir" element to parse
     */
    private void parseDirElement(Element dirElement) {
        // Retrieve event.
        eventElement = DomUtil.getChildElementByTagName(dirElement, "e");
        if (eventElement != null) {
            eventType = eventElement.getAttribute("t");
            eventComponentId = eventElement.getAttribute("i");
        }
        
        // Retrieve property updates.
        Element[] pElements = DomUtil.getChildElementsByTagName(dirElement, "p");
        for (int i = 0; i < pElements.length; ++i) {
            String componentId = pElements[i].getAttribute("i");
            String propertyName = pElements[i].getAttribute("n");
        
            Map propertyMap = (Map) componentUpdateMap.get(componentId);
            if (propertyMap == null) {
                propertyMap = new HashMap();
                componentUpdateMap.put(componentId, propertyMap);
            }
            
            propertyMap.put(propertyName, pElements[i]);
        }
    }
    
    /**
     * @see nextapp.echo.webcontainer.ClientMessage.Processor#process(nextapp.echo.app.util.Context, org.w3c.dom.Element)
     */
    public void process(Context context, Element dirElement) 
    throws IOException {
        parseDirElement(dirElement);
        
        UserInstance userInstance = (UserInstance) context.get(UserInstance.class);
        userInstance.prepareApplicationInstance();
        
        PropertyPeerFactory propertyPeerFactory = (PropertyPeerFactory) context.get(PropertyPeerFactory.class);
        UpdateManager updateManager = userInstance.getApplicationInstance().getUpdateManager();

        Iterator updatedComponentIdIt  = getUpdatedComponentIds();
        while (updatedComponentIdIt.hasNext()) {
            String componentId = (String) updatedComponentIdIt.next();
            Component component = userInstance.getComponentByClientRenderId(componentId);
            ComponentSynchronizePeer componentPeer = SynchronizePeerFactory.getPeerForComponent(component.getClass());
            
            // Process updated properties.
            Iterator updatedPropertyIt = getUpdatedPropertyNames(componentId);
            while (updatedPropertyIt.hasNext()) {
                String propertyName = (String) updatedPropertyIt.next();
                Element propertyElement = getUpdatedProperty(componentId, propertyName);

                Class propertyClass = componentPeer.getInputPropertyClass(propertyName);
                if (propertyClass == null) {
                    // Ignore property.
                    continue;
                }
                
                // Retrieve peer for property class.
                SerialPropertyPeer propertyPeer = propertyPeerFactory.getPeerForProperty(propertyClass);
                
                if (propertyPeer == null) {
                    // Property peer not available, log error, continue.
                    Log.log("No peer available for property: " + propertyName + " of class: " + propertyClass);
                    continue;
                }
                
                try {
                    // Invoke storeInputProperty() method on component peer.
                    Object propertyValue = propertyPeer.toProperty(context, component.getClass(), propertyElement);
                    componentPeer.storeInputProperty(context, component, propertyName, -1, propertyValue);
                } catch (SerialException ex) {
                    throw new SynchronizationException(
                            "Unable to store input property: " + propertyName + " of class: " + propertyClass, ex);
                }
            }
        }
        
        // Process event which caused client-server synchronization request, if applicable.
        if (getEvent() != null) {
            Component component = userInstance.getComponentByClientRenderId(getEventComponentId());
            ComponentSynchronizePeer componentPeer = SynchronizePeerFactory.getPeerForComponent(component.getClass());
            Class eventDataClass = componentPeer.getEventDataClass(getEventType());
            if (eventDataClass == null) {
                componentPeer.processEvent(context, component, getEventType(), null);
            } else {
                SerialPropertyPeer propertyPeer = propertyPeerFactory.getPeerForProperty(eventDataClass);
                if (propertyPeer == null) {
                    Log.log("No peer available for event data for event type: " + getEventType() 
                            + " of class: " + eventDataClass);
                }
                try {
                    Object eventData = propertyPeer.toProperty(context, component.getClass(), getEvent());
                    componentPeer.processEvent(context, component, getEventType(), eventData);
                } catch (SerialException ex) {
                    throw new SynchronizationException(
                            "Unable to store event data for event type: " + getEventType() + " of class: " + eventDataClass, ex);
                }
            }
        }

        updateManager.processClientUpdates();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy