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 2016/02/08 17:51:56 UTC

[08/32] incubator-geode git commit: GEODE-14: Integration of GemFire Session Replication and Hibernate modules

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
new file mode 100644
index 0000000..7490fdd
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionCachingFilter.java
@@ -0,0 +1,652 @@
+/*
+* 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.filter;
+
+import com.gemstone.gemfire.modules.session.internal.filter.GemfireHttpSession;
+import com.gemstone.gemfire.modules.session.internal.filter.GemfireSessionManager;
+import com.gemstone.gemfire.modules.session.internal.filter.SessionManager;
+import com.gemstone.gemfire.modules.session.internal.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.
+   */
+  public 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/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
new file mode 100644
index 0000000..7973bc5
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/filter/SessionListener.java
@@ -0,0 +1,51 @@
+/*
+* 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.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/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
new file mode 100644
index 0000000..7ba5b34
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/Installer.java
@@ -0,0 +1,296 @@
+/*
+* 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.installer;
+
+import com.gemstone.gemfire.modules.session.installer.args.Argument;
+import com.gemstone.gemfire.modules.session.installer.args.ArgumentProcessor;
+import com.gemstone.gemfire.modules.session.installer.args.ArgumentValues;
+import com.gemstone.gemfire.modules.session.installer.args.UnknownArgumentHandler;
+import com.gemstone.gemfire.modules.session.installer.args.UsageException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ *
+ */
+public class Installer {
+
+  private static final String GEMFIRE_FILTER_CLASS =
+      "com.gemstone.gemfire.modules.session.filter.SessionCachingFilter";
+
+  private static final String GEMFIRE_LISTENER_CLASS =
+      "com.gemstone.gemfire.modules.session.filter.SessionListener";
+
+  private ArgumentValues argValues;
+
+  private static final Argument ARG_HELP =
+      new Argument("-h", false).
+          setDescription("Displays this help message.");
+
+  private static Argument ARG_GEMFIRE_PARAMETERS =
+      new Argument("-p", false, "param=value").
+          setDescription("Specific parameter for inclusion into the "
+              + "session filter definition as a regular "
+              + "init-param. Can be given multiple times.");
+
+  private static Argument ARG_CACHE_TYPE =
+      new Argument("-t", false, "cache-type").
+          setDescription(
+              "Type of cache. Must be one of 'peer-to-peer' or "
+                  + "'client-server'. Default is peer-to-peer.").
+          setDefaults("peer-to-peer");
+
+  private static Argument ARG_WEB_XML_FILE =
+      new Argument("-w", true, "web.xml file").
+          setDescription("The web.xml file to be modified.");
+
+
+  /**
+   * Class main method
+   *
+   * @param args Arguments passed in via the command line
+   * @throws Exception in the event of any errors
+   */
+  public static void main(final String[] args) throws Exception {
+    new Installer(args).process();
+  }
+
+  public static void log(String message) {
+    System.err.println(message);
+  }
+
+
+  public Installer(String[] args) throws Exception {
+    final ArgumentProcessor processor = new ArgumentProcessor("Installer");
+
+    argValues = null;
+    try {
+      // These are ordered so as to keep the options alphabetical
+      processor.addArgument(ARG_HELP);
+      processor.addArgument(ARG_GEMFIRE_PARAMETERS);
+      processor.addArgument(ARG_CACHE_TYPE);
+      processor.addArgument(ARG_WEB_XML_FILE);
+
+      processor.setUnknownArgumentHandler(new UnknownArgumentHandler() {
+        @Override
+        public void handleUnknownArgument(
+            final String form, final String[] params) {
+          log("Unknown argument being ignored: "
+              + form + " (" + params.length + " params)");
+          log("Use '-h' argument to display usage");
+        }
+      });
+      argValues = processor.process(args);
+
+      if (argValues.isDefined(ARG_HELP)) {
+        final UsageException usageException =
+            new UsageException("Usage requested by user");
+        usageException.setUsage(processor.getUsage());
+        throw (usageException);
+      }
+
+    } catch (UsageException ux) {
+      final StringBuilder error = new StringBuilder();
+      error.append("\nERROR: ");
+      error.append(ux.getMessage());
+      error.append("\n");
+      if (ux.getUsage() != null) {
+        error.append(ux.getUsage());
+      }
+      log(error.toString());
+      System.exit(2);
+    }
+
+  }
+
+
+  /**
+   * The main entry point for processing
+   *
+   * @throws Exception if any errors occur.
+   */
+  public void process() throws Exception {
+    String argInputFile = argValues.getFirstResult(ARG_WEB_XML_FILE);
+
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    InputStream input = new FileInputStream(argInputFile);
+
+    processWebXml(input, output);
+    input.close();
+
+    System.out.println(output.toString());
+  }
+
+
+  private void processWebXml(final InputStream webXml,
+      final OutputStream out) throws Exception {
+
+    Document doc = createWebXmlDoc(webXml);
+    mangleWebXml(doc);
+
+    streamXML(doc, out);
+  }
+
+
+  private Document createWebXmlDoc(final InputStream webXml)
+      throws Exception {
+    Document doc;
+    final DocumentBuilderFactory factory =
+        DocumentBuilderFactory.newInstance();
+    final DocumentBuilder builder = factory.newDocumentBuilder();
+    doc = builder.parse(webXml);
+
+    return doc;
+  }
+
+
+  private Document mangleWebXml(final Document doc) {
+    final Element docElement = doc.getDocumentElement();
+    final NodeList nodelist = docElement.getChildNodes();
+    Node firstFilter = null;
+    Node displayElement = null;
+    Node afterDisplayElement = null;
+
+    for (int i = 0; i < nodelist.getLength(); i++) {
+      final Node node = nodelist.item(i);
+      final String name = node.getNodeName();
+      if ("display-name".equals(name)) {
+        displayElement = node;
+      } else {
+        if ("filter".equals(name)) {
+          if (firstFilter == null) {
+            firstFilter = node;
+          }
+        }
+        if (displayElement != null && afterDisplayElement == null) {
+          afterDisplayElement = node;
+        }
+      }
+    }
+
+    Node initParam;
+    final Element filter = doc.createElement("filter");
+    append(doc, filter, "filter-name", "gemfire-session-filter");
+    append(doc, filter, "filter-class", GEMFIRE_FILTER_CLASS);
+
+    // Set the type of cache
+    initParam = append(doc, filter, "init-param", null);
+    append(doc, initParam, "param-name", "cache-type");
+    append(doc, initParam, "param-value",
+        argValues.getFirstResult(ARG_CACHE_TYPE));
+
+
+    if (argValues.isDefined(ARG_GEMFIRE_PARAMETERS)) {
+      for (String[] val : argValues.getAllResults(ARG_GEMFIRE_PARAMETERS)) {
+        String gfParam = val[0];
+        int idx = gfParam.indexOf("=");
+        initParam = append(doc, filter, "init-param", null);
+        append(doc, initParam, "param-name", gfParam.substring(0, idx));
+        append(doc, initParam, "param-value", gfParam.substring(idx + 1));
+      }
+    }
+
+    Node first = firstFilter;
+    if (first == null) {
+      if (afterDisplayElement != null) {
+        first = afterDisplayElement;
+      }
+    }
+    if (first == null) {
+      first = docElement.getFirstChild();
+    }
+    docElement.insertBefore(filter, first);
+    final Element filterMapping = doc.createElement("filter-mapping");
+    append(doc, filterMapping, "filter-name", "gemfire-session-filter");
+    append(doc, filterMapping, "url-pattern", "/*");
+    append(doc, filterMapping, "dispatcher", "FORWARD");
+    append(doc, filterMapping, "dispatcher", "INCLUDE");
+    append(doc, filterMapping, "dispatcher", "REQUEST");
+    append(doc, filterMapping, "dispatcher", "ERROR");
+    final Element contextListener = doc.createElement("listener");
+    append(doc, contextListener, "listener-class", GEMFIRE_LISTENER_CLASS);
+    docElement.insertBefore(filterMapping, after(docElement, "filter"));
+    docElement.insertBefore(contextListener,
+        after(docElement, "filter-mapping"));
+    return doc;
+  }
+
+  private Node after(final Node parent, final String nodeName) {
+    final NodeList nodelist = parent.getChildNodes();
+    int index = -1;
+    for (int i = 0; i < nodelist.getLength(); i++) {
+      final Node node = nodelist.item(i);
+      final String name = node.getNodeName();
+      if (nodeName.equals(name)) {
+        index = i;
+      }
+    }
+    if (index == -1)
+      return null;
+    if (nodelist.getLength() > (index + 1)) {
+      return nodelist.item(index + 1);
+    }
+    return null;
+  }
+
+  private Node append(final Document doc, final Node parent,
+      final String element,
+      final String value) {
+    final Element child = doc.createElement(element);
+    if (value != null)
+      child.setTextContent(value);
+    parent.appendChild(child);
+    return child;
+  }
+
+  private void streamXML(final Document doc, final OutputStream out) {
+    try {// Use a Transformer for output
+      final TransformerFactory tFactory = TransformerFactory.newInstance();
+      final Transformer transformer = tFactory.newTransformer();
+      if (doc.getDoctype() != null) {
+        final String systemId = doc.getDoctype().getSystemId();
+        final String publicId = doc.getDoctype().getPublicId();
+        transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicId);
+        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemId);
+      }
+      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+      transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
+          "4");
+      final DOMSource source = new DOMSource(doc);
+      final StreamResult result = new StreamResult(out);
+      transformer.transform(source, result);
+    } catch (final Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/JarClassLoader.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/JarClassLoader.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/JarClassLoader.java
new file mode 100644
index 0000000..ba528ce
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/JarClassLoader.java
@@ -0,0 +1,123 @@
+/*
+* 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.installer;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Classloader, which allows finding classes in jars  within jars. This is used to check
+ * whether a listener, as found in web.xml, is a ServletContextListener
+ */
+public class JarClassLoader extends URLClassLoader {
+
+  public JarClassLoader(URL[] urls, ClassLoader parent) {
+    super(urls, parent);
+
+    try {
+      for (URL url : urls) {
+        if (isJar(url.getFile())) {
+          addJarResource(new File(url.getPath()));
+        }
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private void addJarResource(File file) throws IOException {
+    JarFile jarFile = new JarFile(file);
+    addURL(file.toURL());
+    Enumeration<JarEntry> jarEntries = jarFile.entries();
+    while (jarEntries.hasMoreElements()) {
+      JarEntry jarEntry = jarEntries.nextElement();
+      if (!jarEntry.isDirectory() && isJar(jarEntry.getName())) {
+        addJarResource(jarEntryAsFile(jarFile, jarEntry));
+      }
+    }
+  }
+
+  @Override
+  protected synchronized Class<?> loadClass(String name, boolean resolve)
+      throws ClassNotFoundException {
+    try {
+      Class<?> clazz = findLoadedClass(name);
+      if (clazz == null) {
+        clazz = findClass(name);
+        if (resolve) {
+          resolveClass(clazz);
+        }
+      }
+      return clazz;
+    } catch (ClassNotFoundException e) {
+      return super.loadClass(name, resolve);
+    }
+  }
+
+  private static void close(Closeable closeable) {
+    if (closeable != null) {
+      try {
+        closeable.close();
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private static boolean isJar(String fileName) {
+    return fileName != null && (fileName.toLowerCase().endsWith(".jar") ||
+        fileName.toLowerCase().endsWith(".war") ||
+        fileName.toLowerCase().endsWith(".ear"));
+  }
+
+  private static File jarEntryAsFile(JarFile jarFile,
+      JarEntry jarEntry) throws IOException {
+    InputStream input = null;
+    OutputStream output = null;
+    try {
+      String name = jarEntry.getName().replace('/', '_');
+      int i = name.lastIndexOf(".");
+      String extension = i > -1 ? name.substring(i) : "";
+      File file = File.createTempFile(
+          name.substring(0, name.length() - extension.length()) + ".",
+          extension);
+      file.deleteOnExit();
+      input = jarFile.getInputStream(jarEntry);
+      output = new FileOutputStream(file);
+      int readCount;
+      byte[] buffer = new byte[4096];
+      while ((readCount = input.read(buffer)) != -1) {
+        output.write(buffer, 0, readCount);
+      }
+      return file;
+    } finally {
+      close(input);
+      close(output);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/Argument.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/Argument.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/Argument.java
new file mode 100644
index 0000000..1125c1b
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/Argument.java
@@ -0,0 +1,275 @@
+/*
+* 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.installer.args;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing a single command line argument.
+ */
+public class Argument {
+
+  /**
+   * Parameter names.
+   */
+  private final String[] paramNames;
+
+  /**
+   * Default values for the parameters when not explicitly set.
+   */
+  private String[] defaults;
+
+  /**
+   * Environment variable names forfor each parameter where values will be
+   * pulled in, if not explicitly provided and if the environment variable
+   * exists.
+   */
+  private String[] envVars;
+
+  /**
+   * Flag indicating whether this argument is required on the command line.
+   */
+  private final boolean required;
+
+  /**
+   * Handler used to hook into processing.
+   */
+  private ArgumentHandler handler;
+
+  /**
+   * List of all representation forms.
+   */
+  private final List<String> forms = new ArrayList<String>();
+
+  /**
+   * Usage description.
+   */
+  private String description;
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Constructor:
+
+  /**
+   * Contructor to create an argument definition.
+   *
+   * @param primaryForm    the form of the argument (e.g., --foo).  Should start
+   *                       with a dash.
+   * @param argRequired    flag indicating whether or not the argument is
+   *                       required to be onthe command line
+   * @param parameterNames names of the parameters to this argument for use in
+   *                       the usage generation
+   */
+  public Argument(
+      final String primaryForm,
+      final boolean argRequired,
+      final String... parameterNames) {
+    forms.add(primaryForm);
+    paramNames = parameterNames;
+    required = argRequired;
+  }
+
+  /**
+   * Returns the number of parameters that this argument takes.
+   *
+   * @return parameter count
+   */
+  public int getParameterCount() {
+    return paramNames.length;
+  }
+
+  /**
+   * Returns the name of the parameter position requested.
+   *
+   * @param idx parameter index
+   * @return parameter name
+   */
+  public String getParameterName(final int idx) {
+    return paramNames[idx];
+  }
+
+  /**
+   * Returns whether or not this argument is required to be defined.
+   *
+   * @return true if required, false if optional
+   */
+  public boolean isRequired() {
+    return required;
+  }
+
+  /**
+   * Determines if the argument provisioning has been done via the environment.
+   */
+  public boolean isDefinedInEnv() {
+    if (envVars == null || paramNames.length == 0) {
+      return false;
+    }
+    for (String var : envVars) {
+      if (System.getenv(var) == null) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Sets the argument handler.
+   *
+   * @param aHandler argument handler
+   * @return this argument (for chained calls)
+   */
+  public Argument setArgumentHandler(final ArgumentHandler aHandler) {
+    handler = aHandler;
+    return this;
+  }
+
+  /**
+   * Returns the argument handler.
+   *
+   * @return argument handler
+   */
+  public ArgumentHandler getArgumentHandler() {
+    return handler;
+  }
+
+  /**
+   * Adds a possible representation of the command line argument.
+   *
+   * @param aliasName additional form to accept
+   * @return this argument (for chained calls)
+   */
+  public Argument addForm(final String aliasName) {
+    forms.add(aliasName);
+    return this;
+  }
+
+  /**
+   * Returns the primary form of the argument.
+   *
+   * @return primary form
+   */
+  public String getPrimaryForm() {
+    if (forms.isEmpty()) {
+      return null;
+    } else {
+      return forms.get(0);
+    }
+  }
+
+  /**
+   * Returns a list of all valid representations of this command line argument.
+   *
+   * @return list of all registered forms
+   */
+  public List<String> getForms() {
+    return forms;
+  }
+
+  /**
+   * Sets a usage description for this argument.
+   *
+   * @param str usage description
+   * @return this argument (for chained calls)
+   */
+  public Argument setDescription(final String str) {
+    description = str;
+    return this;
+  }
+
+  /**
+   * Returns a usage description of this argument.
+   *
+   * @return description
+   */
+  public String getDescription() {
+    return description;
+  }
+
+  /**
+   * Sets the default values when no explicit values were provided.
+   *
+   * @param newDefaults default values for all argument parameters
+   * @return this argument (for chained calls)
+   */
+  public Argument setDefaults(final String... newDefaults) {
+    if (newDefaults.length != paramNames.length) {
+      throw (new IllegalArgumentException(
+          "Defaults array length provided is not the correct size"));
+    }
+    defaults = newDefaults;
+    return this;
+  }
+
+  /**
+   * Returns the defaults.
+   *
+   * @return default parameter values
+   */
+  public String[] getDefaults() {
+    return defaults;
+  }
+
+  /**
+   * Sets the environment variables which will be checked for values before
+   * falling back on the default values.
+   *
+   * @param newEnvVars environment variable name array
+   * @return this argument (for chained calls)
+   */
+  public Argument setEnvVars(final String... newEnvVars) {
+    if (newEnvVars.length != paramNames.length) {
+      throw (new IllegalArgumentException(
+          "Environment variables array length provided is not "
+              + "the correct size"));
+    }
+    envVars = newEnvVars;
+    return this;
+  }
+
+  /**
+   * Returns the environment variable names for each parameter.
+   *
+   * @return environment variable names
+   */
+  public String[] getEnvVars() {
+    return envVars;
+  }
+
+  /**
+   * Returns a human readable form.
+   *
+   * @return human readable string
+   */
+  @Override
+  public String toString() {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("[Argument '");
+    builder.append(forms.get(0));
+    builder.append("'");
+    if (paramNames.length > 0) {
+      for (int i = 0; i < paramNames.length; i++) {
+        builder.append(" <");
+        builder.append(paramNames[i]);
+        builder.append(">");
+      }
+    }
+    builder.append("]");
+    return builder.toString();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentHandler.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentHandler.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentHandler.java
new file mode 100644
index 0000000..97c8108
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentHandler.java
@@ -0,0 +1,38 @@
+/*
+* 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.installer.args;
+
+/**
+ * Interface specifying the requirements for objects wiching to be able to
+ * examine arguments (potentially tweaking parameters) at the time of parsing,
+ * thereby allowing for usage display to occur automatically.
+ */
+public interface ArgumentHandler {
+
+  /**
+   * Process the argument values specified.
+   *
+   * @param arg    argument definition
+   * @param form   form which was used on the command line
+   * @param params parameters supplied to the argument
+   * @throws UsageException when usage was suboptimal
+   */
+  void handleArgument(Argument arg, String form, String[] params)
+      throws UsageException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentProcessor.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentProcessor.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentProcessor.java
new file mode 100644
index 0000000..04ecfab
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentProcessor.java
@@ -0,0 +1,397 @@
+/*
+* 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.installer.args;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * This class is used to process command line arguments for Java programs in a
+ * flexible and powerful manner.
+ */
+public class ArgumentProcessor {
+  /**
+   * Logger.
+   */
+  private static final Logger LOG =
+      Logger.getLogger(ArgumentProcessor.class.getName());
+
+  /**
+   * Description line length.
+   */
+  private static final int LINE_LENGTH = 60;
+
+  /**
+   * Map containing all arguments defined, indexed by their unique IDs.
+   */
+  private final List<Argument> args = new ArrayList<Argument>();
+
+  /**
+   * Unknown argument handler.
+   */
+  private UnknownArgumentHandler handler;
+
+  /**
+   * Program name to display in usage.
+   */
+  private String programName;
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Classes:
+
+  /**
+   * Structure used to represent an argument match.
+   */
+  private static class Match {
+    /**
+     * The argument which matched.
+     */
+    private final Argument arg;
+
+    /**
+     * The specific form which matched.
+     */
+    private final String form;
+
+    /**
+     * The parameters to the argument form.
+     */
+    private final String[] params;
+
+    /**
+     * Constructor.
+     *
+     * @param theArgument the argument which matched
+     * @param theForm     the form used
+     * @param theParams   the parameters supplied
+     */
+    public Match(
+        final Argument theArgument,
+        final String theForm, final String[] theParams) {
+      arg = theArgument;
+      form = theForm;
+      params = theParams;
+    }
+
+    /**
+     * Accessor.
+     *
+     * @return argument which matched
+     */
+    public Argument getArgument() {
+      return arg;
+    }
+
+    /**
+     * Accessor.
+     *
+     * @return form which was used
+     */
+    public String getForm() {
+      return form;
+    }
+
+    /**
+     * Accessor.
+     *
+     * @return parameters supplied
+     */
+    public String[] getParams() {
+      return params;
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Constructors:
+
+  /**
+   * Creates a new Argument processor instance for te program name given.
+   *
+   * @param progName program name used in usage
+   */
+  public ArgumentProcessor(final String progName) {
+    programName = progName;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Public methods:
+
+  /**
+   * Adds a new argument.
+   *
+   * @param arg argument to add
+   */
+  public void addArgument(final Argument arg) {
+    args.add(arg);
+  }
+
+  /**
+   * Sets the handler to call when an unknown argument is encountered.
+   *
+   * @param aHandler unknown arg handler, or null to unset
+   */
+  public void setUnknownArgumentHandler(
+      final UnknownArgumentHandler aHandler) {
+    handler = aHandler;
+  }
+
+  /**
+   * Process the command line arguments provided.
+   *
+   * @param programArgs command line arguments supplied to program
+   * @return argument values parsed out of command line
+   * @throws UsageException when usge sucked
+   */
+  public ArgumentValues process(final String[] programArgs)
+      throws UsageException {
+    ArgumentHandler argHandler;
+    final ArgumentValues result = new ArgumentValues();
+    List<Argument> unmatched;
+    List<Match> matches;
+
+    // Find all argument matches and set postArgs
+    matches = checkMatches(programArgs, result);
+
+    // Find arguments which didnt match
+    unmatched = new ArrayList<Argument>();
+    unmatched.addAll(args);
+    for (Match match : matches) {
+      unmatched.remove(match.getArgument());
+    }
+
+    // Error on unmatched yet required args
+    for (Argument arg : unmatched) {
+      if (arg.isRequired() && !arg.isDefinedInEnv()) {
+        final UsageException usageException = new UsageException(
+            "Required argument not provided: " + arg);
+        usageException.setUsage(getUsage());
+        throw usageException;
+      }
+    }
+
+    // Handle the arguments
+    for (Match match : matches) {
+      final Argument arg = match.getArgument();
+      argHandler = arg.getArgumentHandler();
+      if (argHandler != null) {
+        argHandler.handleArgument(
+            arg, match.getForm(), match.getParams());
+      }
+      result.addResult(arg, match.getParams());
+    }
+
+    return result;
+  }
+
+
+  /**
+   * Generates command line usage text for display to user.
+   *
+   * @return usage to dusplay to user
+   */
+  public String getUsage() {
+    final StringBuilder builder = new StringBuilder();
+    List<String> descriptionLines;
+    final String blank20 = "                    ";
+
+    builder.append("\nUSAGE: ");
+    if (programName == null) {
+      builder.append("<program>");
+    } else {
+      builder.append(programName);
+    }
+    if (args.isEmpty()) {
+      builder.append("\nNo arguments supported.\n");
+    } else {
+      builder.append(" <args>\nWHERE <args>:\n\n");
+      for (Argument arg : args) {
+        for (String form : arg.getForms()) {
+          builder.append("    ");
+          builder.append(form);
+
+          for (int i = 0; i < arg.getParameterCount(); i++) {
+            builder.append(" <");
+            builder.append(arg.getParameterName(i));
+            builder.append(">");
+          }
+          builder.append("\n");
+        }
+
+        descriptionLines =
+            breakupString(arg.getDescription(), LINE_LENGTH);
+        if (descriptionLines.isEmpty()) {
+          builder.append(blank20);
+          builder.append("No argument description provided.");
+          builder.append("\n\n");
+        } else {
+          for (String line : descriptionLines) {
+            builder.append(blank20);
+            builder.append(line.trim());
+            builder.append("\n");
+          }
+          builder.append("\n");
+        }
+      }
+    }
+    builder.append("\n");
+
+    return builder.toString();
+  }
+
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Private methods:
+
+  /**
+   * Builds a listof all argument matches and sets the postArgs array.
+   *
+   * @param programArgs command line arguments to search through
+   * @param values      values object in which to store results
+   * @return list of matches
+   * @throws UsageException when there is EBKAC
+   */
+  private List<Match> checkMatches(
+      final String[] programArgs, final ArgumentValues values)
+      throws UsageException {
+    final List<Match> result = new ArrayList<Match>();
+    Match match;
+    String[] params;
+    String[] postArgs;
+    int idx = 0;
+    int idx2;
+
+    while (idx < programArgs.length) {
+      // Check for end-of-parameters arg
+      if ("--".equals(programArgs[idx])) {
+        if (++idx < programArgs.length) {
+          postArgs = new String[programArgs.length - idx];
+          System.arraycopy(programArgs, idx,
+              postArgs, 0, postArgs.length);
+          values.setPostArgs(postArgs);
+        }
+        // We're done processing args'
+        break;
+      }
+
+      // Determine parameter count
+      idx2 = idx;
+      while ((idx2 + 1) < programArgs.length
+          && programArgs[idx2 + 1].charAt(0) != '-') {
+        idx2++;
+      }
+
+      // Generate parameter array
+      params = new String[idx2 - idx];
+      System.arraycopy(programArgs, idx + 1, params, 0, params.length);
+
+      LOG.fine("Arg: " + programArgs[idx]);
+      LOG.fine("Params: " + params.length);
+
+      // Find first argument matches
+      match = null;
+      for (Argument arg : args) {
+        match = checkMatch(programArgs[idx], arg, params);
+        if (match != null) {
+          result.add(match);
+          LOG.fine("Match found: ");
+          LOG.fine("     ID: " + arg);
+          LOG.fine("   Form: " + match.getForm());
+          break;
+        }
+      }
+      if (match == null) {
+        if (handler == null) {
+          final UsageException usageException = new UsageException(
+              "Unknown argument: " + programArgs[idx]
+                  + " with " + params.length + " parameters.");
+          usageException.setUsage(getUsage());
+          throw (usageException);
+        } else {
+          handler.handleUnknownArgument(programArgs[idx], params);
+        }
+      }
+
+      idx += params.length + 1;
+    }
+
+    return result;
+  }
+
+  /**
+   * Checks to see if an rgument form matches the suppies parameter list.
+   *
+   * @param argName argument name
+   * @param arg     argument
+   * @param params  parameters supplied
+   * @return match object on match, null otherwise
+   */
+  private Match checkMatch(
+      final String argName, final Argument arg, final String[] params) {
+    // Look for a matching form
+    for (String form : arg.getForms()) {
+      if (
+          form.equals(argName)
+              && arg.getParameterCount() == params.length) {
+        return new Match(arg, form, params);
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Breaks up a string into sub-strings, each with a length equal to or less
+   * than the max length specified.
+   *
+   * @param str       string to break up
+   * @param maxLength maximum line length to use
+   * @return broken up string
+   */
+  private List<String> breakupString(
+      final String str, final int maxLength) {
+    final List<String> result = new ArrayList<String>();
+    int startIdx = -1;
+    int lastIdx;
+    int idx;
+
+    if (str == null) {
+      return result;
+    }
+
+    do {
+      idx = startIdx;
+      do {
+        lastIdx = idx;
+        idx = str.indexOf(' ', lastIdx + 1);
+        LOG.fine("startIdx=" + startIdx + "  lastIdx=" + lastIdx
+            + "  idx=" + idx);
+        if (idx < 0) {
+          // Canot break line up any further
+          result.add(str.substring(startIdx + 1));
+          return result;
+        }
+      } while ((idx - startIdx) <= maxLength);
+
+      result.add(str.substring(startIdx + 1, lastIdx));
+      startIdx = lastIdx;
+    } while (true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentValues.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentValues.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentValues.java
new file mode 100644
index 0000000..cd412da
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/ArgumentValues.java
@@ -0,0 +1,222 @@
+/*
+* 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.installer.args;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Result object capturing the result of processing command line arguments.
+ */
+public class ArgumentValues {
+
+  /**
+   * Storage location for all arguments found after the "--" pseudo-arg.
+   */
+  private String[] postArgs = new String[]{};
+
+  /**
+   * Storage location for the command line argument values.
+   */
+  private final Map<Argument, List<String[]>> values =
+      new LinkedHashMap<Argument, List<String[]>>();
+
+  /**
+   * Constructor.
+   */
+  ArgumentValues() {
+    // Empty.
+  }
+
+  /**
+   * Sets the post-arguments found after the "--" pseudo-argument.
+   *
+   * @param newPostArgs arguments defined after the special "--" argument
+   */
+  void setPostArgs(final String[] newPostArgs) {
+    postArgs = newPostArgs;
+  }
+
+  /**
+   * After processing the command line arguments, this method may be used to
+   * return all arguments which were excluded from processing by their placement
+   * after the "<code>--</code>" psuedo-argument.
+   *
+   * @return all unprocess arguments
+   */
+  public String[] getPostArgs() {
+    return postArgs;
+  }
+
+  /**
+   * Sets the data values found for a specific argument.
+   *
+   * @param arg         argument
+   * @param paramValues parameter values for the argument
+   */
+  public void addResult(final Argument arg, final String[] paramValues) {
+    List<String[]> list = values.get(arg);
+    if (list == null) {
+      list = new ArrayList<String[]>();
+      list.add(paramValues);
+      values.put(arg, list);
+    } else {
+      list.add(paramValues);
+    }
+  }
+
+  /**
+   * Returns a list of all defined arguments.
+   *
+   * @return set of arguments
+   */
+  public Set<Argument> getDefinedArguments() {
+    return values.keySet();
+  }
+
+  /**
+   * Counts the number of arguments defined on the command line which are in the
+   * list provided.
+   *
+   * @param ofThese the arguments to search for, or null to count all supplied
+   *                arguments
+   * @return count of the defined arguments
+   */
+  public int getDefinedCount(Argument... ofThese) {
+    if (ofThese.length == 0) {
+      return values.keySet().size();
+    }
+
+    int count = 0;
+    for (Argument arg : values.keySet()) {
+      boolean found = false;
+      for (int i = 0; !found && i < ofThese.length; i++) {
+        if (ofThese[i].equals(arg)) {
+          count++;
+          found = true;
+        }
+      }
+    }
+    return count;
+  }
+
+  /**
+   * Returns whetheror not the command line argument was actually provided on
+   * the command line.
+   *
+   * @param arg argument to query
+   * @return true if the argument is defined by the command line, false
+   * otherwise
+   */
+  public boolean isDefined(final Argument arg) {
+    final List<String[]> result = values.get(arg);
+    return (result != null);
+  }
+
+  /**
+   * Returns all results for the specified argument.  If a command line option
+   * is specified more than once, this is the method to use to get all values.
+   *
+   * @param arg argument to query
+   * @return list of all parameter lists defined for this argument
+   */
+  public List<String[]> getAllResults(final Argument arg) {
+    List<String[]> result = values.get(arg);
+
+    if (result == null) {
+      final String[] envVars = arg.getEnvVars();
+      final String[] defaults = arg.getDefaults();
+      final String[] vals = new String[arg.getParameterCount()];
+      boolean found = defaults != null;
+
+      for (int i = 0; i < arg.getParameterCount(); i++) {
+        if (defaults != null) {
+          vals[i] = defaults[i];
+        }
+        if (envVars != null) {
+          String val = System.getenv(envVars[i]);
+          if (val != null) {
+            found = true;
+            vals[i] = val;
+          }
+        }
+      }
+
+      if (found) {
+        result = new ArrayList<String[]>();
+        result.add(vals);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Convenience method to retrieve the first instance of the command line
+   * argument's values.
+   *
+   * @param arg argument to query
+   * @return first parameter list defined for this argument
+   */
+  public String[] getResult(final Argument arg) {
+    final List<String[]> all = getAllResults(arg);
+    if (all == null) {
+      return null;
+    } else {
+      return all.get(0);
+    }
+  }
+
+  /**
+   * Convenience method to return the first value of the first instance of the
+   * command line argument values for the specified argument.
+   *
+   * @param arg argument to query
+   * @return first parameter of the first list of parameters supplied
+   */
+  public String getFirstResult(final Argument arg) {
+    final String[] all = getResult(arg);
+    if (all == null) {
+      return null;
+    } else {
+      return all[0];
+    }
+  }
+
+  /**
+   * Convenience method to return the result of getFirstResult method as an
+   * integer.
+   *
+   * @param arg            argument to query
+   * @param undefinedValue value to return when argument is not defined or is
+   *                       illegally defined
+   * @return value specified, or default value provided
+   */
+  public int getFirstResultAsInt(
+      final Argument arg, final int undefinedValue) {
+    final String value = getFirstResult(arg);
+    if (value == null) {
+      return undefinedValue;
+    } else {
+      return Integer.parseInt(value);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/URLArgumentHandler.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/URLArgumentHandler.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/URLArgumentHandler.java
new file mode 100644
index 0000000..bb4b53a
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/URLArgumentHandler.java
@@ -0,0 +1,77 @@
+/*
+* 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.installer.args;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Argument handler implementation which accepts file paths or URLs and
+ * normalizes the parameters to URLs.
+ */
+public class URLArgumentHandler implements ArgumentHandler {
+
+  /**
+   * Logger.
+   */
+  private static final Logger LOG =
+      Logger.getLogger(URLArgumentHandler.class.getName());
+
+  /**
+   * Ensure that the argument is either a file path or a properly formatted URL.
+   *  If it is a file path, convert to a URL.  If neither, throws a
+   * UsageException.
+   *
+   * @param arg        argument
+   * @param form       form used
+   * @param parameters parameters supplied
+   * @throws UsageException when file not found or not a workable URL
+   */
+  public void handleArgument(
+      final Argument arg,
+      final String form,
+      final String[] parameters)
+      throws UsageException {
+    final File file = new File(parameters[0]);
+    URL result = null;
+
+    if (file.exists()) {
+      try {
+        result = file.toURI().toURL();
+      } catch (MalformedURLException mux) {
+        LOG.log(Level.FINEST, "Caught Exception", mux);
+      }
+    }
+    if (result == null) {
+      try {
+        result = new URL(parameters[0]);
+      } catch (MalformedURLException mux) {
+        LOG.log(Level.FINEST, "Caught Exception", mux);
+      }
+    }
+    if (result == null) {
+      throw (new UsageException(
+          "Argument parameter value is not a valid file "
+              + "path or URL: " + arg));
+    }
+    parameters[0] = result.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UnknownArgumentHandler.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UnknownArgumentHandler.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UnknownArgumentHandler.java
new file mode 100644
index 0000000..4d52f62
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UnknownArgumentHandler.java
@@ -0,0 +1,36 @@
+/*
+ * 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.installer.args;
+
+/**
+ * Interface defining unknown argument handlers, given the opportunity to either
+ * ignore the issue or force the parameter to be dealt with.
+ */
+public interface UnknownArgumentHandler {
+
+  /**
+   * Called when an unknown argument is supplied.
+   *
+   * @param form   argument name used
+   * @param params parameters passed into it
+   * @throws UsageException when the user needs to fix it
+   */
+  void handleUnknownArgument(String form, String[] params)
+      throws UsageException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UsageException.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UsageException.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UsageException.java
new file mode 100644
index 0000000..0879417
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/installer/args/UsageException.java
@@ -0,0 +1,89 @@
+/*
+* 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.installer.args;
+
+/**
+ * Invalid usage exception.
+ */
+public class UsageException extends Exception {
+
+  /**
+   * Serial format version.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Stored usage message.
+   */
+  private String usage;
+
+  /**
+   * Creates a new UsageException.
+   */
+  public UsageException() {
+    super();
+  }
+
+  /**
+   * Creates a new UsageException.
+   *
+   * @param message description of exceptional condition
+   */
+  public UsageException(final String message) {
+    super(message);
+  }
+
+  /**
+   * Creates a new UsageException.
+   *
+   * @param message description of exceptional condition
+   * @param cause   provoking exception
+   */
+  public UsageException(final String message, final Throwable cause) {
+    super(message, cause);
+  }
+
+  /**
+   * Creates a new UsageException.
+   *
+   * @param cause provoking exception
+   */
+  public UsageException(final Throwable cause) {
+    super(cause);
+  }
+
+
+  /**
+   * Attaches a usage message to the exception for later consumption.
+   *
+   * @param usageText text to display to user to guide them to correct usage.
+   *                  This is generated and set by the <code>ArgsProcessor</code>.
+   */
+  public void setUsage(final String usageText) {
+    usage = usageText;
+  }
+
+  /**
+   * Returns the usage message previously set.
+   *
+   * @return message or null if not set.
+   */
+  public String getUsage() {
+    return usage;
+  }
+}

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/AbstractSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java
new file mode 100644
index 0000000..965a97f
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java
@@ -0,0 +1,102 @@
+/*
+* 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.Region;
+import com.gemstone.gemfire.modules.session.catalina.internal.DeltaSessionStatistics;
+import com.gemstone.gemfire.modules.session.internal.filter.util.TypeAwareMap;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+public abstract class AbstractSessionCache implements SessionCache {
+
+  /**
+   * The sessionRegion is the <code>Region</code> that actually stores and
+   * replicates the <code>Session</code>s.
+   */
+  protected Region<String, HttpSession> sessionRegion;
+
+  /**
+   * The operatingRegion is the <code>Region</code> used to do HTTP operations.
+   * if local cache is enabled, then this will be the local <code>Region</code>;
+   * otherwise, it will be the session <code>Region</code>.
+   */
+  protected Region<String, HttpSession> operatingRegion;
+
+  protected Map<CacheProperty, Object> properties =
+      new TypeAwareMap<CacheProperty, Object>(CacheProperty.class);
+
+  protected DeltaSessionStatistics statistics;
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void stop() {
+    sessionRegion.close();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Region<String, HttpSession> getOperatingRegion() {
+    return this.operatingRegion;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Region<String, HttpSession> getSessionRegion() {
+    return this.sessionRegion;
+  }
+
+  protected void createStatistics() {
+    this.statistics =
+        new DeltaSessionStatistics(getCache().getDistributedSystem(),
+            (String) properties.get(CacheProperty.STATISTICS_NAME));
+  }
+
+  /**
+   * Build up a {@code RegionConfiguraton} object from parameters originally
+   * passed in as filter initialization parameters.
+   *
+   * @return a {@code RegionConfiguration} object
+   */
+  protected RegionConfiguration createRegionConfiguration() {
+    RegionConfiguration configuration = new RegionConfiguration();
+
+    configuration.setRegionName(
+        (String) properties.get(CacheProperty.REGION_NAME));
+    configuration.setRegionAttributesId(
+        (String) properties.get(CacheProperty.REGION_ATTRIBUTES_ID));
+
+    configuration.setEnableGatewayDeltaReplication(
+        (Boolean) properties.get(
+            CacheProperty.ENABLE_GATEWAY_DELTA_REPLICATION));
+    configuration.setEnableGatewayReplication(
+        (Boolean) properties.get(CacheProperty.ENABLE_GATEWAY_REPLICATION));
+    configuration.setEnableDebugListener(
+        (Boolean) properties.get(CacheProperty.ENABLE_DEBUG_LISTENER));
+
+    return configuration;
+  }
+}

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/CacheProperty.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java
new file mode 100644
index 0000000..e26281e
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java
@@ -0,0 +1,65 @@
+/*
+* 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;
+
+/**
+ * Used to define cache properties
+ */
+public enum CacheProperty {
+
+  ENABLE_DEBUG_LISTENER(Boolean.class),
+
+  ENABLE_GATEWAY_REPLICATION(Boolean.class),
+
+  ENABLE_GATEWAY_DELTA_REPLICATION(Boolean.class),
+
+  ENABLE_LOCAL_CACHE(Boolean.class),
+
+  REGION_NAME(String.class),
+
+  REGION_ATTRIBUTES_ID(String.class),
+
+  STATISTICS_NAME(String.class),
+
+  /**
+   * This parameter can take the following values which match the respective
+   * attribute container classes
+   * <p/>
+   * delta_queued     : QueuedDeltaSessionAttributes delta_immediate  :
+   * DeltaSessionAttributes immediate        : ImmediateSessionAttributes queued
+   * : QueuedSessionAttributes
+   */
+  SESSION_DELTA_POLICY(String.class),
+
+  /**
+   * This parameter can take the following values:
+   * <p/>
+   * set (default) set_and_get
+   */
+  REPLICATION_TRIGGER(String.class);
+
+  Class clazz;
+
+  CacheProperty(Class clazz) {
+    this.clazz = clazz;
+  }
+
+  public Class getClazz() {
+    return clazz;
+  }
+}