/******************************************************************************* * Copyright (c) 2014, 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.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.packagedrone.utils.AttributedValue; import org.eclipse.packagedrone.utils.Headers; 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TagLibTracker implements ResourceProvider { private final static Logger logger = LoggerFactory.getLogger ( TagLibTracker.class ); private final Set<String> systemTlds = new HashSet<> (); private final BundleTracker<TagLibInfo> bundleTracker; private final BundleTrackerCustomizer<TagLibInfo> customizer = new BundleTrackerCustomizer<TagLibInfo> () { @Override public TagLibInfo addingBundle ( final Bundle bundle, final BundleEvent event ) { return createTagLibInfo ( bundle ); } @Override public void modifiedBundle ( final Bundle bundle, final BundleEvent event, final TagLibInfo object ) { } @Override public void removedBundle ( final Bundle bundle, final BundleEvent event, final TagLibInfo object ) { } }; private final String mappedPrefix; private static class TagLibInfo { private final Map<String, URL> tlds; public TagLibInfo ( final Map<String, URL> tlds ) { this.tlds = tlds; } @Override public String toString () { return String.format ( "[TagLib - tlds: %s]", this.tlds ); } public Set<String> getEntries () { return this.tlds.keySet (); } public Map<String, URL> getTlds () { return this.tlds; } } public TagLibTracker ( final BundleContext context, String mappedPrefix ) { this.systemTlds.add ( "org.apache.taglibs.standard-impl" ); if ( mappedPrefix == null ) { mappedPrefix = "/WEB-INF/"; } this.mappedPrefix = mappedPrefix; this.bundleTracker = new BundleTracker<> ( context, Bundle.RESOLVED | Bundle.ACTIVE, this.customizer ); this.bundleTracker.open (); } @Override public void dispose () { this.bundleTracker.close (); } protected boolean fillFromExportHeader ( final Bundle bundle, final String headerName, final Map<String, URL> tlds ) { final String tldHeader = bundle.getHeaders ().get ( headerName ); if ( tldHeader == null ) { return false; } final List<AttributedValue> list = Headers.parseList ( tldHeader ); for ( final AttributedValue av : list ) { String tld = av.getValue (); if ( !tld.startsWith ( "/" ) ) { tld = "/" + tld; } final URL entry = bundle.getEntry ( tld ); if ( entry == null ) { logger.warn ( "Failed to resolve - {}", tld ); } else { final String key = makeKey ( tld ); logger.info ( "Found tag lib {} in bundle {} (as '{}')", tld, bundle, key ); tlds.put ( key, entry ); } } return true; } private boolean fillFromPlainBundle ( final Bundle bundle, final Map<String, URL> tlds ) { boolean added = false; final Enumeration<String> paths = bundle.getEntryPaths ( "/META-INF/" ); while ( paths.hasMoreElements () ) { final String name = paths.nextElement (); if ( name.endsWith ( ".tld" ) ) { final String key = makeKey ( name ); final URL entry = bundle.getEntry ( name ); if ( entry != null ) { logger.debug ( "Add plain mapping {} -> {} / {}", key, name, entry ); tlds.put ( key, entry ); added = true; } } } return added; } protected TagLibInfo createTagLibInfo ( final Bundle bundle ) { logger.trace ( "Checking for tag lib directories: {}", bundle ); final Map<String, URL> tlds = new HashMap<> (); if ( !fillFromExportHeader ( bundle, "Web-Export-Taglib", tlds ) ) { fillFromPlainBundle ( bundle, tlds ); } if ( tlds.isEmpty () ) { return null; } else { return new TagLibInfo ( tlds ); } } private static String makeKey ( final String tld ) { final String[] toks = tld.split ( "\\/" ); return toks[toks.length - 1]; } public void open () { this.bundleTracker.open (); } public void close () { this.bundleTracker.close (); } @Override public Set<String> getPaths ( final String path ) { if ( !path.equals ( this.mappedPrefix ) ) { return null; } final Set<String> result = new HashSet<> (); for ( final TagLibInfo tli : this.bundleTracker.getTracked ().values () ) { for ( final String name : tli.getEntries () ) { result.add ( this.mappedPrefix + name ); } } return result; } @Override public URL getResource ( final String name ) { logger.trace ( "Getting resource: {}", name ); if ( !name.startsWith ( this.mappedPrefix ) ) // FIXME: maybe remove trailing slash { return null; } final String tldName = name.substring ( this.mappedPrefix.length () ); for ( final TagLibInfo tli : this.bundleTracker.getTracked ().values () ) { final URL result = tli.getTlds ().get ( tldName ); if ( result != null ) { return result; } } return null; } }