Return-Path: X-Original-To: apmail-geode-commits-archive@minotaur.apache.org Delivered-To: apmail-geode-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9E3EE18194 for ; Mon, 8 Feb 2016 16:52:05 +0000 (UTC) Received: (qmail 71170 invoked by uid 500); 8 Feb 2016 16:52:05 -0000 Delivered-To: apmail-geode-commits-archive@geode.apache.org Received: (qmail 71138 invoked by uid 500); 8 Feb 2016 16:52:05 -0000 Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.incubator.apache.org Delivered-To: mailing list commits@geode.incubator.apache.org Received: (qmail 71094 invoked by uid 99); 8 Feb 2016 16:52:05 -0000 Received: from Unknown (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 08 Feb 2016 16:52:05 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id D814AC0D1F for ; Mon, 8 Feb 2016 16:52:04 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -3.649 X-Spam-Level: X-Spam-Status: No, score=-3.649 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.429] autolearn=disabled Received: from mx1-us-east.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id cx_kL_7Lg2VF for ; Mon, 8 Feb 2016 16:51:52 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-us-east.apache.org (ASF Mail Server at mx1-us-east.apache.org) with SMTP id D549942A54 for ; Mon, 8 Feb 2016 16:51:50 +0000 (UTC) Received: (qmail 69525 invoked by uid 99); 8 Feb 2016 16:51:50 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 08 Feb 2016 16:51:50 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id F4177E00BB; Mon, 8 Feb 2016 16:51:49 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jensdeppe@apache.org To: commits@geode.incubator.apache.org Date: Mon, 08 Feb 2016 16:51:49 -0000 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: [01/32] incubator-geode git commit: GEODE-14: Integration of GemFire Session Replication and Hibernate modules Repository: incubator-geode Updated Branches: refs/heads/develop c8251f823 -> f890a14d8 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 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 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 dashXmsList = splitAtDigits(dashXms); + String dashXmsStr = dashXmsList.get(1); + List 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 splitAtDigits(String input) { + Matcher matcher = DIGIT_PATTERN.matcher(input); + List result = new ArrayList(); + 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, Serializable, Declarable { + + private static final long serialVersionUID = 182735509690640051L; + + private static final ExpirationAttributes EXPIRE_NOW = new ExpirationAttributes(1, ExpirationAction.DESTROY); + + public ExpirationAttributes getExpiry(Region.Entry 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 keys = (Set) 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 keys = (Set) 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 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 @@ + + + + + + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + + + + + + 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 @@ + + + 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)) {