You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2015/12/29 22:11:01 UTC
[07/24] incubator-geode git commit: GEODE-14: Move GemFire Sessions
module and relocate all packages to 'internal'
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/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..0060a89
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ListenerEventType.java
@@ -0,0 +1,70 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+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/92ee6a79/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..a01c793
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/SessionManager.java
@@ -0,0 +1,101 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+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/92ee6a79/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..096e63b
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractDeltaSessionAttributes.java
@@ -0,0 +1,97 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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/92ee6a79/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..b5effb4
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/AbstractSessionAttributes.java
@@ -0,0 +1,179 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+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/92ee6a79/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..455ba59
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaEvent.java
@@ -0,0 +1,109 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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/92ee6a79/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..0c8bd57
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaQueuedSessionAttributes.java
@@ -0,0 +1,84 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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/92ee6a79/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..0c11c46
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/DeltaSessionAttributes.java
@@ -0,0 +1,65 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/ImmediateSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/ImmediateSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/ImmediateSessionAttributes.java
new file mode 100644
index 0000000..8bde765
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/ImmediateSessionAttributes.java
@@ -0,0 +1,58 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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 immediately transmitted attributes. All attributes are
+ * transmitted for every attribute update. This is bound to be a performance hit
+ * in some cases but ensures much higher data availability.
+ */
+public class ImmediateSessionAttributes extends AbstractSessionAttributes {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(ImmediateSessionAttributes.class.getName());
+
+ /**
+ * Register ourselves for de-serialization
+ */
+ static {
+ Instantiator.register(
+ new Instantiator(ImmediateSessionAttributes.class, 347) {
+ @Override
+ public DataSerializable newInstance() {
+ return new ImmediateSessionAttributes();
+ }
+ });
+ }
+
+ /**
+ * Default constructor
+ */
+ public ImmediateSessionAttributes() {
+ }
+
+ @Override
+ public Object putAttribute(String attr, Object value) {
+ Object obj = attributes.put(attr, value);
+ flush();
+ return obj;
+ }
+
+ @Override
+ public Object removeAttribute(String attr) {
+ Object obj = attributes.remove(attr);
+ flush();
+ return obj;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/QueuedSessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/QueuedSessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/QueuedSessionAttributes.java
new file mode 100644
index 0000000..85d19ab
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/QueuedSessionAttributes.java
@@ -0,0 +1,55 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+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 an attribute container which delays sending updates
+ * until the session goes out of scope. All attributes are transmitted during
+ * the update.
+ */
+public class QueuedSessionAttributes extends AbstractSessionAttributes {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(QueuedSessionAttributes.class.getName());
+
+ /**
+ * Register ourselves for de-serialization
+ */
+ static {
+ Instantiator.register(new Instantiator(QueuedSessionAttributes.class, 347) {
+ @Override
+ public DataSerializable newInstance() {
+ return new QueuedSessionAttributes();
+ }
+ });
+ }
+
+ /**
+ * Default constructor
+ */
+ public QueuedSessionAttributes() {
+ }
+
+ @Override
+ public Object putAttribute(String attr, Object value) {
+ Object obj = attributes.put(attr, value);
+ return obj;
+ }
+
+ @Override
+ public Object removeAttribute(String attr) {
+ Object obj = attributes.remove(attr);
+ return obj;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/SessionAttributes.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/SessionAttributes.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/SessionAttributes.java
new file mode 100644
index 0000000..cf16e14
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/attributes/SessionAttributes.java
@@ -0,0 +1,111 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter.attributes;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.modules.session.internal.filter.GemfireHttpSession;
+
+import java.util.Set;
+
+/**
+ * Interface for session attribute storage. In reality, this interface is
+ * responsible for anything, in the session which needs to be propagated for
+ * caching - as such it also includes other 'attributes' such as
+ * maxInactiveInterval and lastAccessedTime
+ */
+public interface SessionAttributes extends DataSerializable {
+
+ /**
+ * Set the session to which these attributes belong.
+ *
+ * @param session the session to set
+ */
+ public void setSession(GemfireHttpSession session);
+
+ /**
+ * Set an attribute value.
+ *
+ * @param attr the name of the attribute to set
+ * @param value the value for the attribute
+ * @return the value object
+ */
+ public Object putAttribute(String attr, Object value);
+
+ /**
+ * Retrieve an attribute's value.
+ *
+ * @param attr the name of the attribute
+ * @return the object associated with the attribute or null if none exists.
+ */
+ public Object getAttribute(String attr);
+
+ /**
+ * Remove the named attribute.
+ *
+ * @param attr the name of the attribute to remove
+ * @return the value of the attribute removed or null if the named attribute
+ * did not exist.
+ */
+ public Object removeAttribute(String attr);
+
+ /**
+ * Return a set of all attribute names.
+ *
+ * @return a set of all attribute names
+ */
+ public Set<String> getAttributeNames();
+
+ /**
+ * Set the max inactive interval for replication to other systems
+ *
+ * @param interval the time interval in seconds
+ */
+ public void setMaxInactiveInterval(int interval);
+
+ /**
+ * Retrieve the max inactive interval
+ *
+ * @return the max inactive interval in seconds
+ */
+ public int getMaxIntactiveInterval();
+
+ /**
+ * Set the last accessed time for replication to other systems
+ *
+ * @param time the last accessed time in milliseconds
+ */
+ public void setLastAccessedTime(long time);
+
+ /**
+ * Return the last accessed time in milliseconds
+ *
+ * @return the last accessed time
+ */
+ public long getLastAccessedTime();
+
+ /**
+ * Explicitly flush the attributes to backing store.
+ */
+ public void flush();
+
+ /**
+ * Return the last jvm which 'owned' these attributes
+ *
+ * @return the jvmId
+ */
+ public String getJvmOwnerId();
+
+ /**
+ * Set the jvmId. This is set every time the attributes are flushed to the
+ * cache.
+ *
+ * @param jvmId
+ */
+ public void setJvmOwnerId(String jvmId);
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/NamedThreadFactory.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/NamedThreadFactory.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/NamedThreadFactory.java
new file mode 100644
index 0000000..4771f76
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/NamedThreadFactory.java
@@ -0,0 +1,59 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter.util;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Factory to create named threads for easy identification at runtime.
+ */
+public class NamedThreadFactory implements ThreadFactory {
+
+ private static final Logger LOG = Logger.getLogger(
+ NamedThreadFactory.class.getName());
+
+ private final String id;
+
+ private final AtomicLong serial = new AtomicLong();
+
+ /**
+ * Create a new thread factory, using the specified pool ID as a basis for
+ * naming each thread.
+ *
+ * @param poolID pool name/ID
+ */
+ public NamedThreadFactory(final String poolID) {
+ id = poolID;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * This implementation sets the name of the thread, sets the thread to be a
+ * daemon thread, and adds an uncaught exception handler.
+ */
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thr = new Thread(r);
+ thr.setDaemon(true);
+ thr.setName(id + " - " + serial.incrementAndGet());
+ thr.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ LOG.log(Level.WARNING,
+ "Uncaught Exception in thread: " + t.getName(), e);
+ }
+ });
+ return thr;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/ThreadLocalSession.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/ThreadLocalSession.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/ThreadLocalSession.java
new file mode 100644
index 0000000..c0bc625
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/ThreadLocalSession.java
@@ -0,0 +1,29 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.modules.session.internal.filter.util;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ */
+public class ThreadLocalSession {
+ private static ThreadLocal<HttpSession> threadLocal =
+ new ThreadLocal<HttpSession>();
+
+ public static HttpSession get() {
+ return threadLocal.get();
+ }
+
+ public static void set(HttpSession session) {
+ threadLocal.set(session);
+ }
+
+ public static void remove() {
+ threadLocal.remove();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/TypeAwareMap.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/TypeAwareMap.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/TypeAwareMap.java
new file mode 100644
index 0000000..e65245b
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/util/TypeAwareMap.java
@@ -0,0 +1,45 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter.util;
+
+import com.gemstone.gemfire.modules.session.internal.common.CacheProperty;
+
+import java.util.HashMap;
+
+/**
+ *
+ */
+public class TypeAwareMap<K extends CacheProperty, Object> extends HashMap {
+
+ private Class<K> keyType;
+
+ public TypeAwareMap(Class<K> keyType) {
+ super();
+ this.keyType = keyType;
+ }
+
+ public Object put(K key, Object value) {
+ if (!key.getClazz().isAssignableFrom(value.getClass())) {
+ if (key.getClazz() == Boolean.class) {
+ return (Object) super.put(key, Boolean.valueOf((String) value));
+ } else if (key.getClazz() == Integer.class) {
+ return (Object) super.put(key, Integer.valueOf((String) value));
+ } else {
+ throw new IllegalArgumentException("Value is not of type " +
+ key.getClazz().getName());
+ }
+ }
+
+ return (Object) super.put(key, value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatistics.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatistics.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatistics.java
new file mode 100644
index 0000000..0119e06
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatistics.java
@@ -0,0 +1,69 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.jmx;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Class to manage session statistics
+ */
+public class SessionStatistics implements SessionStatisticsMXBean {
+
+ private AtomicInteger activeSessions = new AtomicInteger(0);
+
+ private AtomicInteger totalSessions = new AtomicInteger(0);
+
+ private AtomicLong regionUpdates = new AtomicLong(0);
+
+ @Override
+ public int getActiveSessions() {
+ return activeSessions.get();
+ }
+
+ @Override
+ public int getTotalSessions() {
+ return totalSessions.get();
+ }
+
+ @Override
+ public long getRegionUpdates() {
+ return regionUpdates.get();
+ }
+
+ public void setActiveSessions(int sessions) {
+ activeSessions.set(sessions);
+ }
+
+ public void setTotalSessions(int sessions) {
+ totalSessions.set(sessions);
+ }
+
+ public void incActiveSessions() {
+ activeSessions.incrementAndGet();
+ totalSessions.incrementAndGet();
+ }
+
+ public void decActiveSessions() {
+ activeSessions.decrementAndGet();
+ }
+
+ public void incTotalSessions() {
+ totalSessions.incrementAndGet();
+ }
+
+ public void decTotalSessions() {
+ totalSessions.decrementAndGet();
+ }
+
+ public void incRegionUpdates() {
+ regionUpdates.incrementAndGet();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatisticsMXBean.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatisticsMXBean.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatisticsMXBean.java
new file mode 100644
index 0000000..a468320
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/jmx/SessionStatisticsMXBean.java
@@ -0,0 +1,14 @@
+
+package com.gemstone.gemfire.modules.session.internal.jmx;
+
+/**
+ * MXBean interface to retrieve Session statistics
+ */
+public interface SessionStatisticsMXBean {
+
+ public int getActiveSessions();
+
+ public int getTotalSessions();
+
+ public long getRegionUpdates();
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/test/resources/log4j.properties b/extensions/gemfire-modules-session/src/test/resources/log4j.properties
new file mode 100644
index 0000000..b346714
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/test/resources/log4j.properties
@@ -0,0 +1,12 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=DEBUG, A1
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
----------------------------------------------------------------------
diff --git a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java b/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
deleted file mode 100644
index 191eb49..0000000
--- a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
+++ /dev/null
@@ -1,639 +0,0 @@
-/*=========================================================================
- * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
- * This product is protected by U.S. and international copyright
- * and intellectual property laws. Pivotal products are covered by
- * one or more patents listed at http://www.pivotal.io/patents.
- *=========================================================================
- */
-package com.gemstone.gemfire.modules.session.filter;
-
-import com.gemstone.gemfire.modules.session.filter.util.ThreadLocalSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-import javax.servlet.http.HttpSession;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.security.Principal;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Primary class which orchestrates everything. This is the class which gets
- * configured in the web.xml.
- */
-public class SessionCachingFilter implements Filter {
-
- /**
- * Logger instance
- */
- private static final Logger LOG =
- LoggerFactory.getLogger(SessionCachingFilter.class.getName());
-
- /**
- * The filter configuration object we are associated with. If this value is
- * null, this filter instance is not currently configured.
- */
- private FilterConfig filterConfig = null;
-
- /**
- * Some containers will want to instantiate multiple instances of this filter,
- * but we only need one SessionManager
- */
- private static SessionManager manager = null;
-
- /**
- * Can be overridden during testing.
- */
- private static AtomicInteger started =
- new AtomicInteger(
- Integer.getInteger("gemfire.override.session.manager.count", 1));
-
- private static int percentInactiveTimeTriggerRebuild =
- Integer.getInteger("gemfire.session.inactive.trigger.rebuild", 80);
-
- /**
- * This latch ensures that at least one thread/instance has fired up the
- * session manager before any other threads complete the init method.
- */
- private static CountDownLatch startingLatch = new CountDownLatch(1);
-
- /**
- * This request wrapper class extends the support class
- * HttpServletRequestWrapper, which implements all the methods in the
- * HttpServletRequest interface, as delegations to the wrapped request. You
- * only need to override the methods that you need to change. You can get
- * access to the wrapped request using the method getRequest()
- */
- public static class RequestWrapper extends HttpServletRequestWrapper {
-
- private static final String URL_SESSION_IDENTIFIER = ";jsessionid=";
-
- private ResponseWrapper response;
-
- private boolean sessionFromCookie = false;
-
- private boolean sessionFromURL = false;
-
- private String requestedSessionId = null;
-
- private GemfireHttpSession session = null;
-
- private SessionManager manager;
-
- private HttpServletRequest outerRequest = null;
-
- /**
- * Need to save this in case we need the original {@code RequestDispatcher}
- */
- private HttpServletRequest originalRequest;
-
- public RequestWrapper(SessionManager manager,
- HttpServletRequest request,
- ResponseWrapper response) {
-
- super(request);
- this.response = response;
- this.manager = manager;
- this.originalRequest = request;
-
- final Cookie[] cookies = request.getCookies();
- if (cookies != null) {
- for (final Cookie cookie : cookies) {
- if (cookie.getName().equalsIgnoreCase(
- manager.getSessionCookieName()) &&
- cookie.getValue().endsWith("-GF")) {
- requestedSessionId = cookie.getValue();
- sessionFromCookie = true;
-
- LOG.debug("Cookie contains sessionId: {}",
- requestedSessionId);
- }
- }
- }
-
- if (requestedSessionId == null) {
- requestedSessionId = extractSessionId();
- LOG.debug("Extracted sessionId from URL {}", requestedSessionId);
- if (requestedSessionId != null) {
- sessionFromURL = true;
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public HttpSession getSession() {
- return getSession(true);
- }
-
- /**
- * Create our own sessions. TODO: Handle invalidated sessions
- *
- * @return a HttpSession
- */
- @Override
- public HttpSession getSession(boolean create) {
- if (session != null && session.isValid()) {
- session.setIsNew(false);
- session.updateAccessTime();
- /*
- * This is a massively gross hack. Currently, there is no way
- * to actually update the last accessed time for a session, so
- * what we do here is once we're into X% of the session's TTL
- * we grab a new session from the container.
- *
- * (inactive * 1000) * (pct / 100) ==> (inactive * 10 * pct)
- */
- if (session.getLastAccessedTime() - session.getCreationTime() >
- (session.getMaxInactiveInterval() * 10 * percentInactiveTimeTriggerRebuild)) {
- HttpSession nativeSession = super.getSession();
- session.failoverSession(nativeSession);
- }
- return session;
- }
-
- if (requestedSessionId != null) {
- session = (GemfireHttpSession) manager.getSession(
- requestedSessionId);
- if (session != null) {
- session.setIsNew(false);
- // This means we've failed over to another node
- if (session.getNativeSession() == null) {
- try {
- ThreadLocalSession.set(session);
- HttpSession nativeSession = super.getSession();
- session.failoverSession(nativeSession);
- session.putInRegion();
- } finally {
- ThreadLocalSession.remove();
- }
- }
- }
- }
-
- if (session == null || !session.isValid()) {
- if (create) {
- try {
- session = (GemfireHttpSession) manager.wrapSession(null);
- ThreadLocalSession.set(session);
- HttpSession nativeSession = super.getSession();
- if (session.getNativeSession() == null) {
- session.setNativeSession(nativeSession);
- } else {
- assert (session.getNativeSession() == nativeSession);
- }
- session.setIsNew(true);
- manager.putSession(session);
- } finally {
- ThreadLocalSession.remove();
- }
- } else {
- // create is false, and session is either null or not valid.
- // The spec says return a null:
- return null;
- }
- }
-
- if (session != null) {
- addSessionCookie(response);
- session.updateAccessTime();
- }
-
- return session;
- }
-
- private void addSessionCookie(HttpServletResponse response) {
- // Don't bother if the response is already committed
- if (response.isCommitted()) {
- return;
- }
-
- // Get the existing cookies
- Cookie[] cookies = getCookies();
-
- Cookie cookie = new Cookie(manager.getSessionCookieName(),
- session.getId());
- cookie.setPath("".equals(getContextPath()) ? "/" : getContextPath());
- // Clear out all old cookies and just set ours
- response.addCookie(cookie);
-
- // Replace all other cookies which aren't JSESSIONIDs
- if (cookies != null) {
- for (Cookie c : cookies) {
- if (manager.getSessionCookieName().equals(c.getName())) {
- continue;
- }
- response.addCookie(c);
- }
- }
-
- }
-
- private String getCookieString(Cookie c) {
- StringBuilder cookie = new StringBuilder();
- cookie.append(c.getName()).append("=").append(c.getValue());
-
- if (c.getPath() != null) {
- cookie.append("; ").append("Path=").append(c.getPath());
- }
- if (c.getDomain() != null) {
- cookie.append("; ").append("Domain=").append(c.getDomain());
- }
- if (c.getSecure()) {
- cookie.append("; ").append("Secure");
- }
-
- cookie.append("; HttpOnly");
-
- return cookie.toString();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isRequestedSessionIdFromCookie() {
- return sessionFromCookie;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isRequestedSessionIdFromURL() {
- return sessionFromURL;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getRequestedSessionId() {
- if (requestedSessionId != null) {
- return requestedSessionId;
- } else {
- return super.getRequestedSessionId();
- }
- }
-
- /*
- * Hmmm... not sure if this is right or even good to do. So, in some
- * cases - for ex. using a Spring security filter, we have 3 possible
- * wrappers to deal with - the original, this one and one created by
- * Spring. When a servlet or JSP is forwarded to the original request
- * is passed in, but then this (the wrapped) request is used by the JSP.
- * In some cases, the outer wrapper also contains information relevant
- * to the request - in this case security info. So here we allow access
- * to that. There's probably a better way....
- */
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Principal getUserPrincipal() {
- if (outerRequest != null) {
- return outerRequest.getUserPrincipal();
- } else {
- return super.getUserPrincipal();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getRemoteUser() {
- if (outerRequest != null) {
- return outerRequest.getRemoteUser();
- } else {
- return super.getRemoteUser();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isUserInRole(String role) {
- if (outerRequest != null) {
- return outerRequest.isUserInRole(role);
- } else {
- return super.isUserInRole(role);
- }
- }
-
- //////////////////////////////////////////////////////////////
- // Non-API methods
-
- void setOuterWrapper(HttpServletRequest outer) {
- this.outerRequest = outer;
- }
-
- //////////////////////////////////////////////////////////////
- // Private methods
- private String extractSessionId() {
- final int prefix = getRequestURL().indexOf(URL_SESSION_IDENTIFIER);
- if (prefix != -1) {
- final int start = prefix + URL_SESSION_IDENTIFIER.length();
- int suffix = getRequestURL().indexOf("?", start);
- if (suffix < 0) {
- suffix = getRequestURL().indexOf("#", start);
- }
- if (suffix <= prefix) {
- return getRequestURL().substring(start);
- }
- return getRequestURL().substring(start, suffix);
- }
- return null;
- }
- }
-
- /**
- * This response wrapper class extends the support class
- * HttpServletResponseWrapper, which implements all the methods in the
- * HttpServletResponse interface, as delegations to the wrapped response. You
- * only need to override the methods that you need to change. You can get
- * access to the wrapped response using the method getResponse()
- */
- class ResponseWrapper extends HttpServletResponseWrapper {
-
- HttpServletResponse originalResponse;
-
- public ResponseWrapper(HttpServletResponse response) throws IOException {
- super(response);
- originalResponse = response;
- }
-
- public HttpServletResponse getOriginalResponse() {
- return originalResponse;
- }
-
- @Override
- public void setHeader(String name, String value) {
- super.setHeader(name, value);
- }
-
- @Override
- public void setIntHeader(String name, int value) {
- super.setIntHeader(name, value);
- }
- }
-
-
- public SessionCachingFilter() {
- }
-
- /**
- * @param request The servlet request we are processing
- * @param response The servlet response we are creating
- * @param chain The filter chain we are processing
- * @throws IOException if an input/output error occurs
- * @throws ServletException if a servlet error occurs
- */
- @Override
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException {
-
- HttpServletRequest httpReq = (HttpServletRequest) request;
- HttpServletResponse httpResp = (HttpServletResponse) response;
-
- /**
- * Early out if this isn't the right kind of request. We might see a
- * RequestWrapper instance during a forward or include request.
- */
- if (request instanceof RequestWrapper ||
- !(request instanceof HttpServletRequest)) {
- LOG.debug("Handling already-wrapped request");
- chain.doFilter(request, response);
- return;
- }
-
- // Create wrappers for the request and response objects.
- // Using these, you can extend the capabilities of the
- // request and response, for example, allow setting parameters
- // on the request before sending the request to the rest of the filter chain,
- // or keep track of the cookies that are set on the response.
- //
- // Caveat: some servers do not handle wrappers very well for forward or
- // include requests.
-
- ResponseWrapper wrappedResponse = new ResponseWrapper(httpResp);
- final RequestWrapper wrappedRequest =
- new RequestWrapper(manager, httpReq, wrappedResponse);
-
- Throwable problem = null;
-
- try {
- chain.doFilter(wrappedRequest, wrappedResponse);
- } catch (Throwable t) {
- // If an exception is thrown somewhere down the filter chain,
- // we still want to execute our after processing, and then
- // rethrow the problem after that.
- problem = t;
- LOG.error("Exception processing filter chain", t);
- }
-
- GemfireHttpSession session =
- (GemfireHttpSession) wrappedRequest.getSession(false);
-
- // If there was a problem, we want to rethrow it if it is
- // a known type, otherwise log it.
- if (problem != null) {
- if (problem instanceof ServletException) {
- throw (ServletException) problem;
- }
- if (problem instanceof IOException) {
- throw (IOException) problem;
- }
- sendProcessingError(problem, response);
- }
-
- /**
- * Commit any updates. What actually happens at that point is
- * dependent on the type of attributes defined for use by the sessions.
- */
- if (session != null) {
- session.commit();
- }
- }
-
- /**
- * Return the filter configuration object for this filter.
- */
- public FilterConfig getFilterConfig() {
- return (this.filterConfig);
- }
-
- /**
- * Set the filter configuration object for this filter.
- *
- * @param filterConfig The filter configuration object
- */
- public void setFilterConfig(FilterConfig filterConfig) {
- this.filterConfig = filterConfig;
- }
-
- /**
- * Destroy method for this filter
- */
- @Override
- public void destroy() {
- if (manager != null) {
- manager.stop();
- }
- }
-
- /**
- * This is where all the initialization happens.
- *
- * @param config
- * @throws ServletException
- */
- @Override
- public void init(final FilterConfig config) {
- LOG.info("Starting Session Filter initialization");
- this.filterConfig = config;
-
- if (started.getAndDecrement() > 0) {
- /**
- * Allow override for testing purposes
- */
- String managerClassStr =
- config.getInitParameter("session-manager-class");
-
- // Otherwise default
- if (managerClassStr == null) {
- managerClassStr = GemfireSessionManager.class.getName();
- }
-
- try {
- manager = (SessionManager) Class.forName(
- managerClassStr).newInstance();
- manager.start(config, this.getClass().getClassLoader());
- } catch (Exception ex) {
- LOG.error("Exception creating Session Manager", ex);
- }
-
- startingLatch.countDown();
- } else {
- try {
- startingLatch.await();
- } catch (InterruptedException iex) {
- }
-
- LOG.debug("SessionManager and listener initialization skipped - "
- + "already done.");
- }
-
- LOG.info("Session Filter initialization complete");
- LOG.debug("Filter class loader {}", this.getClass().getClassLoader());
- }
-
- /**
- * Return a String representation of this object.
- */
- @Override
- public String toString() {
- if (filterConfig == null) {
- return ("SessionCachingFilter()");
- }
- StringBuilder sb = new StringBuilder("SessionCachingFilter(");
- sb.append(filterConfig);
- sb.append(")");
- return (sb.toString());
-
- }
-
-
- private void sendProcessingError(Throwable t, ServletResponse response) {
- String stackTrace = getStackTrace(t);
-
- if (stackTrace != null && !stackTrace.equals("")) {
- try {
- response.setContentType("text/html");
- PrintStream ps = new PrintStream(response.getOutputStream());
- PrintWriter pw = new PrintWriter(ps);
- pw.print(
- "<html>\n<head>\n<title>Error</title>\n</head>\n<body>\n"); //NOI18N
-
- // PENDING! Localize this for next official release
- pw.print("<h1>The resource did not process correctly</h1>\n<pre>\n");
- pw.print(stackTrace);
- pw.print("</pre></body>\n</html>"); //NOI18N
- pw.close();
- ps.close();
- response.getOutputStream().close();
- } catch (Exception ex) {
- }
- } else {
- try {
- PrintStream ps = new PrintStream(response.getOutputStream());
- t.printStackTrace(ps);
- ps.close();
- response.getOutputStream().close();
- } catch (Exception ex) {
- }
- }
- }
-
- public static String getStackTrace(Throwable t) {
- String stackTrace = null;
- try {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- t.printStackTrace(pw);
- pw.close();
- sw.close();
- stackTrace = sw.getBuffer().toString();
- } catch (Exception ex) {
- }
- return stackTrace;
- }
-
- /**
- * Retrieve the SessionManager. This is only here so that tests can get access
- * to the cache.
- */
- static SessionManager getSessionManager() {
- return manager;
- }
-
- /**
- * Return the GemFire session which wraps a native session
- *
- * @param nativeSession the native session for which the corresponding GemFire
- * session should be returned.
- * @return the GemFire session or null if no session maps to the native
- * session
- */
- public static HttpSession getWrappingSession(HttpSession nativeSession) {
- /*
- * This is a special case where the GemFire session has been set as a
- * ThreadLocal during session creation.
- */
- GemfireHttpSession gemfireSession = (GemfireHttpSession) ThreadLocalSession.get();
- if (gemfireSession != null) {
- gemfireSession.setNativeSession(nativeSession);
- return gemfireSession;
- }
- return getSessionManager().getWrappingSession(nativeSession.getId());
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
----------------------------------------------------------------------
diff --git a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java b/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
deleted file mode 100644
index 9726be0..0000000
--- a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*=========================================================================
- * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
- * This product is protected by U.S. and international copyright
- * and intellectual property laws. Pivotal products are covered by
- * one or more patents listed at http://www.pivotal.io/patents.
- *=========================================================================
- */
-package com.gemstone.gemfire.modules.session.filter;
-
-import com.gemstone.gemfire.distributed.DistributedSystemDisconnectedException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionListener;
-
-public class SessionListener implements HttpSessionListener {
-
- private static final Logger LOG =
- LoggerFactory.getLogger(SessionListener.class.getName());
-
- public void sessionCreated(HttpSessionEvent httpSessionEvent) {
- }
-
- /**
- * This will receive events from the container using the native sessions.
- */
- public void sessionDestroyed(HttpSessionEvent event) {
- String nativeId = event.getSession().getId();
- try {
- String sessionId = SessionCachingFilter.getSessionManager().destroyNativeSession(
- nativeId);
- LOG.debug(
- "Received sessionDestroyed event for native session {} (wrapped by {})",
- nativeId, sessionId);
- } catch (DistributedSystemDisconnectedException dex) {
- LOG.debug("Cache disconnected - unable to destroy native session {0}",
- nativeId);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
----------------------------------------------------------------------
diff --git a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java b/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
index ee773d2..57bdde6 100644
--- a/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
+++ b/modules/gemfire-modules-session-external/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
@@ -36,10 +36,10 @@ import java.io.OutputStream;
public class Installer {
private static final String GEMFIRE_FILTER_CLASS =
- "com.gemstone.gemfire.modules.session.filter.SessionCachingFilter";
+ "com.gemstone.gemfire.modules.session.filter.internal.SessionCachingFilter";
private static final String GEMFIRE_LISTENER_CLASS =
- "com.gemstone.gemfire.modules.session.filter.SessionListener";
+ "com.gemstone.gemfire.modules.session.filter.internal.SessionListener";
private ArgumentValues argValues;