View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.ServiceReference;
37  import org.osgi.util.tracker.ServiceTracker;
38  import org.osgi.util.tracker.ServiceTrackerCustomizer;
39  
40  /**
41   * ServiceWatcher
42   * 
43   * When a {@link ContextHandler} is activated as an osgi service we find a jetty deployer
44   * for it. The ContextHandler could be either a WebAppContext or any other derivative of 
45   * ContextHandler.
46   * 
47   * ContextHandlers and WebApps can also be deployed into jetty without creating them as
48   * osgi services. Instead, they can be deployed via manifest headers inside bundles. See
49   * {@link BundleWatcher}.
50   */
51  public class ServiceWatcher implements ServiceTrackerCustomizer
52  {
53      private static Logger LOG = Log.getLogger(ServiceWatcher.class);
54      
55      public static final String FILTER = "(objectclass=" + ServiceProvider.class.getName() + ")";
56  
57      
58      //track all instances of deployers of webapps as bundles       
59      ServiceTracker _serviceTracker;
60      
61      
62       
63      /* ------------------------------------------------------------ */
64      /**
65       * @param registry
66       */
67      public ServiceWatcher() throws Exception
68      {
69          //track all instances of deployers of webapps
70          Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
71          _serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
72          _serviceTracker.open();
73      }
74  
75  
76     
77      /* ------------------------------------------------------------ */
78      /**
79       * @param managedServerName
80       * @return
81       */
82      public Map<ServiceReference, ServiceProvider> getDeployers(String managedServerName)
83      {
84          if (managedServerName == null)
85              managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
86          
87          Map<ServiceReference, ServiceProvider> candidates = new HashMap<ServiceReference, ServiceProvider>();
88          
89          ServiceReference[] references = _serviceTracker.getServiceReferences();
90          if (references != null)
91          {
92              for (ServiceReference ref:references)
93              {
94                  String name = (String)ref.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
95                  if (managedServerName.equalsIgnoreCase(name))
96                  {
97                      ServiceProvider candidate = (ServiceProvider)_serviceTracker.getService(ref);
98                      if (candidate != null)
99                          candidates.put(ref, candidate);
100                 }
101             }
102         }
103        return candidates;
104     }
105 
106     
107 
108 
109     /* ------------------------------------------------------------ */
110     /** 
111      * A Service that is a ContextHandler is detected.
112      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
113      */
114     @Override
115     public Object addingService(ServiceReference reference)
116     {
117         BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
118         ContextHandler contextHandler = (ContextHandler) context.getService(reference); 
119         return addService(context, contextHandler, reference);
120     }
121 
122 
123     /* ------------------------------------------------------------ */
124     /** 
125      * A Service that is a ContextHandler has been modified. We
126      * undeploy and then redeploy the ContextHandler.
127      * 
128      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
129      */
130     @Override
131     public void modifiedService(ServiceReference reference, Object service)
132     {
133         BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
134         ContextHandler contextHandler = (ContextHandler) context.getService(reference);
135         removeService (context, contextHandler, reference);
136         addService (context, contextHandler, reference);
137     }
138 
139 
140     /* ------------------------------------------------------------ */
141     /** 
142      * A Service that is a ContextHandler is being removed.
143      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
144      */
145     @Override
146     public void removedService(ServiceReference reference, Object service)
147     {
148         BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
149         ContextHandler contextHandler = (ContextHandler) context.getService(reference); 
150        removeService (context, contextHandler, reference);
151     }
152     
153     
154     
155     /* ------------------------------------------------------------ */
156     /** Deploy ContextHandler that is a Service.
157      * 
158      * @param reference
159      * @return
160      */
161     public Object addService (BundleContext context, ContextHandler contextHandler, ServiceReference reference)
162     {
163         if (contextHandler.getServer() != null)
164         {
165             // is configured elsewhere.
166             return context.getService(reference);
167         }
168         String watermark = (String)reference.getProperty(OSGiWebappConstants.WATERMARK);
169         if (watermark != null && !"".equals(watermark))
170             return context.getService(reference); //one of our deployers just registered the context as an OSGi service, so we can ignore it
171         
172         //Get a jetty deployer targetted to the named server instance, or the default one if not named
173         String serverName = (String)reference.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);    
174         Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
175         if (candidates != null)
176         {
177             boolean added = false;
178             Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
179             while (!added && itor.hasNext())
180             {
181                 Entry<ServiceReference, ServiceProvider> e = itor.next();
182                 try
183                 {
184                     added = e.getValue().serviceAdded(reference, contextHandler);
185                     if (added && LOG.isDebugEnabled())
186                         LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
187                 }
188                 catch (Exception x)
189                 {
190                     LOG.warn("Error deploying service representing jetty context", x);
191                 }
192             }
193         }
194         return context.getService(reference);
195     }
196     
197     
198     
199     
200     /* ------------------------------------------------------------ */
201     /**
202      * Undeploy a ContextHandler that is a Service.
203      * 
204      * @param reference
205      */
206     public void removeService (BundleContext context, ContextHandler contextHandler, ServiceReference reference)
207     {
208         //Get a jetty deployer targetted to the named server instance, or the default one if not named
209         //The individual deployer  will decide if it can remove the context or not
210         String serverName = (String)reference.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);    
211         Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
212         if (candidates != null)
213         {
214             boolean removed = false;
215             Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
216             while (!removed && itor.hasNext())
217             {
218                 Entry<ServiceReference, ServiceProvider> e = itor.next();
219                 try
220                 {
221                     removed = e.getValue().serviceRemoved(reference, contextHandler);
222                 }
223                 catch (Exception x)
224                 {
225                     LOG.warn("Error undeploying service representing jetty context ", x);
226                 }
227             }
228         }
229     }
230 }