com.google.gdt.eclipse.designer.uibinder.parser.UiBinderRenderer.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gdt.eclipse.designer.uibinder.parser.UiBinderRenderer.java

Source

/*******************************************************************************
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * 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 com.google.gdt.eclipse.designer.uibinder.parser;

import com.google.common.collect.Maps;
import com.google.gdt.eclipse.designer.uibinder.model.widgets.IsWidgetWrappedInfo;

import org.eclipse.wb.core.model.ObjectInfo;
import org.eclipse.wb.internal.core.model.ObjectInfoVisitor;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.xml.DocumentElement;
import org.eclipse.wb.internal.core.xml.model.EditorContext;
import org.eclipse.wb.internal.core.xml.model.XmlObjectInfo;
import org.eclipse.wb.internal.core.xml.model.creation.CreationSupport;
import org.eclipse.wb.internal.core.xml.model.utils.GlobalStateXml;
import org.eclipse.wb.internal.core.xml.model.utils.XmlObjectUtils;

import org.apache.commons.lang.StringUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * Renderer for GWT UiBinder.
 * 
 * @author scheglov_ke
 * @coverage GWT.UiBinder.parser
 */
public final class UiBinderRenderer {
    private final XmlObjectInfo m_rootModel;
    private final UiBinderContext m_context;
    private final Map<String, XmlObjectInfo> m_pathToModelMap = Maps.newHashMap();

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public UiBinderRenderer(XmlObjectInfo rootModel) throws Exception {
        m_rootModel = rootModel;
        m_context = (UiBinderContext) m_rootModel.getContext();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Render
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Renders current content of {@link EditorContext} and fill objects for {@link XmlObjectInfo}s.
     */
    public void render() throws Exception {
        m_context.runDesignTime(new RunnableEx() {
            public void run() throws Exception {
                render0();
            }
        });
    }

    /**
     * Implementation of {@link #render()}.
     */
    private void render0() throws Exception {
        GlobalStateXml.activate(m_rootModel);
        fillMap_pathToModel();
        // load Binder
        Object createdBinder;
        {
            ClassLoader classLoader = m_context.getClassLoader();
            String binderClassName = m_context.getBinderClassName();
            m_context.getState().getDevModeBridge().invalidateRebind(binderClassName);
            Class<?> binderClass = classLoader.loadClass(binderClassName);
            Class<?> classGWT = classLoader.loadClass("com.google.gwt.core.client.GWT");
            createdBinder = ReflectionUtils.invokeMethod(classGWT, "create(java.lang.Class)", binderClass);
            setObjects(createdBinder);
        }
        // render Widget(s)
        ReflectionUtils.invokeMethod(createdBinder, "createAndBindUi(java.lang.Object)", (Object) null);
        setAttributes(createdBinder);
    }

    /**
     * Visits all {@link XmlObjectInfo} and remembers all of them with path.
     */
    private void fillMap_pathToModel() {
        m_rootModel.accept(new ObjectInfoVisitor() {
            @Override
            public void endVisit(ObjectInfo objectInfo) throws Exception {
                if (objectInfo instanceof XmlObjectInfo) {
                    XmlObjectInfo xmlObjectInfo = (XmlObjectInfo) objectInfo;
                    CreationSupport creationSupport = xmlObjectInfo.getCreationSupport();
                    if (!XmlObjectUtils.isImplicit(xmlObjectInfo)) {
                        DocumentElement element = creationSupport.getElement();
                        String path = UiBinderParser.getPath(element);
                        if (xmlObjectInfo instanceof IsWidgetWrappedInfo) {
                            xmlObjectInfo = ((IsWidgetWrappedInfo) xmlObjectInfo).getWrapper();
                        }
                        m_pathToModelMap.put(path, xmlObjectInfo);
                    }
                }
            }
        });
    }

    private void setObjects(Object binder) throws Exception {
        ClassLoader classLoader = binder.getClass().getClassLoader();
        String handlerClassName = binder.getClass().getName() + "$DTObjectHandler";
        Class<?> handlerClass = classLoader.loadClass(handlerClassName);
        Object handler = Proxy.newProxyInstance(classLoader, new Class[] { handlerClass }, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("handle")) {
                    String path = (String) args[0];
                    Object object = args[1];
                    XmlObjectInfo objectInfo = m_pathToModelMap.get(path);
                    objectInfo.setObject(object);
                }
                if (method.getName().equals("provideFactory")) {
                    Class<?> factoryType = (Class<?>) args[0];
                    String methodName = (String) args[1];
                    Object[] factoryArgs = (Object[]) args[2];
                    return UiBinderParser.createProvidedFactory(m_context, factoryType, methodName, factoryArgs);
                }
                if (method.getName().equals("provideField")) {
                    Class<?> fieldType = (Class<?>) args[0];
                    String fieldName = (String) args[1];
                    return UiBinderParser.createProvidedField(m_context, fieldType, fieldName);
                }
                return null;
            }
        });
        ReflectionUtils.setField(binder, "dtObjectHandler", handler);
    }

    private void setAttributes(Object binder) throws Exception {
        @SuppressWarnings("unchecked")
        Map<String, Object> attributes = (Map<String, Object>) ReflectionUtils.getFieldObject(binder,
                "dtAttributes");
        // individual attributes for models
        for (Map.Entry<String, Object> entry : attributes.entrySet()) {
            String path;
            String attribute;
            {
                String key = entry.getKey();
                String[] keyParts = StringUtils.split(key);
                path = keyParts[0];
                attribute = keyParts[1];
            }
            XmlObjectInfo objectInfo = m_pathToModelMap.get(path);
            if (objectInfo != null) {
                Object value = entry.getValue();
                objectInfo.registerAttributeValue(attribute, value);
            }
        }
        // attributes for all elements
        m_context.setAttributeValues(attributes);
    }
}