You are viewing a plain text version of this content. The canonical link for it is here.
Posted to portalapps-dev@portals.apache.org by wo...@apache.org on 2014/07/08 04:25:08 UTC

svn commit: r1608641 - in /portals/applications/webcontent/trunk: ./ reverse-proxy/ reverse-proxy/src/test/java/org/ reverse-proxy/src/test/java/org/apache/ reverse-proxy/src/test/java/org/apache/portals/ reverse-proxy/src/test/java/org/apache/portals/...

Author: woonsan
Date: Tue Jul  8 02:25:08 2014
New Revision: 1608641

URL: http://svn.apache.org/r1608641
Log:
APA-63: adding a test case to verify if commons-chain is good enough for the use cases.

Added:
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/
    portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/CommonsChainTest.java
Modified:
    portals/applications/webcontent/trunk/pom.xml
    portals/applications/webcontent/trunk/reverse-proxy/pom.xml

Modified: portals/applications/webcontent/trunk/pom.xml
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/pom.xml?rev=1608641&r1=1608640&r2=1608641&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/pom.xml (original)
+++ portals/applications/webcontent/trunk/pom.xml Tue Jul  8 02:25:08 2014
@@ -53,6 +53,7 @@
     <commons-beanutils.version>1.8.0</commons-beanutils.version>
     <commons-configuration.version>1.6</commons-configuration.version>
     <commons-digester.version>1.8</commons-digester.version>
+    <commons-chain.version>1.2</commons-chain.version>
     <oro.version>2.0.8</oro.version>
     <velocity.version>1.6.3</velocity.version>
     <velocity-tools.version>1.3</velocity-tools.version>
@@ -260,6 +261,12 @@
       </dependency>
 
       <dependency>
+        <groupId>commons-chain</groupId>
+        <artifactId>commons-chain</artifactId>
+        <version>${commons-chain.version}</version>
+      </dependency>
+
+      <dependency>
         <groupId>oro</groupId>
         <artifactId>oro</artifactId>
         <version>${oro.version}</version>

Modified: portals/applications/webcontent/trunk/reverse-proxy/pom.xml
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/reverse-proxy/pom.xml?rev=1608641&r1=1608640&r2=1608641&view=diff
==============================================================================
--- portals/applications/webcontent/trunk/reverse-proxy/pom.xml (original)
+++ portals/applications/webcontent/trunk/reverse-proxy/pom.xml Tue Jul  8 02:25:08 2014
@@ -96,6 +96,11 @@
     </dependency>
 
     <dependency>
+      <groupId>commons-chain</groupId>
+      <artifactId>commons-chain</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>oro</groupId>
       <artifactId>oro</artifactId>
     </dependency>

Added: portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/CommonsChainTest.java
URL: http://svn.apache.org/viewvc/portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/CommonsChainTest.java?rev=1608641&view=auto
==============================================================================
--- portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/CommonsChainTest.java (added)
+++ portals/applications/webcontent/trunk/reverse-proxy/src/test/java/org/apache/portals/applications/webcontent2/CommonsChainTest.java Tue Jul  8 02:25:08 2014
@@ -0,0 +1,280 @@
+/*
+ * 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.portals.applications.webcontent2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.Closeable;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.chain.Catalog;
+import org.apache.commons.chain.Chain;
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.impl.CatalogBase;
+import org.apache.commons.chain.impl.ChainBase;
+import org.apache.commons.chain.impl.ContextBase;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test case to verify commons-chain is good for the use cases in this project.
+ * <P>
+ * It's necessary to assemble multiple valve components in a pipeline,
+ * with each valve component being able to stop or proceed,
+ * the valves being able to be organized in a hierarchical way,
+ * in different ways such as simple configuration, spring beans assembly or programmatic way.
+ * </P>
+ * <P>
+ * Also, it is not demonstrated here, but one more good thing with commons-chain is that
+ * you can add implement <code>Filter</code> in a command (valve) object to invoke post-processing
+ * individually.
+ * </P>
+ */
+public class CommonsChainTest
+{
+
+    private Catalog catalog;
+
+    /**
+     * The <code>catalog</code> is set up as equivalent as the following here:
+     * <br/>
+     * <xmp>
+     * <catalog>
+     *   <chain name="default">
+     *     <chain name="preprocessing">
+     *       <command className="...InitCommand"/>
+     *     </chain>
+     *     <chain name="processing">
+     *       <command className="...AuthCommand"/>
+     *       <command className="...RenderingCommand"/>
+     *     </chain>
+     *     <chain name="postprocessing">
+     *       <command className="...CleanupCommand"/>
+     *     </chain>
+     *   </chain>
+     * </catalog>
+     * </xmp>
+     * @throws Exception
+     */
+    @Before
+    public void before() throws Exception 
+    {
+        Map<String, Command> commandsMap = new HashMap<String, Command>();
+
+        Command initCommand = new InitCommand();
+        Command authCommand = new AuthCommand();
+        Command renderingCommand = new RenderingCommand();
+        Command cleanupCommand = new CleanupCommand();
+
+        Chain preprocessingChain = new ChainBase(new Command [] { initCommand });
+        Chain processingChain = new ChainBase(new Command [] { authCommand, renderingCommand }) 
+        {
+            @Override
+            public boolean execute(Context context) throws Exception
+            {
+                super.execute(context);
+                // return false here in order to make sure to invoke the postprocessing chain.
+                return false;
+            }
+        };
+        Chain postprocessingChain = new ChainBase(new Command [] { cleanupCommand });
+
+        Chain defaultChain = new ChainBase(new Command [] { preprocessingChain, processingChain, postprocessingChain });
+
+        commandsMap.put("default", defaultChain);
+
+        catalog = new CatalogBase(commandsMap);
+    }
+
+    @Test
+    public void testDefaultChainWithoutAuthorization() throws Exception 
+    {
+        Command defaultCommand = catalog.getCommand("default");
+
+        Context context = new ContextBase();
+        StringWriter sw = new StringWriter();
+        context.put("out", new PrintWriter(sw));
+        context.put("user.name", "John");
+
+        defaultCommand.execute(context);
+
+        assertNull(context.get("error.code"));
+        List<String> logs = (List<String>) context.get("logs");
+        assertTrue(logs.contains("InitCommand is about to execute."));
+        assertTrue(logs.contains("InitCommand has executed."));
+        assertTrue(logs.contains("AuthCommand is about to execute."));
+        assertTrue(logs.contains("AuthCommand has executed."));
+        assertTrue(logs.contains("RenderingCommand has executed."));
+        assertTrue(logs.contains("RenderingCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertEquals("Hello, John!", sw.toString());
+    }
+
+    @Test
+    public void testDefaultChainWithAuthorization() throws Exception 
+    {
+        Command defaultCommand = catalog.getCommand("default");
+
+        Context context = new ContextBase();
+        StringWriter sw = new StringWriter();
+        context.put("out", new PrintWriter(sw));
+        context.put("user.name", "John");
+        context.put("role.allowed", "manager");
+        context.put("user.roles", new HashSet<String>(Arrays.asList("user", "manager")));
+
+        defaultCommand.execute(context);
+
+        assertNull(context.get("error.code"));
+        List<String> logs = (List<String>) context.get("logs");
+        assertTrue(logs.contains("InitCommand is about to execute."));
+        assertTrue(logs.contains("InitCommand has executed."));
+        assertTrue(logs.contains("AuthCommand is about to execute."));
+        assertTrue(logs.contains("AuthCommand has executed."));
+        assertTrue(logs.contains("RenderingCommand has executed."));
+        assertTrue(logs.contains("RenderingCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertEquals("Hello, John!", sw.toString());
+    }
+
+    @Test
+    public void testDefaultChainWithAuthorizationFailure() throws Exception 
+    {
+        Command defaultCommand = catalog.getCommand("default");
+
+        Context context = new ContextBase();
+        StringWriter sw = new StringWriter();
+        context.put("out", new PrintWriter(sw));
+        context.put("user.name", "John");
+        context.put("role.allowed", "manager");
+        context.put("user.roles", new HashSet<String>(Arrays.asList("user", "poweruser")));
+
+        defaultCommand.execute(context);
+
+        assertEquals(Integer.valueOf(403), context.get("error.code"));
+        List<String> logs = (List<String>) context.get("logs");
+        assertTrue(logs.contains("InitCommand is about to execute."));
+        assertTrue(logs.contains("InitCommand has executed."));
+        assertTrue(logs.contains("AuthCommand is about to execute."));
+        assertTrue(logs.contains("AuthCommand has executed."));
+        assertFalse(logs.contains("RenderingCommand has executed."));
+        assertFalse(logs.contains("RenderingCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertTrue(logs.contains("CleanupCommand has executed."));
+        assertEquals("", sw.toString());
+    }
+
+    private abstract class AbstractLoggableCommand implements Command
+    {
+        public final boolean execute(Context context) throws Exception
+        {
+            List<String> logs = (List<String>) context.get("logs");
+
+            if (logs == null) {
+                logs = new LinkedList<String>();
+                context.put("logs", logs);
+            }
+
+            try {
+                logs.add(getClass().getSimpleName() + " is about to execute.");
+                return executeInternal(context);
+            } finally {
+                logs.add(getClass().getSimpleName() + " has executed.");
+            }
+        }
+
+        abstract protected boolean executeInternal(Context context) throws Exception;
+    }
+
+    private class InitCommand extends AbstractLoggableCommand
+    {
+        protected boolean executeInternal(Context context) throws Exception
+        {
+            return false;
+        }
+    }
+
+    private class AuthCommand extends AbstractLoggableCommand
+    {
+        protected boolean executeInternal(Context context) throws Exception
+        {
+            final String roleAllowed = (String) context.get("role.allowed");
+
+            if (roleAllowed == null) 
+            {
+                // no authorization; so continue.
+                return false;
+            }
+
+            Set<String> userRoles = (Set<String>) context.get("user.roles");
+
+            if (userRoles == null || !userRoles.contains(roleAllowed))
+            {
+                // authorization failed; stop processing with error info
+                context.put("error.code", Integer.valueOf(403));
+                return true;
+            }
+
+            // continue processing
+            return false;
+        }
+    }
+
+    private class RenderingCommand extends AbstractLoggableCommand
+    {
+        protected boolean executeInternal(Context context) throws Exception
+        {
+            PrintWriter out = (PrintWriter) context.get("out");
+            out.print("Hello, " + context.get("user.name") + "!");
+            out.flush();
+
+            return false;
+        }
+    }
+
+    private class CleanupCommand extends AbstractLoggableCommand
+    {
+        protected boolean executeInternal(Context context) throws Exception
+        {
+            Collection<Closeable> closeables = (Collection<Closeable>) context.get("closeables");
+
+            if (closeables != null) {
+                for (Closeable closeable : closeables)
+                {
+                    closeable.close();
+                }
+            }
+
+            return false;
+        }
+    }
+
+}