You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/02/09 02:30:06 UTC
[13/50] [abbrv] incubator-geode git commit: GEODE-14: Integration of
GemFire Session Replication and Hibernate modules
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java
new file mode 100644
index 0000000..c5edeea
--- /dev/null
+++ b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java
@@ -0,0 +1,166 @@
+/*
+* 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 com.gemstone.gemfire.modules.util;
+
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.control.ResourceManager;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ResourceManagerValidator {
+
+ private static final Pattern DIGIT_PATTERN = Pattern.compile("(\\d+|[^\\d]+)");
+
+ public static void validateJavaStartupParameters(GemFireCache cache) {
+ // Get the input arguments
+ ResourceManager rm = cache.getResourceManager();
+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
+ List<String> inputArguments = runtimeBean.getInputArguments();
+ if (cache.getLogger().fineEnabled()) {
+ cache.getLogger().fine("Full input java arguments: " + inputArguments);
+ }
+
+ // Validate the arguments based on VM vendor
+ String vmVendor = runtimeBean.getVmVendor();
+ if (vmVendor.startsWith("Sun") || vmVendor.startsWith("Apple")) {
+ // java.vm.vendor = Sun Microsystems Inc. || java.vm.vendor = Apple Inc.
+ validateSunArguments(cache, rm, inputArguments);
+ } else if (vmVendor.startsWith("IBM")) {
+ // java.vm.vendor = IBM Corporation
+ // TODO validate IBM input arguments
+ } else if (vmVendor.startsWith("BEA")) {
+ // java.vm.vendor = BEA Systems, Inc.
+ // TODO validate JRockit input arguments
+ }
+ }
+
+ private static void validateSunArguments(GemFireCache cache, ResourceManager rm, List<String> inputArguments) {
+ // Retrieve the -Xms, -Xmx, UseConcMarkSweepGC and CMSInitiatingOccupancyFraction arguments
+ String dashXms = null, dashXmx = null, useCMS = null, cmsIOF = null;
+ for (String argument : inputArguments) {
+ if (argument.startsWith("-Xms")) {
+ dashXms = argument;
+ } else if (argument.startsWith("-Xmx")) {
+ dashXmx = argument;
+ } else if (argument.equals("-XX:+UseConcMarkSweepGC")) {
+ useCMS = argument;
+ } else if (argument.startsWith("-XX:CMSInitiatingOccupancyFraction")) {
+ cmsIOF = argument;
+ }
+ }
+ if (cache.getLogger().fineEnabled()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Relevant input java arguments: ")
+ .append("dashXms=")
+ .append(dashXms)
+ .append("; dashXmx=")
+ .append(dashXmx)
+ .append("; useCMS=")
+ .append(useCMS)
+ .append("; cmsIOF=")
+ .append(cmsIOF);
+ cache.getLogger().fine(builder.toString());
+ }
+
+ // Validate the heap parameters
+ validateJavaHeapParameters(cache, dashXms, dashXmx);
+
+ // Verify CMS is specified
+ verifyCMSGC(cache, useCMS);
+
+ // Verify CMSInitiatingOccupancyFraction is specified
+ verifyCMSInitiatingOccupancyFraction(cache, rm, cmsIOF);
+ }
+
+ private static void validateJavaHeapParameters(GemFireCache cache, String dashXms, String dashXmx) {
+ if (dashXms == null) {
+ cache.getLogger()
+ .warning(
+ "Setting the initial size of the heap (configured using -Xms) is recommended so that GemFire cache eviction is optimal");
+ } else if (dashXmx == null) {
+ cache.getLogger()
+ .warning(
+ "Setting the maximum size of the heap (configured using -Xmx) is recommended so that GemFire cache eviction is optimal");
+ } else {
+ // Neither heap parameter is null. Parse them and verify they are the same.
+ List<String> dashXmsList = splitAtDigits(dashXms);
+ String dashXmsStr = dashXmsList.get(1);
+ List<String> dashXmxList = splitAtDigits(dashXmx);
+ String dashXmxStr = dashXmxList.get(1);
+ if (!dashXmsStr.equals(dashXmxStr)) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Setting the initial (")
+ .append(dashXmsStr)
+ .append(dashXmsList.get(2))
+ .append(") and maximum (")
+ .append(dashXmxStr)
+ .append(dashXmxList.get(2))
+ .append(") sizes of the heap the same is recommended so that GemFire cache eviction is optimal");
+ cache.getLogger().warning(builder.toString());
+ }
+ }
+ }
+
+ private static void verifyCMSGC(GemFireCache cache, String useCMS) {
+ if (useCMS == null) {
+ cache.getLogger()
+ .warning(
+ "Using the concurrent garbage collector (configured using -XX:+UseConcMarkSweepGC) is recommended so that GemFire cache eviction is optimal");
+ }
+ }
+
+ private static void verifyCMSInitiatingOccupancyFraction(GemFireCache cache, ResourceManager rm, String cmsIOF) {
+ if (cmsIOF == null) {
+ cache.getLogger()
+ .warning(
+ "Setting the CMS initiating occupancy fraction (configured using -XX:CMSInitiatingOccupancyFraction=N) is recommended so that GemFire cache eviction is optimal");
+ } else {
+ // Parse the CMSInitiatingOccupancyFraction. Verify it is less than both eviction and critical thresholds.
+ int cmsIOFVal = Integer.parseInt(cmsIOF.split("=")[1]);
+ float currentEvictionHeapPercentage = rm.getEvictionHeapPercentage();
+ if (currentEvictionHeapPercentage != 0 && currentEvictionHeapPercentage < cmsIOFVal) {
+ cache.getLogger()
+ .warning(
+ "Setting the CMS initiating occupancy fraction (" + cmsIOFVal + ") less than the eviction heap percentage (" + currentEvictionHeapPercentage + ") is recommended so that GemFire cache eviction is optimal");
+ }
+ float currentCriticalHeapPercentage = rm.getCriticalHeapPercentage();
+ if (currentCriticalHeapPercentage != 0 && currentCriticalHeapPercentage < cmsIOFVal) {
+ cache.getLogger()
+ .warning(
+ "Setting the CMS initiating occupancy fraction (" + cmsIOFVal + ") less than the critical heap percentage (" + currentCriticalHeapPercentage + ") is recommended so that GemFire cache eviction is optimal");
+ }
+ }
+ }
+
+ private static List<String> splitAtDigits(String input) {
+ Matcher matcher = DIGIT_PATTERN.matcher(input);
+ List<String> result = new ArrayList<String>();
+ while (matcher.find()) {
+ result.add(matcher.group());
+ }
+ return result;
+ }
+
+ private ResourceManagerValidator() {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java
new file mode 100644
index 0000000..25ee3b1
--- /dev/null
+++ b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java
@@ -0,0 +1,64 @@
+/*
+* 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 com.gemstone.gemfire.modules.util;
+
+import com.gemstone.gemfire.cache.CustomExpiry;
+import com.gemstone.gemfire.cache.Declarable;
+import com.gemstone.gemfire.cache.ExpirationAction;
+import com.gemstone.gemfire.cache.ExpirationAttributes;
+import com.gemstone.gemfire.cache.Region;
+
+import javax.servlet.http.HttpSession;
+import java.io.Serializable;
+import java.util.Properties;
+
+@SuppressWarnings("serial")
+public class SessionCustomExpiry implements CustomExpiry<String, HttpSession>, Serializable, Declarable {
+
+ private static final long serialVersionUID = 182735509690640051L;
+
+ private static final ExpirationAttributes EXPIRE_NOW = new ExpirationAttributes(1, ExpirationAction.DESTROY);
+
+ public ExpirationAttributes getExpiry(Region.Entry<String, HttpSession> entry) {
+ HttpSession session = entry.getValue();
+ if (session != null) {
+ return new ExpirationAttributes(entry.getValue().getMaxInactiveInterval(), ExpirationAction.DESTROY);
+ } else {
+ return EXPIRE_NOW;
+ }
+ }
+
+ public void close() {
+ }
+
+ public void init(Properties props) {
+ }
+
+ public boolean equals(Object obj) {
+ // This method is only implemented so that RegionCreator.validateRegion works properly.
+ // The EntryIdleTimeout comparison fails because two of these instances are not equal.
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || !(obj instanceof SessionCustomExpiry)) {
+ return false;
+ }
+
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java
new file mode 100644
index 0000000..d2b74c8
--- /dev/null
+++ b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java
@@ -0,0 +1,100 @@
+/*
+* 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 com.gemstone.gemfire.modules.util;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.Declarable;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.execute.Function;
+import com.gemstone.gemfire.cache.execute.FunctionContext;
+import com.gemstone.gemfire.cache.execute.RegionFunctionContext;
+import com.gemstone.gemfire.cache.partition.PartitionRegionHelper;
+
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Touches the keys contained in the set of keys by performing a get on the partitioned region.
+ *
+ * @author Barry Oglesby
+ */
+public class TouchPartitionedRegionEntriesFunction implements Function, Declarable {
+
+ private static final long serialVersionUID = -3700389655056961153L;
+
+ private final Cache cache;
+
+ public static final String ID = "touch-partitioned-region-entries";
+
+ public TouchPartitionedRegionEntriesFunction() {
+ this(CacheFactory.getAnyInstance());
+ }
+
+ public TouchPartitionedRegionEntriesFunction(Cache cache) {
+ this.cache = cache;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void execute(FunctionContext context) {
+ RegionFunctionContext rfc = (RegionFunctionContext) context;
+ Set<String> keys = (Set<String>) rfc.getFilter();
+
+ // Get local (primary) data for the context
+ Region primaryDataSet = PartitionRegionHelper.getLocalDataForContext(rfc);
+
+ if (this.cache.getLogger().fineEnabled()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Function ")
+ .append(ID)
+ .append(" received request to touch ")
+ .append(primaryDataSet.getFullPath())
+ .append("->")
+ .append(keys);
+ this.cache.getLogger().fine(builder.toString());
+ }
+
+ // Retrieve each value to update the lastAccessedTime.
+ // Note: getAll is not supported on LocalDataSet.
+ for (String key : keys) {
+ primaryDataSet.get(key);
+ }
+
+ // Return result to get around NPE in LocalResultCollectorImpl
+ context.getResultSender().lastResult(true);
+ }
+
+ public String getId() {
+ return ID;
+ }
+
+ public boolean optimizeForWrite() {
+ return true;
+ }
+
+ public boolean isHA() {
+ return false;
+ }
+
+ public boolean hasResult() {
+ return true;
+ }
+
+ public void init(Properties properties) {
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java
new file mode 100644
index 0000000..735c27f
--- /dev/null
+++ b/extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java
@@ -0,0 +1,97 @@
+/*
+* 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 com.gemstone.gemfire.modules.util;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.Declarable;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.execute.Function;
+import com.gemstone.gemfire.cache.execute.FunctionContext;
+
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Touches the keys contained in the set of keys by performing a get on the replicated region. This is a non-data-aware
+ * function invoked using onMembers or onServers.
+ *
+ * @author Barry Oglesby
+ */
+public class TouchReplicatedRegionEntriesFunction implements Function, Declarable {
+
+ private static final long serialVersionUID = -7424895036162243564L;
+
+ private final Cache cache;
+
+ public static final String ID = "touch-replicated-region-entries";
+
+ public TouchReplicatedRegionEntriesFunction() {
+ this(CacheFactory.getAnyInstance());
+ }
+
+ public TouchReplicatedRegionEntriesFunction(Cache cache) {
+ this.cache = cache;
+ }
+
+ public void execute(FunctionContext context) {
+ Object[] arguments = (Object[]) context.getArguments();
+ String regionName = (String) arguments[0];
+ Set<String> keys = (Set<String>) arguments[1];
+ if (this.cache.getLogger().fineEnabled()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Function ")
+ .append(ID)
+ .append(" received request to touch ")
+ .append(regionName)
+ .append("->")
+ .append(keys);
+ this.cache.getLogger().fine(builder.toString());
+ }
+
+ // Retrieve the appropriate Region and value to update the lastAccessedTime
+ Region region = this.cache.getRegion(regionName);
+ if (region != null) {
+ region.getAll(keys);
+ }
+
+ // Return result to get around NPE in LocalResultCollectorImpl
+ context.getResultSender().lastResult(true);
+ }
+
+ public String getId() {
+ return ID;
+ }
+
+ public boolean optimizeForWrite() {
+ return false;
+ }
+
+ public boolean isHA() {
+ return false;
+ }
+
+ public boolean hasResult() {
+ // Setting this to false caused the onServers method to only execute the
+ // function on one server.
+ return true;
+ }
+
+ public void init(Properties properties) {
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/main/resources/modules-version.properties
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/main/resources/modules-version.properties b/extensions/gemfire-modules/src/main/resources/modules-version.properties
new file mode 100644
index 0000000..7a73b41
--- /dev/null
+++ b/extensions/gemfire-modules/src/main/resources/modules-version.properties
@@ -0,0 +1 @@
+version = @VERSION@
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java
new file mode 100644
index 0000000..12e935d
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java
@@ -0,0 +1,30 @@
+/*
+* 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 com.gemstone.gemfire.modules.session;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Interface which, when implemented, can be put into a servlet context and executed by the servlet.
+ */
+public interface Callback {
+
+ public void call(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java
new file mode 100644
index 0000000..32ac7d8
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java
@@ -0,0 +1,91 @@
+/*
+* 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 com.gemstone.gemfire.modules.session;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ *
+ */
+public class CommandServlet extends HttpServlet {
+
+ private ServletContext context;
+
+ /**
+ * The standard servlet method overridden.
+ *
+ * @param request
+ * @param response
+ * @throws IOException
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+
+ QueryCommand cmd = QueryCommand.UNKNOWN;
+ String param = request.getParameter("param");
+ String value = request.getParameter("value");
+ PrintWriter out = response.getWriter();
+
+ String cmdStr = request.getParameter("cmd");
+ if (cmdStr != null) {
+ cmd = QueryCommand.valueOf(cmdStr);
+ }
+
+ HttpSession session;
+
+ switch (cmd) {
+ case SET:
+ session = request.getSession();
+ session.setAttribute(param, value);
+ break;
+ case GET:
+ session = request.getSession();
+ String val = (String) session.getAttribute(param);
+ if (val != null) {
+ out.write(val);
+ }
+ break;
+ case INVALIDATE:
+ session = request.getSession();
+ session.invalidate();
+ break;
+ case CALLBACK:
+ Callback c = (Callback) context.getAttribute("callback");
+ c.call(request, response);
+ break;
+ }
+ }
+
+ /**
+ * Save a reference to the ServletContext for later use.
+ *
+ * @param config
+ */
+ @Override
+ public void init(ServletConfig config) {
+ this.context = config.getServletContext();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/DualCacheTest.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/DualCacheTest.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/DualCacheTest.java
new file mode 100644
index 0000000..f3927a8
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/DualCacheTest.java
@@ -0,0 +1,62 @@
+/*
+* 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.
+*/
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.gemstone.gemfire.modules.session;
+
+import com.meterware.httpunit.GetMethodWebRequest;
+import com.meterware.httpunit.WebConversation;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+public class DualCacheTest extends TestCase {
+
+ /**
+ * Check that our session persists. The values we pass in as query params are used to set attributes on the session.
+ */
+ public void testSessionFailover() throws Exception {
+ String key = "value_testSessionFailover";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req1 = new GetMethodWebRequest("http://localhost:7890/test");
+ req1.setParameter("cmd", QueryCommand.SET.name());
+ req1.setParameter("param", key);
+ req1.setParameter("value", value);
+ WebResponse response = wc.getResponse(req1);
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ assertNotNull("No apparent session cookie", sessionId);
+
+ WebRequest req2 = new GetMethodWebRequest("http://localhost:7891/test");
+ req2.setHeaderField("Cookie", "JSESSIONID=" + sessionId);
+ req2.setParameter("cmd", QueryCommand.GET.name());
+ req2.setParameter("param", key);
+ response = wc.getResponse(req2);
+ sessionId = response.getNewCookieValue("JSESSIONID");
+
+ assertEquals(value, response.getText());
+ assertTrue("The sessionId does not contain the correct JVM route value", sessionId.contains("JVM-2"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java
new file mode 100644
index 0000000..53a305e
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java
@@ -0,0 +1,193 @@
+/*
+* 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 com.gemstone.gemfire.modules.session;
+
+import com.gemstone.gemfire.modules.session.catalina.JvmRouteBinderValve;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.core.StandardWrapper;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.realm.MemoryRealm;
+import org.apache.catalina.startup.Embedded;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+import javax.servlet.ServletException;
+import java.io.File;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+
+/**
+ *
+ */
+public class EmbeddedTomcat {
+
+ private String contextPath = null;
+ private Embedded container = null;
+ private Log logger = LogFactory.getLog(getClass());
+
+ /**
+ * The directory to create the Tomcat server configuration under.
+ */
+ private String catalinaHome = "tomcat";
+
+ /**
+ * The port to run the Tomcat server on.
+ */
+ private int port = 8089;
+
+ /**
+ * The classes directory for the web application being run.
+ */
+ private String classesDir = "target/classes";
+
+ private Context rootContext = null;
+
+ private Engine engine;
+
+ /**
+ * The web resources directory for the web application being run.
+ */
+ private String webappDir = "";
+
+ public EmbeddedTomcat(String contextPath, int port, String jvmRoute) throws MalformedURLException {
+ this.contextPath = contextPath;
+ this.port = port;
+
+ // create server
+ container = new Embedded();
+ container.setCatalinaHome(catalinaHome);
+ // Not really necessasry, but let's still do it...
+ container.setRealm(new MemoryRealm());
+
+ // create webapp loader
+ WebappLoader loader = new WebappLoader(this.getClass().getClassLoader());
+ if (classesDir != null) {
+ loader.addRepository(new File(classesDir).toURI().toURL().toString());
+ }
+
+ rootContext = container.createContext("", webappDir);
+ rootContext.setLoader(loader);
+ rootContext.setReloadable(true);
+ // Otherwise we get NPE when instantiating servlets
+ rootContext.setIgnoreAnnotations(true);
+
+ // create host
+ Host localHost = container.createHost("127.0.0.1", new File("").getAbsolutePath());
+ localHost.addChild(rootContext);
+
+ localHost.setDeployOnStartup(true);
+
+ // create engine
+ engine = container.createEngine();
+ engine.setName("localEngine");
+ engine.addChild(localHost);
+ engine.setDefaultHost(localHost.getName());
+ engine.setJvmRoute(jvmRoute);
+ engine.setService(new StandardService());
+ container.addEngine(engine);
+
+ // create http connector
+ Connector httpConnector = container.createConnector((InetAddress) null, port, false);
+ container.addConnector(httpConnector);
+ container.setAwait(true);
+
+ // Create the JVMRoute valve for session failover
+ ValveBase valve = new JvmRouteBinderValve();
+ ((StandardEngine) engine).addValve(valve);
+ }
+
+ /**
+ * Starts the embedded Tomcat server.
+ */
+ public void startContainer() throws LifecycleException {
+ // start server
+ container.start();
+
+ // add shutdown hook to stop server
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ stopContainer();
+ }
+ });
+ }
+
+ /**
+ * Stops the embedded Tomcat server.
+ */
+ public void stopContainer() {
+ try {
+ if (container != null) {
+ container.stop();
+ logger.info("Stopped container");
+ }
+ } catch (LifecycleException exception) {
+ logger.warn("Cannot Stop Tomcat" + exception.getMessage());
+ }
+ }
+
+ public StandardWrapper addServlet(String path, String name, String clazz) throws ServletException {
+ StandardWrapper servlet = (StandardWrapper) rootContext.createWrapper();
+ servlet.setName(name);
+ servlet.setServletClass(clazz);
+ servlet.setLoadOnStartup(1);
+
+ rootContext.addChild(servlet);
+ rootContext.addServletMapping(path, name);
+
+ servlet.setParent(rootContext);
+// servlet.load();
+
+ return servlet;
+ }
+
+ public Embedded getEmbedded() {
+ return container;
+ }
+
+ public Context getRootContext() {
+ return rootContext;
+ }
+
+ public String getPath() {
+ return contextPath;
+ }
+
+ public void setPath(String path) {
+ this.contextPath = path;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void addValve(Valve valve) {
+ ((StandardEngine) engine).addValve(valve);
+ }
+
+ public void removeValve(Valve valve) {
+ ((StandardEngine) engine).removeValve(valve);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java
new file mode 100644
index 0000000..a891c5a
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java
@@ -0,0 +1,34 @@
+/*
+ * 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 com.gemstone.gemfire.modules.session;
+
+/**
+ * Basic commands to pass to our test servlet
+ */
+public enum QueryCommand {
+
+ SET,
+
+ GET,
+
+ INVALIDATE,
+
+ CALLBACK,
+
+ UNKNOWN;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
new file mode 100644
index 0000000..4b7ab87
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
@@ -0,0 +1,489 @@
+/*
+* 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 com.gemstone.gemfire.modules.session;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.modules.session.catalina.DeltaSessionManager;
+import com.gemstone.gemfire.modules.session.catalina.PeerToPeerCacheLifecycleListener;
+import com.meterware.httpunit.GetMethodWebRequest;
+import com.meterware.httpunit.WebConversation;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+import org.apache.catalina.core.StandardWrapper;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.beans.PropertyChangeEvent;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import static junit.framework.Assert.*;
+
+/**
+ *
+ */
+public abstract class TestSessionsBase {
+ private static EmbeddedTomcat server;
+
+ private static Region<String, HttpSession> region;
+
+ private static StandardWrapper servlet;
+
+ private static DeltaSessionManager sessionManager;
+
+ // Set up the servers we need
+ public static void setupServer(DeltaSessionManager manager) throws Exception {
+ server = new EmbeddedTomcat("/test", 7890, "JVM-1");
+
+ PeerToPeerCacheLifecycleListener p2pListener = new PeerToPeerCacheLifecycleListener();
+ p2pListener.setProperty("mcast-port", "0");
+ p2pListener.setProperty("log-level", "config");
+ server.getEmbedded().addLifecycleListener(p2pListener);
+ sessionManager = manager;
+ sessionManager.setEnableCommitValve(true);
+ server.getRootContext().setManager(sessionManager);
+
+ servlet = server.addServlet("/test/*", "default", CommandServlet.class.getName());
+ server.startContainer();
+
+ /**
+ * Can only retrieve the region once the container has started up
+ * (and the cache has started too).
+ */
+ region = sessionManager.getSessionCache().getSessionRegion();
+ }
+
+ @AfterClass
+ public static void teardownClass() throws Exception {
+ server.stopContainer();
+ }
+
+ /**
+ * Reset some data
+ */
+ @Before
+ public void setup() throws Exception {
+ sessionManager.setMaxInactiveInterval(30);
+ region.clear();
+ }
+
+ /**
+ * Check that the basics are working
+ */
+ @Test
+ public void testSanity() throws Exception {
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+ req.setParameter("cmd", QueryCommand.GET.name());
+ req.setParameter("param", "null");
+ WebResponse response = wc.getResponse(req);
+
+ assertEquals("JSESSIONID", response.getNewCookieNames()[0]);
+ }
+
+ /**
+ * Test callback functionality. This is here really just as an example. Callbacks are useful to implement per test
+ * actions which can be defined within the actual test method instead of in a separate servlet class.
+ */
+ @Test
+ public void testCallback() throws Exception {
+ final String helloWorld = "Hello World";
+ Callback c = new Callback() {
+
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ PrintWriter out = response.getWriter();
+ out.write(helloWorld);
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ assertEquals(helloWorld, response.getText());
+ }
+
+ /**
+ * Test that calling session.isNew() works for the initial as well as subsequent requests.
+ */
+ @Test
+ public void testIsNew() throws Exception {
+ Callback c = new Callback() {
+
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ HttpSession session = request.getSession();
+ response.getWriter().write(Boolean.toString(session.isNew()));
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ assertEquals("true", response.getText());
+ response = wc.getResponse(req);
+
+ assertEquals("false", response.getText());
+ }
+
+ /**
+ * Check that our session persists. The values we pass in as query params are used to set attributes on the session.
+ */
+ @Test
+ public void testSessionPersists1() throws Exception {
+ String key = "value_testSessionPersists1";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ assertNotNull("No apparent session cookie", sessionId);
+
+ // The request retains the cookie from the prior response...
+ req.setParameter("cmd", QueryCommand.GET.name());
+ req.setParameter("param", key);
+ req.removeParameter("value");
+ response = wc.getResponse(req);
+
+ assertEquals(value, response.getText());
+ }
+
+ /**
+ * Check that our session persists beyond the container restarting.
+ */
+// public void testSessionPersists2() throws Exception {
+// String key = "value_testSessionPersists2";
+// String value = "Foo";
+//
+// WebConversation wc = new WebConversation();
+// WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+// req.setParameter("cmd", QueryCommand.SET.name());
+// req.setParameter("param", key);
+// req.setParameter("value", value);
+// WebResponse response = wc.getResponse(req);
+// String sessionId = response.getNewCookieValue("JSESSIONID");
+//
+// assertNotNull("No apparent session cookie", sessionId);
+//
+// // Restart the container
+// AllTests.teardownClass();
+// AllTests.setupClass();
+//
+// // The request retains the cookie from the prior response...
+// req.setParameter("cmd", QueryCommand.GET.name());
+// req.setParameter("param", key);
+// req.removeParameter("value");
+// response = wc.getResponse(req);
+//
+// assertEquals(value, response.getText());
+// }
+
+ /**
+ * Test that invalidating a session makes it's attributes inaccessible.
+ */
+ @Test
+ public void testInvalidate() throws Exception {
+ String key = "value_testInvalidate";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Set an attribute
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+
+ // Invalidate the session
+ req.removeParameter("param");
+ req.removeParameter("value");
+ req.setParameter("cmd", QueryCommand.INVALIDATE.name());
+ wc.getResponse(req);
+
+ // The attribute should not be accessible now...
+ req.setParameter("cmd", QueryCommand.GET.name());
+ req.setParameter("param", key);
+ response = wc.getResponse(req);
+
+ assertEquals("", response.getText());
+ }
+
+ /**
+ * Test setting the session expiration
+ */
+ @Test
+ public void testSessionExpiration1() throws Exception {
+ // TestSessions only live for a second
+ sessionManager.setMaxInactiveInterval(1);
+
+ String key = "value_testSessionExpiration1";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Set an attribute
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+
+ // Sleep a while
+ Thread.sleep(2000);
+
+ // The attribute should not be accessible now...
+ req.setParameter("cmd", QueryCommand.GET.name());
+ req.setParameter("param", key);
+ response = wc.getResponse(req);
+
+ assertEquals("", response.getText());
+ }
+
+ /**
+ * Test setting the session expiration via a property change as would happen under normal deployment conditions.
+ */
+ @Test
+ public void testSessionExpiration2() throws Exception {
+ // TestSessions only live for a minute
+ sessionManager.propertyChange(
+ new PropertyChangeEvent(server.getRootContext(), "sessionTimeout", new Integer(30), new Integer(1)));
+
+ // Check that the value has been set to 60 seconds
+ assertEquals(60, sessionManager.getMaxInactiveInterval());
+ }
+
+ /**
+ * Test that removing a session attribute also removes it from the region
+ */
+ @Test
+ public void testRemoveAttribute() throws Exception {
+ String key = "value_testRemoveAttribute";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Set an attribute
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ // Implicitly remove the attribute
+ req.removeParameter("value");
+ wc.getResponse(req);
+
+ // The attribute should not be accessible now...
+ req.setParameter("cmd", QueryCommand.GET.name());
+ req.setParameter("param", key);
+ response = wc.getResponse(req);
+
+ assertEquals("", response.getText());
+ assertNull(region.get(sessionId).getAttribute(key));
+ }
+
+ /**
+ * Test that a session attribute gets set into the region too.
+ */
+ @Test
+ public void testBasicRegion() throws Exception {
+ String key = "value_testBasicRegion";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Set an attribute
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ assertEquals(value, region.get(sessionId).getAttribute(key));
+ }
+
+ /**
+ * Test that a session attribute gets removed from the region when the session is invalidated.
+ */
+ @Test
+ public void testRegionInvalidate() throws Exception {
+ String key = "value_testRegionInvalidate";
+ String value = "Foo";
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Set an attribute
+ req.setParameter("cmd", QueryCommand.SET.name());
+ req.setParameter("param", key);
+ req.setParameter("value", value);
+ WebResponse response = wc.getResponse(req);
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ // Invalidate the session
+ req.removeParameter("param");
+ req.removeParameter("value");
+ req.setParameter("cmd", QueryCommand.INVALIDATE.name());
+ wc.getResponse(req);
+
+ assertNull("The region should not have an entry for this session", region.get(sessionId));
+ }
+
+ /**
+ * Test that multiple attribute updates, within the same request result in only the latest one being effective.
+ */
+ @Test
+ public void testMultipleAttributeUpdates() throws Exception {
+ final String key = "value_testMultipleAttributeUpdates";
+ Callback c = new Callback() {
+
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ HttpSession session = request.getSession();
+ for (int i = 0; i < 1000; i++) {
+ session.setAttribute(key, Integer.toString(i));
+ }
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Execute the callback
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ String sessionId = response.getNewCookieValue("JSESSIONID");
+
+ assertEquals("999", region.get(sessionId).getAttribute(key));
+ }
+
+ /*
+ * Test for issue #38 CommitSessionValve throws exception on invalidated sessions
+ */
+ @Test
+ public void testCommitSessionValveInvalidSession() throws Exception {
+ Callback c = new Callback() {
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ HttpSession session = request.getSession();
+ session.invalidate();
+ response.getWriter().write("done");
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Execute the callback
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ assertEquals("done", response.getText());
+ }
+
+ /**
+ * Test for issue #45 Sessions are being created for every request
+ */
+ @Test
+ public void testExtraSessionsNotCreated() throws Exception {
+ Callback c = new Callback() {
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ // Do nothing with sessions
+ response.getWriter().write("done");
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Execute the callback
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ assertEquals("done", response.getText());
+ assertEquals("The region should be empty", 0, region.size());
+ }
+
+ /**
+ * Test for issue #46 lastAccessedTime is not updated at the start of the request, but only at the end.
+ */
+ @Test
+ public void testLastAccessedTime() throws Exception {
+ Callback c = new Callback() {
+ @Override
+ public void call(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ HttpSession session = request.getSession();
+ // Hack to expose the session to our test context
+ session.getServletContext().setAttribute("session", session);
+ session.setAttribute("lastAccessTime", session.getLastAccessedTime());
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ }
+ session.setAttribute("somethingElse", 1);
+ request.getSession();
+ response.getWriter().write("done");
+ }
+ };
+ servlet.getServletContext().setAttribute("callback", c);
+
+ WebConversation wc = new WebConversation();
+ WebRequest req = new GetMethodWebRequest("http://localhost:7890/test");
+
+ // Execute the callback
+ req.setParameter("cmd", QueryCommand.CALLBACK.name());
+ req.setParameter("param", "callback");
+ WebResponse response = wc.getResponse(req);
+
+ HttpSession session = (HttpSession) servlet.getServletContext().getAttribute("session");
+ Long lastAccess = (Long) session.getAttribute("lastAccessTime");
+
+ assertTrue(
+ "Last access time not set correctly: " + lastAccess.longValue() + " not <= " + session.getLastAccessedTime(),
+ lastAccess.longValue() <= session.getLastAccessedTime());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java
new file mode 100644
index 0000000..0ce73ae
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java
@@ -0,0 +1,35 @@
+/*
+* 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 com.gemstone.gemfire.modules.session;
+
+import com.gemstone.gemfire.modules.session.catalina.Tomcat6DeltaSessionManager;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
+
+/**
+ * @author Jens Deppe
+ */
+@Category(UnitTest.class)
+public class Tomcat6SessionsJUnitTest extends TestSessionsBase {
+
+ // Set up the session manager we need
+ @BeforeClass
+ public static void setupClass() throws Exception {
+ setupServer(new Tomcat6DeltaSessionManager());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml b/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml
new file mode 100644
index 0000000..17faf29
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="com.gemstone.gemfire.modules">
+ <class name="Event" table="EVENTS">
+ <cache usage="read-write"/>
+ <id name="id" column="EVENT_ID">
+ <generator class="native"/>
+ </id>
+ <version name="version"/>
+ <property name="date" type="timestamp" column="EVENT_DATE"/>
+ <property name="title"/>
+ </class>
+</hibernate-mapping>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml b/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml
new file mode 100644
index 0000000..c6380e7
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="com.gemstone.gemfire.modules">
+ <class name="Person" table="PERSON">
+ <cache usage="read-write"/>
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+ <set name="e" table="PERSON_EVENT">
+ <cache usage="read-write"/>
+ <key column="PERSON_ID"/>
+ <many-to-many column="EVENT_ID" class="Event"/>
+ </set>
+ </class>
+</hibernate-mapping>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/log4j.properties b/extensions/gemfire-modules/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c136990
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/resources/log4j.properties
@@ -0,0 +1,16 @@
+# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
+# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
+#log4j.rootLogger=DEBUG, stdout, logfile
+log4j.rootLogger=DEBUG, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
+
+#log4j.appender.logfile=org.apache.log4j.RollingFileAppender
+#log4j.appender.logfile.MaxFileSize=512KB
+## Keep three backup files.
+#log4j.appender.logfile.MaxBackupIndex=3
+## Pattern to output: date priority [category] - message
+#log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
+#log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/tomcat/conf/tomcat-users.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/tomcat/conf/tomcat-users.xml b/extensions/gemfire-modules/src/test/resources/tomcat/conf/tomcat-users.xml
new file mode 100644
index 0000000..6c9f217
--- /dev/null
+++ b/extensions/gemfire-modules/src/test/resources/tomcat/conf/tomcat-users.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8'?>
+<tomcat-users>
+</tomcat-users>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/tomcat/logs/.gitkeep
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/tomcat/logs/.gitkeep b/extensions/gemfire-modules/src/test/resources/tomcat/logs/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules/src/test/resources/tomcat/temp/.gitkeep
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules/src/test/resources/tomcat/temp/.gitkeep b/extensions/gemfire-modules/src/test/resources/tomcat/temp/.gitkeep
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/gradle/dependency-versions.properties
----------------------------------------------------------------------
diff --git a/gradle/dependency-versions.properties b/gradle/dependency-versions.properties
index 6ca47f2..f4616be 100644
--- a/gradle/dependency-versions.properties
+++ b/gradle/dependency-versions.properties
@@ -39,6 +39,7 @@ guava.version = 15.0
hadoop.version = 2.4.1
hamcrest-all.version = 1.3
hbase.version = 0.94.27
+httpunit.version = 1.7.2
jackson.version = 2.2.0
jackson-module-scala_2.10.version = 2.1.5
jansi.version = 1.8
@@ -80,3 +81,5 @@ swagger.version = 1.3.2
swagger-springmvc.version = 0.8.2
system-rules.version = 1.15.0
tempus-fugit.version = 1.1
+tomcat6.version = 6.0.37
+tomcat7.version = 7.0.30
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/gradle/rat.gradle
----------------------------------------------------------------------
diff --git a/gradle/rat.gradle b/gradle/rat.gradle
index d66f9bb..f782665 100644
--- a/gradle/rat.gradle
+++ b/gradle/rat.gradle
@@ -25,6 +25,7 @@ rat {
// git
'.git/**',
'**/.gitignore',
+ '**/.gitkeep',
// gradle
'**/.gradle/**',
@@ -45,6 +46,8 @@ rat {
'**/.settings/**',
'**/build-eclipse/**',
'**/*.iml',
+ '**/*.ipr',
+ '**/*.iws',
'.idea/**',
'**/tags',
@@ -79,7 +82,17 @@ rat {
// other text files
'gemfire-spark-connector/project/plugins.sbt',
'gemfire-spark-connector/project/build.properties',
- '**/log4j2*.xml',
+ '**/log4j*.xml',
+
+ // modules
+ 'extensions/**/log4j.properties',
+ 'extensions/**/tomcat-users.xml',
+ 'extensions/gemfire-modules-assembly/release/tcserver/**',
+ 'extensions/gemfire-modules-assembly/release/**/setenv.properties',
+ 'extensions/gemfire-modules/src/main/java/com/gemstone/gemfire/modules/session/catalina/LocalStrings.properties',
+ 'extensions/gemfire-modules/src/main/resources/modules-version.properties',
+ 'extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml',
+ 'extensions/gemfire-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml',
// these are test files that don't expect the first element to be a comment
'gemfire-core/src/test/resources/com/gemstone/gemfire/management/internal/configuration/domain/CacheElementJUnitTest.xml',
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 0e03868..8962b45 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -29,6 +29,11 @@ include 'gemfire-rebalancer'
include 'gemfire-lucene'
include 'gemfire-wan'
include 'gemfire-cq'
+include 'extensions/gemfire-modules'
+include 'extensions/gemfire-modules-tomcat7'
+include 'extensions/gemfire-modules-hibernate'
+include 'extensions/gemfire-modules-session'
+include 'extensions/gemfire-modules-assembly'
def minimumGradleVersion = '2.3'
if (GradleVersion.current() < GradleVersion.version(minimumGradleVersion)) {