blob: 18050c7d6f6695d3cd1a4aaf77c8b99d6e01d6a4 [file] [log] [blame]
/**
* 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.openejb.server.httpd;
import org.apache.openejb.cdi.CdiAppContextsService;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.spi.SecurityService;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.spi.ContextsService;
import javax.enterprise.context.RequestScoped;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.Properties;
// its pupose is to start/stop request scope in async tasks
// and ensure logout is propagated to security service
public class EEFilter implements Filter {
private SecurityService securityService;
private boolean active;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
final SystemInstance si = SystemInstance.isInitialized() ? SystemInstance.get() : null;
final Properties config = si != null ? si.getProperties() : System.getProperties();
securityService = si != null ? si.getComponent(SecurityService.class) : null;
active = Boolean.parseBoolean(config.getProperty("tomee.http.request.wrap", "true"));
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final boolean shouldWrap = active && HttpServletRequest.class.isInstance(servletRequest);
if (!HttpServletRequest.class.isInstance(servletRequest)) {
filterChain.doFilter(shouldWrap ?
new NoCdiRequest(HttpServletRequest.class.cast(servletRequest), this) : servletRequest, servletResponse);
return;
}
WebBeansContext ctx;
filterChain.doFilter(servletRequest.isAsyncSupported() && (ctx = WebBeansContext.currentInstance()) != null ?
new CdiRequest(HttpServletRequest.class.cast(servletRequest), ctx, this) :
(shouldWrap ? new NoCdiRequest(HttpServletRequest.class.cast(servletRequest), this) : servletRequest),
servletResponse);
}
private void onLogout(final HttpServletRequest request) {
securityService.onLogout(request);
}
@Override
public void destroy() {
// no-op
}
public static class NoCdiRequest extends HttpServletRequestWrapper {
private final EEFilter filter;
public NoCdiRequest(final HttpServletRequest cast, final EEFilter filter) {
super(cast);
this.filter = filter;
}
@Override
public void logout() throws ServletException {
try {
super.logout();
} finally {
filter.onLogout(HttpServletRequest.class.cast(getRequest()));
}
}
}
public static class CdiRequest extends NoCdiRequest {
private final WebBeansContext webBeansContext;
public CdiRequest(final HttpServletRequest cast, final WebBeansContext webBeansContext, final EEFilter filter) {
super(cast, filter);
this.webBeansContext = webBeansContext;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
return new AsynContextWrapper(super.startAsync(), this, webBeansContext);
}
@Override
public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse) throws IllegalStateException {
return new AsynContextWrapper(super.startAsync(servletRequest, servletResponse), servletRequest, webBeansContext);
}
}
public static class AsynContextWrapper implements AsyncContext {
private final AsyncContext delegate;
private final CdiAppContextsService service;
private final ServletRequest request;
private volatile ServletRequestEvent event;
public AsynContextWrapper(final AsyncContext asyncContext, final ServletRequest request, final WebBeansContext webBeansContext) {
this.delegate = asyncContext;
this.service = CdiAppContextsService.class.cast(webBeansContext.getService(ContextsService.class));
this.event = null;
this.request = request;
}
private boolean startRequestScope() {
if (service.getRequestContext(false) == null) {
service.startContext(RequestScoped.class, getEvent());
return true;
}
return false;
}
private void stopRequestScope() {
service.endContext(RequestScoped.class, getEvent());
}
private ServletRequestEvent getEvent() {
final ServletRequest request = getRequest();
if (event == null || event.getServletRequest() != request) {
synchronized (this) {
if (event == null || event.getServletRequest() != request) {
event = new ServletRequestEvent(request.getServletContext(), request);
}
}
}
return event;
}
@Override
public ServletRequest getRequest() {
return request;
}
@Override
public ServletResponse getResponse() {
return delegate.getResponse();
}
@Override
public boolean hasOriginalRequestAndResponse() {
return delegate.hasOriginalRequestAndResponse();
}
@Override
public void dispatch() {
delegate.dispatch();
}
@Override
public void dispatch(final String s) {
delegate.dispatch(s);
}
@Override
public void dispatch(final ServletContext servletContext, final String s) {
delegate.dispatch(servletContext, s);
}
@Override
public void complete() {
final boolean created = startRequestScope();
try {
delegate.complete();
} finally {
if (created) {
stopRequestScope();
}
}
}
@Override
public void start(final Runnable runnable) {
delegate.start(new Runnable() {
@Override
public void run() {
startRequestScope();
try {
runnable.run();
} finally {
stopRequestScope();
}
}
});
}
@Override
public void addListener(final AsyncListener asyncListener) {
delegate.addListener(wrapListener(asyncListener));
}
private AsyncListener wrapListener(final AsyncListener asyncListener) {
return new ScopeAwareListener(asyncListener);
}
@Override
public void addListener(final AsyncListener asyncListener, final ServletRequest servletRequest, final ServletResponse servletResponse) {
delegate.addListener(wrapListener(asyncListener), servletRequest, servletResponse);
}
@Override
public <T extends AsyncListener> T createListener(final Class<T> aClass) throws ServletException {
return delegate.createListener(aClass);
}
@Override
public void setTimeout(final long l) {
delegate.setTimeout(l);
}
@Override
public long getTimeout() {
return delegate.getTimeout();
}
private class ScopeAwareListener implements AsyncListener {
private final AsyncListener delegate;
public ScopeAwareListener(final AsyncListener asyncListener) {
this.delegate = asyncListener;
}
@Override
public void onComplete(final AsyncEvent event) throws IOException {
final boolean created = startRequestScope();
try {
delegate.onComplete(event);
} finally {
if (created) {
stopRequestScope();
}
}
}
@Override
public void onTimeout(final AsyncEvent event) throws IOException {
final boolean created = startRequestScope();
try {
delegate.onTimeout(event);
} finally {
if (created) {
stopRequestScope();
}
}
}
@Override
public void onError(final AsyncEvent event) throws IOException {
final boolean created = startRequestScope();
try {
delegate.onError(event);
} finally {
if (created) {
stopRequestScope();
}
}
}
@Override
public void onStartAsync(final AsyncEvent event) throws IOException {
final boolean created = startRequestScope();
try {
delegate.onStartAsync(event);
} finally {
if (created) {
stopRequestScope();
}
}
}
}
}
}