/******************************************************************************* * Copyright (c) 2014 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.resources; import java.net.URL; import java.util.LinkedList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.packagedrone.utils.AttributedValue; import org.eclipse.packagedrone.utils.Headers; import org.eclipse.packagedrone.web.RequestHandler; import org.eclipse.packagedrone.web.RequestHandlerFactory; import org.eclipse.packagedrone.web.ResourceRequestHandler; import org.eclipse.packagedrone.web.util.Requests; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; public class ResourceTracker implements RequestHandlerFactory { private final org.osgi.util.tracker.BundleTracker<ResourceHandlerProvider> tracker; private static class CompositeResourceEntry implements ResourceHandlerProvider { private final List<ResourceHandlerProvider> providers; public CompositeResourceEntry ( final List<ResourceHandlerProvider> providers ) { this.providers = providers; } @Override public RequestHandler findHandler ( final String requestPath ) { for ( final ResourceHandlerProvider provider : this.providers ) { final RequestHandler resource = provider.findHandler ( requestPath ); if ( resource != null ) { return resource; } } return null; } } private static class ResourceEntry implements ResourceHandlerProvider { private final Bundle bundle; private final String prefix; private final String target; public ResourceEntry ( final Bundle bundle, final String prefix, final String target ) { this.bundle = bundle; this.prefix = prefix; this.target = target; } @Override public RequestHandler findHandler ( final String requestPath ) { if ( !requestPath.startsWith ( this.target ) ) { return null; } final String entryName = this.prefix + requestPath.substring ( this.target.length () ); final URL entry = this.bundle.getEntry ( entryName ); return new ResourceRequestHandler ( entry, this.bundle.getLastModified () ); } } private final BundleTrackerCustomizer<ResourceHandlerProvider> customizer = new BundleTrackerCustomizer<ResourceHandlerProvider> () { @Override public void removedBundle ( final Bundle bundle, final BundleEvent event, final ResourceHandlerProvider object ) { } @Override public void modifiedBundle ( final Bundle bundle, final BundleEvent event, final ResourceHandlerProvider object ) { } @Override public ResourceHandlerProvider addingBundle ( final Bundle bundle, final BundleEvent event ) { final List<ResourceHandlerProvider> entries = new LinkedList<> (); { final String resources = bundle.getHeaders ().get ( "Web-Static-Resources" ); final List<AttributedValue> result = Headers.parseList ( resources ); if ( result != null ) { for ( final AttributedValue av : result ) { final String prefix = av.getValue (); String target = av.getAttributes ().get ( "target" ); if ( target == null ) { target = prefix; } entries.add ( new ResourceEntry ( bundle, prefix, target ) ); } } } if ( entries.isEmpty () ) { return null; } else if ( entries.size () == 1 ) { return entries.get ( 0 ); } else { return new CompositeResourceEntry ( entries ); } } }; public ResourceTracker ( final BundleContext context ) { this.tracker = new BundleTracker<> ( context, Bundle.ACTIVE | Bundle.INSTALLED, this.customizer ); this.tracker.open (); } @Override public void close () { this.tracker.close (); } @Override public RequestHandler handleRequest ( final HttpServletRequest request, final HttpServletResponse response ) { final String method = request.getMethod ().toUpperCase (); if ( ! ( method.equals ( "GET" ) || method.equals ( "HEAD" ) ) ) { return null; } final String requestPath = Requests.getRequestPath ( request ); for ( final ResourceHandlerProvider entry : this.tracker.getTracked ().values () ) { final RequestHandler handler = entry.findHandler ( requestPath ); if ( handler != null ) { return handler; } } return null; } }