diff options
author | Raymond Auge | 2016-07-07 02:31:02 +0000 |
---|---|---|
committer | Thomas Watson | 2016-08-18 18:24:31 +0000 |
commit | 6bfd9bef40482dd0e0766758bbdd1f29e562b99e (patch) | |
tree | c20f10ca1c72a572787214c735dd8e9967749840 | |
parent | 51197e523ee8f565d365d81e056001e989d9cfe2 (diff) | |
download | rt.equinox.bundles-6bfd9bef40482dd0e0766758bbdd1f29e562b99e.tar.gz rt.equinox.bundles-6bfd9bef40482dd0e0766758bbdd1f29e562b99e.tar.xz rt.equinox.bundles-6bfd9bef40482dd0e0766758bbdd1f29e562b99e.zip |
Bug 497435 - [http servlet] performance optimizations, CPU and memoryY20160825-1000I20160824-1429I20160823-1359I20160823-0759
https://issues.liferay.com/browse/LPS-66801
https://issues.liferay.com/browse/LPS-66813
https://issues.liferay.com/browse/LPS-66827
https://issues.liferay.com/browse/LPS-66847
https://issues.liferay.com/browse/LPS-66881
https://issues.liferay.com/browse/LPS-66903
https://issues.liferay.com/browse/LPS-66904
https://issues.liferay.com/browse/LPS-66908
https://issues.liferay.com/browse/LPS-66911
https://issues.liferay.com/browse/LPS-66959
Change-Id: I0374bfa5d566c2f01d34af57a64fd982b92ba4b8
Signed-off-by: shuyangzhou <shuyang.zhou@liferay.com>
Signed-off-by: Matthew Tambara <matthew.tambara@liferay.com>
Signed-off-by: Raymond Auge <raymond.auge@liferay.com>
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
8 files changed, 276 insertions, 155 deletions
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java index 9af775c60..2a15d8a4a 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java @@ -15,6 +15,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.AccessController; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; @@ -142,7 +144,7 @@ public class ContextController { this.trackingContext = trackingContextParam; this.consumingContext = consumingContext; - this.string = getClass().getSimpleName() + '[' + serviceId + "][" + contextName + ", " + consumingContext.getBundle() + ']'; //$NON-NLS-1$ + this.string = SIMPLE_NAME + '[' + serviceId + "][" + contextName + ", " + trackingContextParam.getBundle() + ']'; //$NON-NLS-1$ listenerServiceTracker = new ServiceTracker<EventListener, AtomicReference<ListenerRegistration>>( trackingContext, httpServiceRuntime.getListenerFilter(), @@ -1180,20 +1182,22 @@ public class ContextController { } private void flushActiveSessions() { - Collection<HttpSessionAdaptor> currentActiveSessions; - synchronized (activeSessions) { - currentActiveSessions = new ArrayList<HttpSessionAdaptor>(activeSessions.values()); - activeSessions.clear(); - } - for (HttpSessionAdaptor httpSessionAdaptor : currentActiveSessions) { + Collection<HttpSessionAdaptor> httpSessionAdaptors = + activeSessions.values(); + + Iterator<HttpSessionAdaptor> iterator = httpSessionAdaptors.iterator(); + + while (iterator.hasNext()) { + HttpSessionAdaptor httpSessionAdaptor = iterator.next(); + httpSessionAdaptor.invalidate(); + + iterator.remove(); } } public void removeActiveSession(HttpSession session) { - synchronized (activeSessions) { - activeSessions.remove(session); - } + activeSessions.remove(session.getId()); } public void fireSessionIdChanged(String oldSessionId) { @@ -1208,11 +1212,7 @@ public class ContextController { return; } - Collection<HttpSessionAdaptor> currentActiveSessions; - synchronized (activeSessions) { - currentActiveSessions = new ArrayList<HttpSessionAdaptor>(activeSessions.values()); - } - for (HttpSessionAdaptor httpSessionAdaptor : currentActiveSessions) { + for (HttpSessionAdaptor httpSessionAdaptor : activeSessions.values()) { HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSessionAdaptor); for (javax.servlet.http.HttpSessionIdListener listener : listeners) { listener.sessionIdChanged(httpSessionEvent, oldSessionId); @@ -1222,22 +1222,35 @@ public class ContextController { public HttpSessionAdaptor getSessionAdaptor( HttpSession session, ServletContext servletContext) { - boolean created = false; - HttpSessionAdaptor sessionAdaptor; - synchronized (activeSessions) { - sessionAdaptor = activeSessions.get(session); - if (sessionAdaptor == null) { - created = true; - sessionAdaptor = HttpSessionAdaptor.createHttpSessionAdaptor(session, servletContext, this); - activeSessions.put(session, sessionAdaptor); - } + + String sessionId = session.getId(); + + HttpSessionAdaptor httpSessionAdaptor = activeSessions.get(sessionId); + + if (httpSessionAdaptor != null) { + return httpSessionAdaptor; } - if (created) { - for (HttpSessionListener listener : eventListeners.get(HttpSessionListener.class)) { - listener.sessionCreated(new HttpSessionEvent(sessionAdaptor)); - } + + httpSessionAdaptor = HttpSessionAdaptor.createHttpSessionAdaptor( + session, servletContext, this); + + HttpSessionAdaptor previousHttpSessionAdaptor = + activeSessions.putIfAbsent(sessionId, httpSessionAdaptor); + + if (previousHttpSessionAdaptor != null) { + return previousHttpSessionAdaptor; + } + + HttpSessionEvent httpSessionEvent = new HttpSessionEvent( + httpSessionAdaptor); + + for (HttpSessionListener listener : eventListeners.get( + HttpSessionListener.class)) { + + listener.sessionCreated(httpSessionEvent); } - return sessionAdaptor; + + return httpSessionAdaptor; } private void validate(String preValidationContextName, String preValidationContextPath) { @@ -1261,6 +1274,8 @@ public class ContextController { private static final String[] DISPATCHER = new String[] {DispatcherType.REQUEST.toString()}; + private static final String SIMPLE_NAME = ContextController.class.getSimpleName(); + private static final Pattern contextNamePattern = Pattern.compile("^([a-zA-Z_0-9\\-]+\\.)*[a-zA-Z_0-9\\-]+$"); //$NON-NLS-1$ private final Map<String, String> initParams; @@ -1272,7 +1287,7 @@ public class ContextController { private final Set<EndpointRegistration<?>> endpointRegistrations = new ConcurrentSkipListSet<EndpointRegistration<?>>(); private final EventListeners eventListeners = new EventListeners(); private final Set<FilterRegistration> filterRegistrations = new ConcurrentSkipListSet<FilterRegistration>(); - private final Map<HttpSession, HttpSessionAdaptor> activeSessions = new HashMap<HttpSession, HttpSessionAdaptor>(); + private final ConcurrentMap<String, HttpSessionAdaptor> activeSessions = new ConcurrentHashMap<String, HttpSessionAdaptor>(); private final HttpServiceRuntimeImpl httpServiceRuntime; private final Set<ListenerRegistration> listenerRegistrations = new HashSet<ListenerRegistration>(); diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java index 903166f77..6e30ca04a 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/DispatchTargets.java @@ -54,8 +54,6 @@ public class DispatchTargets { this.servletPath = (servletPath == null) ? Const.BLANK : servletPath; this.pathInfo = pathInfo; this.queryString = queryString; - - this.string = SIMPLE_NAME + '[' + contextController.getFullContextPath() + requestURI + (queryString != null ? '?' + queryString : "") + ", " + endpointRegistration.toString() + ']'; //$NON-NLS-1$ //$NON-NLS-2$ } public void addRequestParameters(HttpServletRequest request) { @@ -197,7 +195,15 @@ public class DispatchTargets { @Override public String toString() { - return string; + String value = string; + + if (value == null) { + value = SIMPLE_NAME + '[' + contextController.getFullContextPath() + requestURI + (queryString != null ? '?' + queryString : "") + ", " + endpointRegistration.toString() + ']'; //$NON-NLS-1$ + + string = value; + } + + return value; } private static Map<String, String[]> queryStringToParameterMap(String queryString) { @@ -266,6 +272,6 @@ public class DispatchTargets { private final String servletPath; private final String servletName; private final Map<String, Object> specialOverides = new ConcurrentHashMap<String, Object>(); - private final String string; + private String string; }
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java index 067a04fc8..2c8e87d80 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/EndpointRegistration.java @@ -168,7 +168,19 @@ public abstract class EndpointRegistration<D extends DTO> @Override public String toString() { - return getClass().getSimpleName() + '[' + getD().toString() + ']'; + String toString = _toString; + + if (toString == null) { + toString = SIMPLE_NAME + '[' + getD().toString() + ']'; + + _toString = toString; + } + + return toString; } + private static final String SIMPLE_NAME = + EndpointRegistration.class.getSimpleName(); + + private String _toString; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java index 0df5d73a0..4e3e612f8 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java @@ -12,6 +12,11 @@ *******************************************************************************/ package org.eclipse.equinox.http.servlet.internal.registration; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.osgi.dto.DTO; public abstract class Registration<T, D extends DTO> { @@ -19,42 +24,82 @@ public abstract class Registration<T, D extends DTO> { private final D d; private final T t; - protected int referenceCount; + protected final AtomicInteger referenceCount = new AtomicInteger(); public Registration(T t, D d) { this.t = t; this.d = d; } - public synchronized void addReference() { - ++referenceCount; + public void addReference() { + readLock.lock(); + + try { + referenceCount.incrementAndGet(); + } + finally { + readLock.unlock(); + } } - public synchronized void removeReference() { - --referenceCount; - if (referenceCount == 0) { - notifyAll(); + public void removeReference() { + readLock.lock(); + + try { + if (referenceCount.decrementAndGet() == 0 && destroyed) { + readLock.unlock(); + + writeLock.lock(); + + try { + condition.signalAll(); + } + finally { + writeLock.unlock(); + + readLock.lock(); + } + } + } + finally { + readLock.unlock(); } } - public synchronized void destroy() { + public void destroy() { boolean interrupted = false; + + writeLock.lock(); + + destroyed = true; + try { - while (referenceCount != 0) { + while (referenceCount.get() != 0) { try { - (new Exception()).printStackTrace(); - wait(); - } catch (InterruptedException e) { - // wait until the servlet is inactive but save the interrupted status + condition.await(); + } + catch (InterruptedException ie) { interrupted = true; } } - } finally { - if (interrupted) - Thread.currentThread().interrupt(); //restore the interrupted state + } + finally { + writeLock.unlock(); + + if (interrupted) { + Thread.currentThread().interrupt(); + } } } + private volatile boolean destroyed; + + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + private final Lock readLock = readWriteLock.readLock(); + private final Lock writeLock = readWriteLock.writeLock(); + private final Condition condition = writeLock.newCondition(); + public D getD() { return d; } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java index 30f03be2e..6472681f1 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java @@ -32,24 +32,26 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { private Map<String, Part> parts; private final Lock lock = new ReentrantLock(); - private static final String[] dispatcherAttributes = new String[] { - RequestDispatcher.ERROR_EXCEPTION, - RequestDispatcher.ERROR_EXCEPTION_TYPE, - RequestDispatcher.ERROR_MESSAGE, - RequestDispatcher.ERROR_REQUEST_URI, - RequestDispatcher.ERROR_SERVLET_NAME, - RequestDispatcher.ERROR_STATUS_CODE, - RequestDispatcher.FORWARD_CONTEXT_PATH, - RequestDispatcher.FORWARD_PATH_INFO, - RequestDispatcher.FORWARD_QUERY_STRING, - RequestDispatcher.FORWARD_REQUEST_URI, - RequestDispatcher.FORWARD_SERVLET_PATH, - RequestDispatcher.INCLUDE_CONTEXT_PATH, - RequestDispatcher.INCLUDE_PATH_INFO, - RequestDispatcher.INCLUDE_QUERY_STRING, - RequestDispatcher.INCLUDE_REQUEST_URI, - RequestDispatcher.INCLUDE_SERVLET_PATH - }; + private static final Set<String> dispatcherAttributes = new HashSet<String>(); + + static { + dispatcherAttributes.add(RequestDispatcher.ERROR_EXCEPTION); + dispatcherAttributes.add(RequestDispatcher.ERROR_EXCEPTION_TYPE); + dispatcherAttributes.add(RequestDispatcher.ERROR_MESSAGE); + dispatcherAttributes.add(RequestDispatcher.ERROR_REQUEST_URI); + dispatcherAttributes.add(RequestDispatcher.ERROR_SERVLET_NAME); + dispatcherAttributes.add(RequestDispatcher.ERROR_STATUS_CODE); + dispatcherAttributes.add(RequestDispatcher.FORWARD_CONTEXT_PATH); + dispatcherAttributes.add(RequestDispatcher.FORWARD_PATH_INFO); + dispatcherAttributes.add(RequestDispatcher.FORWARD_QUERY_STRING); + dispatcherAttributes.add(RequestDispatcher.FORWARD_REQUEST_URI); + dispatcherAttributes.add(RequestDispatcher.FORWARD_SERVLET_PATH); + dispatcherAttributes.add(RequestDispatcher.INCLUDE_CONTEXT_PATH); + dispatcherAttributes.add(RequestDispatcher.INCLUDE_PATH_INFO); + dispatcherAttributes.add(RequestDispatcher.INCLUDE_QUERY_STRING); + dispatcherAttributes.add(RequestDispatcher.INCLUDE_REQUEST_URI); + dispatcherAttributes.add(RequestDispatcher.INCLUDE_SERVLET_PATH); + } public static HttpServletRequestWrapperImpl findHttpRuntimeRequest( HttpServletRequest request) { @@ -87,11 +89,13 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { } public String getPathInfo() { - if ((dispatchTargets.peek().getServletName() != null) || - (dispatchTargets.peek().getDispatcherType() == DispatcherType.INCLUDE)) { + DispatchTargets currentDispatchTargets = dispatchTargets.peek(); + + if ((currentDispatchTargets.getServletName() != null) || + (currentDispatchTargets.getDispatcherType() == DispatcherType.INCLUDE)) { return this.dispatchTargets.get(0).getPathInfo(); } - return this.dispatchTargets.peek().getPathInfo(); + return currentDispatchTargets.getPathInfo(); } public DispatcherType getDispatcherType() { @@ -120,20 +124,24 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { @Override public String getQueryString() { - if ((dispatchTargets.peek().getServletName() != null) || - (dispatchTargets.peek().getDispatcherType() == DispatcherType.INCLUDE)) { + DispatchTargets currentDispatchTargets = dispatchTargets.peek(); + + if ((currentDispatchTargets.getServletName() != null) || + (currentDispatchTargets.getDispatcherType() == DispatcherType.INCLUDE)) { return request.getQueryString(); } - return this.dispatchTargets.peek().getQueryString(); + return currentDispatchTargets.getQueryString(); } @Override public String getRequestURI() { - if ((dispatchTargets.peek().getServletName() != null) || - (dispatchTargets.peek().getDispatcherType() == DispatcherType.INCLUDE)) { + DispatchTargets currentDispatchTargets = dispatchTargets.peek(); + + if ((currentDispatchTargets.getServletName() != null) || + (currentDispatchTargets.getDispatcherType() == DispatcherType.INCLUDE)) { return request.getRequestURI(); } - return this.dispatchTargets.peek().getRequestURI(); + return currentDispatchTargets.getRequestURI(); } public ServletContext getServletContext() { @@ -141,14 +149,16 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { } public String getServletPath() { - if ((dispatchTargets.peek().getServletName() != null) || - (dispatchTargets.peek().getDispatcherType() == DispatcherType.INCLUDE)) { + DispatchTargets currentDispatchTargets = dispatchTargets.peek(); + + if ((currentDispatchTargets.getServletName() != null) || + (currentDispatchTargets.getDispatcherType() == DispatcherType.INCLUDE)) { return this.dispatchTargets.get(0).getServletPath(); } - if (dispatchTargets.peek().getServletPath().equals(Const.SLASH)) { + if (currentDispatchTargets.getServletPath().equals(Const.SLASH)) { return Const.BLANK; } - return this.dispatchTargets.peek().getServletPath(); + return currentDispatchTargets.getServletPath(); } public String getContextPath() { @@ -157,19 +167,20 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { public Object getAttribute(String attributeName) { DispatchTargets current = dispatchTargets.peek(); - + DispatcherType dispatcherType = current.getDispatcherType(); + boolean hasServletName = (current.getServletName() != null); Map<String, Object> specialOverides = current.getSpecialOverides(); - if (current.getDispatcherType() == DispatcherType.ERROR) { - if ((Arrays.binarySearch(dispatcherAttributes, attributeName) > -1) && + if (dispatcherType == DispatcherType.ERROR) { + if (dispatcherAttributes.contains(attributeName) && !attributeName.startsWith("javax.servlet.error.")) { //$NON-NLS-1$ return null; } } - else if (current.getDispatcherType() == DispatcherType.INCLUDE) { + else if (dispatcherType == DispatcherType.INCLUDE) { if (attributeName.equals(RequestDispatcher.INCLUDE_CONTEXT_PATH)) { - if (current.getServletName() != null) { + if (hasServletName) { return null; } if (specialOverides.containsKey(RequestDispatcher.INCLUDE_CONTEXT_PATH)) { @@ -178,7 +189,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return current.getContextController().getContextPath(); } else if (attributeName.equals(RequestDispatcher.INCLUDE_PATH_INFO)) { - if (current.getServletName() != null) { + if (hasServletName) { return null; } if (specialOverides.containsKey(RequestDispatcher.INCLUDE_PATH_INFO)) { @@ -187,7 +198,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return current.getPathInfo(); } else if (attributeName.equals(RequestDispatcher.INCLUDE_QUERY_STRING)) { - if (current.getServletName() != null) { + if (hasServletName) { return null; } if (specialOverides.containsKey(RequestDispatcher.INCLUDE_QUERY_STRING)) { @@ -196,7 +207,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return current.getQueryString(); } else if (attributeName.equals(RequestDispatcher.INCLUDE_REQUEST_URI)) { - if (current.getServletName() != null) { + if (hasServletName) { return null; } if (specialOverides.containsKey(RequestDispatcher.INCLUDE_REQUEST_URI)) { @@ -205,7 +216,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return current.getRequestURI(); } else if (attributeName.equals(RequestDispatcher.INCLUDE_SERVLET_PATH)) { - if (current.getServletName() != null) { + if (hasServletName) { return null; } if (specialOverides.containsKey(RequestDispatcher.INCLUDE_SERVLET_PATH)) { @@ -214,60 +225,49 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { return current.getServletPath(); } - if (Arrays.binarySearch(dispatcherAttributes, attributeName) > -1) { + if (dispatcherAttributes.contains(attributeName)) { return null; } } - else if (current.getDispatcherType() == DispatcherType.FORWARD) { + else if (dispatcherType == DispatcherType.FORWARD) { + if (hasServletName && attributeName.startsWith("javax.servlet.forward")) { + return null; + } + DispatchTargets original = dispatchTargets.get(0); if (attributeName.equals(RequestDispatcher.FORWARD_CONTEXT_PATH)) { - if (current.getServletName() != null) { - return null; - } if (specialOverides.containsKey(RequestDispatcher.FORWARD_CONTEXT_PATH)) { return specialOverides.get(RequestDispatcher.FORWARD_CONTEXT_PATH); } return original.getContextController().getContextPath(); } else if (attributeName.equals(RequestDispatcher.FORWARD_PATH_INFO)) { - if (current.getServletName() != null) { - return null; - } if (specialOverides.containsKey(RequestDispatcher.FORWARD_PATH_INFO)) { return specialOverides.get(RequestDispatcher.FORWARD_PATH_INFO); } return original.getPathInfo(); } else if (attributeName.equals(RequestDispatcher.FORWARD_QUERY_STRING)) { - if (current.getServletName() != null) { - return null; - } if (specialOverides.containsKey(RequestDispatcher.FORWARD_QUERY_STRING)) { return specialOverides.get(RequestDispatcher.FORWARD_QUERY_STRING); } return original.getQueryString(); } else if (attributeName.equals(RequestDispatcher.FORWARD_REQUEST_URI)) { - if (current.getServletName() != null) { - return null; - } if (specialOverides.containsKey(RequestDispatcher.FORWARD_REQUEST_URI)) { return specialOverides.get(RequestDispatcher.FORWARD_REQUEST_URI); } return original.getRequestURI(); } else if (attributeName.equals(RequestDispatcher.FORWARD_SERVLET_PATH)) { - if (current.getServletName() != null) { - return null; - } if (specialOverides.containsKey(RequestDispatcher.FORWARD_SERVLET_PATH)) { return specialOverides.get(RequestDispatcher.FORWARD_SERVLET_PATH); } return original.getServletPath(); } - if (Arrays.binarySearch(dispatcherAttributes, attributeName) > -1) { + if (dispatcherAttributes.contains(attributeName)) { return null; } } @@ -276,12 +276,14 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { } public RequestDispatcher getRequestDispatcher(String path) { + DispatchTargets currentDispatchTarget = dispatchTargets.peek(); + ContextController contextController = - this.dispatchTargets.peek().getContextController(); + currentDispatchTarget.getContextController(); // support relative paths if (!path.startsWith(Const.SLASH)) { - path = this.dispatchTargets.peek().getServletPath() + Const.SLASH + path; + path = currentDispatchTarget.getServletPath() + Const.SLASH + path; } // if the path starts with the full context path strip it else if (path.startsWith(contextController.getFullContextPath())) { @@ -305,20 +307,16 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { } public HttpSession getSession() { - HttpSession session = request.getSession(); - if (session != null) { - return dispatchTargets.peek().getContextController().getSessionAdaptor( - session, dispatchTargets.peek().getServletRegistration().getT().getServletConfig().getServletContext()); - } - - return null; + return getSession(true); } public HttpSession getSession(boolean create) { HttpSession session = request.getSession(create); if (session != null) { - return dispatchTargets.peek().getContextController().getSessionAdaptor( - session, dispatchTargets.peek().getServletRegistration().getT().getServletConfig().getServletContext()); + DispatchTargets currentDispatchTarget = dispatchTargets.peek(); + + return currentDispatchTarget.getContextController().getSessionAdaptor( + session, currentDispatchTarget.getServletRegistration().getT().getServletConfig().getServletContext()); } return null; @@ -336,7 +334,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { } public void removeAttribute(String name) { - if (Arrays.binarySearch(dispatcherAttributes, name) > -1) { + if (dispatcherAttributes.contains(name)) { DispatchTargets current = dispatchTargets.peek(); current.getSpecialOverides().remove(name); @@ -345,7 +343,9 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { request.removeAttribute(name); } - EventListeners eventListeners = dispatchTargets.peek().getContextController().getEventListeners(); + DispatchTargets currentDispatchTarget = dispatchTargets.peek(); + + EventListeners eventListeners = currentDispatchTarget.getContextController().getEventListeners(); List<ServletRequestAttributeListener> listeners = eventListeners.get( ServletRequestAttributeListener.class); @@ -356,7 +356,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { ServletRequestAttributeEvent servletRequestAttributeEvent = new ServletRequestAttributeEvent( - dispatchTargets.peek().getServletRegistration().getServletContext(), this, name, null); + currentDispatchTarget.getServletRegistration().getServletContext(), this, name, null); for (ServletRequestAttributeListener servletRequestAttributeListener : listeners) { servletRequestAttributeListener.attributeRemoved( @@ -367,7 +367,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { public void setAttribute(String name, Object value) { boolean added = (request.getAttribute(name) == null); - if (Arrays.binarySearch(dispatcherAttributes, name) > -1) { + if (dispatcherAttributes.contains(name)) { DispatchTargets current = dispatchTargets.peek(); if (value == null) { @@ -381,7 +381,9 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { request.setAttribute(name, value); } - EventListeners eventListeners = dispatchTargets.peek().getContextController().getEventListeners(); + DispatchTargets currentDispatchTarget = dispatchTargets.peek(); + + EventListeners eventListeners = currentDispatchTarget.getContextController().getEventListeners(); List<ServletRequestAttributeListener> listeners = eventListeners.get( ServletRequestAttributeListener.class); @@ -392,7 +394,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper { ServletRequestAttributeEvent servletRequestAttributeEvent = new ServletRequestAttributeEvent( - dispatchTargets.peek().getServletRegistration().getServletContext(), this, name, value); + currentDispatchTarget.getServletRegistration().getServletContext(), this, name, value); for (ServletRequestAttributeListener servletRequestAttributeListener : listeners) { if (added) { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java index 14212dd67..58ca6e53e 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java @@ -14,6 +14,7 @@ package org.eclipse.equinox.http.servlet.internal.servlet; import java.io.Serializable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContext; import javax.servlet.http.*; import org.eclipse.equinox.http.servlet.internal.context.ContextController; @@ -27,7 +28,7 @@ public class HttpSessionAdaptor implements HttpSession, Serializable { private static final long serialVersionUID = 4626167646903550760L; private static final String PARENT_SESSION_LISTENER_KEY = "org.eclipse.equinox.http.parent.session.listener"; //$NON-NLS-1$ - transient final Set<HttpSessionAdaptor> innerSessions = new HashSet<HttpSessionAdaptor>(); + transient final Set<HttpSessionAdaptor> innerSessions = Collections.newSetFromMap(new ConcurrentHashMap<HttpSessionAdaptor, Boolean>()); @Override public void valueBound(HttpSessionBindingEvent event) { // do nothing @@ -37,42 +38,64 @@ public class HttpSessionAdaptor implements HttpSession, Serializable { public void valueUnbound(HttpSessionBindingEvent event) { // Here we assume the unbound event is signifying the session is being invalidated. // Must invalidate the inner sessions - Set<HttpSessionAdaptor> innerSessionsToInvalidate; - synchronized (innerSessions) { - // copy the sessions to invalidate and clear the set - innerSessionsToInvalidate = new HashSet<HttpSessionAdaptor>(innerSessions); - innerSessions.clear(); - } - for (HttpSessionAdaptor innerSession : innerSessionsToInvalidate) { - innerSession.invalidate(); + Iterator<HttpSessionAdaptor> iterator = innerSessions.iterator(); + + while (iterator.hasNext()) { + HttpSessionAdaptor innerSession = iterator.next(); + + iterator.remove(); + + ContextController contextController = + innerSession.getController(); + + EventListeners eventListeners = + contextController.getEventListeners(); + + List<HttpSessionListener> httpSessionListeners = + eventListeners.get(HttpSessionListener.class); + + if (!httpSessionListeners.isEmpty()) { + HttpSessionEvent httpSessionEvent = new HttpSessionEvent( + innerSession); + + for (HttpSessionListener listener : httpSessionListeners) { + try { + listener.sessionDestroyed(httpSessionEvent); + } + catch (IllegalStateException ise) { + // outer session is already invalidated + } + } + } + + contextController.removeActiveSession( + innerSession.getSession()); } } static void addHttpSessionAdaptor(HttpSessionAdaptor innerSession) { + HttpSession httpSession = innerSession.getSession(); + ParentSessionListener parentListener; // need to have a global lock here because we must ensure that this is added only once - synchronized (ParentSessionListener.class) { - parentListener = (ParentSessionListener) innerSession.getSession().getAttribute(PARENT_SESSION_LISTENER_KEY); + synchronized (httpSession) { + parentListener = (ParentSessionListener) httpSession.getAttribute(PARENT_SESSION_LISTENER_KEY); if (parentListener == null) { parentListener = new ParentSessionListener(); - innerSession.getSession().setAttribute(PARENT_SESSION_LISTENER_KEY, parentListener); + httpSession.setAttribute(PARENT_SESSION_LISTENER_KEY, parentListener); } } - synchronized (parentListener.innerSessions) { - parentListener.innerSessions.add(innerSession); - } + + parentListener.innerSessions.add(innerSession); } static void removeHttpSessionAdaptor(HttpSessionAdaptor innerSession) { - ParentSessionListener parentListener; - // need to have a global lock here because we must ensure that this is added only once - synchronized (ParentSessionListener.class) { - parentListener = (ParentSessionListener) innerSession.getSession().getAttribute(PARENT_SESSION_LISTENER_KEY); - } + HttpSession httpSession = innerSession.getSession(); + + ParentSessionListener parentListener = (ParentSessionListener) httpSession.getAttribute(PARENT_SESSION_LISTENER_KEY); + if (parentListener != null) { - synchronized (parentListener.innerSessions) { - parentListener.innerSessions.remove(innerSession); - } + parentListener.innerSessions.remove(innerSession); } } } @@ -172,7 +195,7 @@ public class HttpSessionAdaptor implements HttpSession, Serializable { this.controller = controller; this.attributePrefix = "equinox.http." + controller.getContextName(); //$NON-NLS-1$ - this.string = getClass().getSimpleName() + '[' + session.getId() + ", " + attributePrefix + ']'; //$NON-NLS-1$ + this.string = SIMPLE_NAME + '[' + session.getId() + ", " + attributePrefix + ']'; //$NON-NLS-1$ } public ContextController getController() { @@ -317,4 +340,8 @@ public class HttpSessionAdaptor implements HttpSession, Serializable { public String toString() { return string; } + + private static final String SIMPLE_NAME = + HttpSessionAdaptor.class.getSimpleName(); + } diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/RequestDispatcherAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/RequestDispatcherAdaptor.java index c3791adfd..c07d8189e 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/RequestDispatcherAdaptor.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/RequestDispatcherAdaptor.java @@ -21,6 +21,8 @@ import org.eclipse.equinox.http.servlet.internal.context.DispatchTargets; //This class unwraps the request so it can be processed by the underlying servlet container. public class RequestDispatcherAdaptor implements RequestDispatcher { + private static final String SIMPLE_NAME = RequestDispatcherAdaptor.class.getSimpleName(); + private final DispatchTargets dispatchTargets; private final String path; private final String string; @@ -31,7 +33,7 @@ public class RequestDispatcherAdaptor implements RequestDispatcher { this.dispatchTargets = dispatchTargets; this.path = path; - this.string = getClass().getSimpleName() + '[' + path + ", " + dispatchTargets + ']'; //$NON-NLS-1$ + this.string = SIMPLE_NAME + '[' + path + ", " + dispatchTargets + ']'; //$NON-NLS-1$ } public void forward(ServletRequest request, ServletResponse response) diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java index 9eb656646..35a87d47a 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ServletContextAdaptor.java @@ -88,7 +88,7 @@ public class ServletContextAdaptor { this.classLoader = bundleWiring.getClassLoader(); - this.string = getClass().getSimpleName() + '[' + contextController + ']'; + this.string = SIMPLE_NAME + '[' + contextController + ']'; } public ServletContext createServletContext() { @@ -385,7 +385,13 @@ public class ServletContextAdaptor { } Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - servletContextTL.set((ServletContext)proxy); + boolean useThreadLocal = + "removeAttribute".equals(method.getName()) || + "setAttribute".equals(method.getName()); + + if (useThreadLocal) { + servletContextTL.set((ServletContext)proxy); + } try { Method m = contextToHandlerMethods.get(method); @@ -399,7 +405,9 @@ public class ServletContextAdaptor { } } finally { - servletContextTL.remove(); + if (useThreadLocal) { + servletContextTL.remove(); + } } } @@ -422,6 +430,11 @@ public class ServletContextAdaptor { } + private final static String SIMPLE_NAME = + ServletContextAdaptor.class.getSimpleName(); + + private final static ThreadLocal<ServletContext> servletContextTL = new ThreadLocal<ServletContext>(); + private final AccessControlContext acc; private final Bundle bundle; private final ClassLoader classLoader; @@ -430,7 +443,6 @@ public class ServletContextAdaptor { private final ProxyContext proxyContext; private final ServletContext servletContext; final ServletContextHelper servletContextHelper; - private final ThreadLocal<ServletContext> servletContextTL = new ThreadLocal<ServletContext>(); private final String string; } |