View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.osgi.boot.internal.webapp;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Map.Entry;
29  
30  import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
31  import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
32  import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
33  import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
34  import org.eclipse.jetty.osgi.boot.ServiceProvider;
35  import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
36  import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
37  import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
38  import org.eclipse.jetty.server.handler.ContextHandler;
39  import org.eclipse.jetty.util.log.Log;
40  import org.eclipse.jetty.util.log.Logger;
41  import org.eclipse.jetty.util.Scanner;
42  import org.eclipse.jetty.webapp.WebAppContext;
43  import org.osgi.framework.Bundle;
44  import org.osgi.framework.BundleContext;
45  import org.osgi.framework.FrameworkUtil;
46  import org.osgi.framework.ServiceEvent;
47  import org.osgi.framework.ServiceListener;
48  import org.osgi.framework.ServiceReference;
49  import org.osgi.util.tracker.ServiceTracker;
50  
51  /**
52   * JettyContextHandlerServiceTracker
53   * 
54   * When a {@link ContextHandler} is activated as an osgi service we find a jetty deployer
55   * for it. The ContextHandler could be either a WebAppContext or any other derivative of 
56   * ContextHandler.
57   * 
58   * ContextHandlers and WebApps can also be deployed into jetty without creating them as
59   * osgi services. Instead, they can be deployed via manifest headers inside bundles. See
60   * {@link WebBundleTrackerCustomizer}.
61   */
62  public class JettyContextHandlerServiceTracker implements ServiceListener
63  {
64      private static Logger LOG = Log.getLogger(JettyContextHandlerServiceTracker.class);
65      
66      public static final String FILTER = "(objectclass=" + ServiceProvider.class.getName() + ")";
67  
68      
69      //track all instances of deployers of webapps as bundles       
70      ServiceTracker _serviceTracker;
71      
72      
73       
74      /* ------------------------------------------------------------ */
75      /**
76       * @param registry
77       */
78      public JettyContextHandlerServiceTracker() throws Exception
79      {
80          //track all instances of deployers of webapps
81          Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
82          _serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
83          _serviceTracker.open();
84      }
85  
86  
87     
88      /* ------------------------------------------------------------ */
89      /**
90       * @param managedServerName
91       * @return
92       */
93      public Map<ServiceReference, ServiceProvider> getDeployers(String managedServerName)
94      {
95          if (managedServerName == null)
96              managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
97          
98          Map<ServiceReference, ServiceProvider> candidates = new HashMap<ServiceReference, ServiceProvider>();
99          
100         ServiceReference[] references = _serviceTracker.getServiceReferences();
101         if (references != null)
102         {
103             for (ServiceReference ref:references)
104             {
105                 String name = (String)ref.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
106                 if (managedServerName.equalsIgnoreCase(name))
107                 {
108                     ServiceProvider candidate = (ServiceProvider)_serviceTracker.getService(ref);
109                     if (candidate != null)
110                         candidates.put(ref, candidate);
111                 }
112             }
113         }
114        return candidates;
115     }
116 
117     /* ------------------------------------------------------------ */
118     /**
119      * Receives notification that a service has had a lifecycle change.
120      * 
121      * @param ev The <code>ServiceEvent</code> object.
122      */
123     /** 
124      * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
125      */
126     public void serviceChanged(ServiceEvent ev)
127     {
128         ServiceReference sr = ev.getServiceReference();
129         switch (ev.getType())
130         {
131             case ServiceEvent.MODIFIED:
132             case ServiceEvent.UNREGISTERING:
133             {
134                 BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
135                 ContextHandler contextHandler = (ContextHandler) context.getService(sr);
136               
137                 //if this was not a service that another of our deployers may have deployed (in which case they will undeploy it)
138                 String watermark = (String)sr.getProperty(OSGiWebappConstants.WATERMARK);
139                 if (watermark != null && !"".equals(watermark))
140                 {
141                     //Get a jetty deployer targetted to the named server instance, or the default one if not named
142                     String serverName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);    
143                     Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
144                     if (candidates != null)
145                     {
146                         boolean removed = false;
147                         Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
148                         while (!removed && itor.hasNext())
149                         {
150                             Entry<ServiceReference, ServiceProvider> e = itor.next();
151                             try
152                             {
153                                 removed = e.getValue().serviceRemoved(sr, contextHandler);
154                             }
155                             catch (Exception x)
156                             {
157                                 LOG.warn("Error undeploying service representing jetty context ", x);
158                             }
159                         }
160                     }
161                 }
162             }
163             if (ev.getType() == ServiceEvent.UNREGISTERING)
164             {
165                 break;
166             }
167             else
168             {
169                 // modified, meaning: we reload it. now that we stopped it;
170                 // we can register it.
171             }
172             case ServiceEvent.REGISTERED:
173             {
174                 Bundle contributor = sr.getBundle();
175                 BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
176                 ContextHandler contextHandler = (ContextHandler) context.getService(sr);
177                 if (contextHandler.getServer() != null)
178                 {
179                     // is configured elsewhere.
180                     return;
181                 }
182                 String watermark = (String)sr.getProperty(OSGiWebappConstants.WATERMARK);
183                 if (watermark != null && !"".equals(watermark))
184                     return; //another of our deployers is responsible for handling service registrations for this context
185                 
186                 //Get a jetty deployer targetted to the named server instance, or the default one if not named
187                 String serverName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);    
188                 Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
189                 if (candidates != null)
190                 {
191                     boolean added = false;
192                     Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
193                     while (!added && itor.hasNext())
194                     {
195                         Entry<ServiceReference, ServiceProvider> e = itor.next();
196                         try
197                         {
198                             added = e.getValue().serviceAdded(sr, contextHandler);
199                             if (added && LOG.isDebugEnabled())
200                                 LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
201                         }
202                         catch (Exception x)
203                         {
204                             LOG.warn("Error deploying service representing jetty context", x);
205                         }
206                     }
207                 }
208                 break;
209             }
210         }
211     }
212 }