1 /******************************************************************************* 2 * Copyright (c) 2005, 2016 Cognos Incorporated, IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Cognos Incorporated - initial API and implementation 13 * IBM Corporation - bug fixes and enhancements 14 * Raymond Augé <raymond.auge@liferay.com> - Bug 436698 15 * Juan Gonzalez <juan.gonzalez@liferay.com> - Bug 486412 16 *******************************************************************************/ 17 package org.eclipse.equinox.http.servlet.internal.servlet; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.lang.reflect.*; 22 import java.net.URL; 23 import java.security.*; 24 import java.util.*; 25 import javax.servlet.*; 26 import org.eclipse.equinox.http.servlet.internal.context.*; 27 import org.eclipse.equinox.http.servlet.internal.util.Const; 28 import org.eclipse.equinox.http.servlet.internal.util.EventListeners; 29 import org.osgi.framework.Bundle; 30 import org.osgi.framework.wiring.BundleWiring; 31 import org.osgi.service.http.context.ServletContextHelper; 32 33 public class ServletContextAdaptor { 34 35 private final static Map<Method, Method> contextToHandlerMethods; 36 37 static { 38 contextToHandlerMethods = createContextToHandlerMethods(); 39 } 40 createContextToHandlerMethods()41 private static Map<Method, Method> createContextToHandlerMethods() { 42 Map<Method, Method> methods = new HashMap<Method, Method>(); 43 Method[] handlerMethods = 44 ServletContextAdaptor.class.getDeclaredMethods(); 45 46 for (Method handlerMethod : handlerMethods) { 47 String name = handlerMethod.getName(); 48 Class<?>[] parameterTypes = handlerMethod.getParameterTypes(); 49 50 try { 51 Method method = ServletContext.class.getMethod( 52 name, parameterTypes); 53 methods.put(method, handlerMethod); 54 } 55 catch (NoSuchMethodException e) { 56 // do nothing 57 } 58 } 59 60 try { 61 Method equalsMethod = Object.class.getMethod("equals", Object.class); //$NON-NLS-1$ 62 Method equalsHandlerMethod = ServletContextAdaptor.class.getMethod("equals", Object.class); //$NON-NLS-1$ 63 methods.put(equalsMethod, equalsHandlerMethod); 64 65 Method hashCodeMethod = Object.class.getMethod("hashCode", (Class<?>[])null); //$NON-NLS-1$ 66 Method hashCodeHandlerMethod = ServletContextAdaptor.class.getMethod("hashCode", (Class<?>[])null); //$NON-NLS-1$ 67 methods.put(hashCodeMethod, hashCodeHandlerMethod); 68 } 69 catch (NoSuchMethodException e) { 70 // do nothing 71 } 72 73 return methods; 74 } 75 ServletContextAdaptor( ContextController contextController, Bundle bundle, ServletContextHelper servletContextHelper, EventListeners eventListeners, AccessControlContext acc)76 public ServletContextAdaptor( 77 ContextController contextController, Bundle bundle, 78 ServletContextHelper servletContextHelper, 79 EventListeners eventListeners, AccessControlContext acc) { 80 81 this.contextController = contextController; 82 this.proxyContext = contextController.getProxyContext(); 83 this.servletContext = proxyContext.getServletContext(); 84 this.servletContextHelper = servletContextHelper; 85 this.eventListeners = eventListeners; 86 this.acc = acc; 87 this.bundle = bundle; 88 89 BundleWiring bundleWiring = this.bundle.adapt(BundleWiring.class); 90 91 this.classLoader = bundleWiring.getClassLoader(); 92 } 93 createServletContext()94 public ServletContext createServletContext() { 95 Class<?> clazz = getClass(); 96 ClassLoader curClassLoader = clazz.getClassLoader(); 97 Class<?>[] interfaces = new Class[] {ServletContext.class}; 98 99 return (ServletContext)Proxy.newProxyInstance( 100 curClassLoader, interfaces, new AdaptorInvocationHandler()); 101 } 102 103 @Override equals(Object obj)104 public boolean equals (Object obj) { 105 if (!(obj instanceof ServletContext)) { 106 return false; 107 } 108 109 if (!(Proxy.isProxyClass(obj.getClass()))) { 110 return false; 111 } 112 113 InvocationHandler invocationHandler = Proxy.getInvocationHandler(obj); 114 115 if (!(invocationHandler instanceof AdaptorInvocationHandler)) { 116 return false; 117 } 118 119 AdaptorInvocationHandler adaptorInvocationHandler = (AdaptorInvocationHandler)invocationHandler; 120 121 return contextController.equals(adaptorInvocationHandler.getContextController()); 122 } 123 getClassLoader()124 public ClassLoader getClassLoader() { 125 return classLoader; 126 } 127 getContextPath()128 public String getContextPath() { 129 return contextController.getFullContextPath(); 130 } 131 getAttribute(String attributeName)132 public Object getAttribute(String attributeName) { 133 Dictionary<String, Object> attributes = getContextAttributes(); 134 135 if (attributeName.equals("osgi-bundlecontext")) { //$NON-NLS-1$ 136 return bundle.getBundleContext(); 137 } 138 139 return attributes.get(attributeName); 140 } 141 getAttributeNames()142 public Enumeration<String> getAttributeNames() { 143 Dictionary<String, Object> attributes = getContextAttributes(); 144 return attributes.keys(); 145 } 146 getInitParameter(String name)147 public String getInitParameter(String name) { 148 return contextController.getInitParams().get(name); 149 } 150 getInitParameterNames()151 public Enumeration<String> getInitParameterNames() { 152 return Collections.enumeration( 153 contextController.getInitParams().keySet()); 154 } 155 getMimeType(final String name)156 public String getMimeType(final String name) { 157 String mimeType = null; 158 159 try { 160 mimeType = AccessController.doPrivileged( 161 new PrivilegedExceptionAction<String>() { 162 @Override 163 public String run() throws Exception { 164 return servletContextHelper.getMimeType(name); 165 } 166 }, acc 167 ); 168 } 169 catch (PrivilegedActionException e) { 170 servletContext.log(e.getException().getMessage(), e.getException()); 171 } 172 173 return (mimeType != null) ? mimeType : servletContext.getMimeType(name); 174 } 175 getNamedDispatcher(String servletName)176 public RequestDispatcher getNamedDispatcher(String servletName) { 177 DispatchTargets dispatchTargets = contextController.getDispatchTargets( 178 servletName, null, null, null, null, null, Match.EXACT, null); 179 180 if (dispatchTargets == null) { 181 return null; 182 } 183 184 return new RequestDispatcherAdaptor(dispatchTargets, servletName); 185 } 186 getRealPath(final String path)187 public String getRealPath(final String path) { 188 try { 189 return AccessController.doPrivileged( 190 new PrivilegedExceptionAction<String>() { 191 @Override 192 public String run() throws Exception { 193 return servletContextHelper.getRealPath(path); 194 } 195 }, acc 196 ); 197 } 198 catch (PrivilegedActionException e) { 199 servletContext.log(e.getException().getMessage(), e.getException()); 200 } 201 202 return null; 203 } 204 205 public RequestDispatcher getRequestDispatcher(String path) { 206 // no relative paths supported, must begin with '/' 207 if (!path.startsWith(Const.SLASH)) { 208 return null; 209 } 210 // if the path starts with the full context path strip it 211 if (path.startsWith(contextController.getFullContextPath())) { 212 path = path.substring(contextController.getFullContextPath().length()); 213 } 214 215 DispatchTargets dispatchTargets = contextController.getDispatchTargets(path, null); 216 217 if (dispatchTargets == null) { 218 return null; 219 } 220 221 return new RequestDispatcherAdaptor(dispatchTargets, path); 222 } 223 224 public URL getResource(final String name) { 225 try { 226 return AccessController.doPrivileged( 227 new PrivilegedExceptionAction<URL>() { 228 @Override 229 public URL run() throws Exception { 230 return servletContextHelper.getResource(name); 231 } 232 }, acc 233 ); 234 } 235 catch (PrivilegedActionException e) { 236 servletContext.log(e.getException().getMessage(), e.getException()); 237 } 238 239 return null; 240 } 241 242 public InputStream getResourceAsStream(String name) { 243 URL url = getResource(name); 244 245 if (url != null) { 246 try { 247 return url.openStream(); 248 } 249 catch (IOException ioe) { 250 servletContext.log(ioe.getMessage(), ioe); 251 } 252 } 253 254 return null; 255 } 256 257 /** 258 * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) 259 */ 260 public Set<String> getResourcePaths(final String name) { 261 if (name == null || !name.startsWith(Const.SLASH)) 262 return null; 263 264 try { 265 return AccessController.doPrivileged( 266 new PrivilegedExceptionAction<Set<String>>() { 267 @Override 268 public Set<String> run() throws Exception { 269 return servletContextHelper.getResourcePaths(name); 270 } 271 }, acc 272 ); 273 } 274 catch (PrivilegedActionException e) { 275 servletContext.log(e.getException().getMessage(), e.getException()); 276 } 277 278 return null; 279 } 280 281 public String getServletContextName() { 282 return contextController.getContextName(); 283 } 284 285 @Override 286 public int hashCode() { 287 return contextController.hashCode(); 288 } 289 290 public void removeAttribute(String attributeName) { 291 Dictionary<String, Object> attributes = getContextAttributes(); 292 Object attributeValue = attributes.remove(attributeName); 293 294 List<ServletContextAttributeListener> listeners = 295 eventListeners.get(ServletContextAttributeListener.class); 296 297 if (listeners.isEmpty()) { 298 return; 299 } 300 301 ServletContextAttributeEvent servletContextAttributeEvent = 302 new ServletContextAttributeEvent( 303 servletContextTL.get(), attributeName, attributeValue); 304 305 for (ServletContextAttributeListener servletContextAttributeListener : listeners) { 306 servletContextAttributeListener.attributeRemoved( 307 servletContextAttributeEvent); 308 } 309 } 310 311 public void addFilter(String arg1, Class<? extends Filter> arg2) { 312 throw new UnsupportedOperationException(); 313 } 314 public void addFilter(String arg1, String arg2) { 315 throw new UnsupportedOperationException(); 316 } 317 public void addFilter(String arg1, Filter arg2) { 318 throw new UnsupportedOperationException(); 319 } 320 321 public void addListener(Class<?> arg1){ 322 throw new UnsupportedOperationException(); 323 } 324 public void addListener(String arg1){ 325 throw new UnsupportedOperationException(); 326 } 327 public void addListener(EventListener arg1){ 328 throw new UnsupportedOperationException(); 329 } 330 331 public void addServlet(String arg1, Class<? extends Servlet> arg2) { 332 throw new UnsupportedOperationException(); 333 } 334 public void addServlet(String arg1, String arg2) { 335 throw new UnsupportedOperationException(); 336 } 337 public void addServlet(String arg1, Servlet arg2) { 338 throw new UnsupportedOperationException(); 339 } 340 341 public void createFilter(Class<?> arg1) { 342 throw new UnsupportedOperationException(); 343 } 344 public void createServlet(Class<?> arg1) { 345 throw new UnsupportedOperationException(); 346 } 347 public void createListener(Class<?> arg1) { 348 throw new UnsupportedOperationException(); 349 } 350 351 public void declareRoles(String... arg1) { 352 throw new UnsupportedOperationException(); 353 } 354 355 public void setAttribute(String attributeName, Object attributeValue) { 356 if (attributeValue == null) { 357 removeAttribute(attributeName); 358 359 return; 360 } 361 362 Dictionary<String, Object> attributes = getContextAttributes(); 363 boolean added = (attributes.get(attributeName) == null); 364 attributes.put(attributeName, attributeValue); 365 366 List<ServletContextAttributeListener> listeners = 367 eventListeners.get(ServletContextAttributeListener.class); 368 369 if (listeners.isEmpty()) { 370 return; 371 } 372 373 ServletContextAttributeEvent servletContextAttributeEvent = 374 new ServletContextAttributeEvent( 375 servletContextTL.get(), attributeName, attributeValue); 376 377 for (ServletContextAttributeListener servletContextAttributeListener : listeners) { 378 if (added) { 379 servletContextAttributeListener.attributeAdded( 380 servletContextAttributeEvent); 381 } 382 else { 383 servletContextAttributeListener.attributeReplaced( 384 servletContextAttributeEvent); 385 } 386 } 387 } 388 389 @Override 390 public String toString() { 391 String value = string; 392 393 if (value == null) { 394 value = SIMPLE_NAME + '[' + contextController + ']'; 395 396 string = value; 397 } 398 399 return value; 400 } 401 402 Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 403 boolean useThreadLocal = 404 "removeAttribute".equals(method.getName()) || //$NON-NLS-1$ 405 "setAttribute".equals(method.getName()); //$NON-NLS-1$ 406 407 if (useThreadLocal) { 408 servletContextTL.set((ServletContext)proxy); 409 } 410 411 try { 412 Method m = contextToHandlerMethods.get(method); 413 try { 414 if (m != null) { 415 return m.invoke(this, args); 416 } 417 return method.invoke(servletContext, args); 418 } catch (InvocationTargetException e) { 419 throw e.getCause(); 420 } 421 } 422 finally { 423 if (useThreadLocal) { 424 servletContextTL.remove(); 425 } 426 } 427 } 428 429 private Dictionary<String, Object> getContextAttributes() { 430 return proxyContext.getContextAttributes(contextController); 431 } 432 433 private class AdaptorInvocationHandler implements InvocationHandler { 434 public AdaptorInvocationHandler() {} 435 436 public ContextController getContextController() { 437 return contextController; 438 } 439 440 @Override 441 public Object invoke(Object proxy, Method method, Object[] args) 442 throws Throwable { 443 444 return ServletContextAdaptor.this.invoke(proxy, method, args); 445 } 446 447 } 448 449 private final static String SIMPLE_NAME = 450 ServletContextAdaptor.class.getSimpleName(); 451 452 private final static ThreadLocal<ServletContext> servletContextTL = new ThreadLocal<ServletContext>(); 453 454 private final AccessControlContext acc; 455 private final Bundle bundle; 456 private final ClassLoader classLoader; 457 final ContextController contextController; 458 private final EventListeners eventListeners; 459 private final ProxyContext proxyContext; 460 private final ServletContext servletContext; 461 final ServletContextHelper servletContextHelper; 462 private String string; 463 464 } 465