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;
+ }
+ }
+
+}