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.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 
140                 //Get a jetty deployer targetted to the named server instance, or the default one if not named
141                 //The individual deployer  will decide if it can remove the context or not
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             if (ev.getType() == ServiceEvent.UNREGISTERING)
163             {
164                 break;
165             }
166             else
167             {
168                 // modified, meaning: we reload it. now that we stopped it;
169                 // we can register it.
170             }
171             case ServiceEvent.REGISTERED:
172             {
173                 Bundle contributor = sr.getBundle();
174                 BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
175                 ContextHandler contextHandler = (ContextHandler) context.getService(sr);
176                 if (contextHandler.getServer() != null)
177                 {
178                     // is configured elsewhere.
179                     return;
180                 }
181                 String watermark = (String)sr.getProperty(OSGiWebappConstants.WATERMARK);
182                 if (watermark != null && !"".equals(watermark))
183                     return; //one of our deployers just registered the context as an OSGi service, so we can ignore it
184                 
185                 //Get a jetty deployer targetted to the named server instance, or the default one if not named
186                 String serverName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);    
187                 Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
188                 if (candidates != null)
189                 {
190                     boolean added = false;
191                     Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
192                     while (!added && itor.hasNext())
193                     {
194                         Entry<ServiceReference, ServiceProvider> e = itor.next();
195                         try
196                         {
197                             added = e.getValue().serviceAdded(sr, contextHandler);
198                             if (added && LOG.isDebugEnabled())
199                                 LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
200                         }
201                         catch (Exception x)
202                         {
203                             LOG.warn("Error deploying service representing jetty context", x);
204                         }
205                     }
206                 }
207                 break;
208             }
209         }
210     }
211 }