/*******************************************************************************
* Copyright (c) 2015 IBH SYSTEMS GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBH SYSTEMS GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.packagedrone.web.dispatcher.internal;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FilterTracker implements Filter
{
private final static Logger logger = LoggerFactory.getLogger ( FilterTracker.TrackedFilter.class );
public static class TrackedFilter
{
private final Filter filter;
private final ServiceReference<Filter> reference;
private final BundleContext context;
public TrackedFilter ( final BundleContext context, final Filter filter, final ServiceReference<Filter> reference )
{
this.filter = filter;
this.context = context;
this.reference = reference;
}
public void doFilter ( final ServletRequest request, final ServletResponse response, final FilterChain filterChain ) throws IOException, ServletException
{
this.filter.doFilter ( request, response, filterChain );
}
public void dispose ()
{
this.context.ungetService ( this.reference );
}
}
private final ServiceTracker<Filter, TrackedFilter> tracker;
private BundleContext context;
private TrackedFilter[] filters = null;
public FilterTracker ( final BundleContext context )
{
this.context = context;
this.tracker = new ServiceTracker<> ( context, Filter.class, new ServiceTrackerCustomizer<Filter, TrackedFilter> () {
@Override
public TrackedFilter addingService ( final ServiceReference<Filter> reference )
{
return addFilter ( reference );
}
@Override
public void modifiedService ( final ServiceReference<Filter> reference, final TrackedFilter service )
{
}
@Override
public void removedService ( final ServiceReference<Filter> reference, final TrackedFilter service )
{
service.dispose ();
FilterTracker.this.filters = null; // reset cache
}
} );
}
protected TrackedFilter addFilter ( final ServiceReference<Filter> reference )
{
final Filter filter = this.context.getService ( reference );
this.filters = null; // reset cache
return new TrackedFilter ( this.context, filter, reference );
}
@Override
public void doFilter ( final ServletRequest request, final ServletResponse response, final FilterChain filterChain ) throws IOException, ServletException
{
TrackedFilter[] localFilters;
synchronized ( this )
{
if ( this.filters == null )
{
this.filters = this.tracker.getServices ( new TrackedFilter[0] );
}
localFilters = this.filters;
}
doRunFilter ( localFilters, 0, request, response, filterChain );
}
private void doRunFilter ( final TrackedFilter[] localFilters, final int i, final ServletRequest request, final ServletResponse response, final FilterChain lastFilterChain ) throws IOException, ServletException
{
if ( i < localFilters.length )
{
// recurse
localFilters[i].doFilter ( request, response, new FilterChain () {
@Override
public void doFilter ( final ServletRequest chainRequest, final ServletResponse chainResponse ) throws IOException, ServletException
{
doRunFilter ( localFilters, i + 1, chainRequest, chainResponse, lastFilterChain );
}
} );
}
else
{
// abort
lastFilterChain.doFilter ( request, response );
}
}
@Override
public void init ( final FilterConfig filterConfig ) throws ServletException
{
logger.info ( "Open tracker" );
this.tracker.open ();
}
@Override
public void destroy ()
{
logger.info ( "Close tracker" );
this.tracker.close ();
}
}