You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ab...@apache.org on 2016/02/17 19:23:34 UTC

[30/51] [partial] incubator-geode git commit: GEODE-917: rename gemfire subprojects to geode

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f6c4c2f9/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java b/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/ResourceManagerValidator.java
new file mode 100644
index 0000000..c5edeea
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java b/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/SessionCustomExpiry.java
new file mode 100644
index 0000000..25ee3b1
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java b/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchPartitionedRegionEntriesFunction.java
new file mode 100644
index 0000000..d2b74c8
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java b/extensions/geode-modules/src/main/java/com/gemstone/gemfire/modules/util/TouchReplicatedRegionEntriesFunction.java
new file mode 100644
index 0000000..735c27f
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/main/resources/modules-version.properties
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/resources/modules-version.properties b/extensions/geode-modules/src/main/resources/modules-version.properties
new file mode 100644
index 0000000..7a73b41
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Callback.java
new file mode 100644
index 0000000..12e935d
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/CommandServlet.java
new file mode 100644
index 0000000..32ac7d8
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/EmbeddedTomcat.java
new file mode 100644
index 0000000..53a305e
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/QueryCommand.java
new file mode 100644
index 0000000..a891c5a
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
new file mode 100644
index 0000000..544658e
--- /dev/null
+++ b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/TestSessionsBase.java
@@ -0,0 +1,493 @@
+/*
+* 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.internal.AvailablePortHelper;
+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;
+
+  private static int port;
+
+  // Set up the servers we need
+  public static void setupServer(DeltaSessionManager manager) throws Exception {
+    port = AvailablePortHelper.getRandomAvailableTCPPort();
+    server = new EmbeddedTomcat("/test", port, "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(String.format("http://localhost:%d/test", port));
+    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(String.format("http://localhost:%d/test", port));
+
+    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(String.format("http://localhost:%d/test", port));
+
+    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(String.format("http://localhost:%d/test", port));
+    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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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(String.format("http://localhost:%d/test", port));
+
+    // 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/f6c4c2f9/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java b/extensions/geode-modules/src/test/java/com/gemstone/gemfire/modules/session/Tomcat6SessionsJUnitTest.java
new file mode 100644
index 0000000..0ce73ae
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml b/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Event.hbm.xml
new file mode 100644
index 0000000..17faf29
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml b/extensions/geode-modules/src/test/resources/com/gemstone/gemfire/modules/Person.hbm.xml
new file mode 100644
index 0000000..c6380e7
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/log4j.properties b/extensions/geode-modules/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c136990
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/tomcat/conf/tomcat-users.xml
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/tomcat/conf/tomcat-users.xml b/extensions/geode-modules/src/test/resources/tomcat/conf/tomcat-users.xml
new file mode 100644
index 0000000..6c9f217
--- /dev/null
+++ b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/tomcat/logs/.gitkeep
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/tomcat/logs/.gitkeep b/extensions/geode-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/f6c4c2f9/extensions/geode-modules/src/test/resources/tomcat/temp/.gitkeep
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/resources/tomcat/temp/.gitkeep b/extensions/geode-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/f6c4c2f9/gemfire-assembly/build.gradle
----------------------------------------------------------------------
diff --git a/gemfire-assembly/build.gradle b/gemfire-assembly/build.gradle
deleted file mode 100755
index 72e97c5..0000000
--- a/gemfire-assembly/build.gradle
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * 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.
- */
-import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact;
-
-apply plugin: 'distribution'
-
-// disable artifact generation for this project
-jar.enabled = false
-extraArchive {
-  sources = false
-  javadoc = false
-  tests = false
-}
-
-disableMavenPublishing()
-
-// Gradle doesn't automatically remove the jar artifact even though we disabled it
-// this causes publishing to fail.  So we nuke all the disabled artifacts from all configurations.
-configurations.all {
-  artifacts.removeAll artifacts.findAll { it instanceof ArchivePublishArtifact && !it.archiveTask.enabled }
-}
-
-gradle.taskGraph.whenReady( { graph ->
-  tasks.withType(Tar).each { tar ->
-    tar.compression = Compression.GZIP
-    tar.extension = 'tar.gz'
-  }
-})
-
-dependencies {
-  provided project(':gemfire-core')
-  
-  archives project(':gemfire-common')  
-  archives project(':gemfire-json')  
-  archives project(':gemfire-joptsimple')  
-  archives project(':gemfire-core')  
-  archives project(':gemfire-lucene')
-  archives project(':gemfire-web')
-  archives project(':gemfire-web-api')
-  archives project(':gemfire-pulse')
-  archives project(':gemfire-wan')
-  archives project(':gemfire-cq')
-
-  testCompile project(':gemfire-junit')
-  testCompile project(path: ':gemfire-core', configuration: 'testOutput')
-
-  testRuntime files("${System.getProperty('java.home')}/../lib/tools.jar")
-}
-
-sourceSets {
-  // need to remove this since we use the dependencies jar out of the install dir
-  //test.runtimeClasspath -= configurations.provided
-}
-
-test {
-  // test from the actual classpath not the gradle classpath
-  dependsOn installDist
-  // @TODO: this doesn't seem to be working need to get basename first.
-  classpath += files "$buildDir/install/apache-geode/lib/gemfire-core-dependencies.jar"
-}
-
-tasks.withType(Test){
-  environment 'GEMFIRE', "$buildDir/install/${distributions.main.baseName}/lib"
-}
-
-task defaultDistributionConfig(type: JavaExec, dependsOn: classes) {
-  outputs.file file("$buildDir/gemfire.properties")
-  main 'com.gemstone.gemfire.distributed.internal.DistributionConfigImpl'
-  classpath project(':gemfire-core').sourceSets.main.runtimeClasspath
-  workingDir buildDir
-  
-  doFirst {
-    buildDir.mkdirs()
-  }
-}
-
-task defaultCacheConfig(type: JavaExec, dependsOn: classes) {
-  outputs.file file("$buildDir/cache.xml")
-  main 'com.gemstone.gemfire.internal.cache.xmlcache.CacheXmlGenerator'
-  classpath project(':gemfire-core').sourceSets.main.runtimeClasspath
-  workingDir buildDir
-
-  doFirst {
-    buildDir.mkdirs()
-  }
-}
-
-// This closure sets the gemfire classpath.  If we add another jar to the classpath it must
-// be included in the filter logic below.
-def cp = {
-  // first add all the dependent project jars
-  def jars = configurations.archives.dependencies.collect { it.dependencyProject }
-    .findAll { !it.name.contains('web') }
-    .collect { it.jar.archiveName }
-    .join(' ')
-
-  // then add all the dependencies of the dependent jars
-  jars += ' ' + configurations.archives.dependencies.collect { 
-    it.dependencyProject.configurations.runtime.collect { it.getName() }.findAll {
-      // depedencies from gemfire-core
-      it.contains('antlr') ||
-      it.contains('commons-io') ||
-      it.contains('commons-lang') ||
-      it.contains('commons-logging') ||
-      it.contains('fastutil') ||
-      it.contains('jackson-annotations') ||
-      it.contains('jackson-core') ||
-      it.contains('jackson-databind') ||
-      it.contains('jansi') ||
-      it.contains('javax.resource-api') ||
-      it.contains('javax.servlet-api') ||
-      it.contains('javax.transaction-api') ||
-      it.contains('jetty-http') ||
-      it.contains('jetty-io') ||
-      it.contains('jetty-security') ||
-      it.contains('jetty-server') ||
-      it.contains('jetty-servlet') ||
-      it.contains('jetty-webapp') ||
-      it.contains('jetty-util') ||
-      it.contains('jetty-xml') ||
-      it.contains('jline') ||
-      it.contains('jna') ||
-      it.contains('log4j-api') ||
-      it.contains('log4j-core') ||
-      it.contains('log4j-jcl') ||
-      it.contains('log4j-jul') ||
-      it.contains('log4j-slf4j-impl') ||
-      it.contains('slf4j-api') ||
-      it.contains('spring-core') ||
-      it.contains('spring-shell') ||
-      it.contains('snappy-java') ||
-      it.contains('hbase') ||
-      it.contains('jgroups') ||
-      it.contains('netty') ||
-      it.contains('gemfire-wan') ||
-      it.contains('gemfire-cq') ||
-      
-      // dependencies from gemfire-lucene
-      it.contains('lucene-analyzers-common') ||
-      it.contains('lucene-core') ||
-      it.contains('lucene-queries') ||
-      it.contains('lucene-queryparser')
-    }
-  }.flatten().unique().join(' ')
-
-  return jars
-}
-
-// Note: this dependency doesn't work if you change a library version from
-// a dependent project.  Please fix me.
-task depsJar (type: Jar, dependsOn: ':gemfire-core:classes') {
-  description 'Assembles the jar archive that defines the gemfire classpath.'
-  archiveName 'gemfire-core-dependencies.jar'
-  doFirst {
-    manifest { 
-      attributes("Class-Path": cp())
-    }
-  }
-}
-
-// Note: this dependency doesn't work if you change a library version from
-// a dependent project.  Please fix me.
-task gfshDepsJar (type: Jar, dependsOn: ':gemfire-core:classes') {
-  description 'Assembles the jar archive that defines the gfsh classpath.'
-  def springWeb = configurations.runtime.collect { it.getName() }.find { it.contains('spring-web') }
-  archiveName 'gfsh-dependencies.jar'
-  doFirst {
-    manifest {
-      attributes("Class-Path": cp() + 
-        ' ' + project(':gemfire-core').webJar.archiveName +
-        ' ' + springWeb
-      )
-    }
-  }
-}
-
-
-def docsDir = file("$buildDir/javadocs")
-task docs(type: Javadoc) {
-    options.addStringOption('Xdoclint:none', '-quiet')
-    options.encoding='UTF-8'
-    source parent.subprojects*.javadoc*.source
-    classpath = files(parent.subprojects*.javadoc*.classpath)
-    title = "Apache Geode ${project.version}"
-    include 'com/gemstone/gemfire/**/'
-    exclude 'com/gemstone/gemfire/internal/**/'
-    exclude 'com/gemstone/gemfire/**/internal/**/'
-    exclude 'com/gemstone/gemfire/**/xml/**/'
-    exclude 'com/gemstone/gemfire/distributed/**/util/**/'
-    exclude 'com/gemstone/gemfire/test/**/'
-    destinationDir = docsDir
-}
-
-gradle.taskGraph.whenReady( { graph ->
-  tasks.withType(AbstractArchiveTask).findAll {
-    it.name.toLowerCase().contains("dist")
-  }.each { archive ->
-    archive.doLast {
-      ant.checksum file:"${archive.archivePath}", algorithm:"md5"
-      ant.checksum file:"${archive.archivePath}", algorithm:"sha-256"
-    }
-  }
-})
-
-distributions {
-  src {
-    baseName = 'apache-geode-src'
-    contents {
-      from (rootDir) {
-        exclude 'KEYS'
-        exclude 'gradlew'
-        exclude 'gradlew.bat'
-        exclude 'gradle/wrapper/gradle-wrapper.jar'
-        exclude 'gradle/wrapper/gradle-wrapper.properties'
-        exclude '.gradle'
-        exclude '**/build/**'
-        exclude '**/.project'
-        exclude '**/.classpath'
-        exclude '**/.settings/**'
-        exclude '**/build-eclipse/**'
-        exclude '.idea/**'
-        exclude '**/*.iml'
-        exclude '**/*.ipr'
-        exclude '**/*.iws'
-        exclude '**/tags'
-      }
-    }
-  }
-
-  main {
-    baseName = 'apache-geode' //TODO rootProject.name
-    contents {
-      duplicatesStrategy 'exclude'
-      exclude '*.asc'
-      
-      exclude '*.asc'
-      exclude '*-sources.jar'
-      exclude '*-javadoc.jar'
-
-      into ('config') {
-        from defaultCacheConfig
-        from defaultDistributionConfig
-        from (project(':gemfire-core').sourceSets.main.resources.files.find {
-          it.name == 'log4j2.xml' 
-        })
-      }
-      
-      into ('lib') {
-        from project(":gemfire-common").configurations.runtime
-        from project(":gemfire-common").configurations.archives.allArtifacts.files
-
-        from project(":gemfire-json").configurations.runtime
-        from project(":gemfire-json").configurations.archives.allArtifacts.files
-
-        from project(":gemfire-joptsimple").configurations.runtime
-        from project(":gemfire-joptsimple").configurations.archives.allArtifacts.files
-
-        from project(":gemfire-wan").configurations.runtime
-        from project(":gemfire-wan").configurations.archives.allArtifacts.files
-
-        from project(":gemfire-cq").configurations.runtime
-        from project(":gemfire-cq").configurations.archives.allArtifacts.files
-
-        from project(":gemfire-core").configurations.runtime
-        // Copying from provided configuration is only for supporting Spring Data GemFire.
-        // If there are more dependencies added to provided configuration, this will need
-        // to change
-        from (project(":gemfire-core").configurations.provided) {
-          include 'spring-data-gemfire-*'
-        }
-        from project(":gemfire-core").configurations.archives.allArtifacts.files
-        from project(":gemfire-core").webJar
-        from project(":gemfire-core").raJar
-        from project(":gemfire-core").jcaJar
-        
-        from project(":gemfire-lucene").configurations.runtime
-        from project(":gemfire-lucene").configurations.archives.allArtifacts.files
-
-        // include this jar        
-        from project(":gemfire-web-api").jar
-        
-        // dependency jars
-        from depsJar
-        from gfshDepsJar
-      }
-
-      into ('tools/Extensions') {
-        from (project(":gemfire-web").configurations.archives.allArtifacts.files) {
-          exclude '*.jar'
-        }
-        from (project(":gemfire-web-api").configurations.archives.allArtifacts.files) {
-          exclude '*.jar'
-        }
-      }
-
-      into ('javadoc') {
-        from docs
-      }
-
-      into ('tools/Pulse') {
-        from (project(":gemfire-pulse").configurations.archives.allArtifacts.files) {
-          exclude '*.jar'
-        }
-      }
-
-      into ('tools/Modules') {
-        from (project(':extensions/gemfire-modules-assembly').configurations.moduleDistOutputs.files)
-      }
-    }
-  }
-}
-
-// Create a configuration closure to configure test targets with the install directory
-def dependOnInstalledProduct = {
-  dependsOn installDist
-  def install = file("$buildDir/install/${distributions.main.baseName}")
-  environment ('GEMFIRE', install)
-}
-
-// Add the configuration closure to the test targets so they depend on the install directory
-test dependOnInstalledProduct
-distributedTest dependOnInstalledProduct
-integrationTest dependOnInstalledProduct
-
-// Make build final task to generate all test and product resources
-build.dependsOn installDist
-
-installDist.dependsOn ':extensions/gemfire-modules-assembly:dist'

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f6c4c2f9/gemfire-assembly/src/main/dist/DISCLAIMER
----------------------------------------------------------------------
diff --git a/gemfire-assembly/src/main/dist/DISCLAIMER b/gemfire-assembly/src/main/dist/DISCLAIMER
deleted file mode 100644
index 43c734d..0000000
--- a/gemfire-assembly/src/main/dist/DISCLAIMER
+++ /dev/null
@@ -1,6 +0,0 @@
-Apache Geode is an effort undergoing incubation at The Apache Software Foundation (ASF),
-sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until
-a further review indicates that the infrastructure, communications, and decision making process
-have stabilized in a manner consistent with other successful ASF projects. While incubation
-status is not necessarily a reflection of the completeness or stability of the code, it does
-indicate that the project has yet to be fully endorsed by the ASF.