Whoa, I obviously missed an important thread. Can someone provide a
link, please, to the thread in which this was discussed?

Do we have a software grant on file? That's the very minimum we need
if this is a donation from Google and not from an (unaffiliated)
individual. We probably also need to go through IP Clearance.

--
Martin Cooper


On Tue, Jan 26, 2010 at 11:44 PM,  <lukaszlen...@apache.org> wrote:
> Author: lukaszlenart
> Date: Wed Jan 27 07:44:32 2010
> New Revision: 903559
>
> URL: http://svn.apache.org/viewvc?rev=903559&view=rev
> Log:
> Initial commit of all code donated by Google, all packages were renamed to 
> org.apache.struts
>
> Added:
>    struts/sandbox/trunk/struts2-gxp-plugin/
>    struts/sandbox/trunk/struts2-gxp-plugin/pom.xml
>    struts/sandbox/trunk/struts2-gxp-plugin/src/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/main/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxp.java
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxpResult.java
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Gxp.java
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpInstance.java
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpResult.java
>    
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Param.java
>    struts/sandbox/trunk/struts2-gxp-plugin/src/test/
>    struts/sandbox/trunk/struts2-gxp-plugin/src/test/java/
>
> Added: struts/sandbox/trunk/struts2-gxp-plugin/pom.xml
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/pom.xml?rev=903559&view=auto
> ==============================================================================
> --- struts/sandbox/trunk/struts2-gxp-plugin/pom.xml (added)
> +++ struts/sandbox/trunk/struts2-gxp-plugin/pom.xml Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,71 @@
> +<project xmlns="http://maven.apache.org/POM/4.0.0"; 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
> +         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
> http://maven.apache.org/maven-v4_0_0.xsd";>
> +    <modelVersion>4.0.0</modelVersion>
> +    <parent>
> +        <groupId>org.apache.struts</groupId>
> +        <artifactId>struts2-plugins</artifactId>
> +        <version>2.2.0-SNAPSHOT</version>
> +    </parent>
> +
> +    <groupId>org.apache.struts</groupId>
> +    <artifactId>struts2-gxp-plugin</artifactId>
> +    <packaging>jar</packaging>
> +    <name>Struts 2 GXP Plugin</name>
> +    <url>http://struts.apache.org</url>
> +
> +    <scm>
> +        
> <connection>scm:svn:http://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-gxp-plugin</connection>
> +        
> <developerConnection>scm:svn:https://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-gxp-plugin</developerConnection>
> +        
> <url>http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/struts2-gxp-plugin</url>
> +    </scm>
> +
> +    <dependencies>
> +        <dependency>
> +            <groupId>org.apache.struts</groupId>
> +            <artifactId>struts2-core</artifactId>
> +            <version>2.2.0-SNAPSHOT</version>
> +        </dependency>
> +        <dependency>
> +            <groupId>javax.servlet</groupId>
> +            <artifactId>servlet-api</artifactId>
> +            <version>2.4</version>
> +            <scope>provided</scope>
> +        </dependency>
> +        <!--
> +          Until GXP is added to the Google Maven Repository in early 2010 
> (http://code.google.com/p/gxp/issues/detail?id=5)
> +          Download http://gxp.googlecode.com/files/gxp-0.2.4-beta.jar
> +          Run the following at the command line (do not use 
> WindowsPowershell)
> +          mvn install:install-file -DgroupId=com.google -DartifactId=gxp 
> -Dversion=0.2.4-BETA -Dpackaging=jar -Dfile=gxp-0.2.4-beta.jar
> +        -->
> +        <dependency>
> +            <groupId>com.google</groupId>
> +            <artifactId>gxp</artifactId>
> +            <version>0.2.4-BETA</version>
> +        </dependency>
> +        <dependency>
> +            <groupId>junit</groupId>
> +            <artifactId>junit</artifactId>
> +            <version>3.8.1</version>
> +            <scope>test</scope>
> +        </dependency>
> +        <dependency>
> +            <groupId>com.google.collections</groupId>
> +            <artifactId>google-collections</artifactId>
> +            <version>1.0</version>
> +        </dependency>
> +    </dependencies>
> +
> +    <build>
> +        <defaultGoal>install</defaultGoal>
> +        <plugins>
> +            <plugin>
> +                <artifactId>maven-compiler-plugin</artifactId>
> +                <configuration>
> +                    <source>1.5</source>
> +                    <target>1.5</target>
> +                </configuration>
> +            </plugin>
> +        </plugins>
> +    </build>
> +
> +</project>
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxp.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxp.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxp.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxp.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,348 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.google.common.annotations.VisibleForTesting;
> +import com.google.gxp.base.GxpContext;
> +import com.google.gxp.base.MarkupClosure;
> +import com.opensymphony.xwork2.ActionContext;
> +import com.opensymphony.xwork2.inject.Inject;
> +import com.opensymphony.xwork2.util.ValueStack;
> +import com.opensymphony.xwork2.util.ValueStackFactory;
> +
> +import java.io.PrintWriter;
> +import java.io.StringWriter;
> +import java.lang.reflect.InvocationTargetException;
> +import java.lang.reflect.Method;
> +import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> +
> +/**
> + * Struts2 to GXP adapter. Can be used to write a GXP or create a
> + * {...@link MarkupClosure}. Pulls GXP parameters from Struts2 value stack.
> + *
> + * @author Bob Lee
> + */
> +public abstract class AbstractGxp<T extends MarkupClosure> {
> +
> +    ValueStackFactory valueStackFactory;
> +    Map defaultValues = new HashMap();
> +    List<Param> params;
> +    Class gxpClass;
> +    Method writeMethod;
> +    Method getGxpClosureMethod;
> +    boolean hasBodyParam;
> +
> +    protected AbstractGxp(Class gxpClass) {
> +        this(gxpClass, lookupMethodByName(gxpClass, "write"), 
> lookupMethodByName(gxpClass, "getGxpClosure"));
> +    }
> +
> +    protected AbstractGxp(Class gxpClass, Method writeMethod, Method 
> getGxpClosureMethod) {
> +        this.gxpClass = gxpClass;
> +        this.writeMethod = writeMethod;
> +        this.getGxpClosureMethod = getGxpClosureMethod;
> +        this.params = lookupParams();
> +    }
> +
> +    /**
> +     * Writes GXP. Pulls GXP parameters from Struts2's value stack.
> +     */
> +    public void write(Appendable out, GxpContext gxpContext) {
> +        write(out, gxpContext, null);
> +    }
> +
> +    /**
> +     * Writes GXP. Pulls GXP parameters from Struts2's value stack.
> +     *
> +     * @param overrides parameter map pushed onto the value stack
> +     */
> +    protected void write(Appendable out, GxpContext gxpContext, Map 
> overrides) {
> +        Object[] args = getArgs(out, gxpContext, overrides);
> +
> +        try {
> +            writeMethod.invoke(getGxpInstance(), args);
> +        } catch (Exception e) {
> +            throw new RuntimeException(createDebugString(args, e), e);
> +        }
> +    }
> +
> +    protected Object[] getArgs(Appendable out, GxpContext gxpContext, Map 
> overrides) {
> +        List<Object> argList = getArgListFromValueStack(overrides);
> +        Object[] args = new Object[argList.size() + 2];
> +        args[0] = out;
> +        args[1] = gxpContext;
> +        int index = 2;
> +        for (Iterator<Object> i = argList.iterator(); i.hasNext(); index++) {
> +            args[index] = i.next();
> +        }
> +        return args;
> +    }
> +
> +    /**
> +     * @return the object on which to call the write and getGxpClosure 
> methods. If
> +     *         the methods are static, this can return {...@code null}
> +     */
> +    protected Object getGxpInstance() {
> +        return null;
> +    }
> +
> +    /**
> +     * Creates GXP closure. Pulls GXP parameters from Struts 2 value stack.
> +     */
> +    public T getGxpClosure() {
> +        return getGxpClosure(null, null);
> +    }
> +
> +    /**
> +     * Creates GXP closure. Pulls GXP parameters from Struts 2 value stack.
> +     *
> +     * @param body   is pushed onto the stack if this GXP has a
> +     *               {...@link MarkupClosure} (or subclass) parameter named 
> "body".
> +     * @param params comes first on the value stack.
> +     */
> +   �...@suppresswarnings("unchecked")
> +    protected T getGxpClosure(T body, Map params) {
> +        final Map overrides = getOverrides(body, params);
> +
> +        Object[] args = getArgListFromValueStack(overrides).toArray();
> +
> +        try {
> +            return (T) getGxpClosureMethod.invoke(getGxpInstance(), args);
> +        } catch (IllegalArgumentException e) {
> +            throw new RuntimeException(createDebugString(args, e), e);
> +        } catch (IllegalAccessException e) {
> +            throw new RuntimeException(createDebugString(args, e), e);
> +        } catch (InvocationTargetException e) {
> +            throw new RuntimeException(createDebugString(args, e), e);
> +        }
> +    }
> +
> +    protected Map getOverrides(T body, Map params) {
> +        final Map overrides = new HashMap();
> +        if (hasBodyParam && body != null) {
> +            overrides.put(Param.BODY_PARAM_NAME, body);
> +        }
> +        if (params != null) {
> +            overrides.putAll(params);
> +        }
> +        return overrides;
> +    }
> +
> +    /**
> +     * Iterates over GXP parameters, pulls value from value stack for each
> +     * parameter, and appends the values to an argument list which will
> +     * be passed to a method on a GXP.
> +     *
> +     * @param overrides parameter map pushed onto the value stack
> +     */
> +    List getArgListFromValueStack(Map overrides) {
> +
> +        ValueStack valueStack = 
> valueStackFactory.createValueStack(ActionContext.getContext().getValueStack());
> +
> +        // add default values to the bottom of the stack. if no action 
> provides
> +        // a getter for a param, the default value will be used.
> +        valueStack.getRoot().add(this.defaultValues);
> +
> +        // push override parameters onto the stack.
> +        if (overrides != null && !overrides.isEmpty()) {
> +            valueStack.push(overrides);
> +        }
> +
> +        List args = new ArrayList(params.size());
> +        for (Param param : getParams()) {
> +            try {
> +                args.add(valueStack.findValue(param.getName(), 
> param.getType()));
> +            } catch (Exception e) {
> +                throw new RuntimeException("Exception while finding '" + 
> param.getName() + "'.", e);
> +            }
> +        }
> +
> +        return args;
> +    }
> +
> +    /**
> +     * Combines parameter names and types into <code>Param</code> objects.
> +     */
> +    List<Param> lookupParams() {
> +        List<Param> params = new ArrayList<Param>();
> +
> +        List<String> parameterNames = lookupParameterNames();
> +        List<Class<?>> parameterTypes = lookupParameterTypes();
> +        Iterator<Class<?>> parameterTypeIterator = parameterTypes.iterator();
> +
> +        // If there are more parameter names than parameter types it means 
> that we are
> +        // using instantiable GXPs and there are 1 or more constructor 
> parameters.
> +        // Constructor params will always be first in the list, so just drop 
> an appropriate
> +        // number of elements from the beginning of the list.
> +        if (parameterNames.size() > parameterTypes.size()) {
> +            parameterNames = parameterNames.subList(parameterNames.size() - 
> parameterTypes.size(), parameterNames.size());
> +        }
> +
> +        for (String name : parameterNames) {
> +            Class paramType = parameterTypeIterator.next();
> +            Param param = new Param(gxpClass, name, paramType);
> +            params.add(param);
> +
> +            if (param.isBody()) {
> +                hasBodyParam = true;
> +            }
> +
> +            if (param.isOptional()) {
> +                defaultValues.put(param.getName(), param.getDefaultValue());
> +            }
> +        }
> +
> +        this.defaultValues = Collections.unmodifiableMap(this.defaultValues);
> +        return Collections.unmodifiableList(params);
> +    }
> +
> +    /**
> +     * Gets list of parameter types.
> +     */
> +    List<Class<?>> lookupParameterTypes() {
> +        List<Class<?>> parameterTypes = 
> Arrays.asList(writeMethod.getParameterTypes());
> +        // skip the first two, gxp_out and gxp_context. they are for 
> internal use.
> +        return parameterTypes.subList(2, parameterTypes.size());
> +    }
> +
> +    /**
> +     * Gets list of parameter names.
> +     */
> +    List<String> lookupParameterNames() {
> +        try {
> +            return (List<String>) 
> gxpClass.getMethod("getArgList").invoke(null);
> +        } catch (Exception e) {
> +            throw new RuntimeException(e);
> +        }
> +    }
> +
> +    /**
> +     * Returns first method with the given name. Should not be used if the
> +     * method is overloaded.
> +     */
> +    protected static Method lookupMethodByName(Class clazz, String name) {
> +        Method[] methods = clazz.getMethods();
> +        for (int i = 0; i < methods.length; i++) {
> +            if (methods[i].getName().equals(name)) {
> +                return methods[i];
> +            }
> +        }
> +        throw new RuntimeException("No " + name + "(...) method found for "
> +                + clazz.getName() + ".");
> +    }
> +
> +    public Class getGxpClass() {
> +        return this.gxpClass;
> +    }
> +
> +    /**
> +     * Returns list of parameters requested by GXP.
> +     */
> +    public List<Param> getParams() {
> +        return params;
> +    }
> +
> +    /**
> +     * Returns generated GXP class given an absolute path to a GXP file.
> +     * The current implementation assumes that the GXP and generated Java 
> source
> +     * file share the same name with different extensions.
> +     */
> +   �...@visiblefortesting
> +    public static Class getGxpClassForPath(String gxpPath) {
> +        int offset = (gxpPath.charAt(0) == '/') ? 1 : 0;
> +        String className = gxpPath.substring(offset, gxpPath.length() - 
> 4).replace('/', '.');
> +        try {
> +            return getClassLoader().loadClass(className);
> +        } catch (ClassNotFoundException e) {
> +            throw new RuntimeException(e);
> +        }
> +    }
> +
> +    static ClassLoader getClassLoader() {
> +        ClassLoader loader = Thread.currentThread().getContextClassLoader();
> +        return (loader == null) ? ClassLoader.getSystemClassLoader() : 
> loader;
> +    }
> +
> +    /**
> +     * Creates debug String which can be tacked onto an exception.
> +     */
> +    String createDebugString(Object[] args, Exception exception) {
> +        StringBuffer buffer = new StringBuffer();
> +        printExceptionTraceToBuffer(exception, buffer);
> +        buffer.append("\nException in GXP: 
> ").append(gxpClass.getName()).append(". Params:");
> +        int index = 2;
> +        for (Param param : getParams()) {
> +            try {
> +                Object arg = args[index++];
> +                String typesMatch = "n/a (null)";
> +                if (arg != null) {
> +                    if (doesArgumentTypeMatchParamType(param, arg)) {
> +                        typesMatch = "YES";
> +                    } else {
> +                        typesMatch = "NO";
> +                    }
> +                }
> +                buffer.append("\n  ")
> +                        .append(param.toString())
> +                        .append(" = ")
> +                        .append(arg)
> +                        .append("; ")
> +                        .append("[types match? ")
> +                        .append(typesMatch)
> +                        .append("]");
> +            } catch (Exception e) {
> +                buffer.append(" >Error getting information for param # 
> ").append(index).append("< ");
> +            }
> +        }
> +        buffer.append("\nStack trace: ");
> +        return buffer.toString();
> +    }
> +
> +    private void printExceptionTraceToBuffer(Exception e,
> +                                             StringBuffer buffer) {
> +        StringWriter out = new StringWriter();
> +        e.printStackTrace(new PrintWriter(out));
> +        buffer.append(out.getBuffer().toString());
> +    }
> +
> +    private boolean doesArgumentTypeMatchParamType(Param param, Object arg) {
> +        Class paramType = param.getType();
> +        Class<? extends Object> argClass = arg.getClass();
> +
> +        // TODO(jpelly): Handle all primitive unwrapping (ie, Boolean --> 
> boolean).
> +        if (boolean.class.equals(paramType) && 
> Boolean.class.equals(argClass)) {
> +            return true;
> +        } else if (char.class.equals(paramType) && 
> Character.class.equals(argClass)) {
> +            return true;
> +        }
> +        return paramType.isAssignableFrom(argClass);
> +    }
> +
> +   �...@inject
> +    public void setValueStackFactory(ValueStackFactory valueStackFactory) {
> +        this.valueStackFactory = valueStackFactory;
> +    }
> +}
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxpResult.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxpResult.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxpResult.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/AbstractGxpResult.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,126 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.opensymphony.xwork2.Result;
> +import org.apache.struts2.ServletActionContext;
> +
> +import javax.servlet.http.HttpServletResponse;
> +import java.io.IOException;
> +import java.io.Writer;
> +import java.util.Locale;
> +
> +/**
> + * The abstract base class for our Struts 2 GXP result type implementation. 
> It
> + * outputs GXP, and pulls GXP parameters from Struts 2's value stack. 
> Implementing
> + * classes have to:
> + * <ol>
> + * <li>Implement <code>execute(ActionInvocation)</code>, which must instruct 
> the
> + * GXP to write itself to the output stream. See {...@link GxpResult} for a
> + * sample implementation.</li>
> + * <li>Add a <code>public static final</code> field <b>DEFAULT_PARAM</b> with
> + * the value 'gxpName'. Struts 2 needs this to set the name of your
> + * template into this object.</li>
> + * </ol>
> + * <p/>
> + * <p>If you want to use instantiated GXPs (using the nested
> + * {...@code Interface}), you can set the u...@code useInstances} parameter 
> to
> + * {...@code true}:
> + * <pre>
> + *     &lt;result-types>
> + *       &lt;result-type name="gxp" 
> class="org.apache.struts2.views.gxp.GxpResult">
> + *         &lt;param name="useInstances">true&lt;/param>
> + *       &lt;/result-type>
> + *     &lt;/result-types>
> + * </pre>
> + * This means that Struts 2 will attempt to instantiate the {...@code 
> Interface}
> + * using the {...@link com.opensymphony.xwork2.ObjectFactory}. If
> + * {...@link com.google.webwork.GuiceWebWorkIntegrationModule} is installed, 
> or
> + * {...@link com.google.webwork.ContainerObjectFactory} is set as the static
> + * {...@code ObjectFactory} instance, then Guice will be used to instantiate 
> the
> + * GXP instance; otherwise, only GXPs with no constructor parameters will 
> work.
> + *
> + * @author Bob Lee
> + */
> +public abstract class AbstractGxpResult implements Result {
> +
> +    private boolean useInstances = false;
> +    private String gxpName;
> +
> +    public void setGxpName(String gxpName) {
> +        this.gxpName = gxpName;
> +    }
> +
> +    protected final String getGxpName() {
> +        return gxpName;
> +    }
> +
> +    public void setUseInstances(boolean useInstances) {
> +        this.useInstances = useInstances;
> +    }
> +
> +    protected final boolean getUseInstances() {
> +        return useInstances;
> +    }
> +
> +    /**
> +     * Provides resources necessary to execute a GXP.
> +     */
> +    protected interface GxpResourceProvider {
> +        Writer getWriter() throws IOException;
> +
> +        Locale getLocale();
> +    }
> +
> +    /**
> +     * Uses reasonable defaults to provide resources.
> +     */
> +    protected static class DefaultProvider implements GxpResourceProvider {
> +
> +        private final String contentType;
> +
> +        public DefaultProvider(String contentType) {
> +            this.contentType = contentType;
> +        }
> +
> +        public Writer getWriter() throws IOException {
> +            setContentType();
> +            return ServletActionContext.getResponse().getWriter();
> +        }
> +
> +        public Locale getLocale() {
> +            return ServletActionContext.getRequest().getLocale();
> +        }
> +
> +        void setContentType() {
> +            HttpServletResponse response = 
> ServletActionContext.getResponse();
> +            // set content type if it hasn't already been set.
> +            if (response.getContentType() == null || 
> response.getContentType().isEmpty()) {
> +                response.setContentType(contentType);
> +            }
> +            // If no character encoding was set in the content type, default 
> to UTF-8.
> +            if (response.getCharacterEncoding() == null || 
> response.getCharacterEncoding().isEmpty()) {
> +                response.setCharacterEncoding("UTF-8");
> +            }
> +        }
> +    }
> +
> +}
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Gxp.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Gxp.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Gxp.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Gxp.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,82 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.google.common.base.Function;
> +import com.google.common.collect.MapMaker;
> +import com.google.gxp.html.HtmlClosure;
> +
> +import java.lang.reflect.Method;
> +import java.util.Map;
> +
> +/**
> + * Struts 2 to GXP adapter. Can be used to write a GXP or create
> + * a HtmlClosure. Pulls GXP parameters from Struts 2 value stack.
> + *
> + * @author Bob Lee
> + */
> +public class Gxp extends AbstractGxp<HtmlClosure> {
> +
> +    Gxp(Class gxpClass) {
> +        this(gxpClass, lookupMethodByName(gxpClass, "write"), 
> lookupMethodByName(gxpClass, "getGxpClosure"));
> +    }
> +
> +    Gxp(Class gxpClass, Method writeMethod, Method getGxpClosureMethod) {
> +        super(gxpClass, writeMethod, getGxpClosureMethod);
> +    }
> +
> +    static final Map<Class, Gxp> classToGxp = new 
> MapMaker().weakKeys().softValues().makeComputingMap(new Function<Class, 
> Gxp>() {
> +        public Gxp apply(Class from) {
> +            return classToGxp.containsKey(from) ? classToGxp.get(from) : new 
> Gxp(from);
> +        }
> +    });
> +
> +    static final Map<String, Gxp> pathToGxp = new 
> MapMaker().softValues().makeComputingMap(new Function<String, Gxp>() {
> +        public Gxp apply(String from) {
> +            return pathToGxp.containsKey(from) ? pathToGxp.get(from) : 
> getInstance(getGxpClassForPath(from));
> +        }
> +    });
> +
> +    /**
> +     * Looks up Gxp instance for GXP with given path.
> +     */
> +    public static Gxp getInstance(String gxpPath) {
> +        try {
> +            return pathToGxp.get(gxpPath);
> +        } catch (RuntimeException e) {
> +            if (e.getCause() instanceof ClassNotFoundException) {
> +                // Couldn't find or load the GXP class.  Return null.
> +                // It would be simpler if classToGxp.create() could return 
> null,
> +                // but the contract of ReferenceCache doesn't allow it to.
> +                return null;
> +            }
> +            throw e;
> +        }
> +    }
> +
> +    /**
> +     * Looks up Gxp instance for the given GXP class.
> +     */
> +    public static Gxp getInstance(Class gxpClass) {
> +        return classToGxp.get(gxpClass);
> +    }
> +
> +}
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpInstance.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpInstance.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpInstance.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpInstance.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,138 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.google.common.base.Function;
> +import com.google.common.collect.MapMaker;
> +import com.opensymphony.xwork2.ObjectFactory;
> +import com.opensymphony.xwork2.inject.Inject;
> +
> +import java.util.Map;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + * Struts 2 to GXP adapter that uses instances of GXP Interfaces, as created 
> by
> + * the {...@link ObjectFactory}. Can be used to write a GXP or create a
> + * HtmlClosure. Pulls non-constructor GXP parameters from Struts 2 value 
> stack.
> + *
> + * @author David P. Baker
> + */
> +public class GxpInstance extends Gxp {
> +
> +    private static final Logger logger = 
> Logger.getLogger(GxpInstance.class.getCanonicalName());
> +
> +    private Class<?> gxpInterface;
> +    private Class<?> gxpInstance;
> +    private ObjectFactory objectFactory;
> +
> +    GxpInstance(Class<?> gxpClass) {
> +        super(gxpClass,
> +                lookupMethodByName(getNestedClass(gxpClass, "Interface"), 
> "write"),
> +                lookupMethodByName(getNestedClass(gxpClass, "Interface"), 
> "getGxpClosure"));
> +        this.gxpInterface = getNestedClass(gxpClass, "Interface");
> +        this.gxpInstance = getNestedClass(gxpClass, "Instance");
> +    }
> +
> +    private static Class<?> getNestedClass(Class<?> clazz, String 
> nestedClassName) {
> +        for (Class<?> nested : clazz.getDeclaredClasses()) {
> +            if (nestedClassName.equals(nested.getSimpleName())) {
> +                return nested;
> +            }
> +        }
> +        throw new IllegalArgumentException(String.format("Cannot find class 
> %s.%s", clazz.getCanonicalName(), nestedClassName));
> +    }
> +
> +    /**
> +     * {...@inheritdoc}
> +     * <p> This implementation uses the {...@link ObjectFactory} to try to 
> create an
> +     * instance of the {...@code Interface} class that is nested within the 
> GXP
> +     * class. If that doesn't work, it falls back to trying to use the
> +     * {...@code ObjectFactory} to create an instance of the nested 
> {...@code Instance}
> +     * class, in case there is no binding for the {...@code Interface}.
> +     */
> +   �...@override
> +    protected Object getGxpInstance() {
> +        try {
> +            return objectFactory.buildBean(gxpInterface, null);
> +        } catch (Exception e) {
> +            logger.log(
> +                    Level.INFO, "Error instantiating {0}; trying {1}",
> +                    new Object[]{gxpInterface.getCanonicalName(), 
> gxpInstance.getCanonicalName(),});
> +            try {
> +                return objectFactory.buildBean(gxpInstance, null);
> +            } catch (Exception e1) {
> +                throw new RuntimeException(String.format("Error 
> instantiating %s",
> +                        gxpInterface.getCanonicalName(), 
> gxpInstance.getCanonicalName()),
> +                        e1);
> +            }
> +        }
> +    }
> +
> +   �...@override
> +    public Class<?> getGxpClass() {
> +        return this.gxpInterface;
> +    }
> +
> +    private static final Map<Class<?>, GxpInstance> classToGxpInstance = new 
> MapMaker().weakKeys().softValues()
> +            .makeComputingMap(new Function<Class<?>, GxpInstance>() {
> +                public GxpInstance apply(Class<?> from) {
> +                    return classToGxpInstance.containsKey(from) ? 
> classToGxpInstance.get(from) : new GxpInstance(from);
> +                }
> +            });
> +
> +    private static final Map<String, GxpInstance> pathToGxpInstance = new 
> MapMaker().softValues()
> +            .makeComputingMap(new Function<String, GxpInstance>() {
> +                public GxpInstance apply(String from) {
> +                    return pathToGxpInstance.containsKey(from) ? 
> pathToGxpInstance.get(from) : getInstance(getGxpClassForPath(from));
> +                }
> +            });
> +
> +    /**
> +     * Looks up Gxp instance for GXP with given path.
> +     */
> +    public static GxpInstance getInstance(String gxpPath) {
> +        try {
> +            return pathToGxpInstance.get(gxpPath);
> +        } catch (RuntimeException e) {
> +            if (e.getCause() instanceof ClassNotFoundException) {
> +                // Couldn't find or load the GXP class.  Return null.
> +                // It would be simpler if classToGxp.create() could return 
> null,
> +                // but the contract of ReferenceCache doesn't allow it to.
> +                return null;
> +            }
> +            throw e;
> +        }
> +    }
> +
> +    /**
> +     * Looks up {...@code GxpInstance} instance for the given GXP class.
> +     */
> +    public static GxpInstance getInstance(Class<?> gxpClass) {
> +        return classToGxpInstance.get(gxpClass);
> +    }
> +
> +   �...@inject
> +    public void setObjectFactory(ObjectFactory objectFactory) {
> +        this.objectFactory = objectFactory;
> +    }
> +
> +}
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpResult.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpResult.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpResult.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/GxpResult.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,145 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.google.gxp.base.GxpContext;
> +import com.google.gxp.html.HtmlClosure;
> +import com.opensymphony.xwork2.ActionInvocation;
> +import com.opensymphony.xwork2.inject.Container;
> +import com.opensymphony.xwork2.inject.Inject;
> +
> +import java.io.IOException;
> +
> +/**
> + * Struts 2 GXP result type implementation. Outputs GXP. Pulls GXP parameters
> + * from Struts 2's value stack.
> + * <p/>
> + * <p>Declare the GXP result type for your package in the xwork.xml file:</p>
> + * <p/>
> + * <pre>
> + *     &lt;result-types>
> + *       &lt;result-type name="gxp" 
> class="org.apache.struts2.views.gxp.GxpResult"/>
> + *     &lt;/result-types>
> + * </pre>
> + * <p/>
> + * <p>Or if you want to output XML instead of HTML:</p>
> + * <p/>
> + * <pre>
> + *     &lt;result-types>
> + *       &lt;result-type name="gxp" 
> class="org.apache.struts2.views.gxp.GxpResult">
> + *         &lt;param name="outputXml">true&lt;/param>
> + *       &lt;/result-type>
> + *     &lt;/result-types>
> + * </pre>
> + * <p/>
> + * <p>Outputting XML changes the content type from text/html to 
> application/xml
> + * and configures the {...@link GxpContext} to output XML. This is useful in
> + * situations like specifying the doctype of your GXP to be 'mobile'.</p>
> + * <p/>
> + * <p>Use the GXP result type for the result of an action. For example:</p>
> + * <p/>
> + * <pre>
> + *   &lt;result name="success" type="gxp">/myPackage/MyGxp.gxp&lt;/result>
> + * </pre>
> + *
> + * @author Bob Lee
> + * @see org.apache.struts2.views.gxp.AbstractGxpResult
> + */
> +public class GxpResult extends AbstractGxpResult {
> +
> +    /**
> +     * Tells Struts 2 which parameter name to use if it's not already 
> specified.
> +     */
> +    public static final String DEFAULT_PARAM = "gxpName";
> +
> +    private Container container;
> +    private boolean outputXml = false;
> +
> +    /**
> +     * Whether or not this GXP should output XML.
> +     */
> +    public void setOutputXml(boolean outputXml) {
> +        this.outputXml = outputXml;
> +    }
> +
> +    protected HtmlClosure getGxpClosure() {
> +        final Gxp gxp = getUseInstances() ? 
> GxpInstance.getInstance(getGxpName()) : Gxp.getInstance(getGxpName());
> +
> +        if (null == gxp) {
> +            // TODO(lwerner): OGNL or Struts 2 seems to be swallowing this 
> exception
> +            // rather than logging or rethrowing it, so you never see this 
> message
> +            // TODO(dpb): Is this true now that this work is not done in a 
> setter?
> +            throw new NullPointerException("The GXP " + getGxpName()
> +                    + " could not be loaded.  This is probably because you 
> have"
> +                    + " a typo in your config.");
> +        }
> +        container.inject(gxp);
> +        return new HtmlClosure() {
> +            public void write(Appendable out, GxpContext gxpContext) throws 
> IOException {
> +                gxp.write(out, gxpContext);
> +            }
> +        };
> +    }
> +
> +    /**
> +     * Tells the GXP to write itself to the output stream.
> +     */
> +    public void execute(ActionInvocation actionInvocation) {
> +        GxpResourceProvider provider = getProvider();
> +        try {
> +            getGxpClosure().write(provider.getWriter(), new 
> GxpContext(provider.getLocale(), outputXml));
> +        } catch (Exception e) {
> +            throw new RuntimeException("Exception while rendering "
> +                    + getGxpName()
> +                    + " coming from "
> +                    + actionInvocation.getAction().getClass().getName() + 
> ".",
> +                    e);
> +        }
> +    }
> +
> +    /**
> +     * Gets appropriate provider.
> +     */
> +    GxpResourceProvider getProvider() {
> +        return new HtmlOrXmlProvider(outputXml);
> +    }
> +
> +    /**
> +     * Uses reasonable defaults to provide resources.
> +     */
> +    private static class HtmlOrXmlProvider extends DefaultProvider {
> +
> +        /**
> +         * Default content-type to use for responses.
> +         */
> +        private static final String HTML_CONTENT_TYPE = "text/html; 
> charset=UTF-8";
> +        private static final String XML_CONTENT_TYPE = "application/xml; 
> charset=UTF-8";
> +
> +        HtmlOrXmlProvider(boolean outputXml) {
> +            super(outputXml ? XML_CONTENT_TYPE : HTML_CONTENT_TYPE);
> +        }
> +    }
> +
> +   �...@inject
> +    public void setContainer(Container container) {
> +        this.container = container;
> +    }
> +}
>
> Added: 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Param.java
> URL: 
> http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Param.java?rev=903559&view=auto
> ==============================================================================
> --- 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Param.java
>  (added)
> +++ 
> struts/sandbox/trunk/struts2-gxp-plugin/src/main/java/org/apache/struts2/views/gxp/Param.java
>  Wed Jan 27 07:44:32 2010
> @@ -0,0 +1,96 @@
> +/*
> + * $Id$
> + *
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + */
> +package org.apache.struts2.views.gxp;
> +
> +import com.google.gxp.html.HtmlClosure;
> +
> +import java.lang.reflect.Method;
> +
> +/**
> + * @author Bob Lee
> + */
> +public class Param {
> +
> +    public static final String BODY_PARAM_NAME = "body";
> +
> +    String name;
> +    Class type;
> +    Class gxpClass;
> +    boolean optional;
> +    Object defaultValue;
> +
> +    Param(Class gxpClass, String name, Class type) {
> +        this.gxpClass = gxpClass;
> +        this.name = name;
> +        this.type = type;
> +
> +        // if you specify a default parameter value in a GXP, a 
> getDefaultXxx()
> +        // method will be present.
> +        try {
> +            Method defaultGetter = gxpClass.getMethod("getDefault" + 
> capitalize(name));
> +            this.defaultValue = defaultGetter.invoke(null);
> +            this.optional = true;
> +        } catch (NoSuchMethodException ignored) {
> +        } catch (Exception e) {
> +            throw new RuntimeException(e);
> +        }
> +    }
> +
> +    private static String capitalize(String s) {
> +        if (s.isEmpty()) {
> +            return s;
> +        }
> +        char first = s.charAt(0);
> +        char capitalized = Character.toUpperCase(first);
> +        return (first == capitalized) ? s : capitalized + s.substring(1);
> +    }
> +
> +    public String getName() {
> +        return name;
> +    }
> +
> +    public Class getType() {
> +        return type;
> +    }
> +
> +    boolean isBody() {
> +        return name.equals(BODY_PARAM_NAME) && 
> type.equals(HtmlClosure.class);
> +    }
> +
> +    public String toString() {
> +        return "Param[name: " + name
> +                + ", type: " + type.getName()
> +                + ", optional: " + optional
> +                + (optional ? ", defaultValue: " + defaultValue : "")
> +                + "]";
> +    }
> +
> +    public boolean isOptional() {
> +        return optional;
> +    }
> +
> +    public Object getDefaultValue() {
> +        if (!optional)
> +            throw new RuntimeException("Parameter '" + name + "' in " + 
> gxpClass.getName() + " is not optional.");
> +        return defaultValue;
> +    }
> +
> +}
> \ No newline at end of file
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@struts.apache.org
For additional commands, e-mail: dev-h...@struts.apache.org

Reply via email to