package edu.mayo.cts2.framework.webapp.rest.osgi; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; 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.apache.commons.lang.StringUtils; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import edu.mayo.cts2.framework.core.plugin.ExtensionPoint; import edu.mayo.cts2.framework.core.plugin.PluginManager; public class OsgiExtensionPointFilterProxy implements Filter, ExtensionPoint { private ServiceTracker osgiFilterTracker; private FilterConfig filterConfig; public final static String ORDER_PROPERTY = "ORDER"; public final static String ORDER_FIRST = "FIRST"; public final static String ORDER_LAST = "LAST"; private static Comparator<ServiceReference> SERVICE_REF_COMPARATOR = new Comparator<ServiceReference>(){ @Override public int compare(ServiceReference o1, ServiceReference o2) { String prop1 = (String)o1.getProperty(ORDER_PROPERTY); String prop2 = (String)o2.getProperty(ORDER_PROPERTY); if(prop1 == null && prop2 == null){ return 0; } else if(StringUtils.equalsIgnoreCase(prop1, prop2)){ throw new IllegalStateException("More than one Filter registered with ORDER: " + prop1); } else if(StringUtils.equals(prop1, ORDER_FIRST) || StringUtils.equals(prop2, ORDER_LAST) ){ return -1; } else if(StringUtils.equals(prop2, ORDER_FIRST) || StringUtils.equals(prop1, ORDER_LAST) ){ return 1; } throw new IllegalStateException("Illegal Filter ORDER combination."); } }; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; PluginManager pluginManager = (PluginManager) filterConfig .getServletContext() .getAttribute(PluginManager.class.getName()); pluginManager.registerExtensionPoint(this); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServiceReference[] refs = this.osgiFilterTracker.getServiceReferences(); FilterChain chainToUse; if (refs != null && refs.length > 0) { Arrays.sort(refs, SERVICE_REF_COMPARATOR); Filter[] filters = new Filter[refs.length]; for(int i=0;i<refs.length;i++) { filters[i] = (Filter) this.osgiFilterTracker.getService(refs[i]); } chainToUse = new DelegatingFilterChain( chain, filters); } else { chainToUse = chain; } chainToUse.doFilter(request, response); } @Override public void destroy() { Object[] filters = (Object[]) this.osgiFilterTracker.getServices(); if(filters != null){ for (Object filter : filters) { ( (Filter)filter ).destroy(); } } this.osgiFilterTracker.close(); } protected Filter[] getTrackedFilters() { return (Filter[]) this.osgiFilterTracker.getServices(); } @Override public Class<?> getServiceClass() { return Filter.class; } @Override public void setServiceTracker(ServiceTracker serviceTracker) { this.osgiFilterTracker = serviceTracker; } @Override public ServiceTrackerCustomizer addServiceTrackerCustomizer() { return new ServiceTrackerCustomizer() { @Override public Object addingService(ServiceReference reference) { Filter service = (Filter) reference.getBundle() .getBundleContext().getService(reference); try { service.init(filterConfig); } catch (ServletException e) { throw new IllegalStateException(e); } return service; } @Override public void modifiedService(ServiceReference reference, Object service) { // } @Override public void removedService(ServiceReference reference, Object service) { ((Filter) service).destroy(); } }; } }