View Javadoc

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