geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [19/50] [abbrv] incubator-geode git commit: GEODE-14: Integration of GemFire Session Replication and Hibernate modules
Date Tue, 09 Feb 2016 01:30:12 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
new file mode 100644
index 0000000..a23888c
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
@@ -0,0 +1,186 @@
+/*
+* 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.internal.common;
+
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.client.ClientCache;
+import com.gemstone.gemfire.cache.client.ClientRegionFactory;
+import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
+import com.gemstone.gemfire.cache.execute.Execution;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.modules.util.BootstrappingFunction;
+import com.gemstone.gemfire.modules.util.CreateRegionFunction;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+import com.gemstone.gemfire.modules.util.RegionStatus;
+
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which defines a client/server cache.
+ */
+public class ClientServerSessionCache extends AbstractSessionCache {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(PeerToPeerSessionCache.class.getName());
+
+  private ClientCache cache;
+
+  protected static final String DEFAULT_REGION_ATTRIBUTES_ID =
+      RegionShortcut.PARTITION_REDUNDANT.toString();
+
+  protected static final Boolean DEFAULT_ENABLE_LOCAL_CACHE = true;
+
+  /**
+   * Constructor
+   *
+   * @param cache
+   * @param properties
+   */
+  public ClientServerSessionCache(ClientCache cache,
+      Map<CacheProperty, Object> properties) {
+    super();
+    this.cache = cache;
+
+    /**
+     * Set some default properties for this cache if they haven't already
+     * been set
+     */
+    this.properties.put(CacheProperty.REGION_ATTRIBUTES_ID,
+        DEFAULT_REGION_ATTRIBUTES_ID);
+    this.properties.put(CacheProperty.ENABLE_LOCAL_CACHE,
+        DEFAULT_ENABLE_LOCAL_CACHE);
+    this.properties.putAll(properties);
+  }
+
+  @Override
+  public void initialize() {
+    // Bootstrap the servers
+    bootstrapServers();
+
+    // Create or retrieve the region
+    createOrRetrieveRegion();
+
+    // Set the session region directly as the operating region since there is no difference
+    // between the local cache region and the session region.
+    operatingRegion = sessionRegion;
+
+    // Create or retrieve the statistics
+    createStatistics();
+  }
+
+  @Override
+  public GemFireCache getCache() {
+    return cache;
+  }
+
+  @Override
+  public boolean isClientServer() {
+    return true;
+  }
+
+
+  ////////////////////////////////////////////////////////////////////////
+  // Private methods
+
+  private void bootstrapServers() {
+    Execution execution = FunctionService.onServers(this.cache);
+    ResultCollector collector = execution.execute(new BootstrappingFunction());
+    // Get the result. Nothing is being done with it.
+    try {
+      collector.getResult();
+    } catch (Exception e) {
+      // If an exception occurs in the function, log it.
+      LOG.warn("Caught unexpected exception:", e);
+    }
+  }
+
+  private void createOrRetrieveRegion() {
+    // Retrieve the local session region
+    this.sessionRegion =
+        this.cache.getRegion(
+            (String) properties.get(CacheProperty.REGION_NAME));
+
+    // If necessary, create the regions on the server and client
+    if (this.sessionRegion == null) {
+      // Create the PR on the servers
+      createSessionRegionOnServers();
+
+      // Create the region on the client
+      this.sessionRegion = createLocalSessionRegion();
+      LOG.debug("Created session region: " + this.sessionRegion);
+    } else {
+      LOG.debug("Retrieved session region: " + this.sessionRegion);
+    }
+  }
+
+  private void createSessionRegionOnServers() {
+    // Create the RegionConfiguration
+    RegionConfiguration configuration = createRegionConfiguration();
+
+    // Send it to the server tier
+    Execution execution = FunctionService.onServer(this.cache).withArgs(
+        configuration);
+    ResultCollector collector = execution.execute(CreateRegionFunction.ID);
+
+    // Verify the region was successfully created on the servers
+    List<RegionStatus> results = (List<RegionStatus>) collector.getResult();
+    for (RegionStatus status : results) {
+      if (status == RegionStatus.INVALID) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(
+            "An exception occurred on the server while attempting to create or validate region named ");
+        builder.append(properties.get(CacheProperty.REGION_NAME));
+        builder.append(". See the server log for additional details.");
+        throw new IllegalStateException(builder.toString());
+      }
+    }
+  }
+
+  private Region<String, HttpSession> createLocalSessionRegion() {
+    ClientRegionFactory<String, HttpSession> factory = null;
+    boolean enableLocalCache =
+        (Boolean) properties.get(CacheProperty.ENABLE_LOCAL_CACHE);
+
+    String regionName = (String) properties.get(CacheProperty.REGION_NAME);
+    if (enableLocalCache) {
+      // Create the region factory with caching and heap LRU enabled
+      factory = ((ClientCache) this.cache).
+          createClientRegionFactory(
+              ClientRegionShortcut.CACHING_PROXY_HEAP_LRU);
+      LOG.info("Created new local client session region: {}", regionName);
+    } else {
+      // Create the region factory without caching enabled
+      factory = ((ClientCache) this.cache).createClientRegionFactory(
+          ClientRegionShortcut.PROXY);
+      LOG.info(
+          "Created new local client (uncached) session region: {} without any session expiry",
+          regionName);
+    }
+
+    // Create the region
+    return factory.create(regionName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
new file mode 100644
index 0000000..878adaa
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
@@ -0,0 +1,184 @@
+/*
+* 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.internal.common;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionFactory;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.modules.session.catalina.callback.LocalSessionCacheLoader;
+import com.gemstone.gemfire.modules.session.catalina.callback.LocalSessionCacheWriter;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+import com.gemstone.gemfire.modules.util.RegionHelper;
+import com.gemstone.gemfire.modules.util.TouchPartitionedRegionEntriesFunction;
+import com.gemstone.gemfire.modules.util.TouchReplicatedRegionEntriesFunction;
+
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which defines a peer-to-peer cache
+ */
+public class PeerToPeerSessionCache extends AbstractSessionCache {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(PeerToPeerSessionCache.class.getName());
+
+  private Cache cache;
+
+  private static final String DEFAULT_REGION_ATTRIBUTES_ID =
+      RegionShortcut.REPLICATE.toString();
+
+  private static final Boolean DEFAULT_ENABLE_LOCAL_CACHE = false;
+
+  /**
+   * Constructor
+   *
+   * @param cache
+   * @param properties
+   */
+  public PeerToPeerSessionCache(Cache cache,
+      Map<CacheProperty, Object> properties) {
+    super();
+    this.cache = cache;
+
+    /**
+     * Set some default properties for this cache if they haven't already
+     * been set
+     */
+    this.properties.put(CacheProperty.REGION_ATTRIBUTES_ID,
+        DEFAULT_REGION_ATTRIBUTES_ID);
+    this.properties.put(CacheProperty.ENABLE_LOCAL_CACHE,
+        DEFAULT_ENABLE_LOCAL_CACHE);
+    this.properties.putAll(properties);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void initialize() {
+    // Register Functions
+    registerFunctions();
+
+    // Create or retrieve the region
+    createOrRetrieveRegion();
+
+    /**
+     * If local cache is enabled, create the local region fronting the
+     * session region and set it as the operating region; otherwise, use
+     * the session region directly as the operating region.
+     */
+    boolean enableLocalCache =
+        (Boolean) properties.get(CacheProperty.ENABLE_LOCAL_CACHE);
+    operatingRegion = enableLocalCache
+        ? createOrRetrieveLocalRegion()
+        : this.sessionRegion;
+
+    // Create or retrieve the statistics
+    createStatistics();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GemFireCache getCache() {
+    return cache;
+  }
+
+  @Override
+  public boolean isClientServer() {
+    return false;
+  }
+
+  private void registerFunctions() {
+    // Register the touch partitioned region entries function if it is not already registered
+    if (!FunctionService.isRegistered(
+        TouchPartitionedRegionEntriesFunction.ID)) {
+      FunctionService.registerFunction(
+          new TouchPartitionedRegionEntriesFunction());
+    }
+
+    // Register the touch replicated region entries function if it is not already registered
+    if (!FunctionService.isRegistered(
+        TouchReplicatedRegionEntriesFunction.ID)) {
+      FunctionService.registerFunction(
+          new TouchReplicatedRegionEntriesFunction());
+    }
+  }
+
+  private void createOrRetrieveRegion() {
+    // Create the RegionConfiguration
+    RegionConfiguration configuration = createRegionConfiguration();
+
+    // Attempt to retrieve the region
+    // If it already exists, validate it
+    // If it doesn't already exist, create it
+    Region region = this.cache.getRegion(
+        (String) properties.get(CacheProperty.REGION_NAME));
+    if (region == null) {
+      // Create the region
+      region = RegionHelper.createRegion(cache, configuration);
+      LOG.info("Created new session region: {}", region);
+    } else {
+      // Validate the existing region
+      LOG.info("Retrieved existing session region: {}", region);
+      RegionHelper.validateRegion(cache, configuration, region);
+    }
+
+    // Set the session region
+    this.sessionRegion = region;
+  }
+
+  /**
+   * Create a local region fronting the main region.
+   *
+   * @return
+   */
+  private Region<String, HttpSession> createOrRetrieveLocalRegion() {
+    // Attempt to retrieve the fronting region
+    String frontingRegionName = this.sessionRegion.getName() + "_local";
+    Region<String, HttpSession> frontingRegion =
+        this.cache.getRegion(frontingRegionName);
+
+    if (frontingRegion == null) {
+      // Create the region factory
+      RegionFactory<String, HttpSession> factory =
+          this.cache.createRegionFactory(RegionShortcut.LOCAL_HEAP_LRU);
+
+      // Add the cache loader and writer
+      factory.setCacheLoader(new LocalSessionCacheLoader(this.sessionRegion));
+      factory.setCacheWriter(new LocalSessionCacheWriter(this.sessionRegion));
+
+      // Create the region
+      frontingRegion = factory.create(frontingRegionName);
+      LOG.info("Created new local session region: {}", frontingRegion);
+    } else {
+      LOG.info("Retrieved existing local session region: {}",
+          frontingRegion);
+    }
+
+    return frontingRegion;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
new file mode 100644
index 0000000..7562dff
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
@@ -0,0 +1,68 @@
+/*
+* 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.internal.common;
+
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Interface to basic cache operations.
+ */
+public interface SessionCache {
+
+  /**
+   * Initialize the cache and create the appropriate region.
+   */
+  public void initialize();
+
+  /**
+   * Stop the cache.
+   */
+  public void stop();
+
+  /**
+   * Retrieve the cache reference.
+   *
+   * @return a {@code GemFireCache} reference
+   */
+  public GemFireCache getCache();
+
+  /**
+   * Get the {@code Region} being used by client code to put attributes.
+   *
+   * @return a {@code Region<String, HttpSession>} reference
+   */
+  public Region<String, HttpSession> getOperatingRegion();
+
+  /**
+   * Get the backing {@code Region} being used. This may not be the same as the
+   * region being used by client code to put attributes.
+   *
+   * @return a {@code Region<String, HttpSession>} reference
+   */
+  public Region<String, HttpSession> getSessionRegion();
+
+  /**
+   * Is this cache client-server? The only other alternative is peer-to-peer.
+   *
+   * @return true if this cache is client-server.
+   */
+  public boolean isClientServer();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
new file mode 100644
index 0000000..648e711
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
@@ -0,0 +1,53 @@
+/*
+* 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.internal.common;
+
+import com.gemstone.gemfire.cache.Declarable;
+import com.gemstone.gemfire.cache.EntryEvent;
+import com.gemstone.gemfire.cache.Operation;
+import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
+
+import java.util.Properties;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SessionExpirationCacheListener extends
+    CacheListenerAdapter<String, HttpSession> implements Declarable {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(SessionExpirationCacheListener.class.getName());
+
+  @Override
+  public void afterDestroy(EntryEvent<String, HttpSession> event) {
+    /**
+     * A Session expired. If it was destroyed by GemFire expiration,
+     * process it. If it was destroyed via Session.invalidate, ignore it
+     * since it has already been processed.
+     */
+    if (event.getOperation() == Operation.EXPIRE_DESTROY) {
+      HttpSession session = (HttpSession) event.getOldValue();
+      session.invalidate();
+    }
+  }
+
+  @Override
+  public void init(Properties p) {
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java
new file mode 100644
index 0000000..4ce8733
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.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.internal.filter;
+
+/**
+ * Various constant values used through the app
+ */
+public class Constants {
+
+  public static String GEMFIRE_SESSION_REQUEST = "_gemfire_session_request_";
+
+  public static String SESSION_STATISTICS_MBEAN_NAME =
+      "com.gemstone:type=SessionStatistics,name=sessionStatistics";
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
new file mode 100644
index 0000000..9628912
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
@@ -0,0 +1,132 @@
+/*
+* 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.internal.filter;
+
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Class which fakes an in-memory basic session manager for testing purposes.
+ */
+public class DummySessionManager implements SessionManager {
+
+  /**
+   * Map of sessions
+   */
+  private final Map<String, HttpSession> sessions =
+      new HashMap<String, HttpSession>();
+
+  private class Attributes extends AbstractSessionAttributes {
+
+    @Override
+    public Object putAttribute(String attr, Object value) {
+      return attributes.put(attr, value);
+    }
+
+    @Override
+    public Object removeAttribute(String attr) {
+      return attributes.remove(attr);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void start(Object config, ClassLoader loader) {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void stop() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSession getSession(String id) {
+    return sessions.get(id);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSession wrapSession(HttpSession nativeSession) {
+    String id = generateId();
+    AbstractSessionAttributes attributes = new Attributes();
+    GemfireHttpSession session = new GemfireHttpSession(id, nativeSession);
+    session.setManager(this);
+    session.setAttributes(attributes);
+    sessions.put(id, session);
+
+    return session;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSession getWrappingSession(String nativeId) {
+    return sessions.get(nativeId);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void putSession(HttpSession session) {
+    // shouldn't ever get called
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void destroySession(String id) {
+    sessions.remove(id);
+  }
+
+  @Override
+  public String destroyNativeSession(String id) {
+    return null;
+  }
+
+  public String getSessionCookieName() {
+    return "JSESSIONID";
+  }
+
+  public String getJvmId() {
+    return "jvm-id";
+  }
+
+  /**
+   * Generate an ID string
+   */
+  private String generateId() {
+    return UUID.randomUUID().toString().toUpperCase() + "-GF";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
new file mode 100644
index 0000000..695a03b
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
@@ -0,0 +1,526 @@
+/*
+* 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.internal.filter;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.Delta;
+import com.gemstone.gemfire.Instantiator;
+import com.gemstone.gemfire.InvalidDeltaException;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.SessionAttributes;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+import com.gemstone.gemfire.modules.util.ClassLoaderObjectInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which implements a Gemfire persisted {@code HttpSession}
+ */
+public class GemfireHttpSession implements
+    HttpSession, DataSerializable, Delta {
+
+  private static transient final Logger LOG =
+      LoggerFactory.getLogger(GemfireHttpSession.class.getName());
+
+  /**
+   * Serial id
+   */
+  private static final long serialVersionUID = 238915238964017823L;
+
+  /**
+   * Id for the session
+   */
+  private String id;
+
+  /**
+   * Attributes really hold the essence of persistence.
+   */
+  private SessionAttributes attributes;
+
+  private transient SessionManager manager;
+
+  private HttpSession nativeSession = null;
+
+  /**
+   * A session becomes invalid if it is explicitly invalidated or if it
+   * expires.
+   */
+  private boolean isValid = true;
+
+  private boolean isNew = true;
+
+  private boolean isDirty = false;
+
+  /**
+   * This is set during serialization and then reset by the SessionManager when
+   * it is retrieved from the attributes.
+   */
+  private AtomicBoolean serialized = new AtomicBoolean(false);
+
+  /**
+   * Register ourselves for de-serialization
+   */
+  static {
+    Instantiator.register(new Instantiator(GemfireHttpSession.class, 27315) {
+      @Override
+      public DataSerializable newInstance() {
+        return new GemfireHttpSession();
+      }
+    });
+  }
+
+  /**
+   * Constructor used for de-serialization
+   */
+  private GemfireHttpSession() {
+  }
+
+  /**
+   * Constructor
+   */
+  public GemfireHttpSession(String id, HttpSession nativeSession) {
+    this();
+    this.id = id;
+    this.nativeSession = nativeSession;
+    if (nativeSession != null) {
+      attributes.setMaxInactiveInterval(nativeSession.getMaxInactiveInterval());
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Object getAttribute(String name) {
+    if (!isValid) {
+      throw new IllegalStateException("Session is already invalidated");
+    }
+    Object obj = attributes.getAttribute(name);
+
+    if (obj != null) {
+      Object tmpObj = null;
+      ClassLoader loader = ((GemfireSessionManager) manager).getReferenceClassLoader();
+
+      if (obj.getClass().getClassLoader() != loader) {
+        LOG.debug(
+            "Attribute '{}' needs to be reconstructed with a new classloader",
+            name);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+          ObjectOutputStream oos = new ObjectOutputStream(baos);
+          oos.writeObject(obj);
+          oos.close();
+
+          ObjectInputStream ois = new ClassLoaderObjectInputStream(
+              new ByteArrayInputStream(baos.toByteArray()),
+              loader);
+          tmpObj = ois.readObject();
+        } catch (IOException e) {
+          LOG.error("Exception while recreating attribute '" + name +
+              "'", e);
+        } catch (ClassNotFoundException e) {
+          LOG.error("Exception while recreating attribute '" + name +
+              "'", e);
+        }
+        if (tmpObj != null) {
+          setAttribute(name, tmpObj);
+          obj = tmpObj;
+        }
+      }
+    }
+
+    return obj;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Enumeration getAttributeNames() {
+    if (!isValid) {
+      throw new IllegalStateException("Session is already invalidated");
+    }
+    return Collections.enumeration(attributes.getAttributeNames());
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public long getCreationTime() {
+    if (nativeSession != null) {
+      return nativeSession.getCreationTime();
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public long getLastAccessedTime() {
+    if (!isValid) {
+      throw new IllegalStateException("Session is already invalidated");
+    }
+    return attributes.getLastAccessedTime();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ServletContext getServletContext() {
+    if (nativeSession != null) {
+      return nativeSession.getServletContext();
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSessionContext getSessionContext() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Object getValue(String name) {
+    return getAttribute(name);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String[] getValueNames() {
+    return attributes.getAttributeNames().toArray(new String[0]);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void invalidate() {
+    nativeSession.invalidate();
+    manager.destroySession(id);
+    isValid = false;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isNew() {
+    if (!isValid) {
+      throw new IllegalStateException("Session is already invalidated");
+    }
+    return isNew;
+  }
+
+  public void setIsNew(boolean isNew) {
+    this.isNew = isNew;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setMaxInactiveInterval(int interval) {
+    if (nativeSession != null) {
+      nativeSession.setMaxInactiveInterval(interval);
+    }
+    attributes.setMaxInactiveInterval(interval);
+    isDirty = true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getMaxInactiveInterval() {
+    if (nativeSession != null) {
+      return nativeSession.getMaxInactiveInterval();
+    } else {
+      return attributes.getMaxIntactiveInterval();
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void putValue(String name, Object value) {
+    setAttribute(name, value);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void removeAttribute(final String name) {
+    LOG.debug("Session {} removing attribute {}", getId(), name);
+    nativeSession.removeAttribute(name);
+    attributes.removeAttribute(name);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void removeValue(String name) {
+    removeAttribute(name);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setAttribute(final String name, final Object value) {
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Session {} setting attribute {} = '{}'",
+          new Object[]{id, name, value});
+    }
+
+    isDirty = true;
+    nativeSession.setAttribute(name, value);
+    if (value == null) {
+      removeAttribute(name);
+    } else {
+      attributes.putAttribute(name, value);
+    }
+  }
+
+  /**
+   * Gemfire serialization {@inheritDoc}
+   */
+  @Override
+  public void toData(DataOutput out) throws IOException {
+    DataSerializer.writeString(id, out);
+    DataSerializer.writeObject(attributes, out);
+  }
+
+  /**
+   * Gemfire de-serialization {@inheritDoc}
+   */
+  @Override
+  public void fromData(DataInput in) throws IOException,
+      ClassNotFoundException {
+    id = DataSerializer.readString(in);
+    attributes = DataSerializer.readObject(in);
+    if (getNativeSession() != null) {
+      for (String s : attributes.getAttributeNames()) {
+        getNativeSession().setAttribute(s, attributes.getAttribute(s));
+      }
+    }
+
+    // Explicit sets
+    serialized.set(true);
+    attributes.setSession(this);
+  }
+
+  /**
+   * These three methods handle delta propagation and are deferred to the
+   * attribute object.
+   */
+  @Override
+  public boolean hasDelta() {
+    return isDirty;
+  }
+
+  @Override
+  public void toDelta(DataOutput out) throws IOException {
+    if (attributes instanceof Delta) {
+      ((Delta) attributes).toDelta(out);
+    } else {
+      toData(out);
+    }
+  }
+
+  @Override
+  public void fromDelta(DataInput in) throws IOException,
+      InvalidDeltaException {
+    if (attributes instanceof Delta) {
+      ((Delta) attributes).fromDelta(in);
+    } else {
+      try {
+        fromData(in);
+      } catch (ClassNotFoundException cex) {
+        throw new IOException("Unable to forward fromDelta() call "
+            + "to fromData()", cex);
+      }
+    }
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder builder = new StringBuilder();
+    builder.append("[id=").append(id)
+        .append(", isNew=").append(isNew)
+        .append(", isValid=").append(isValid)
+        .append(", hasDelta=").append(hasDelta())
+        .append(", lastAccessedTime=").append(attributes.getLastAccessedTime())
+        .append(", jvmOwnerId=").append(attributes.getJvmOwnerId());
+    builder.append("]");
+    return builder.toString();
+  }
+
+  /**
+   * Flush the session object to the region
+   */
+  public void putInRegion() {
+
+    manager.putSession(this);
+    isDirty = false;
+  }
+
+  /**
+   * Determine whether the session is still valid or whether it has expired.
+   *
+   * @return true or false
+   */
+  public boolean isValid() {
+    if (!isValid) {
+      return false;
+    }
+    if (getMaxInactiveInterval() >= 0) {
+      long now = System.currentTimeMillis();
+      if (now - attributes.getLastAccessedTime() >= getMaxInactiveInterval() * 1000) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Is this session dirty and should it be written to cache
+   */
+  public boolean isDirty() {
+    return isDirty;
+  }
+
+  public void setManager(SessionManager manager) {
+    this.manager = manager;
+  }
+
+  /**
+   * For testing allow retrieval of the wrapped, native session.
+   */
+  public HttpSession getNativeSession() {
+    return nativeSession;
+  }
+
+
+  public void setNativeSession(HttpSession session) {
+    this.nativeSession = session;
+  }
+
+  /**
+   * Handle the process of failing over the session to a new native session
+   * object.
+   *
+   * @param session
+   */
+  public void failoverSession(HttpSession session) {
+    LOG.debug("Failing over session {} to {}", getId(), session.getId());
+    setNativeSession(session);
+    for (String name : attributes.getAttributeNames()) {
+      LOG.debug("Copying '{}' => {}", name, attributes.getAttribute(name));
+      session.setAttribute(name, attributes.getAttribute(name));
+    }
+    session.setMaxInactiveInterval(attributes.getMaxIntactiveInterval());
+    manager.putSession(this);
+  }
+
+
+  /**
+   * Update the last accessed time
+   */
+  public void updateAccessTime() {
+    attributes.setLastAccessedTime(System.currentTimeMillis());
+  }
+
+  /**
+   * The {@code SessionManager} injects this when creating a new session.
+   *
+   * @param attributes
+   */
+  public void setAttributes(AbstractSessionAttributes attributes) {
+    this.attributes = attributes;
+  }
+
+  /**
+   * This is called on deserialization. You can only call it once to get a
+   * meaningful value as it resets the serialized state. In other words, this
+   * call is not idempotent.
+   *
+   * @return whether this object has just been serialized
+   */
+  public boolean justSerialized() {
+    return serialized.getAndSet(false);
+  }
+
+  /**
+   * Called when the session is about to go out of scope. If the session has
+   * been defined to use async queued attributes then they will be written out
+   * at this point.
+   */
+  public void commit() {
+    attributes.setJvmOwnerId(manager.getJvmId());
+    attributes.flush();
+  }
+
+  public String getJvmOwnerId() {
+    if (attributes != null) {
+      return attributes.getJvmOwnerId();
+    }
+
+    return null;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
new file mode 100644
index 0000000..3ce81be
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
@@ -0,0 +1,41 @@
+/*
+* 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.internal.filter;
+
+/**
+ * Exception class for Gemfire Session Cache specific exceptions.
+ */
+public class GemfireSessionException extends Exception {
+
+  public GemfireSessionException() {
+    super();
+  }
+
+  public GemfireSessionException(String message) {
+    super(message);
+  }
+
+  public GemfireSessionException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public GemfireSessionException(Throwable cause) {
+    super(cause);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
new file mode 100644
index 0000000..a3d3c10
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
@@ -0,0 +1,511 @@
+/*
+* 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.internal.filter;
+
+import com.gemstone.gemfire.cache.CacheClosedException;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.EntryNotFoundException;
+import com.gemstone.gemfire.cache.control.ResourceManager;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.modules.session.bootstrap.AbstractCache;
+import com.gemstone.gemfire.modules.session.bootstrap.ClientServerCache;
+import com.gemstone.gemfire.modules.session.bootstrap.LifecycleTypeAdapter;
+import com.gemstone.gemfire.modules.session.bootstrap.PeerToPeerCache;
+import com.gemstone.gemfire.modules.session.internal.common.CacheProperty;
+import com.gemstone.gemfire.modules.session.internal.common.ClientServerSessionCache;
+import com.gemstone.gemfire.modules.session.internal.common.PeerToPeerSessionCache;
+import com.gemstone.gemfire.modules.session.internal.common.SessionCache;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.DeltaQueuedSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.DeltaSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.ImmediateSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.util.TypeAwareMap;
+import com.gemstone.gemfire.modules.session.internal.jmx.SessionStatistics;
+import com.gemstone.gemfire.modules.util.RegionHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.InitialContext;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpSession;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * This class implements the session management using a Gemfire distributedCache
+ * as a persistent store for the session objects
+ */
+public class GemfireSessionManager implements SessionManager {
+
+  private final Logger LOG;
+
+  /**
+   * Prefix of init param string used to set gemfire properties
+   */
+  private static final String GEMFIRE_PROPERTY = "gemfire.property.";
+
+  /**
+   * Prefix of init param string used to set gemfire distributedCache setting
+   */
+  private static final String GEMFIRE_CACHE = "gemfire.cache.";
+
+  private static final String INIT_PARAM_CACHE_TYPE = "cache-type";
+  private static final String CACHE_TYPE_CLIENT_SERVER = "client-server";
+  private static final String CACHE_TYPE_PEER_TO_PEER = "peer-to-peer";
+  private static final String INIT_PARAM_SESSION_COOKIE_NAME = "session-cookie-name";
+  private static final String INIT_PARAM_JVM_ID = "jvm-id";
+  private static final String DEFAULT_JVM_ID = "default";
+
+  private SessionCache sessionCache = null;
+
+  /**
+   * Reference to the distributed system
+   */
+  private AbstractCache distributedCache = null;
+
+  /**
+   * Boolean indicating whether the manager is shutting down
+   */
+  private boolean isStopping = false;
+
+  /**
+   * Boolean indicating whether this manager is defined in the same context (war
+   * / classloader) as the filter.
+   */
+  private boolean isolated = false;
+
+  /**
+   * Map of wrapping GemFire session id to native session id
+   */
+  private Map<String, String> nativeSessionMap =
+      new HashMap<String, String>();
+
+  /**
+   * MBean for statistics
+   */
+  private SessionStatistics mbean;
+
+  /**
+   * This CL is used to compare against the class loader of attributes getting
+   * pulled out of the cache. This variable should be set to the CL of the
+   * filter running everything.
+   */
+  private ClassLoader referenceClassLoader;
+
+  private String sessionCookieName = "JSESSIONID";
+
+  /**
+   * Give this JVM a unique identifier.
+   */
+  private String jvmId = "default";
+
+  /**
+   * Set up properties with default values
+   */
+  private TypeAwareMap<CacheProperty, Object> properties =
+      new TypeAwareMap<CacheProperty, Object>(CacheProperty.class) {{
+        put(CacheProperty.REGION_NAME, RegionHelper.NAME + "_sessions");
+        put(CacheProperty.ENABLE_GATEWAY_DELTA_REPLICATION, Boolean.FALSE);
+        put(CacheProperty.ENABLE_GATEWAY_REPLICATION, Boolean.FALSE);
+        put(CacheProperty.ENABLE_DEBUG_LISTENER, Boolean.FALSE);
+        put(CacheProperty.STATISTICS_NAME, "gemfire_statistics");
+        put(CacheProperty.SESSION_DELTA_POLICY, "delta_queued");
+        put(CacheProperty.REPLICATION_TRIGGER, "set");
+        /**
+         * For REGION_ATTRIBUTES_ID and ENABLE_LOCAL_CACHE the default
+         * is different for ClientServerCache and PeerToPeerCache
+         * so those values are set in the relevant constructors when
+         * these properties are passed in to them.
+         */
+      }};
+
+  public GemfireSessionManager() {
+    LOG = LoggerFactory.getLogger(GemfireSessionManager.class.getName());
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void start(Object conf, ClassLoader loader) {
+    this.referenceClassLoader = loader;
+    FilterConfig config = (FilterConfig) conf;
+
+    startDistributedSystem(config);
+    initializeSessionCache(config);
+
+    // Register MBean
+    registerMBean();
+
+    if (distributedCache.getClass().getClassLoader() == loader) {
+      isolated = true;
+    }
+
+    String sessionCookieName = config.getInitParameter(
+        INIT_PARAM_SESSION_COOKIE_NAME);
+    if (sessionCookieName != null && !sessionCookieName.isEmpty()) {
+      this.sessionCookieName = sessionCookieName;
+      LOG.info("Session cookie name set to: {}", this.sessionCookieName);
+    }
+
+    jvmId = config.getInitParameter(INIT_PARAM_JVM_ID);
+    if (jvmId == null || jvmId.isEmpty()) {
+      jvmId = DEFAULT_JVM_ID;
+    }
+
+    LOG.info("Started GemfireSessionManager (isolated={}, jvmId={})",
+        isolated, jvmId);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void stop() {
+    isStopping = true;
+
+    if (isolated) {
+      if (distributedCache != null) {
+        LOG.info("Closing distributed cache - assuming isolated cache");
+        distributedCache.close();
+      }
+    } else {
+      LOG.info("Not closing distributed cache - assuming common cache");
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSession getSession(String id) {
+    GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+        id);
+
+    if (session != null) {
+      if (session.justSerialized()) {
+        session.setManager(this);
+        LOG.debug("Recovered serialized session {} (jvmId={})", id,
+            session.getJvmOwnerId());
+      }
+      LOG.debug("Retrieved session id {}", id);
+    } else {
+      LOG.debug("Session id {} not found", id);
+    }
+    return session;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public HttpSession wrapSession(HttpSession nativeSession) {
+    String id = generateId();
+    GemfireHttpSession session =
+        new GemfireHttpSession(id, nativeSession);
+
+    /**
+     * Set up the attribute container depending on how things are configured
+     */
+    AbstractSessionAttributes attributes;
+    if ("delta_queued".equals(
+        properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+      attributes = new DeltaQueuedSessionAttributes();
+      ((DeltaQueuedSessionAttributes) attributes).setReplicationTrigger(
+          (String) properties.get(CacheProperty.REPLICATION_TRIGGER));
+    } else if ("delta_immediate".equals(
+        properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+      attributes = new DeltaSessionAttributes();
+    } else if ("immediate".equals(
+        properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+      attributes = new ImmediateSessionAttributes();
+    } else {
+      attributes = new DeltaSessionAttributes();
+      LOG.warn(
+          "No session delta policy specified - using default of 'delta_immediate'");
+    }
+
+    attributes.setSession(session);
+    attributes.setJvmOwnerId(jvmId);
+
+    session.setManager(this);
+    session.setAttributes(attributes);
+
+    LOG.debug("Creating new session {}", id);
+    sessionCache.getOperatingRegion().put(id, session);
+
+    mbean.incActiveSessions();
+
+    return session;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public HttpSession getWrappingSession(String nativeId) {
+    HttpSession session = null;
+    String gemfireId = getGemfireSessionIdFromNativeId(nativeId);
+
+    if (gemfireId != null) {
+      session = getSession(gemfireId);
+    }
+    return session;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void destroySession(String id) {
+    if (!isStopping) {
+      try {
+        GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+            id);
+        if (session != null && session.getJvmOwnerId().equals(jvmId)) {
+          LOG.debug("Destroying session {}", id);
+          sessionCache.getOperatingRegion().destroy(id);
+          mbean.decActiveSessions();
+        }
+      } catch (EntryNotFoundException nex) {
+      }
+    } else {
+      if (sessionCache.isClientServer()) {
+        LOG.debug("Destroying session {}", id);
+        try {
+          sessionCache.getOperatingRegion().localDestroy(id);
+        } catch (EntryNotFoundException nex) {
+          // Ignored
+        } catch (CacheClosedException ccex) {
+          // Ignored
+        }
+      } else {
+        GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+            id);
+        if (session != null) {
+          session.setNativeSession(null);
+        }
+      }
+    }
+
+    synchronized (nativeSessionMap) {
+      String nativeId = nativeSessionMap.remove(id);
+      LOG.debug("destroySession called for {} wrapping {}", id, nativeId);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void putSession(HttpSession session) {
+    sessionCache.getOperatingRegion().put(session.getId(), session);
+    mbean.incRegionUpdates();
+    nativeSessionMap.put(session.getId(),
+        ((GemfireHttpSession) session).getNativeSession().getId());
+  }
+
+  @Override
+  public String destroyNativeSession(String nativeId) {
+    String gemfireSessionId = getGemfireSessionIdFromNativeId(nativeId);
+    if (gemfireSessionId != null) {
+      destroySession(gemfireSessionId);
+    }
+    return gemfireSessionId;
+  }
+
+  public ClassLoader getReferenceClassLoader() {
+    return referenceClassLoader;
+  }
+
+  /**
+   * This method is called when a native session gets destroyed. It will check
+   * if the GemFire session is actually still valid/not expired and will then
+   * attach a new, native session.
+   *
+   * @param nativeId the id of the native session
+   * @return the id of the newly attached native session or null if the GemFire
+   * session was already invalid
+   */
+  public String refreshSession(String nativeId) {
+    String gemfireId = getGemfireSessionIdFromNativeId(nativeId);
+    if (gemfireId == null) {
+      return null;
+    }
+
+    GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+        gemfireId);
+    if (session.isValid()) {
+
+    }
+
+    return null;
+  }
+
+  public String getSessionCookieName() {
+    return sessionCookieName;
+  }
+
+  public String getJvmId() {
+    return jvmId;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////////
+  // Private methods
+
+  private String getGemfireSessionIdFromNativeId(String nativeId) {
+    if (nativeId == null) {
+      return null;
+    }
+
+    for (Map.Entry<String, String> e : nativeSessionMap.entrySet()) {
+      if (nativeId.equals(e.getValue())) {
+        return e.getKey();
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Start the underlying distributed system
+   *
+   * @param config
+   */
+  private void startDistributedSystem(FilterConfig config) {
+    // Get the distributedCache type
+    final String cacheType = config.getInitParameter(INIT_PARAM_CACHE_TYPE);
+    if (CACHE_TYPE_CLIENT_SERVER.equals(cacheType)) {
+      distributedCache = ClientServerCache.getInstance();
+    } else if (CACHE_TYPE_PEER_TO_PEER.equals(cacheType)) {
+      distributedCache = PeerToPeerCache.getInstance();
+    } else {
+      LOG.error("No 'cache-type' initialization param set. "
+          + "Cache will not be started");
+      return;
+    }
+
+    if (!distributedCache.isStarted()) {
+      /**
+       * Process all the init params and see if any apply to the
+       * distributed system.
+       */
+      for (Enumeration<String> e = config.getInitParameterNames(); e.hasMoreElements(); ) {
+        String param = e.nextElement();
+        if (!param.startsWith(GEMFIRE_PROPERTY)) {
+          continue;
+        }
+
+        String gemfireProperty = param.substring(GEMFIRE_PROPERTY.length());
+        LOG.info("Setting gemfire property: {} = {}",
+            gemfireProperty, config.getInitParameter(param));
+        distributedCache.setProperty(gemfireProperty,
+            config.getInitParameter(param));
+      }
+
+      distributedCache.lifecycleEvent(LifecycleTypeAdapter.START);
+    }
+  }
+
+  /**
+   * Initialize the distributedCache
+   */
+  private void initializeSessionCache(FilterConfig config) {
+    // Retrieve the distributedCache
+    GemFireCacheImpl cache = (GemFireCacheImpl) CacheFactory.getAnyInstance();
+    if (cache == null) {
+      throw new IllegalStateException("No cache exists. Please configure "
+          + "either a PeerToPeerCacheLifecycleListener or "
+          + "ClientServerCacheLifecycleListener in the "
+          + "server.xml file.");
+    }
+
+    /**
+     * Process all the init params and see if any apply to the distributedCache
+     */
+    ResourceManager rm = cache.getResourceManager();
+    for (Enumeration<String> e = config.getInitParameterNames(); e.hasMoreElements(); ) {
+      String param = e.nextElement();
+
+      // Uggh - don't like this non-generic stuff
+      if (param.equalsIgnoreCase("criticalHeapPercentage")) {
+        float val = Float.parseFloat(config.getInitParameter(param));
+        rm.setCriticalHeapPercentage(val);
+      }
+
+      if (param.equalsIgnoreCase("evictionHeapPercentage")) {
+        float val = Float.parseFloat(config.getInitParameter(param));
+        rm.setEvictionHeapPercentage(val);
+      }
+
+
+      if (!param.startsWith(GEMFIRE_CACHE)) {
+        continue;
+      }
+
+      String gemfireWebParam = param.substring(GEMFIRE_CACHE.length());
+      LOG.info("Setting cache parameter: {} = {}",
+          gemfireWebParam, config.getInitParameter(param));
+      properties.put(CacheProperty.valueOf(gemfireWebParam.toUpperCase()),
+          config.getInitParameter(param));
+    }
+
+    // Create the appropriate session distributedCache
+    sessionCache = cache.isClient()
+        ? new ClientServerSessionCache(cache, properties)
+        : new PeerToPeerSessionCache(cache, properties);
+
+    // Initialize the session distributedCache
+    sessionCache.initialize();
+  }
+
+  /**
+   * Register a bean for statistic gathering purposes
+   */
+  private void registerMBean() {
+    mbean = new SessionStatistics();
+
+    try {
+      InitialContext ctx = new InitialContext();
+      MBeanServer mbs = MBeanServer.class.cast(
+          ctx.lookup("java:comp/env/jmx/runtime"));
+      ObjectName oname = new ObjectName(
+          Constants.SESSION_STATISTICS_MBEAN_NAME);
+
+      mbs.registerMBean(mbean, oname);
+    } catch (Exception ex) {
+      LOG.warn("Unable to register statistics MBean. Error: {}",
+          ex.getMessage());
+    }
+  }
+
+
+  /**
+   * Generate an ID string
+   */
+  private String generateId() {
+    return UUID.randomUUID().toString().toUpperCase() + "-GF";
+  }
+
+  AbstractCache getCache() {
+    return distributedCache;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ListenerEventType.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ListenerEventType.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ListenerEventType.java
new file mode 100644
index 0000000..b040dda
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ListenerEventType.java
@@ -0,0 +1,75 @@
+/*
+* 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.internal.filter;
+
+/**
+ * Enumeration of all possible event types which can be listened for.
+ */
+public enum ListenerEventType {
+
+  /**
+   * HttpSessionAttributeListener
+   */
+  SESSION_ATTRIBUTE_ADDED,
+  SESSION_ATTRIBUTE_REMOVED,
+  SESSION_ATTRIBUTE_REPLACED,
+
+  /**
+   * HttpSessionBindingListener
+   */
+  SESSION_VALUE_BOUND,
+  SESSION_VALUE_UNBOUND,
+
+  /**
+   * HttpSessionListener
+   */
+  SESSION_CREATED,
+  SESSION_DESTROYED,
+
+  /**
+   * HttpSessionActivationListener
+   */
+  SESSION_WILL_ACTIVATE,
+  SESSION_DID_PASSIVATE,
+
+  /**
+   * ServletContextListener
+   */
+  SERVLET_CONTEXT_INITIALIZED,
+  SERVLET_CONTEXT_DESTROYED,
+
+  /**
+   * ServletContextAttributeListener
+   */
+  SERVLET_CONTEXT_ATTRIBUTE_ADDED,
+  SERVLET_CONTEXT_ATTRIBUTE_REMOVED,
+  SERVLET_CONTEXT_ATTRIBUTE_REPLACED,
+
+  /**
+   * ServletRequestListener
+   */
+  SERVLET_REQUEST_DESTROYED,
+  SERVLET_REQUEST_INITIALIZED,
+
+  /**
+   * ServletRequestAttributeListener
+   */
+  SERVLET_REQUEST_ATTRIBUTE_ADDED,
+  SERVLET_REQUEST_ATTRIBUTE_REMOVED,
+  SERVLET_REQUEST_ATTRIBUTE_REPLACED;
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/SessionManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/SessionManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/SessionManager.java
new file mode 100644
index 0000000..9d8996c
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/SessionManager.java
@@ -0,0 +1,110 @@
+/*
+* 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.internal.filter;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Interface to session management. This class would be responsible for creating
+ * new sessions.
+ */
+public interface SessionManager {
+
+  /**
+   * Start the manager possibly using the config passed in.
+   *
+   * @param config Config object specific to individual implementations.
+   * @param loader This is a hack. When the manager is started it wants to be
+   *               able to determine if the cache, which it would create, and
+   *               the filter which starts everything, are defined by the same
+   *               classloader. This is so that during shutdown, the manager can
+   *               decide whether or not to also stop the cache. This option
+   *               allows the filter's classloader to be passed in.
+   */
+  public void start(Object config, ClassLoader loader);
+
+  /**
+   * Stop the session manager and free up any resources.
+   */
+  public void stop();
+
+  /**
+   * Write the session to the region
+   *
+   * @param session the session to write
+   */
+  public void putSession(HttpSession session);
+
+  /**
+   * Return a session if it exists or null otherwise
+   *
+   * @param id The session id to attempt to retrieve
+   * @return a HttpSession object if a session was found otherwise null.
+   */
+  public HttpSession getSession(String id);
+
+  /**
+   * Create a new session, wrapping a container session.
+   *
+   * @param nativeSession
+   * @return the HttpSession object
+   */
+  public HttpSession wrapSession(HttpSession nativeSession);
+
+  /**
+   * Get the wrapped (GemFire) session from a native session id. This method
+   * would typically be used from within session/http event listeners which
+   * receive the original session id.
+   *
+   * @param nativeId
+   * @return the wrapped GemFire session which maps the native session
+   */
+  public HttpSession getWrappingSession(String nativeId);
+
+  /**
+   * Destroy the session associated with the given id.
+   *
+   * @param id The id of the session to destroy.
+   */
+  public void destroySession(String id);
+
+  /**
+   * Destroy the session associated with a given native session
+   *
+   * @param id the id of the native session
+   * @return the corresponding Gemfire session which wrapped the native session
+   * and was destroyed.
+   */
+  public String destroyNativeSession(String id);
+
+  /**
+   * Returns the cookie name used to hold the session id. By default this is
+   * JSESSIONID.
+   *
+   * @return the name of the cookie which contains the session id
+   */
+  public String getSessionCookieName();
+
+  /**
+   * Get the JVM Id - this is a unique string used internally to identify who
+   * last touched a session.
+   *
+   * @return the jvm id
+   */
+  public String getJvmId();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractDeltaSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractDeltaSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractDeltaSessionAttributes.java
new file mode 100644
index 0000000..f46495d
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractDeltaSessionAttributes.java
@@ -0,0 +1,107 @@
+/*
+* 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.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.Delta;
+import com.gemstone.gemfire.InvalidDeltaException;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This abstract class contains the structures and methods to handle delta
+ * updates to attributes.
+ */
+public abstract class AbstractDeltaSessionAttributes
+    extends AbstractSessionAttributes implements Delta {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(AbstractDeltaSessionAttributes.class.getName());
+
+  /**
+   * This map holds the updates to attributes
+   */
+  protected transient Map<String, DeltaEvent> deltas =
+      Collections.synchronizedMap(new HashMap<String, DeltaEvent>());
+
+  @Override
+  public boolean hasDelta() {
+    return true;
+  }
+
+  @Override
+  public void toDelta(DataOutput out) throws IOException {
+    out.writeInt(maxInactiveInterval);
+    out.writeLong(lastAccessedTime);
+
+    synchronized (deltas) {
+      DataSerializer.writeInteger(deltas.size(), out);
+      for (Map.Entry<String, DeltaEvent> e : deltas.entrySet()) {
+        DataSerializer.writeString(e.getKey(), out);
+        DataSerializer.writeObject(e.getValue(), out);
+      }
+      deltas.clear();
+    }
+
+    out.writeUTF(jvmOwnerId);
+  }
+
+  @Override
+  public void fromDelta(DataInput in)
+      throws IOException, InvalidDeltaException {
+    maxInactiveInterval = in.readInt();
+    lastAccessedTime = in.readLong();
+    Map<String, DeltaEvent> localDeltas = new HashMap<String, DeltaEvent>();
+    try {
+      int size = DataSerializer.readInteger(in);
+      for (int i = 0; i < size; i++) {
+        String key = DataSerializer.readString(in);
+        DeltaEvent evt = DataSerializer.readObject(in);
+        localDeltas.put(key, evt);
+      }
+    } catch (ClassNotFoundException ex) {
+      LOG.error("Unable to de-serialize delta events", ex);
+      return;
+    }
+
+    LOG.debug("Processing {} delta events for {}",
+        localDeltas.size(), session);
+    for (DeltaEvent e : localDeltas.values()) {
+      if (e.isUpdate()) {
+        attributes.put(e.getName(), e.getValue());
+        if (session.getNativeSession() != null) {
+          session.getNativeSession().setAttribute(e.getName(), e.getValue());
+        }
+      } else {
+        attributes.remove(e.getName());
+        if (session.getNativeSession() != null) {
+          session.getNativeSession().setAttribute(e.getName(), null);
+        }
+      }
+    }
+    jvmOwnerId = in.readUTF();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractSessionAttributes.java
new file mode 100644
index 0000000..c4af041
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractSessionAttributes.java
@@ -0,0 +1,188 @@
+/*
+* 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.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.internal.util.BlobHelper;
+import com.gemstone.gemfire.modules.session.internal.filter.GemfireHttpSession;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract implementation for attributes. Should be sub-classed to provide
+ * differing implementations for synchronous or delta propagation. The backing
+ * store used is defined by the session manager.
+ */
+public abstract class AbstractSessionAttributes implements SessionAttributes {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(AbstractSessionAttributes.class.getName());
+
+  /**
+   * Internal attribute store.
+   */
+  protected Map<String, Object> attributes =
+      Collections.synchronizedMap(new HashMap<String, Object>());
+
+  /**
+   * The session to which these attributes belong
+   */
+  protected transient GemfireHttpSession session;
+
+  /**
+   * The last accessed time
+   */
+  protected long lastAccessedTime;
+
+  /**
+   * The maximum inactive interval. Default is 1800 seconds.
+   */
+  protected int maxInactiveInterval = 60 * 30;
+
+  /**
+   * The JVM Id who last committed these attributes
+   */
+  protected String jvmOwnerId;
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setSession(GemfireHttpSession session) {
+    this.session = session;
+  }
+
+  /**
+   * {@inheritDoc} The actual de-serialization of any domain objects is deferred
+   * until the point at which they are actually retrieved by the application
+   * layer.
+   */
+  @Override
+  public Object getAttribute(String name) {
+    Object value = attributes.get(name);
+
+    // If the value is a byte[] (meaning it came from the server),
+    // deserialize it and re-add it to attributes map before returning it.
+    if (value instanceof byte[]) {
+      try {
+        value = BlobHelper.deserializeBlob((byte[]) value);
+        attributes.put(name, value);
+      } catch (Exception iox) {
+        LOG.error("Attribute '" + name +
+            " contains a byte[] that cannot be deserialized due "
+            + "to the following exception", iox);
+      }
+    }
+
+    return value;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<String> getAttributeNames() {
+    return attributes.keySet();
+  }
+
+  /**
+   * {@inheritDoc} +
+   */
+  @Override
+  public void setMaxInactiveInterval(int interval) {
+    maxInactiveInterval = interval;
+  }
+
+  @Override
+  public int getMaxIntactiveInterval() {
+    return maxInactiveInterval;
+  }
+
+  @Override
+  public void setLastAccessedTime(long time) {
+    lastAccessedTime = time;
+  }
+
+  @Override
+  public long getLastAccessedTime() {
+    return lastAccessedTime;
+  }
+
+  /**
+   * {@inheritDoc} This method calls back into the session to flush the whole
+   * session including its attributes.
+   */
+  @Override
+  public void flush() {
+    session.putInRegion();
+  }
+
+  /**
+   * Use DeltaEvents to propagate the actual attribute data - DeltaEvents turn
+   * the values into byte arrays which means that the actual domain classes are
+   * not required on the server.
+   */
+  @Override
+  public void toData(DataOutput out) throws IOException {
+    out.writeInt(maxInactiveInterval);
+    out.writeLong(lastAccessedTime);
+
+    synchronized (attributes) {
+      out.writeInt(attributes.size());
+      for (Map.Entry<String, Object> entry : attributes.entrySet()) {
+        DeltaEvent delta = new DeltaEvent(true, entry.getKey(),
+            entry.getValue());
+        DataSerializer.writeObject(delta, out);
+      }
+    }
+
+    out.writeUTF(jvmOwnerId);
+  }
+
+  @Override
+  public void fromData(
+      DataInput in) throws IOException, ClassNotFoundException {
+    maxInactiveInterval = in.readInt();
+    lastAccessedTime = in.readLong();
+    int size = in.readInt();
+    while (size-- > 0) {
+      DeltaEvent event = DataSerializer.readObject(in);
+      attributes.put(event.getName(), event.getValue());
+    }
+    jvmOwnerId = in.readUTF();
+  }
+
+  @Override
+  public void setJvmOwnerId(String jvmId) {
+    this.jvmOwnerId = jvmId;
+  }
+
+  @Override
+  public String getJvmOwnerId() {
+    return jvmOwnerId;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaEvent.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaEvent.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaEvent.java
new file mode 100644
index 0000000..4c248dd
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaEvent.java
@@ -0,0 +1,119 @@
+/*
+* 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.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.internal.util.BlobHelper;
+import com.gemstone.gemfire.modules.session.internal.filter.GemfireHttpSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * Capture the update to a particular name
+ */
+public class DeltaEvent implements DataSerializable {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(DeltaEvent.class.getName());
+  /**
+   * The event is either an update (true) or a remove (false)
+   */
+  private boolean update;
+
+  private String name;
+
+  private Object value = null;
+
+  private GemfireHttpSession session = null;
+
+  /**
+   * Constructor for de-serialization only
+   */
+  public DeltaEvent() {
+  }
+
+  /**
+   * Constructor which creates a 'deferred' event. This is used when the value
+   * should only be applied when the object is serialized.
+   *
+   * @param session   the session from which the value ultimately will be
+   *                  retrieved
+   * @param attribute the name of the attribute
+   */
+  public DeltaEvent(GemfireHttpSession session, String attribute) {
+    this.session = session;
+    this.name = attribute;
+    this.update = true;
+  }
+
+  public DeltaEvent(boolean update, String attribute, Object value) {
+    this.update = update;
+    this.name = attribute;
+    this.value = value;
+    blobifyValue();
+  }
+
+  private void blobifyValue() {
+    if (value instanceof byte[]) {
+      LOG.warn("Session attribute is already a byte[] - problems may "
+          + "occur transmitting this delta.");
+    }
+    try {
+      value = BlobHelper.serializeToBlob(value);
+    } catch (IOException iox) {
+      LOG.error("Attribute '" + name + "' value: " + value
+          + " cannot be serialized due to the following exception", iox);
+    }
+  }
+
+  public boolean isUpdate() {
+    return update;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Object getValue() {
+    return value;
+  }
+
+  @Override
+  public void toData(DataOutput out) throws IOException {
+    if (session != null) {
+      value = session.getNativeSession().getAttribute(name);
+      blobifyValue();
+    }
+    out.writeBoolean(update);
+    DataSerializer.writeString(name, out);
+    DataSerializer.writeObject(value, out);
+  }
+
+  @Override
+  public void fromData(
+      DataInput in) throws IOException, ClassNotFoundException {
+    update = in.readBoolean();
+    name = DataSerializer.readString(in);
+    value = DataSerializer.readObject(in);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaQueuedSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaQueuedSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaQueuedSessionAttributes.java
new file mode 100644
index 0000000..cb4f673
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaQueuedSessionAttributes.java
@@ -0,0 +1,94 @@
+/*
+* 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.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.Instantiator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements delayed attribute delta propagation. Updates to
+ * attributes are only propagated once the session goes out of scope - i.e. as
+ * the request is done being processed.
+ */
+public class DeltaQueuedSessionAttributes extends AbstractDeltaSessionAttributes {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(DeltaQueuedSessionAttributes.class.getName());
+
+  private Trigger trigger = Trigger.SET;
+
+  private enum Trigger {
+    SET,
+    SET_AND_GET;
+  }
+
+  /**
+   * Register ourselves for de-serialization
+   */
+  static {
+    Instantiator.register(
+        new Instantiator(DeltaQueuedSessionAttributes.class, 3479) {
+          @Override
+          public DataSerializable newInstance() {
+            return new DeltaQueuedSessionAttributes();
+          }
+        });
+  }
+
+  /**
+   * Default constructor
+   */
+  public DeltaQueuedSessionAttributes() {
+  }
+
+  public void setReplicationTrigger(String trigger) {
+    this.trigger = Trigger.valueOf(trigger.toUpperCase());
+  }
+
+  @Override
+  public Object getAttribute(String attr) {
+    if (trigger == Trigger.SET_AND_GET) {
+      deltas.put(attr, new DeltaEvent(session, attr));
+    }
+    return super.getAttribute(attr);
+  }
+
+  /**
+   * {@inheritDoc} Put an attribute, setting the dirty flag. The changes are
+   * flushed at the end of filter processing.
+   */
+  @Override
+  public Object putAttribute(String attr, Object value) {
+    Object obj = attributes.put(attr, value);
+    deltas.put(attr, new DeltaEvent(true, attr, value));
+    return obj;
+  }
+
+  /**
+   * {@inheritDoc} Remove an attribute, setting the dirty flag. The changes are
+   * flushed at the end of filter processing.
+   */
+  @Override
+  public Object removeAttribute(String attr) {
+    Object obj = attributes.remove(attr);
+    deltas.put(attr, new DeltaEvent(false, attr, null));
+    return obj;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaSessionAttributes.java
new file mode 100644
index 0000000..8cc9866
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaSessionAttributes.java
@@ -0,0 +1,75 @@
+/*
+* 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.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.Instantiator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements synchronous attribute delta propagation. Updates to
+ * attributes are immediately propagated.
+ */
+public class DeltaSessionAttributes extends AbstractDeltaSessionAttributes {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(DeltaSessionAttributes.class.getName());
+
+  /**
+   * Register ourselves for de-serialization
+   */
+  static {
+    Instantiator.register(new Instantiator(DeltaSessionAttributes.class, 347) {
+      @Override
+      public DataSerializable newInstance() {
+        return new DeltaSessionAttributes();
+      }
+    });
+  }
+
+  /**
+   * Default constructor
+   */
+  public DeltaSessionAttributes() {
+  }
+
+  /**
+   * {@inheritDoc} Put an attribute, setting the dirty flag and immediately
+   * flushing the delta queue.
+   */
+  @Override
+  public Object putAttribute(String attr, Object value) {
+    Object obj = attributes.put(attr, value);
+    deltas.put(attr, new DeltaEvent(true, attr, value));
+    flush();
+    return obj;
+  }
+
+  /**
+   * {@inheritDoc} Remove an attribute, setting the dirty flag and immediately
+   * flushing the delta queue.
+   */
+  @Override
+  public Object removeAttribute(String attr) {
+    Object obj = attributes.remove(attr);
+    deltas.put(attr, new DeltaEvent(false, attr, null));
+    flush();
+    return obj;
+  }
+}



Mime
View raw message