KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > update > internal > configurator > ConfigurationActivator


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.update.internal.configurator;
12
13 import java.io.*;
14 import java.net.*;
15 import java.util.*;
16
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.framework.log.*;
19 import org.eclipse.osgi.service.datalocation.*;
20 import org.eclipse.osgi.service.debug.*;
21 import org.eclipse.osgi.util.ManifestElement;
22 import org.eclipse.osgi.util.NLS;
23 import org.eclipse.update.configurator.*;
24 import org.osgi.framework.*;
25 import org.osgi.service.packageadmin.*;
26 import org.osgi.service.startlevel.*;
27 import org.osgi.util.tracker.*;
28
29 public class ConfigurationActivator implements BundleActivator, IBundleGroupProvider, IConfigurationConstants {
30
31     public static String JavaDoc PI_CONFIGURATOR = "org.eclipse.update.configurator"; //$NON-NLS-1$
32
public static final String JavaDoc INSTALL_LOCATION = "osgi.installLocation"; //$NON-NLS-1$
33
public static final String JavaDoc LAST_CONFIG_STAMP = "last.config.stamp"; //$NON-NLS-1$
34
public static final String JavaDoc NAME_SPACE = "org.eclipse.update"; //$NON-NLS-1$
35
public static final String JavaDoc UPDATE_PREFIX = "update@"; //$NON-NLS-1$
36
private static final String JavaDoc INITIAL_PREFIX = "initial@"; //$NON-NLS-1$
37

38     // debug options
39
public static String JavaDoc OPTION_DEBUG = PI_CONFIGURATOR + "/debug"; //$NON-NLS-1$
40
// debug values
41
public static boolean DEBUG = false;
42     
43     private static BundleContext context;
44     private ServiceTracker platformTracker;
45     private ServiceRegistration configurationFactorySR;
46     private ServiceRegistration bundleGroupProviderSR;
47     private PlatformConfiguration configuration;
48     
49     // Location of the configuration data
50
private Location configLocation;
51     
52     //Need to store that because it is not provided by the platformConfiguration
53
private long lastTimeStamp;
54
55     // The expected states timestamp
56
private long lastStateTimeStamp;
57     
58     // Singleton
59
private static ConfigurationActivator configurator;
60
61     public ConfigurationActivator() {
62         configurator = this;
63     }
64     
65     public void start(BundleContext ctx) throws Exception JavaDoc {
66         context = ctx;
67         loadOptions();
68         acquireFrameworkLogService();
69         initialize();
70         
71         //Short cut, if the configuration has not changed
72
if (canRunWithCachedData()) {
73             Utils.debug("Running with cached data"); //$NON-NLS-1$
74
registerBundleGroupProvider();
75             return;
76         }
77
78         Utils.debug("Starting update configurator..."); //$NON-NLS-1$
79

80         String JavaDoc reconcile = System.getProperty("org.eclipse.update.reconcile"); //$NON-NLS-1$
81
if (reconcile == null || reconcile.equalsIgnoreCase("true")) //$NON-NLS-1$
82
installBundles();
83         registerBundleGroupProvider();
84     }
85
86     private void registerBundleGroupProvider() {
87         bundleGroupProviderSR = getBundleContext().registerService(IBundleGroupProvider.class.getName(), this, null);
88     }
89     
90     private void initialize() throws Exception JavaDoc {
91         // TODO this test is not really needed any more than any plugin has
92
// to test to see if the runtime is running. It was there from earlier days
93
// where startup was much more disjoint. Some day that level of decoupling
94
// will return but for now...
95
if (!Utils.isRunning())
96             throw new Exception JavaDoc(Messages.ConfigurationActivator_initialize);
97         
98         configLocation = Utils.getConfigurationLocation();
99         // create the name space directory for update (configuration/org.eclipse.update)
100
if (!configLocation.isReadOnly()) {
101             try {
102                 URL privateURL = new URL(configLocation.getURL(), NAME_SPACE);
103                 File f = new File(privateURL.getFile());
104                 if(!f.exists())
105                     f.mkdirs();
106             } catch (MalformedURLException e1) {
107                 // ignore
108
}
109         }
110         configurationFactorySR = context.registerService(IPlatformConfigurationFactory.class.getName(), new PlatformConfigurationFactory(), null);
111         configuration = getPlatformConfiguration(Utils.getInstallURL(), configLocation);
112         if (configuration == null)
113             throw Utils.newCoreException(NLS.bind(Messages.ConfigurationActivator_createConfig, (new String JavaDoc[] { configLocation.getURL().toExternalForm() })), null);
114
115         DataInputStream stream = null;
116         try {
117             stream = new DataInputStream(new URL(configLocation.getURL(),NAME_SPACE+'/'+LAST_CONFIG_STAMP).openStream());
118             lastTimeStamp = stream.readLong();
119             lastStateTimeStamp = stream.readLong();
120         } catch (Exception JavaDoc e) {
121             lastTimeStamp = configuration.getChangeStamp() - 1;
122             lastStateTimeStamp = -1;
123         } finally {
124             if (stream != null)
125                 try {
126                     stream.close();
127                 } catch (IOException e1) {
128                     Utils.log(e1.getLocalizedMessage());
129                 }
130         }
131     }
132
133
134     public void stop(BundleContext ctx) throws Exception JavaDoc {
135         // quick fix (hack) for bug 47861
136
try {
137             PlatformConfiguration.shutdown();
138         } catch (IOException e) {
139             // TODO Auto-generated catch block
140
e.printStackTrace();
141         }
142         configurationFactorySR.unregister();
143         if (bundleGroupProviderSR != null)
144             bundleGroupProviderSR.unregister();
145         Utils.shutdown();
146     }
147
148     public boolean installBundles() {
149         Utils.debug("Installing bundles..."); //$NON-NLS-1$
150
ServiceReference reference = context.getServiceReference(StartLevel.class.getName());
151         int startLevel = 4;
152         String JavaDoc defaultStartLevel = context.getProperty("osgi.bundles.defaultStartLevel"); //$NON-NLS-1$
153
if (defaultStartLevel != null) {
154             try {
155                 startLevel = Integer.parseInt(defaultStartLevel);
156             } catch (NumberFormatException JavaDoc e1) {
157                 startLevel = 4;
158             }
159         }
160         if (startLevel < 1)
161             startLevel = 4;
162         
163         StartLevel start = null;
164         if (reference != null)
165             start = (StartLevel) context.getService(reference);
166         try {
167             // Get the list of cached bundles and compare with the ones to be installed.
168
// Uninstall all the cached bundles that do not appear on the new list
169
Bundle[] cachedBundles = context.getBundles();
170             URL[] plugins = configuration.getPluginPath();
171                 
172             // starts the list of bundles to refresh with all currently unresolved bundles (see bug 50680)
173
List toRefresh = getUnresolvedBundles();
174
175             Bundle[] bundlesToUninstall = getBundlesToUninstall(cachedBundles, plugins);
176             for (int i=0; i<bundlesToUninstall.length; i++) {
177                 try {
178                     if (DEBUG)
179                         Utils.debug("Uninstalling " + bundlesToUninstall[i].getLocation()); //$NON-NLS-1$
180
// include every bundle being uninstalled in the list of bundles to refresh (see bug 82393)
181
toRefresh.add(bundlesToUninstall[i]);
182                     bundlesToUninstall[i].uninstall();
183                 } catch (Exception JavaDoc e) {
184                     Utils.log(NLS.bind(Messages.ConfigurationActivator_uninstallBundle, (new String JavaDoc[] { bundlesToUninstall[i].getLocation() })));
185                 }
186             }
187             
188             // Get the urls to install
189
String JavaDoc[] bundlesToInstall = getBundlesToInstall(cachedBundles, plugins);
190             ArrayList lazyActivationBundles = new ArrayList(bundlesToInstall.length);
191             for (int i = 0; i < bundlesToInstall.length; i++) {
192                 try {
193                     if (DEBUG)
194                         Utils.debug("Installing " + bundlesToInstall[i]); //$NON-NLS-1$
195
URL bundleURL = new URL("reference:file:"+bundlesToInstall[i]); //$NON-NLS-1$
196
//Bundle target = context.installBundle(bundlesToInstall[i]);
197
Bundle target = context.installBundle(UPDATE_PREFIX+bundlesToInstall[i], bundleURL.openStream());
198                     // any new bundle should be refreshed as well
199
toRefresh.add(target);
200                     if (start != null)
201                         start.setBundleStartLevel(target, startLevel);
202                     // check the bundle manifest to see if it defines a lazy activation policy
203
if (hasLazyActivationPolicy(target))
204                         lazyActivationBundles.add(target);
205                 } catch (Exception JavaDoc e) {
206                     if (!Utils.isAutomaticallyStartedBundle(bundlesToInstall[i]))
207                         Utils.log(NLS.bind(Messages.ConfigurationActivator_installBundle, (new String JavaDoc[] { bundlesToInstall[i] })) + " " + e.getMessage()); //$NON-NLS-1$
208
}
209             }
210             context.ungetService(reference);
211             removeInitialBundles(toRefresh, cachedBundles);
212             refreshPackages((Bundle[]) toRefresh.toArray(new Bundle[toRefresh.size()]));
213             // after resolving all the bundles; activate the bundles that have a lazy activation policy
214
for (Iterator activateBundles = lazyActivationBundles.iterator(); activateBundles.hasNext();) {
215                 Bundle toActivate = (Bundle) activateBundles.next();
216                 try {
217                     // use the START_ACTIVATION_POLICY option so this is not an eager activation.
218
toActivate.start(Bundle.START_ACTIVATION_POLICY);
219                 } catch (BundleException e) {
220                     if ((toActivate.getState() & Bundle.RESOLVED) != 0)
221                         // only log errors if the bundle is resolved
222
Utils.log(NLS.bind(Messages.ConfigurationActivator_installBundle, (new String JavaDoc[] { toActivate.getLocation() })) + " " + e.getMessage()); //$NON-NLS-1$
223
}
224             }
225             // keep track of the last config successfully processed
226
writePlatformConfigurationTimeStamp();
227             return true;
228         } catch (Exception JavaDoc e) {
229             return false;
230         }
231     }
232
233     private static boolean hasLazyActivationPolicy(Bundle target) {
234         // check the bundle manifest to see if it defines a lazy activation policy
235
Dictionary headers = target.getHeaders(""); //$NON-NLS-1$
236
// first check to see if this is a fragment bundle
237
String JavaDoc fragmentHost = (String JavaDoc) headers.get(Constants.FRAGMENT_HOST);
238         if (fragmentHost != null)
239             return false; // do not activate fragment bundles
240
// look for the OSGi defined Bundle-ActivationPolicy header
241
String JavaDoc activationPolicy = (String JavaDoc) headers.get(Constants.BUNDLE_ACTIVATIONPOLICY);
242         try {
243             if (activationPolicy != null) {
244                 ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy);
245                 if (elements != null && elements.length > 0) {
246                     // if the value is "lazy" then it has a lazy activation poliyc
247
if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue()))
248                         return true;
249                 }
250             } else {
251                 // check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart"
252
String JavaDoc eclipseLazyStart = (String JavaDoc) headers.get("Eclipse-LazyStart"); //$NON-NLS-1$
253
if (eclipseLazyStart == null)
254                     eclipseLazyStart = (String JavaDoc) headers.get("Eclipse-AutoStart"); //$NON-NLS-1$
255
ManifestElement[] elements = ManifestElement.parseHeader("Eclipse-LazyStart", eclipseLazyStart); //$NON-NLS-1$
256
if (elements != null && elements.length > 0) {
257                     // if the value is true then it is lazy activated
258
if ("true".equals(elements[0].getValue())) //$NON-NLS-1$
259
return true;
260                     // otherwise it is only lazy activated if it defines an exceptions directive.
261
else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$
262
return true;
263                 }
264             }
265         } catch (BundleException be) {
266             // ignore this
267
}
268         return false;
269     }
270
271     private void removeInitialBundles(List bundles, Bundle[] cachedBundles) {
272         String JavaDoc[] initialSymbolicNames = getInitialSymbolicNames(cachedBundles);
273         Iterator iter = bundles.iterator();
274         while(iter.hasNext()) {
275             Bundle bundle = (Bundle) iter.next();
276             String JavaDoc symbolicName = bundle.getSymbolicName();
277             for(int i = 0; i < initialSymbolicNames.length; i++) {
278                 if (initialSymbolicNames[i].equals(symbolicName)) {
279                     iter.remove();
280                     break;
281                 }
282             }
283         }
284     }
285
286     private String JavaDoc[] getInitialSymbolicNames(Bundle[] cachedBundles) {
287         ArrayList initial = new ArrayList();
288         for (int i = 0; i < cachedBundles.length; i++) {
289             Bundle bundle = cachedBundles[i];
290             if (bundle.getLocation().startsWith(INITIAL_PREFIX)) {
291                 String JavaDoc symbolicName = bundle.getSymbolicName();
292                 if (symbolicName != null)
293                     initial.add(symbolicName);
294             }
295         }
296         return (String JavaDoc[]) initial.toArray(new String JavaDoc[initial.size()]);
297     }
298
299     private List getUnresolvedBundles() {
300         Bundle[] allBundles = context.getBundles();
301         List unresolved = new ArrayList();
302         for (int i = 0; i < allBundles.length; i++)
303             if (allBundles[i].getState() == Bundle.INSTALLED)
304                 unresolved.add(allBundles[i]);
305         return unresolved;
306     }
307
308     private String JavaDoc[] getBundlesToInstall(Bundle[] cachedBundles, URL[] newPlugins) {
309         // First, create a map of the cached bundles, for faster lookup
310
HashSet cachedBundlesSet = new HashSet(cachedBundles.length);
311         int offset = UPDATE_PREFIX.length();
312         for (int i=0; i<cachedBundles.length; i++) {
313             if (cachedBundles[i].getBundleId() == 0)
314                 continue; // skip the system bundle
315
String JavaDoc bundleLocation = cachedBundles[i].getLocation();
316             // Ignore bundles not installed by us
317
if (!bundleLocation.startsWith(UPDATE_PREFIX))
318                 continue;
319             
320             bundleLocation = bundleLocation.substring(offset);
321             cachedBundlesSet.add(bundleLocation);
322             // On windows, we will be doing case insensitive search as well, so lower it now
323
if (Utils.isWindows)
324                 cachedBundlesSet.add(bundleLocation.toLowerCase());
325         }
326         
327         ArrayList bundlesToInstall = new ArrayList(newPlugins.length);
328         for (int i = 0; i < newPlugins.length; i++) {
329             String JavaDoc location = Utils.makeRelative(Utils.getInstallURL(), newPlugins[i]).getFile();
330             // check if already installed
331
if (cachedBundlesSet.contains(location))
332                 continue;
333             if (Utils.isWindows && cachedBundlesSet.contains(location.toLowerCase()))
334                 continue;
335             
336             bundlesToInstall.add(location);
337         }
338         return (String JavaDoc[])bundlesToInstall.toArray(new String JavaDoc[bundlesToInstall.size()]);
339     }
340     
341     
342     private Bundle[] getBundlesToUninstall(Bundle[] cachedBundles, URL[] newPlugins) {
343         // First, create a map for faster lookups
344
HashSet newPluginsSet = new HashSet(newPlugins.length);
345         for (int i=0; i<newPlugins.length; i++) {
346             
347             String JavaDoc pluginLocation = Utils.makeRelative(Utils.getInstallURL(), newPlugins[i]).getFile();
348             newPluginsSet.add(pluginLocation);
349             // On windows, we will be doing case insensitive search as well, so lower it now
350
if (Utils.isWindows)
351                 newPluginsSet.add(pluginLocation.toLowerCase());
352         }
353         
354         ArrayList bundlesToUninstall = new ArrayList();
355         int offset = UPDATE_PREFIX.length();
356         for (int i=0; i<cachedBundles.length; i++) {
357             if (cachedBundles[i].getBundleId() == 0)
358                 continue; // skip the system bundle
359
String JavaDoc cachedBundleLocation = cachedBundles[i].getLocation();
360             // Only worry about bundles we installed
361
if (!cachedBundleLocation.startsWith(UPDATE_PREFIX))
362                 continue;
363             cachedBundleLocation = cachedBundleLocation.substring(offset);
364
365             if (newPluginsSet.contains(cachedBundleLocation))
366                 continue;
367             if (Utils.isWindows && newPluginsSet.contains(cachedBundleLocation.toLowerCase()))
368                 continue;
369             
370             bundlesToUninstall.add(cachedBundles[i]);
371         }
372         return (Bundle[])bundlesToUninstall.toArray(new Bundle[bundlesToUninstall.size()]);
373     }
374     
375
376     /**
377      * Creates and starts the platform configuration.
378      * @return the just started platform configuration
379      */

380     private PlatformConfiguration getPlatformConfiguration(URL installURL, Location configLocation) {
381         try {
382             PlatformConfiguration.startup(installURL, configLocation);
383         } catch (Exception JavaDoc e) {
384             if (platformTracker != null) {
385                 String JavaDoc message = e.getMessage();
386                 if (message == null)
387                     message = ""; //$NON-NLS-1$
388
Utils.log(Utils.newStatus(message, e));
389             }
390         }
391         return PlatformConfiguration.getCurrent();
392
393     }
394
395     /**
396      * Do PackageAdmin.refreshPackages() in a synchronous way. After installing
397      * all the requested bundles we need to do a refresh and want to ensure that
398      * everything is done before returning.
399      * @param bundles
400      */

401     private void refreshPackages(Bundle[] bundles) {
402         if (bundles.length == 0)
403             return;
404         ServiceReference packageAdminRef = context.getServiceReference(PackageAdmin.class.getName());
405         PackageAdmin packageAdmin = null;
406         if (packageAdminRef != null) {
407             packageAdmin = (PackageAdmin) context.getService(packageAdminRef);
408             if (packageAdmin == null)
409                 return;
410         }
411         // TODO this is such a hack it is silly. There are still cases for race conditions etc
412
// but this should allow for some progress...
413
// (patch from John A.)
414
final boolean[] flag = new boolean[] {false};
415         FrameworkListener listener = new FrameworkListener() {
416             public void frameworkEvent(FrameworkEvent event) {
417                 if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED)
418                     synchronized (flag) {
419                         flag[0] = true;
420                         flag.notifyAll();
421                     }
422             }
423         };
424         context.addFrameworkListener(listener);
425         packageAdmin.refreshPackages(bundles);
426         synchronized (flag) {
427             while (!flag[0]) {
428                 try {
429                     flag.wait();
430                 } catch (InterruptedException JavaDoc e) {
431                 }
432             }
433         }
434         context.removeFrameworkListener(listener);
435         context.ungetService(packageAdminRef);
436     }
437     
438     private void writePlatformConfigurationTimeStamp() {
439         DataOutputStream stream = null;
440         try {
441             if (configLocation.isReadOnly())
442                 return;
443             
444             String JavaDoc configArea = configLocation.getURL().getFile();
445             lastTimeStamp = configuration.getChangeStamp();
446             lastStateTimeStamp = Utils.getStateStamp();
447             stream = new DataOutputStream(new FileOutputStream(configArea +File.separator+ NAME_SPACE+ File.separator+ LAST_CONFIG_STAMP));
448             stream.writeLong(lastTimeStamp);
449             stream.writeLong(lastStateTimeStamp);
450         } catch (Exception JavaDoc e) {
451             Utils.log(e.getLocalizedMessage());
452         } finally {
453             if (stream != null)
454                 try {
455                     stream.close();
456                 } catch (IOException e1) {
457                     Utils.log(e1.getLocalizedMessage());
458                 }
459         }
460     }
461
462     private void loadOptions() {
463         // all this is only to get the application args
464
DebugOptions service = null;
465         ServiceReference reference = context.getServiceReference(DebugOptions.class.getName());
466         if (reference != null)
467             service = (DebugOptions) context.getService(reference);
468         if (service == null)
469             return;
470         try {
471             DEBUG = service.getBooleanOption(OPTION_DEBUG, false);
472         } finally {
473             // we have what we want - release the service
474
context.ungetService(reference);
475         }
476     }
477     
478     private boolean canRunWithCachedData() {
479         return !"true".equals(context.getProperty("osgi.checkConfiguration")) && //$NON-NLS-1$ //$NON-NLS-2$
480
lastTimeStamp==configuration.getChangeStamp() &&
481                 lastStateTimeStamp==Utils.getStateStamp();
482     }
483                 
484     public static BundleContext getBundleContext() {
485         return context;
486     }
487         
488     /* (non-Javadoc)
489      * @see org.eclipse.core.runtime.IBundleGroupProvider#getName()
490      */

491     public String JavaDoc getName() {
492         return Messages.BundleGroupProvider;
493     }
494     /* (non-Javadoc)
495      * @see org.eclipse.core.runtime.IBundleGroupProvider#getBundleGroups()
496      */

497     public IBundleGroup[] getBundleGroups() {
498         if (configuration == null)
499             return new IBundleGroup[0];
500         
501         IPlatformConfiguration.IFeatureEntry[] features = configuration.getConfiguredFeatureEntries();
502         ArrayList bundleGroups = new ArrayList(features.length);
503         for (int i=0; i<features.length; i++) {
504             if (features[i] instanceof FeatureEntry
505                 && ((FeatureEntry)features[i]).hasBranding())
506                 bundleGroups.add(features[i]);
507         }
508         return (IBundleGroup[])bundleGroups.toArray(new IBundleGroup[bundleGroups.size()]);
509     }
510
511     public static void setConfigurator(ConfigurationActivator configurator) {
512         ConfigurationActivator.configurator = configurator;
513     }
514
515     public static ConfigurationActivator getConfigurator() {
516         return configurator;
517     }
518     
519     private void acquireFrameworkLogService() throws Exception JavaDoc{
520         ServiceReference logServiceReference = context.getServiceReference(FrameworkLog.class.getName());
521         if (logServiceReference == null)
522             return;
523         Utils.log = (FrameworkLog) context.getService(logServiceReference);
524     }
525 }
526
527
Popular Tags