View Javadoc

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