ignite-45 - rename web component
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/2bf5da74 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/2bf5da74 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/2bf5da74 Branch: refs/heads/ignite-45 Commit: 2bf5da742228e1001cc0adb6ffed83647e8711fc Parents: 2272d55 Author: Yakov Zhdanov <yzhda...@gridgain.com> Authored: Fri Mar 20 18:18:56 2015 +0300 Committer: Yakov Zhdanov <yzhda...@gridgain.com> Committed: Fri Mar 20 18:18:56 2015 +0300 ---------------------------------------------------------------------- .../main/java/org/apache/ignite/Ignition.java | 2 +- .../org/apache/ignite/internal/IgnitionEx.java | 2 +- modules/core/src/test/webapp/WEB-INF/web.xml | 2 +- .../cache/websession/IgniteWebSession.java | 286 ------------ .../websession/IgniteWebSessionFilter.java | 466 ------------------ .../websession/IgniteWebSessionListener.java | 196 -------- .../ignite/cache/websession/WebSession.java | 286 ++++++++++++ .../cache/websession/WebSessionFilter.java | 467 +++++++++++++++++++ .../cache/websession/WebSessionListener.java | 196 ++++++++ .../IgniteServletContextListenerStartup.java | 181 ------- .../startup/servlet/IgniteServletStartup.java | 187 -------- .../servlet/ServletContextListenerStartup.java | 181 +++++++ .../ignite/startup/servlet/ServletStartup.java | 187 ++++++++ 13 files changed, 1320 insertions(+), 1319 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/core/src/main/java/org/apache/ignite/Ignition.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/Ignition.java b/modules/core/src/main/java/org/apache/ignite/Ignition.java index 5def17b..3017342 100644 --- a/modules/core/src/main/java/org/apache/ignite/Ignition.java +++ b/modules/core/src/main/java/org/apache/ignite/Ignition.java @@ -34,7 +34,7 @@ import java.util.*; * {@link org.apache.ignite.startup} package, for example: * <ul> * <li>{@link org.apache.ignite.startup.cmdline.CommandLineStartup}</li> - * <li>{@ignitelink org.apache.ignite.startup.servlet.IgniteServletStartup}</li> + * <li>{@ignitelink org.apache.ignite.startup.servlet.ServletStartup}</li> * </ul> * <h1 class="header">Examples</h1> * Use {@link #start()} method to start grid with default configuration. You can also use http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java index 48aaaa2..51f7979 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java @@ -82,7 +82,7 @@ import static org.apache.ignite.plugin.segmentation.GridSegmentationPolicy.*; * {@link org.apache.ignite.startup} package, for example: * <ul> * <li>{@code CommandLineStartup}</li> - * <li>{@code IgniteServletStartup}</li> + * <li>{@code ServletStartup}</li> * </ul> * <h1 class="header">Examples</h1> * Use {@link #start()} method to start grid with default configuration. You can also use http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/core/src/test/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/modules/core/src/test/webapp/WEB-INF/web.xml b/modules/core/src/test/webapp/WEB-INF/web.xml index 2710e6e..e9969dc 100644 --- a/modules/core/src/test/webapp/WEB-INF/web.xml +++ b/modules/core/src/test/webapp/WEB-INF/web.xml @@ -31,7 +31,7 @@ <!-- Declare filter for web sessions caching. --> <filter> <filter-name>IgniteWebSessionsFilter</filter-name> - <filter-class>org.apache.ignite.cache.websession.IgniteWebSessionFilter</filter-class> + <filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class> </filter> <filter-mapping> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSession.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSession.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSession.java deleted file mode 100644 index 70c4e27..0000000 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSession.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.cache.websession; - -import org.apache.ignite.internal.util.tostring.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; -import org.jetbrains.annotations.*; - -import javax.servlet.*; -import javax.servlet.http.*; -import java.io.*; -import java.util.*; - -/** - * Session implementation. - */ -@SuppressWarnings({"deprecation", "NonSerializableObjectBoundToHttpSession"}) -class IgniteWebSession implements HttpSession, Externalizable { - /** */ - private static final long serialVersionUID = 0L; - - /** Empty session context. */ - private static final HttpSessionContext EMPTY_SES_CTX = new HttpSessionContext() { - @Nullable @Override public HttpSession getSession(String id) { - return null; - } - - @Override public Enumeration<String> getIds() { - return Collections.enumeration(Collections.<String>emptyList()); - } - }; - - /** Session ID. */ - private String id; - - /** Creation time. */ - private long createTime; - - /** Last access time. */ - private long accessTime; - - /** Maximum inactive interval. */ - private int maxInactiveInterval; - - /** Attributes. */ - @GridToStringInclude - private Map<String, Object> attrs; - - /** Servlet context. */ - @GridToStringExclude - private transient ServletContext ctx; - - /** Listener. */ - @GridToStringExclude - private transient IgniteWebSessionListener lsnr; - - /** New session flag. */ - private transient boolean isNew; - - /** Updates list. */ - private transient Collection<T2<String, Object>> updates; - - /** - * Required by {@link Externalizable}. - */ - public IgniteWebSession() { - // No-op. - } - - /** - * @param ses Session. - */ - IgniteWebSession(HttpSession ses) { - assert ses != null; - - id = ses.getId(); - createTime = ses.getCreationTime(); - accessTime = ses.getLastAccessedTime(); - maxInactiveInterval = ses.getMaxInactiveInterval(); - isNew = ses.isNew(); - - attrs = new HashMap<>(); - - Enumeration<String> names = ses.getAttributeNames(); - - while (names.hasMoreElements()) { - String name = names.nextElement(); - - attrs.put(name, ses.getAttribute(name)); - } - } - - /** - * @param ses Session. - * @param isNew Is new flag. - */ - IgniteWebSession(HttpSession ses, boolean isNew) { - this(ses); - - this.isNew = isNew; - } - - /** - * @param accessTime Last access time. - */ - void accessTime(long accessTime) { - this.accessTime = accessTime; - } - - /** - * @param ctx Servlet context. - */ - public void servletContext(ServletContext ctx) { - assert ctx != null; - - this.ctx = ctx; - } - - /** - * @param lsnr Listener. - */ - public void listener(IgniteWebSessionListener lsnr) { - assert lsnr != null; - - this.lsnr = lsnr; - } - - /** - * Resets updates list. - */ - public void resetUpdates() { - updates = new LinkedList<>(); - } - - /** - * @return Updates list. - */ - public Collection<T2<String, Object>> updates() { - Collection<T2<String, Object>> updates0 = updates; - - updates = null; - - return updates0; - } - - /** {@inheritDoc} */ - @Override public String getId() { - return id; - } - - /** {@inheritDoc} */ - @Override public ServletContext getServletContext() { - return ctx; - } - - /** {@inheritDoc} */ - @Override public long getCreationTime() { - return createTime; - } - - /** {@inheritDoc} */ - @Override public long getLastAccessedTime() { - return accessTime; - } - - /** {@inheritDoc} */ - @Override public int getMaxInactiveInterval() { - return maxInactiveInterval; - } - - /** {@inheritDoc} */ - @Override public void setMaxInactiveInterval(int interval) { - maxInactiveInterval = interval; - } - - /** {@inheritDoc} */ - @Override public Object getAttribute(String name) { - return attrs.get(name); - } - - /** {@inheritDoc} */ - @Override public Object getValue(String name) { - return attrs.get(name); - } - - /** {@inheritDoc} */ - @Override public Enumeration<String> getAttributeNames() { - return Collections.enumeration(attrs.keySet()); - } - - /** {@inheritDoc} */ - @Override public String[] getValueNames() { - return attrs.keySet().toArray(new String[attrs.size()]); - } - - /** {@inheritDoc} */ - @Override public void setAttribute(String name, Object val) { - attrs.put(name, val); - - if (updates != null) - updates.add(new T2<>(name, val)); - } - - /** {@inheritDoc} */ - @Override public void putValue(String name, Object val) { - setAttribute(name, val); - } - - /** {@inheritDoc} */ - @Override public void removeAttribute(String name) { - attrs.remove(name); - - if (updates != null) - updates.add(new T2<>(name, null)); - } - - /** {@inheritDoc} */ - @Override public void removeValue(String name) { - removeAttribute(name); - } - - /** {@inheritDoc} */ - @Override public void invalidate() { - attrs.clear(); - - updates = null; - - lsnr.destroySession(id); - } - - /** - * @param isNew New session flag. - */ - void setNew(boolean isNew) { - this.isNew = isNew; - } - - /** {@inheritDoc} */ - @Override public boolean isNew() { - return isNew; - } - - /** {@inheritDoc} */ - @Override public HttpSessionContext getSessionContext() { - return EMPTY_SES_CTX; - } - - /** {@inheritDoc} */ - @Override public void writeExternal(ObjectOutput out) throws IOException { - U.writeString(out, id); - out.writeLong(createTime); - out.writeLong(accessTime); - out.writeInt(maxInactiveInterval); - U.writeMap(out, attrs); - } - - /** {@inheritDoc} */ - @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - id = U.readString(in); - createTime = in.readLong(); - accessTime = in.readLong(); - maxInactiveInterval = in.readInt(); - attrs = U.readMap(in); - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(IgniteWebSession.class, this); - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionFilter.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionFilter.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionFilter.java deleted file mode 100644 index aead242..0000000 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionFilter.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.cache.websession; - -import org.apache.ignite.*; -import org.apache.ignite.cache.*; -import org.apache.ignite.configuration.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; -import org.apache.ignite.lang.*; -import org.apache.ignite.transactions.*; - -import javax.cache.*; -import javax.cache.expiry.*; -import javax.servlet.*; -import javax.servlet.http.*; -import java.io.*; -import java.util.*; - -import static java.util.concurrent.TimeUnit.*; -import static org.apache.ignite.cache.CacheAtomicityMode.*; -import static org.apache.ignite.cache.CacheMode.*; -import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*; -import static org.apache.ignite.transactions.TransactionConcurrency.*; -import static org.apache.ignite.transactions.TransactionIsolation.*; - -/** - * Filter for web sessions caching. - * <p> - * This is a request filter, that you need to specify in your {@code web.xml} along - * with {@link org.apache.ignite.startup.servlet.IgniteServletContextListenerStartup} to enable web sessions caching: - * <pre name="code" class="xml"> - * <listener> - * <listener-class>org.apache.ignite.startup.servlet.IgniteServletContextListenerStartup</listener-class> - * </listener> - * - * <filter> - * <filter-name>IgniteWebSessionFilter</filter-name> - * <filter-class>org.apache.ignite.cache.websession.IgniteWebSessionFilter</filter-class> - * </filter> - * - * <!-- You can also specify a custom URL pattern. --> - * <filter-mapping> - * <filter-name>IgniteWebSessionsFilter</filter-name> - * <url-pattern>/*</url-pattern> - * </filter-mapping> - * </pre> - * It is also possible to specify a servlet name in a filter mapping, and a servlet URL pattern will - * be used in this case: - * <pre name="code" class="xml"> - * <filter> - * <filter-name>IgniteWebSessionFilter</filter-name> - * <filter-class>org.apache.ignite.cache.websession.IgniteWebSessionFilter</filter-class> - * </filter> - * - * <filter-mapping> - * <filter-name>IgniteWebSessionFilter</filter-name> - * <servlet-name>YourServletName</servlet-name> - * </filter-mapping> - * </pre> - * The filter has the following optional configuration parameters: - * <table class="doctable"> - * <tr> - * <th>Name</th> - * <th>Description</th> - * <th>Default</th> - * </tr> - * <tr> - * <td>IgniteWebSessionsGridName</td> - * <td>Name of the grid that contains cache for web session storage.</td> - * <td>{@code null} (default grid)</td> - * </tr> - * <tr> - * <td>IgniteWebSessionsCacheName</td> - * <td>Name of the cache for web session storage.</td> - * <td>{@code null} (default cache)</td> - * </tr> - * <tr> - * <td>IgniteWebSessionsMaximumRetriesOnFail</td> - * <td> - * Valid for {@code ATOMIC} caches only. Maximum number of retries for session updates in case - * node leaves topology and update fails. If retry is enabled, - * some updates can be applied more than once, otherwise some - * updates can be lost. - * <p> - * To disable retries, set this parameter to {@code 0}. - * </td> - * <td>{@code 3}</td> - * </tr> - * </table> - * These parameters are taken from either filter init parameter list or - * servlet context parameters. You can specify filter init parameters as follows: - * <pre name="code" class="xml"> - * <filter> - * <filter-name>IgniteWebSessionFilter</filter-name> - * <filter-class>org.apache.ignite.cache.websession.IgniteWebSessionFilter</filter-class> - * <init-param> - * <param-name>IgniteWebSessionsGridName</param-name> - * <param-value>WebGrid</param-value> - * </init-param> - * <init-param> - * <param-name>IgniteWebSessionsCacheName</param-name> - * <param-value>WebCache</param-value> - * </init-param> - * - * <!-- Valid for ATOMIC caches only. --> - * <init-param> - * <param-name>IgniteWebSessionsMaximumRetriesOnFail</param-name> - * <param-value>10</param-value> - * </init-param> - * </filter> - * </pre> - * <b>Note:</b> filter init parameter has a priority over servlet context - * parameter; if you specify both, the servlet context parameter will be ignored. - * <h1 class="header">Web sessions caching and concurrent requests</h1> - * If your web application can accept concurrent request for one session, - * consider using {@link org.apache.ignite.cache.CacheAtomicityMode#TRANSACTIONAL} cache - * instead of {@link org.apache.ignite.cache.CacheAtomicityMode#ATOMIC}. In this case each request - * be processed inside pessimistic transaction which will guarantee that all - * updates will be applied in correct order. This is important, for example, - * if you get some attribute from the session, update its value and set new - * value back to the session. In case of {@link org.apache.ignite.cache.CacheAtomicityMode#ATOMIC} - * cache concurrent requests can get equal value, but {@link org.apache.ignite.cache.CacheAtomicityMode#TRANSACTIONAL} - * cache will always process such updates one after another. - */ -public class IgniteWebSessionFilter implements Filter { - /** Web sessions caching grid name parameter name. */ - public static final String WEB_SES_NAME_PARAM = "IgniteWebSessionsGridName"; - - /** Web sessions caching cache name parameter name. */ - public static final String WEB_SES_CACHE_NAME_PARAM = "IgniteWebSessionsCacheName"; - - /** Web sessions caching retry on fail parameter name (valid for ATOMIC */ - public static final String WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM = "IgniteWebSessionsMaximumRetriesOnFail"; - - /** Default retry on fail flag value. */ - public static final int DFLT_MAX_RETRIES_ON_FAIL = 3; - - /** Cache. */ - private IgniteCache<String, IgniteWebSession> cache; - - /** Transactions. */ - private IgniteTransactions txs; - - /** Listener. */ - private IgniteWebSessionListener lsnr; - - /** Logger. */ - private IgniteLogger log; - - /** Servlet context. */ - private ServletContext ctx; - - /** Session ID transformer. */ - private IgniteClosure<String, String> sesIdTransformer; - - /** Transactions enabled flag. */ - private boolean txEnabled; - - /** {@inheritDoc} */ - @Override public void init(FilterConfig cfg) throws ServletException { - ctx = cfg.getServletContext(); - - String gridName = U.firstNotNull( - cfg.getInitParameter(WEB_SES_NAME_PARAM), - ctx.getInitParameter(WEB_SES_NAME_PARAM)); - - String cacheName = U.firstNotNull( - cfg.getInitParameter(WEB_SES_CACHE_NAME_PARAM), - ctx.getInitParameter(WEB_SES_CACHE_NAME_PARAM)); - - String retriesStr = U.firstNotNull( - cfg.getInitParameter(WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM), - ctx.getInitParameter(WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM)); - - int retries; - - try { - retries = retriesStr != null ? Integer.parseInt(retriesStr) : DFLT_MAX_RETRIES_ON_FAIL; - } - catch (NumberFormatException e) { - throw new IgniteException("Maximum number of retries parameter is invalid: " + retriesStr, e); - } - - Ignite webSesIgnite = G.ignite(gridName); - - if (webSesIgnite == null) - throw new IgniteException("Grid for web sessions caching is not started (is it configured?): " + - gridName); - - txs = webSesIgnite.transactions(); - - log = webSesIgnite.log(); - - if (webSesIgnite == null) - throw new IgniteException("Grid for web sessions caching is not started (is it configured?): " + - gridName); - - cache = webSesIgnite.jcache(cacheName); - - if (cache == null) - throw new IgniteException("Cache for web sessions is not started (is it configured?): " + cacheName); - - CacheConfiguration cacheCfg = cache.getConfiguration(CacheConfiguration.class); - - if (cacheCfg.getWriteSynchronizationMode() == FULL_ASYNC) - throw new IgniteException("Cache for web sessions cannot be in FULL_ASYNC mode: " + cacheName); - - if (!cacheCfg.isEagerTtl()) - throw new IgniteException("Cache for web sessions cannot operate with lazy TTL. " + - "Consider setting eagerTtl to true for cache: " + cacheName); - - if (cacheCfg.getCacheMode() == LOCAL) - U.quietAndWarn(webSesIgnite.log(), "Using LOCAL cache for web sessions caching " + - "(this is only OK in test mode): " + cacheName); - - if (cacheCfg.getCacheMode() == PARTITIONED && cacheCfg.getAtomicityMode() != ATOMIC) - U.quietAndWarn(webSesIgnite.log(), "Using " + cacheCfg.getAtomicityMode() + " atomicity for web sessions " + - "caching (switch to ATOMIC mode for better performance)"); - - if (log.isInfoEnabled()) - log.info("Started web sessions caching [gridName=" + gridName + ", cacheName=" + cacheName + - ", maxRetriesOnFail=" + retries + ']'); - - txEnabled = cacheCfg.getAtomicityMode() == TRANSACTIONAL; - - lsnr = new IgniteWebSessionListener(webSesIgnite, cache, retries); - - String srvInfo = ctx.getServerInfo(); - - // Special case for WebLogic, which appends timestamps to session - // IDs upon session creation (the created session ID looks like: - // pdpTSTcCcG6CVM8BTZWzxjTB1lh3w7zFbYVvwBb4bJGjrBx3TMPl!-508312620!1385045122601). - if (srvInfo != null && srvInfo.contains("WebLogic")) { - sesIdTransformer = new C1<String, String>() { - @Override public String apply(String s) { - // Find first exclamation mark. - int idx = s.indexOf('!'); - - // Return original string if not found. - if (idx < 0 || idx == s.length() - 1) - return s; - - // Find second exclamation mark. - idx = s.indexOf('!', idx + 1); - - // Return original string if not found. - if (idx < 0) - return s; - - // Return the session ID without timestamp. - return s.substring(0, idx); - } - }; - } - } - - /** {@inheritDoc} */ - @Override public void destroy() { - // No-op. - } - - /** {@inheritDoc} */ - @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) - throws IOException, ServletException { - assert ctx != null; - - if (req instanceof HttpServletRequest) { - HttpServletRequest httpReq = (HttpServletRequest)req; - - String sesId = null; - - try { - if (txEnabled) { - try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) { - sesId = doFilter0(httpReq, res, chain); - - tx.commit(); - } - } - else - sesId = doFilter0(httpReq, res, chain); - } - catch (Exception e) { - U.error(log, "Failed to update web session: " + sesId, e); - } - } - else - chain.doFilter(req, res); - } - - /** - * @param httpReq Request. - * @param res Response. - * @param chain Filter chain. - * @return Session ID. - * @throws IOException In case of I/O error. - * @throws ServletException In case oif servlet error. - * @throws CacheException In case of other error. - */ - private String doFilter0(HttpServletRequest httpReq, ServletResponse res, FilterChain chain) throws IOException, - ServletException, CacheException { - IgniteWebSession cached; - - String sesId = httpReq.getRequestedSessionId(); - - if (sesId != null) { - cached = cache.get(sesId); - - if (cached != null) { - if (log.isDebugEnabled()) - log.debug("Using cached session for ID: " + sesId); - - if (cached.isNew()) - cached = new IgniteWebSession(cached, false); - } - else { - if (log.isDebugEnabled()) - log.debug("Cached session was invalidated and doesn't exist: " + sesId); - - HttpSession ses = httpReq.getSession(false); - - if (ses != null) { - try { - ses.invalidate(); - } - catch (IllegalStateException ignore) { - // Session was already invalidated. - } - } - - cached = createSession(httpReq); - } - } - else { - cached = createSession(httpReq); - - sesId = cached.getId(); - } - - assert cached != null; - - cached.servletContext(ctx); - cached.listener(lsnr); - cached.resetUpdates(); - - httpReq = new RequestWrapper(httpReq, cached); - - chain.doFilter(httpReq, res); - - HttpSession ses = httpReq.getSession(false); - - if (ses != null && ses instanceof IgniteWebSession) { - Collection<T2<String, Object>> updates = ((IgniteWebSession)ses).updates(); - - if (updates != null) - lsnr.updateAttributes(ses.getId(), updates, ses.getMaxInactiveInterval()); - } - - return sesId; - } - - /** - * @param httpReq HTTP request. - * @return Cached session. - */ - @SuppressWarnings("unchecked") - private IgniteWebSession createSession(HttpServletRequest httpReq) { - HttpSession ses = httpReq.getSession(true); - - String sesId = sesIdTransformer != null ? sesIdTransformer.apply(ses.getId()) : ses.getId(); - - if (log.isDebugEnabled()) - log.debug("Session created: " + sesId); - - IgniteWebSession cached = new IgniteWebSession(ses, true); - - try { - while (true) { - try { - IgniteCache<String, IgniteWebSession> cache0; - - if (cached.getMaxInactiveInterval() > 0) { - long ttl = cached.getMaxInactiveInterval() * 1000; - - ExpiryPolicy plc = new ModifiedExpiryPolicy(new Duration(MILLISECONDS, ttl)); - - cache0 = cache.withExpiryPolicy(plc); - } - else - cache0 = cache; - - IgniteWebSession old = cache0.getAndPutIfAbsent(sesId, cached); - - if (old != null) { - cached = old; - - if (cached.isNew()) - cached = new IgniteWebSession(cached, false); - } - - break; - } - catch (CachePartialUpdateException e) { - if (log.isDebugEnabled()) - log.debug(e.getMessage()); - } - } - } - catch (CacheException e) { - throw new IgniteException("Failed to save session: " + sesId, e); - } - - return cached; - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(IgniteWebSessionFilter.class, this); - } - - /** - * Request wrapper. - */ - private static class RequestWrapper extends HttpServletRequestWrapper { - /** Session. */ - private final IgniteWebSession ses; - - /** - * @param req Request. - * @param ses Session. - */ - private RequestWrapper(HttpServletRequest req, IgniteWebSession ses) { - super(req); - - assert ses != null; - - this.ses = ses; - } - - /** {@inheritDoc} */ - @Override public HttpSession getSession(boolean create) { - return ses; - } - - /** {@inheritDoc} */ - @Override public HttpSession getSession() { - return ses; - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionListener.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionListener.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionListener.java deleted file mode 100644 index 06d7a7f..0000000 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/IgniteWebSessionListener.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.cache.websession; - -import org.apache.ignite.*; -import org.apache.ignite.cache.*; -import org.apache.ignite.internal.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; - -import javax.cache.*; -import javax.cache.expiry.*; -import javax.cache.processor.*; -import java.io.*; -import java.util.*; - -import static java.util.concurrent.TimeUnit.*; - -/** - * Session listener for web sessions caching. - */ -class IgniteWebSessionListener { - /** */ - private static final long RETRY_DELAY = 1; - - /** Cache. */ - private final IgniteCache<String, IgniteWebSession> cache; - - /** Maximum retries. */ - private final int retries; - - /** Logger. */ - private final IgniteLogger log; - - /** - * @param ignite Grid. - * @param cache Cache. - * @param retries Maximum retries. - */ - IgniteWebSessionListener(Ignite ignite, IgniteCache<String, IgniteWebSession> cache, int retries) { - assert ignite != null; - assert cache != null; - - this.cache = cache; - this.retries = retries > 0 ? retries : 1; - - log = ignite.log(); - } - - /** - * @param sesId Session ID. - */ - public void destroySession(String sesId) { - assert sesId != null; - - try { - if (cache.remove(sesId) && log.isDebugEnabled()) - log.debug("Session destroyed: " + sesId); - } - catch (CacheException e) { - U.error(log, "Failed to remove session: " + sesId, e); - } - } - - /** - * @param sesId Session ID. - * @param updates Updates list. - * @param maxInactiveInterval Max session inactive interval. - */ - @SuppressWarnings("unchecked") - public void updateAttributes(String sesId, Collection<T2<String, Object>> updates, int maxInactiveInterval) { - assert sesId != null; - assert updates != null; - - if (log.isDebugEnabled()) - log.debug("Session attributes updated [id=" + sesId + ", updates=" + updates + ']'); - - try { - for (int i = 0; i < retries; i++) { - try { - IgniteCache<String, IgniteWebSession> cache0; - - if (maxInactiveInterval > 0) { - long ttl = maxInactiveInterval * 1000; - - ExpiryPolicy plc = new ModifiedExpiryPolicy(new Duration(MILLISECONDS, ttl)); - - cache0 = cache.withExpiryPolicy(plc); - } - else - cache0 = cache; - - cache0.invoke(sesId, new AttributesProcessor(updates)); - - break; - } - catch (CachePartialUpdateException ignored) { - if (i == retries - 1) { - U.warn(log, "Failed to apply updates for session (maximum number of retries exceeded) [sesId=" + - sesId + ", retries=" + retries + ']'); - } - else { - U.warn(log, "Failed to apply updates for session (will retry): " + sesId); - - U.sleep(RETRY_DELAY); - } - } - } - } - catch (CacheException | IgniteInterruptedCheckedException e) { - U.error(log, "Failed to update session attributes [id=" + sesId + ']', e); - } - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(IgniteWebSessionListener.class, this); - } - - /** - * Multiple attributes update transformer. - */ - private static class AttributesProcessor implements EntryProcessor<String, IgniteWebSession, Void>, Externalizable { - /** */ - private static final long serialVersionUID = 0L; - - /** Updates list. */ - private Collection<T2<String, Object>> updates; - - /** - * Required by {@link Externalizable}. - */ - public AttributesProcessor() { - // No-op. - } - - /** - * @param updates Updates list. - */ - AttributesProcessor(Collection<T2<String, Object>> updates) { - assert updates != null; - - this.updates = updates; - } - - /** {@inheritDoc} */ - @Override public Void process(MutableEntry<String, IgniteWebSession> entry, Object... args) { - if (!entry.exists()) - return null; - - IgniteWebSession ses = new IgniteWebSession(entry.getValue()); - - for (T2<String, Object> update : updates) { - String name = update.get1(); - - assert name != null; - - Object val = update.get2(); - - if (val != null) - ses.setAttribute(name, val); - else - ses.removeAttribute(name); - } - - entry.setValue(ses); - - return null; - } - - /** {@inheritDoc} */ - @Override public void writeExternal(ObjectOutput out) throws IOException { - U.writeCollection(out, updates); - } - - /** {@inheritDoc} */ - @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - updates = U.readCollection(in); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java new file mode 100644 index 0000000..dac3b1f --- /dev/null +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java @@ -0,0 +1,286 @@ +/* + * 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 org.apache.ignite.cache.websession; + +import org.apache.ignite.internal.util.tostring.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.jetbrains.annotations.*; + +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.*; +import java.util.*; + +/** + * Session implementation. + */ +@SuppressWarnings({"deprecation", "NonSerializableObjectBoundToHttpSession"}) +class WebSession implements HttpSession, Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** Empty session context. */ + private static final HttpSessionContext EMPTY_SES_CTX = new HttpSessionContext() { + @Nullable @Override public HttpSession getSession(String id) { + return null; + } + + @Override public Enumeration<String> getIds() { + return Collections.enumeration(Collections.<String>emptyList()); + } + }; + + /** Session ID. */ + private String id; + + /** Creation time. */ + private long createTime; + + /** Last access time. */ + private long accessTime; + + /** Maximum inactive interval. */ + private int maxInactiveInterval; + + /** Attributes. */ + @GridToStringInclude + private Map<String, Object> attrs; + + /** Servlet context. */ + @GridToStringExclude + private transient ServletContext ctx; + + /** Listener. */ + @GridToStringExclude + private transient WebSessionListener lsnr; + + /** New session flag. */ + private transient boolean isNew; + + /** Updates list. */ + private transient Collection<T2<String, Object>> updates; + + /** + * Required by {@link Externalizable}. + */ + public WebSession() { + // No-op. + } + + /** + * @param ses Session. + */ + WebSession(HttpSession ses) { + assert ses != null; + + id = ses.getId(); + createTime = ses.getCreationTime(); + accessTime = ses.getLastAccessedTime(); + maxInactiveInterval = ses.getMaxInactiveInterval(); + isNew = ses.isNew(); + + attrs = new HashMap<>(); + + Enumeration<String> names = ses.getAttributeNames(); + + while (names.hasMoreElements()) { + String name = names.nextElement(); + + attrs.put(name, ses.getAttribute(name)); + } + } + + /** + * @param ses Session. + * @param isNew Is new flag. + */ + WebSession(HttpSession ses, boolean isNew) { + this(ses); + + this.isNew = isNew; + } + + /** + * @param accessTime Last access time. + */ + void accessTime(long accessTime) { + this.accessTime = accessTime; + } + + /** + * @param ctx Servlet context. + */ + public void servletContext(ServletContext ctx) { + assert ctx != null; + + this.ctx = ctx; + } + + /** + * @param lsnr Listener. + */ + public void listener(WebSessionListener lsnr) { + assert lsnr != null; + + this.lsnr = lsnr; + } + + /** + * Resets updates list. + */ + public void resetUpdates() { + updates = new LinkedList<>(); + } + + /** + * @return Updates list. + */ + public Collection<T2<String, Object>> updates() { + Collection<T2<String, Object>> updates0 = updates; + + updates = null; + + return updates0; + } + + /** {@inheritDoc} */ + @Override public String getId() { + return id; + } + + /** {@inheritDoc} */ + @Override public ServletContext getServletContext() { + return ctx; + } + + /** {@inheritDoc} */ + @Override public long getCreationTime() { + return createTime; + } + + /** {@inheritDoc} */ + @Override public long getLastAccessedTime() { + return accessTime; + } + + /** {@inheritDoc} */ + @Override public int getMaxInactiveInterval() { + return maxInactiveInterval; + } + + /** {@inheritDoc} */ + @Override public void setMaxInactiveInterval(int interval) { + maxInactiveInterval = interval; + } + + /** {@inheritDoc} */ + @Override public Object getAttribute(String name) { + return attrs.get(name); + } + + /** {@inheritDoc} */ + @Override public Object getValue(String name) { + return attrs.get(name); + } + + /** {@inheritDoc} */ + @Override public Enumeration<String> getAttributeNames() { + return Collections.enumeration(attrs.keySet()); + } + + /** {@inheritDoc} */ + @Override public String[] getValueNames() { + return attrs.keySet().toArray(new String[attrs.size()]); + } + + /** {@inheritDoc} */ + @Override public void setAttribute(String name, Object val) { + attrs.put(name, val); + + if (updates != null) + updates.add(new T2<>(name, val)); + } + + /** {@inheritDoc} */ + @Override public void putValue(String name, Object val) { + setAttribute(name, val); + } + + /** {@inheritDoc} */ + @Override public void removeAttribute(String name) { + attrs.remove(name); + + if (updates != null) + updates.add(new T2<>(name, null)); + } + + /** {@inheritDoc} */ + @Override public void removeValue(String name) { + removeAttribute(name); + } + + /** {@inheritDoc} */ + @Override public void invalidate() { + attrs.clear(); + + updates = null; + + lsnr.destroySession(id); + } + + /** + * @param isNew New session flag. + */ + void setNew(boolean isNew) { + this.isNew = isNew; + } + + /** {@inheritDoc} */ + @Override public boolean isNew() { + return isNew; + } + + /** {@inheritDoc} */ + @Override public HttpSessionContext getSessionContext() { + return EMPTY_SES_CTX; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + U.writeString(out, id); + out.writeLong(createTime); + out.writeLong(accessTime); + out.writeInt(maxInactiveInterval); + U.writeMap(out, attrs); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + id = U.readString(in); + createTime = in.readLong(); + accessTime = in.readLong(); + maxInactiveInterval = in.readInt(); + attrs = U.readMap(in); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(WebSession.class, this); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java new file mode 100644 index 0000000..896c987 --- /dev/null +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java @@ -0,0 +1,467 @@ +/* + * 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 org.apache.ignite.cache.websession; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.configuration.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.startup.servlet.*; +import org.apache.ignite.transactions.*; + +import javax.cache.*; +import javax.cache.expiry.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.*; +import java.util.*; + +import static java.util.concurrent.TimeUnit.*; +import static org.apache.ignite.cache.CacheAtomicityMode.*; +import static org.apache.ignite.cache.CacheMode.*; +import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*; +import static org.apache.ignite.transactions.TransactionConcurrency.*; +import static org.apache.ignite.transactions.TransactionIsolation.*; + +/** + * Filter for web sessions caching. + * <p> + * This is a request filter, that you need to specify in your {@code web.xml} along + * with {@link ServletContextListenerStartup} to enable web sessions caching: + * <pre name="code" class="xml"> + * <listener> + * <listener-class>org.apache.ignite.startup.servlet.IgniteServletContextListenerStartup</listener-class> + * </listener> + * + * <filter> + * <filter-name>WebSessionFilter</filter-name> + * <filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class> + * </filter> + * + * <!-- You can also specify a custom URL pattern. --> + * <filter-mapping> + * <filter-name>IgniteWebSessionsFilter</filter-name> + * <url-pattern>/*</url-pattern> + * </filter-mapping> + * </pre> + * It is also possible to specify a servlet name in a filter mapping, and a servlet URL pattern will + * be used in this case: + * <pre name="code" class="xml"> + * <filter> + * <filter-name>WebSessionFilter</filter-name> + * <filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class> + * </filter> + * + * <filter-mapping> + * <filter-name>WebSessionFilter</filter-name> + * <servlet-name>YourServletName</servlet-name> + * </filter-mapping> + * </pre> + * The filter has the following optional configuration parameters: + * <table class="doctable"> + * <tr> + * <th>Name</th> + * <th>Description</th> + * <th>Default</th> + * </tr> + * <tr> + * <td>IgniteWebSessionsGridName</td> + * <td>Name of the grid that contains cache for web session storage.</td> + * <td>{@code null} (default grid)</td> + * </tr> + * <tr> + * <td>IgniteWebSessionsCacheName</td> + * <td>Name of the cache for web session storage.</td> + * <td>{@code null} (default cache)</td> + * </tr> + * <tr> + * <td>IgniteWebSessionsMaximumRetriesOnFail</td> + * <td> + * Valid for {@code ATOMIC} caches only. Maximum number of retries for session updates in case + * node leaves topology and update fails. If retry is enabled, + * some updates can be applied more than once, otherwise some + * updates can be lost. + * <p> + * To disable retries, set this parameter to {@code 0}. + * </td> + * <td>{@code 3}</td> + * </tr> + * </table> + * These parameters are taken from either filter init parameter list or + * servlet context parameters. You can specify filter init parameters as follows: + * <pre name="code" class="xml"> + * <filter> + * <filter-name>WebSessionFilter</filter-name> + * <filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class> + * <init-param> + * <param-name>IgniteWebSessionsGridName</param-name> + * <param-value>WebGrid</param-value> + * </init-param> + * <init-param> + * <param-name>IgniteWebSessionsCacheName</param-name> + * <param-value>WebCache</param-value> + * </init-param> + * + * <!-- Valid for ATOMIC caches only. --> + * <init-param> + * <param-name>IgniteWebSessionsMaximumRetriesOnFail</param-name> + * <param-value>10</param-value> + * </init-param> + * </filter> + * </pre> + * <b>Note:</b> filter init parameter has a priority over servlet context + * parameter; if you specify both, the servlet context parameter will be ignored. + * <h1 class="header">Web sessions caching and concurrent requests</h1> + * If your web application can accept concurrent request for one session, + * consider using {@link org.apache.ignite.cache.CacheAtomicityMode#TRANSACTIONAL} cache + * instead of {@link org.apache.ignite.cache.CacheAtomicityMode#ATOMIC}. In this case each request + * be processed inside pessimistic transaction which will guarantee that all + * updates will be applied in correct order. This is important, for example, + * if you get some attribute from the session, update its value and set new + * value back to the session. In case of {@link org.apache.ignite.cache.CacheAtomicityMode#ATOMIC} + * cache concurrent requests can get equal value, but {@link org.apache.ignite.cache.CacheAtomicityMode#TRANSACTIONAL} + * cache will always process such updates one after another. + */ +public class WebSessionFilter implements Filter { + /** Web sessions caching grid name parameter name. */ + public static final String WEB_SES_NAME_PARAM = "IgniteWebSessionsGridName"; + + /** Web sessions caching cache name parameter name. */ + public static final String WEB_SES_CACHE_NAME_PARAM = "IgniteWebSessionsCacheName"; + + /** Web sessions caching retry on fail parameter name (valid for ATOMIC */ + public static final String WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM = "IgniteWebSessionsMaximumRetriesOnFail"; + + /** Default retry on fail flag value. */ + public static final int DFLT_MAX_RETRIES_ON_FAIL = 3; + + /** Cache. */ + private IgniteCache<String, WebSession> cache; + + /** Transactions. */ + private IgniteTransactions txs; + + /** Listener. */ + private WebSessionListener lsnr; + + /** Logger. */ + private IgniteLogger log; + + /** Servlet context. */ + private ServletContext ctx; + + /** Session ID transformer. */ + private IgniteClosure<String, String> sesIdTransformer; + + /** Transactions enabled flag. */ + private boolean txEnabled; + + /** {@inheritDoc} */ + @Override public void init(FilterConfig cfg) throws ServletException { + ctx = cfg.getServletContext(); + + String gridName = U.firstNotNull( + cfg.getInitParameter(WEB_SES_NAME_PARAM), + ctx.getInitParameter(WEB_SES_NAME_PARAM)); + + String cacheName = U.firstNotNull( + cfg.getInitParameter(WEB_SES_CACHE_NAME_PARAM), + ctx.getInitParameter(WEB_SES_CACHE_NAME_PARAM)); + + String retriesStr = U.firstNotNull( + cfg.getInitParameter(WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM), + ctx.getInitParameter(WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM)); + + int retries; + + try { + retries = retriesStr != null ? Integer.parseInt(retriesStr) : DFLT_MAX_RETRIES_ON_FAIL; + } + catch (NumberFormatException e) { + throw new IgniteException("Maximum number of retries parameter is invalid: " + retriesStr, e); + } + + Ignite webSesIgnite = G.ignite(gridName); + + if (webSesIgnite == null) + throw new IgniteException("Grid for web sessions caching is not started (is it configured?): " + + gridName); + + txs = webSesIgnite.transactions(); + + log = webSesIgnite.log(); + + if (webSesIgnite == null) + throw new IgniteException("Grid for web sessions caching is not started (is it configured?): " + + gridName); + + cache = webSesIgnite.jcache(cacheName); + + if (cache == null) + throw new IgniteException("Cache for web sessions is not started (is it configured?): " + cacheName); + + CacheConfiguration cacheCfg = cache.getConfiguration(CacheConfiguration.class); + + if (cacheCfg.getWriteSynchronizationMode() == FULL_ASYNC) + throw new IgniteException("Cache for web sessions cannot be in FULL_ASYNC mode: " + cacheName); + + if (!cacheCfg.isEagerTtl()) + throw new IgniteException("Cache for web sessions cannot operate with lazy TTL. " + + "Consider setting eagerTtl to true for cache: " + cacheName); + + if (cacheCfg.getCacheMode() == LOCAL) + U.quietAndWarn(webSesIgnite.log(), "Using LOCAL cache for web sessions caching " + + "(this is only OK in test mode): " + cacheName); + + if (cacheCfg.getCacheMode() == PARTITIONED && cacheCfg.getAtomicityMode() != ATOMIC) + U.quietAndWarn(webSesIgnite.log(), "Using " + cacheCfg.getAtomicityMode() + " atomicity for web sessions " + + "caching (switch to ATOMIC mode for better performance)"); + + if (log.isInfoEnabled()) + log.info("Started web sessions caching [gridName=" + gridName + ", cacheName=" + cacheName + + ", maxRetriesOnFail=" + retries + ']'); + + txEnabled = cacheCfg.getAtomicityMode() == TRANSACTIONAL; + + lsnr = new WebSessionListener(webSesIgnite, cache, retries); + + String srvInfo = ctx.getServerInfo(); + + // Special case for WebLogic, which appends timestamps to session + // IDs upon session creation (the created session ID looks like: + // pdpTSTcCcG6CVM8BTZWzxjTB1lh3w7zFbYVvwBb4bJGjrBx3TMPl!-508312620!1385045122601). + if (srvInfo != null && srvInfo.contains("WebLogic")) { + sesIdTransformer = new C1<String, String>() { + @Override public String apply(String s) { + // Find first exclamation mark. + int idx = s.indexOf('!'); + + // Return original string if not found. + if (idx < 0 || idx == s.length() - 1) + return s; + + // Find second exclamation mark. + idx = s.indexOf('!', idx + 1); + + // Return original string if not found. + if (idx < 0) + return s; + + // Return the session ID without timestamp. + return s.substring(0, idx); + } + }; + } + } + + /** {@inheritDoc} */ + @Override public void destroy() { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException { + assert ctx != null; + + if (req instanceof HttpServletRequest) { + HttpServletRequest httpReq = (HttpServletRequest)req; + + String sesId = null; + + try { + if (txEnabled) { + try (Transaction tx = txs.txStart(PESSIMISTIC, REPEATABLE_READ)) { + sesId = doFilter0(httpReq, res, chain); + + tx.commit(); + } + } + else + sesId = doFilter0(httpReq, res, chain); + } + catch (Exception e) { + U.error(log, "Failed to update web session: " + sesId, e); + } + } + else + chain.doFilter(req, res); + } + + /** + * @param httpReq Request. + * @param res Response. + * @param chain Filter chain. + * @return Session ID. + * @throws IOException In case of I/O error. + * @throws ServletException In case oif servlet error. + * @throws CacheException In case of other error. + */ + private String doFilter0(HttpServletRequest httpReq, ServletResponse res, FilterChain chain) throws IOException, + ServletException, CacheException { + WebSession cached; + + String sesId = httpReq.getRequestedSessionId(); + + if (sesId != null) { + cached = cache.get(sesId); + + if (cached != null) { + if (log.isDebugEnabled()) + log.debug("Using cached session for ID: " + sesId); + + if (cached.isNew()) + cached = new WebSession(cached, false); + } + else { + if (log.isDebugEnabled()) + log.debug("Cached session was invalidated and doesn't exist: " + sesId); + + HttpSession ses = httpReq.getSession(false); + + if (ses != null) { + try { + ses.invalidate(); + } + catch (IllegalStateException ignore) { + // Session was already invalidated. + } + } + + cached = createSession(httpReq); + } + } + else { + cached = createSession(httpReq); + + sesId = cached.getId(); + } + + assert cached != null; + + cached.servletContext(ctx); + cached.listener(lsnr); + cached.resetUpdates(); + + httpReq = new RequestWrapper(httpReq, cached); + + chain.doFilter(httpReq, res); + + HttpSession ses = httpReq.getSession(false); + + if (ses != null && ses instanceof WebSession) { + Collection<T2<String, Object>> updates = ((WebSession)ses).updates(); + + if (updates != null) + lsnr.updateAttributes(ses.getId(), updates, ses.getMaxInactiveInterval()); + } + + return sesId; + } + + /** + * @param httpReq HTTP request. + * @return Cached session. + */ + @SuppressWarnings("unchecked") + private WebSession createSession(HttpServletRequest httpReq) { + HttpSession ses = httpReq.getSession(true); + + String sesId = sesIdTransformer != null ? sesIdTransformer.apply(ses.getId()) : ses.getId(); + + if (log.isDebugEnabled()) + log.debug("Session created: " + sesId); + + WebSession cached = new WebSession(ses, true); + + try { + while (true) { + try { + IgniteCache<String, WebSession> cache0; + + if (cached.getMaxInactiveInterval() > 0) { + long ttl = cached.getMaxInactiveInterval() * 1000; + + ExpiryPolicy plc = new ModifiedExpiryPolicy(new Duration(MILLISECONDS, ttl)); + + cache0 = cache.withExpiryPolicy(plc); + } + else + cache0 = cache; + + WebSession old = cache0.getAndPutIfAbsent(sesId, cached); + + if (old != null) { + cached = old; + + if (cached.isNew()) + cached = new WebSession(cached, false); + } + + break; + } + catch (CachePartialUpdateException e) { + if (log.isDebugEnabled()) + log.debug(e.getMessage()); + } + } + } + catch (CacheException e) { + throw new IgniteException("Failed to save session: " + sesId, e); + } + + return cached; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(WebSessionFilter.class, this); + } + + /** + * Request wrapper. + */ + private static class RequestWrapper extends HttpServletRequestWrapper { + /** Session. */ + private final WebSession ses; + + /** + * @param req Request. + * @param ses Session. + */ + private RequestWrapper(HttpServletRequest req, WebSession ses) { + super(req); + + assert ses != null; + + this.ses = ses; + } + + /** {@inheritDoc} */ + @Override public HttpSession getSession(boolean create) { + return ses; + } + + /** {@inheritDoc} */ + @Override public HttpSession getSession() { + return ses; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java new file mode 100644 index 0000000..442f83f --- /dev/null +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java @@ -0,0 +1,196 @@ +/* + * 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 org.apache.ignite.cache.websession; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; + +import javax.cache.*; +import javax.cache.expiry.*; +import javax.cache.processor.*; +import java.io.*; +import java.util.*; + +import static java.util.concurrent.TimeUnit.*; + +/** + * Session listener for web sessions caching. + */ +class WebSessionListener { + /** */ + private static final long RETRY_DELAY = 1; + + /** Cache. */ + private final IgniteCache<String, WebSession> cache; + + /** Maximum retries. */ + private final int retries; + + /** Logger. */ + private final IgniteLogger log; + + /** + * @param ignite Grid. + * @param cache Cache. + * @param retries Maximum retries. + */ + WebSessionListener(Ignite ignite, IgniteCache<String, WebSession> cache, int retries) { + assert ignite != null; + assert cache != null; + + this.cache = cache; + this.retries = retries > 0 ? retries : 1; + + log = ignite.log(); + } + + /** + * @param sesId Session ID. + */ + public void destroySession(String sesId) { + assert sesId != null; + + try { + if (cache.remove(sesId) && log.isDebugEnabled()) + log.debug("Session destroyed: " + sesId); + } + catch (CacheException e) { + U.error(log, "Failed to remove session: " + sesId, e); + } + } + + /** + * @param sesId Session ID. + * @param updates Updates list. + * @param maxInactiveInterval Max session inactive interval. + */ + @SuppressWarnings("unchecked") + public void updateAttributes(String sesId, Collection<T2<String, Object>> updates, int maxInactiveInterval) { + assert sesId != null; + assert updates != null; + + if (log.isDebugEnabled()) + log.debug("Session attributes updated [id=" + sesId + ", updates=" + updates + ']'); + + try { + for (int i = 0; i < retries; i++) { + try { + IgniteCache<String, WebSession> cache0; + + if (maxInactiveInterval > 0) { + long ttl = maxInactiveInterval * 1000; + + ExpiryPolicy plc = new ModifiedExpiryPolicy(new Duration(MILLISECONDS, ttl)); + + cache0 = cache.withExpiryPolicy(plc); + } + else + cache0 = cache; + + cache0.invoke(sesId, new AttributesProcessor(updates)); + + break; + } + catch (CachePartialUpdateException ignored) { + if (i == retries - 1) { + U.warn(log, "Failed to apply updates for session (maximum number of retries exceeded) [sesId=" + + sesId + ", retries=" + retries + ']'); + } + else { + U.warn(log, "Failed to apply updates for session (will retry): " + sesId); + + U.sleep(RETRY_DELAY); + } + } + } + } + catch (CacheException | IgniteInterruptedCheckedException e) { + U.error(log, "Failed to update session attributes [id=" + sesId + ']', e); + } + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(WebSessionListener.class, this); + } + + /** + * Multiple attributes update transformer. + */ + private static class AttributesProcessor implements EntryProcessor<String, WebSession, Void>, Externalizable { + /** */ + private static final long serialVersionUID = 0L; + + /** Updates list. */ + private Collection<T2<String, Object>> updates; + + /** + * Required by {@link Externalizable}. + */ + public AttributesProcessor() { + // No-op. + } + + /** + * @param updates Updates list. + */ + AttributesProcessor(Collection<T2<String, Object>> updates) { + assert updates != null; + + this.updates = updates; + } + + /** {@inheritDoc} */ + @Override public Void process(MutableEntry<String, WebSession> entry, Object... args) { + if (!entry.exists()) + return null; + + WebSession ses = new WebSession(entry.getValue()); + + for (T2<String, Object> update : updates) { + String name = update.get1(); + + assert name != null; + + Object val = update.get2(); + + if (val != null) + ses.setAttribute(name, val); + else + ses.removeAttribute(name); + } + + entry.setValue(ses); + + return null; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + U.writeCollection(out, updates); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + updates = U.readCollection(in); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletContextListenerStartup.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletContextListenerStartup.java b/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletContextListenerStartup.java deleted file mode 100644 index 18d6bc4..0000000 --- a/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletContextListenerStartup.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.startup.servlet; - -import org.apache.ignite.*; -import org.apache.ignite.configuration.*; -import org.apache.ignite.internal.*; -import org.apache.ignite.internal.processors.resource.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; -import org.apache.ignite.lang.*; - -import javax.servlet.*; -import java.net.*; -import java.util.*; - -/** - * This class defines Ignite startup based on servlet context listener. - * This startup can be used to start Ignite inside any web container. - * <p> - * This startup must be defined in {@code web.xml} file. - * <pre name="code" class="xml"> - * <listener> - * <listener-class>org.apache.ignite.startup.servlet.IgniteServletContextListenerStartup</listener-class> - * </listener> - * - * <context-param> - * <param-name>IgniteConfigurationFilePath</param-name> - * <param-value>config/default-config.xml</param-value> - * </context-param> - * </pre> - * <p> - * Servlet context listener based startup may be used in any web container like Tomcat, Jetty and etc. - * Depending on the way this startup is deployed the Ignite instance can be accessed - * by either all web applications or by only one. See web container class loading architecture: - * <ul> - * <li><a target=_blank href="http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html">http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html</a></li> - * <li><a target=_blank href="http://docs.codehaus.org/display/JETTY/Classloading">http://docs.codehaus.org/display/JETTY/Classloading</a></li> - * </ul> - * <p> - * <h2 class="header">Tomcat</h2> - * There are two ways to start Ignite on Tomcat. - * <ul> - * <li>Ignite started when web container starts and Ignite instance is accessible only to all web applications. - * <ol> - * <li>Add Ignite libraries in Tomcat common loader. - * Add in file {@code $TOMCAT_HOME/conf/catalina.properties} for property {@code common.loader} - * the following {@code $IGNITE_HOME/*.jar,$IGNITE_HOME/libs/*.jar} - * (replace {@code $IGNITE_HOME} with absolute path). - * </li> - * <li>Configure this startup in {@code $TOMCAT_HOME/conf/web.xml} - * <pre name="code" class="xml"> - * <listener> - * <listener-class>org.apache.ignite.startup.servlet.IgniteServletContextListenerStartup</listener-class> - * </listener> - * - * <context-param> - * <param-name>IgniteConfigurationFilePath</param-name> - * <param-value>config/default-config.xml</param-value> - * </context-param> - * </pre> - * </li> - * </ol> - * </li> - * <li> - * Ignite started from WAR-file and Ignite instance is accessible only to that web application. - * Difference with approach described above is that {@code web.xml} file and all libraries should - * be added in WAR file without changes in Tomcat configuration files. - * </li> - * </ul> - */ -public class IgniteServletContextListenerStartup implements ServletContextListener { - /** Configuration file path parameter name. */ - public static final String IGNITE_CFG_FILE_PATH_PARAM = "IgniteConfigurationFilePath"; - - /** Names of started grids. */ - private final Collection<String> gridNames = new ArrayList<>(); - - /** {@inheritDoc} */ - @Override public void contextInitialized(ServletContextEvent evt) { - ServletContext ctx = evt.getServletContext(); - - String cfgFile = ctx.getInitParameter(IGNITE_CFG_FILE_PATH_PARAM); - - Collection<IgniteConfiguration> cfgs; - GridSpringResourceContext rsrcCtx = null; - - if (cfgFile != null) { - URL cfgUrl = null; - - try { - cfgUrl = evt.getServletContext().getResource("/META-INF/" + cfgFile); - } - catch (MalformedURLException ignored) { - // Ignore, we still need to try with IGNITE_HOME. - } - - if (cfgUrl == null) - // Try with IGNITE_HOME and with context class loader. - cfgUrl = U.resolveIgniteUrl(cfgFile); - - if (cfgUrl == null) - throw new IgniteException("Failed to find Spring configuration file (path provided should be " + - "either absolute, relative to IGNITE_HOME, or relative to META-INF folder): " + cfgFile); - - IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> t; - - try { - t = IgnitionEx.loadConfigurations(cfgUrl); - } - catch (IgniteCheckedException e) { - throw new IgniteException("Failed to load Ignite configuration.", e); - } - - cfgs = t.get1(); - rsrcCtx = t.get2(); - - if (cfgs.isEmpty()) - throw new IgniteException("Can't find grid factory configuration in: " + cfgUrl); - } - else - cfgs = Collections.<IgniteConfiguration>singleton(new IgniteConfiguration()); - - try { - assert !cfgs.isEmpty(); - - for (IgniteConfiguration cfg : cfgs) { - assert cfg != null; - - Ignite ignite; - - synchronized (IgniteServletContextListenerStartup.class) { - try { - ignite = G.ignite(cfg.getGridName()); - } - catch (IgniteIllegalStateException ignored) { - ignite = IgnitionEx.start(new IgniteConfiguration(cfg), rsrcCtx); - } - } - - // Check if grid is not null - started properly. - if (ignite != null) - gridNames.add(ignite.name()); - } - } - catch (IgniteCheckedException e) { - // Stop started grids only. - for (String name : gridNames) - G.stop(name, true); - - throw new IgniteException("Failed to start Ignite.", e); - } - } - - /** {@inheritDoc} */ - @Override public void contextDestroyed(ServletContextEvent evt) { - // Stop started grids only. - for (String name: gridNames) - G.stop(name, true); - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(IgniteServletContextListenerStartup.class, this); - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/2bf5da74/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletStartup.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletStartup.java b/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletStartup.java deleted file mode 100644 index 3824596..0000000 --- a/modules/web/src/main/java/org/apache/ignite/startup/servlet/IgniteServletStartup.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.startup.servlet; - -import org.apache.ignite.*; -import org.apache.ignite.configuration.*; -import org.apache.ignite.internal.*; -import org.apache.ignite.internal.processors.resource.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; -import org.apache.ignite.lang.*; - -import javax.servlet.*; -import javax.servlet.http.*; -import java.net.*; -import java.util.*; - -/** - * This class defines servlet-based Ignite startup. This startup can be used to start Ignite - * inside any web container as servlet. - * <p> - * This startup must be defined in {@code web.xml} file. - * <pre name="code" class="xml"> - * <servlet> - * <servlet-name>Ignite</servlet-name> - * <servlet-class>org.apache.ignite.startup.servlet.IgniteServletStartup</servlet-class> - * <init-param> - * <param-name>cfgFilePath</param-name> - * <param-value>config/default-config.xml</param-value> - * </init-param> - * <load-on-startup>1</load-on-startup> - * </servlet> - * </pre> - * <p> - * Servlet-based startup may be used in any web container like Tomcat, Jetty and etc. - * Depending on the way this startup is deployed the Ignite instance can be accessed - * by either all web applications or by only one. See web container class loading architecture: - * <ul> - * <li><a target=_blank href="http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html">http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html</a></li> - * <li><a target=_blank href="http://docs.codehaus.org/display/JETTY/Classloading">http://docs.codehaus.org/display/JETTY/Classloading</a></li> - * </ul> - * <p> - * <h2 class="header">Tomcat</h2> - * There are two ways to start Ignite on Tomcat. - * <ul> - * <li>Ignite started when web container starts and Ignite instance is accessible only to all web applications. - * <ol> - * <li>Add Ignite libraries in Tomcat common loader. - * Add in file {@code $TOMCAT_HOME/conf/catalina.properties} for property {@code shared.loader} - * the following {@code $IGNITE_HOME/ignite.jar,$IGNITE_HOME/libs/*.jar} - * (replace {@code $IGNITE_HOME} with absolute path). - * </li> - * <li>Configure startup in {@code $TOMCAT_HOME/conf/web.xml} - * <pre name="code" class="xml"> - * <servlet> - * <servlet-name>Ignite</servlet-name> - * <servlet-class>org.apache.ignite.startup.servlet.IgniteServletStartup</servlet-class> - * <init-param> - * <param-name>cfgFilePath</param-name> - * <param-value>config/default-config.xml</param-value> - * </init-param> - * <load-on-startup>1</load-on-startup> - * </servlet> - * </pre> - * </li> - * </ol> - * </li> - * <li> - * Ignite started from WAR-file and Ignite instance is accessible only to that web application. - * Difference with approach described above is that {@code web.xml} file and all libraries should - * be added in WAR file without changes in Tomcat configuration files. - * </li> - * </ul> - * <p> - * <h2 class="header">Jetty</h2> - * Below is Java code example with Jetty API: - * <pre name="code" class="java"> - * Server service = new Server(); - * - * service.addListener("localhost:8090"); - * - * ServletHttpContext ctx = (ServletHttpContext)service.getContext("/"); - * - * ServletHolder servlet = ctx.addServlet("Ignite", "/IgniteStartup", - * "org.apache.ignite.startup.servlet.IgniteServletStartup"); - * - * servlet.setInitParameter("cfgFilePath", "config/default-config.xml"); - * - * servlet.setInitOrder(1); - * - * servlet.start(); - * - * service.start(); - * </pre> - */ -public class IgniteServletStartup extends HttpServlet { - /** */ - private static final long serialVersionUID = 0L; - - /** Grid loaded flag. */ - private static boolean loaded; - - /** Configuration file path variable name. */ - private static final String cfgFilePathParam = "cfgFilePath"; - - /** */ - private Collection<String> gridNames = new ArrayList<>(); - - /** {@inheritDoc} */ - @SuppressWarnings({"unchecked"}) - @Override public void init() throws ServletException { - // Avoid multiple servlet instances. Ignite should be loaded once. - if (loaded) - return; - - String cfgFile = getServletConfig().getInitParameter(cfgFilePathParam); - - if (cfgFile == null) - throw new ServletException("Failed to read property: " + cfgFilePathParam); - - URL cfgUrl = U.resolveIgniteUrl(cfgFile); - - if (cfgUrl == null) - throw new ServletException("Failed to find Spring configuration file (path provided should be " + - "either absolute, relative to IGNITE_HOME, or relative to META-INF folder): " + cfgFile); - - try { - IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> t = - IgnitionEx.loadConfigurations(cfgUrl); - - Collection<IgniteConfiguration> cfgs = t.get1(); - - if (cfgs == null) - throw new ServletException("Failed to find a single grid factory configuration in: " + cfgUrl); - - for (IgniteConfiguration cfg : cfgs) { - assert cfg != null; - - IgniteConfiguration adapter = new IgniteConfiguration(cfg); - - Ignite ignite = IgnitionEx.start(adapter, t.get2()); - - // Test if grid is not null - started properly. - if (ignite != null) - gridNames.add(ignite.name()); - } - } - catch (IgniteCheckedException e) { - // Stop started grids only. - for (String name: gridNames) - G.stop(name, true); - - throw new ServletException("Failed to start Ignite.", e); - } - - loaded = true; - } - - /** {@inheritDoc} */ - @Override public void destroy() { - // Stop started grids only. - for (String name: gridNames) - G.stop(name, true); - - loaded = false; - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(IgniteServletStartup.class, this); - } -}