Skip to main content
summaryrefslogblamecommitdiffstats
blob: 9ae3fb7f3d2d6643598c5377d1d2f1e6275ae74a (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                                                           
                                        








                                                                           






                                                                           
                                                       
                                      
                                 
                                      


                                                     

   

                                                                            

                                                  


                               


        




                                                                               
       



                                                                                

                      
   

                                                                            
 





















                                                                                    














                                                                        
         
 

                                                                                
           








                                                                                    
           





                                                                                    







                                                                                               
         
 
























                                                                                    




                                                                                                  
                                                                                                                                    

                                                                    



                                                                                                               





                                                                                                         
                            


                               
                                                                                                            
                                                                                             







                                                                                                          
                             














                                                                                
                        






                                                                          
                                                                                                  
             
                                                 








                                                                              
                                                                                      


                                                                                            
                            




                                                  
                                                                                             



             
                                                                                                     



                                                                                             


                                          











                                                                            
                                                                         







                                                      
    







                                                                             


        
 
// ========================================================================
// Copyright (c) 2009-2010 Intalio, Inc.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at 
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses. 
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;

import java.net.URL;
import java.util.Dictionary;

import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.util.log.Log;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;


/**
 * Support bundles that declare the webapp directly through headers in their
 * manifest.
 * <p>
 * Those headers will define a new WebApplication:
 * <ul>
 * <li>Web-ContextPath</li>
 * <li>Jetty-WarFolderPath</li>
 * </ul>
 * </p>
 * <p>
 * Those headers will define a new app started via a jetty-context or a list of
 * them. ',' column is the separator between the various context files.
 * <ul>
 * <li>Jetty-ContextFilePath</li>
 * </ul>
 * </p>
 * And generate a jetty WebAppContext or another ContextHandler then registers
 * it as service. Kind of simpler than declarative services and their xml files.
 * Also avoid having the contributing bundle depend on jetty's package for
 * WebApp.
 * 
 * @author hmalphettes
 */
public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
	

	/**
	 * A bundle is being added to the <code>BundleTracker</code>.
	 * 
	 * <p>
	 * This method is called before a bundle which matched the search parameters
	 * of the <code>BundleTracker</code> is added to the
	 * <code>BundleTracker</code>. This method should return the object to be
	 * tracked for the specified <code>Bundle</code>. The returned object is
	 * stored in the <code>BundleTracker</code> and is available from the
	 * {@link BundleTracker#getObject(Bundle) getObject} method.
	 * 
	 * @param bundle The <code>Bundle</code> being added to the
	 *        <code>BundleTracker</code>.
	 * @param event The bundle event which caused this customizer method to be
	 *        called or <code>null</code> if there is no bundle event associated
	 *        with the call to this method.
	 * @return The object to be tracked for the specified <code>Bundle</code>
	 *         object or <code>null</code> if the specified <code>Bundle</code>
	 *         object should not be tracked.
	 */
	public Object addingBundle(Bundle bundle, BundleEvent event)
	{
		if (bundle.getState() == Bundle.ACTIVE)
		{
			boolean isWebBundle = register(bundle);
			return isWebBundle ? bundle : null;
		}
		else if (bundle.getState() == Bundle.STOPPING)
		{
			unregister(bundle);
		}
		else
		{
			//we should not be called in that state as
			//we are registered only for ACTIVE and STOPPING
		}
		return null;
	}

	/**
	 * A bundle tracked by the <code>BundleTracker</code> has been modified.
	 * 
	 * <p>
	 * This method is called when a bundle being tracked by the
	 * <code>BundleTracker</code> has had its state modified.
	 * 
	 * @param bundle The <code>Bundle</code> whose state has been modified.
	 * @param event The bundle event which caused this customizer method to be
	 *        called or <code>null</code> if there is no bundle event associated
	 *        with the call to this method.
	 * @param object The tracked object for the specified bundle.
	 */
	public void modifiedBundle(Bundle bundle, BundleEvent event,
			Object object)
	{
		//nothing the web-bundle was already track. something changed.
		//we only reload the webapps if the bundle is stopped and restarted.
//		System.err.println(bundle.getSymbolicName());
		if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
		{
			unregister(bundle);
		}
		if (bundle.getState() == Bundle.ACTIVE)
		{
			register(bundle);
		}
	}

	/**
	 * A bundle tracked by the <code>BundleTracker</code> has been removed.
	 * 
	 * <p>
	 * This method is called after a bundle is no longer being tracked by the
	 * <code>BundleTracker</code>.
	 * 
	 * @param bundle The <code>Bundle</code> that has been removed.
	 * @param event The bundle event which caused this customizer method to be
	 *        called or <code>null</code> if there is no bundle event associated
	 *        with the call to this method.
	 * @param object The tracked object for the specified bundle.
	 */
	public void removedBundle(Bundle bundle, BundleEvent event,
			Object object)
	{
		unregister(bundle);
	}
	
	
	/**
	 * @param bundle
	 * @return true if this bundle in indeed a web-bundle.
	 */
    private boolean register(Bundle bundle)
    {
        Dictionary<?, ?> dic = bundle.getHeaders();
        String warFolderRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
        if (warFolderRelativePath != null)
        {
            String contextPath = getWebContextPath(bundle, dic, false);//(String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
            if (contextPath == null || !contextPath.startsWith("/"))
            {
            	Log.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH +
                		": " + warFolderRelativePath + "' in the bundle " + bundle.getSymbolicName() + 
                		" is not valid: there is no Web-ContextPath defined in the manifest.");
            	return false;
            }
            // create the corresponding service and publish it in the context of
            // the contributor bundle.
            try
            {
                JettyBootstrapActivator.registerWebapplication(bundle,warFolderRelativePath,contextPath);
                return true;
            }
            catch (Throwable e)
            {
            	Log.warn("Starting the web-bundle " + bundle.getSymbolicName() + " threw an exception.", e);
                return true;//maybe it did not work maybe it did. safer to track this bundle.
            }
        }
        else if (dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH) != null)
        {
            String contextFileRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
            if (contextFileRelativePath == null)
            {
                // nothing to register here.
                return false;
            }
            // support for multiple webapps in the same bundle:
            String[] pathes = contextFileRelativePath.split(",;");
            for (String path : pathes)
            {
                try
                {
                    JettyBootstrapActivator.registerContext(bundle,path.trim());
                }
                catch (Throwable e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return true;
        }
        else
        {
            // support for OSGi-RFC66; disclaimer, no access to the actual
            // (draft) of the spec: just a couple of posts on the
            // world-wide-web.
            URL rfc66Webxml = bundle.getEntry("/WEB-INF/web.xml");
            if (rfc66Webxml == null && dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) == null)
            {
                return false;// no webapp in here
            }
            // this is risky: should we make sure that there is no classes and
            // jars directly available
            // at the root of the of the bundle: otherwise they are accessible
            // through the browser. we should enforce that the whole classpath
            // is
            // pointing to files and folders inside WEB-INF. We should
            // filter-out
            // META-INF too
            String rfc66ContextPath = getWebContextPath(bundle,dic,rfc66Webxml==null);
            try
            {
                JettyBootstrapActivator.registerWebapplication(bundle,".",rfc66ContextPath);
                return true;
            }
            catch (Throwable e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return true;//maybe it did not work maybe it did. safer to track this bundle.
            }
        }
    }

    private String getWebContextPath(Bundle bundle, Dictionary<?, ?> dic, boolean webinfWebxmlExists)
    {
        String rfc66ContextPath = (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
        if (rfc66ContextPath == null)
        {
        	if (!webinfWebxmlExists) {
        		return null;
        	}
            // extract from the last token of the bundle's location:
            // (really ?
            // could consider processing the symbolic name as an alternative
            // the location will often reflect the version.
            // maybe this is relevant when the file is a war)
            String location = bundle.getLocation();
            String toks[] = location.replace('\\','/').split("/");
            rfc66ContextPath = toks[toks.length - 1];
            // remove .jar, .war etc:
            int lastDot = rfc66ContextPath.lastIndexOf('.');
            if (lastDot != -1)
            {
            	rfc66ContextPath = rfc66ContextPath.substring(0,lastDot);
            }
        }
        if (!rfc66ContextPath.startsWith("/"))
        {
            rfc66ContextPath = "/" + rfc66ContextPath;
        }
        return rfc66ContextPath;
    }
    
    private void unregister(Bundle bundle)
    {
        // nothing to do: when the bundle is stopped, each one of its service
        // reference is also stopped and that is what we use to stop the
        // corresponding
        // webapps registered in that bundle.
    }


	
	
}

Back to the top