Framework.java

00001 /*
00002  * Copyright (c) 2003-2006, KNOPFLERFISH project
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  * - Redistributions in binary form must reproduce the above
00013  *   copyright notice, this list of conditions and the following
00014  *   disclaimer in the documentation and/or other materials
00015  *   provided with the distribution.
00016  *
00017  * - Neither the name of the KNOPFLERFISH project nor the names of its
00018  *   contributors may be used to endorse or promote products derived
00019  *   from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00030  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032  * OF THE POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 package org.knopflerfish.framework;
00036 
00037 import java.io.*;
00038 import java.net.*;
00039 import java.security.*;
00040 
00041 import java.util.Set;
00042 import java.util.List;
00043 import java.util.HashSet;
00044 import java.util.Iterator;
00045 import java.util.Locale;
00046 import java.util.Dictionary;
00047 
00048 import org.osgi.framework.*;
00049 import org.osgi.service.packageadmin.PackageAdmin;
00050 import org.osgi.service.startlevel.StartLevel;
00051 
00058 public class Framework {
00059 
00063   static final String SPEC_VERSION = "1.3";
00064 
00068   boolean active;
00069 
00073   boolean shuttingdown /*= false*/;
00074 
00078   public Bundles bundles;
00079 
00083   Listeners listeners;
00084 
00088   Packages packages;
00089 
00093   Services services;
00094 
00098   PermissionOps perm;
00099 
00100 
00104   SystemBundle systemBundle;
00105 
00106   BundleContextImpl systemBC;
00107 
00111   BundleStorage storage;
00112 
00116   FileTree dataStorage /*= null*/;
00117 
00121   Object mainHandle;
00122 
00126   StartLevelImpl startLevelService;
00127  
00128 
00132   ServiceURLStreamHandlerFactory urlStreamHandlerFactory;
00133 
00137   ServiceContentHandlerFactory   contentHandlerFactory;
00138 
00142   final static String TRUE   = "true";
00143   final static String FALSE  = "false";
00144 
00145   final static String osArch = System.getProperty("os.arch");
00146   final static String osName = System.getProperty("os.name");
00147   static String osVersion;
00148 
00149   // If set to true, then during the UNREGISTERING event the Listener
00150   // can use the ServiceReference to receive an instance of the service.
00151   public final static boolean UNREGISTERSERVICE_VALID_DURING_UNREGISTERING =
00152           TRUE.equals(System.getProperty("org.knopflerfish.servicereference.valid.during.unregistering",
00153                                      FALSE));
00154 
00155   // If set to true, set the bundle startup thread's context class
00156   // loader to the bundle class loader. This is useful for tests
00157   // but shouldn't really be used in production.
00158   final static boolean SETCONTEXTCLASSLOADER =
00159     TRUE.equals(System.getProperty("org.knopflerfish.osgi.setcontextclassloader", FALSE));
00160 
00161   final static boolean REGISTERSERVICEURLHANDLER =
00162     TRUE.equals(System.getProperty("org.knopflerfish.osgi.registerserviceurlhandler", TRUE));
00163 
00164 
00165 
00166   static boolean bIsMemoryStorage /*= false*/;
00167   
00168   private static final String USESTARTLEVEL_PROP = "org.knopflerfish.startlevel.use";
00169 
00173   private final static String CLASSPATH_DIR = "classpath";
00174   private final static String BOOT_CLASSPATH_FILE = "boot";
00175   private final static String FRAMEWORK_CLASSPATH_FILE = "framework";
00176 
00181   private Set    eeCacheSet = new HashSet();
00182   private String eeCache = null;
00183 
00188   static boolean SUPPORTS_EXTENSION_BUNDLES;
00189 
00190   final static boolean EXIT_ON_SHUTDOWN =
00191     TRUE.equals(System.getProperty(Main.EXITONSHUTDOWN_PROP, TRUE));
00192 
00193   final static int EXIT_CODE_NORMAL  = 0;
00194   final static int EXIT_CODE_RESTART = 200;
00195 
00196   final static boolean USING_WRAPPER_SCRIPT = TRUE.equals(System.getProperty(Main.USINGWRAPPERSCRIPT_PROP, FALSE));
00197 
00202   public Framework(Object m) throws Exception {
00203 
00204     String whichStorageImpl = "org.knopflerfish.framework.bundlestorage." + 
00205       System.getProperty("org.knopflerfish.framework.bundlestorage", "file") +
00206       ".BundleStorageImpl";
00207 
00208     bIsMemoryStorage = whichStorageImpl.equals("org.knopflerfish.framework.bundlestorage.memory.BundleStorageImpl");
00209     if (bIsMemoryStorage ||
00210         !EXIT_ON_SHUTDOWN ||
00211         !USING_WRAPPER_SCRIPT) {
00212       SUPPORTS_EXTENSION_BUNDLES = false;
00213       // we can not support this in this mode.
00214     } else {
00215       SUPPORTS_EXTENSION_BUNDLES = true;
00216     }
00217     
00218     String ver = System.getProperty("os.version");
00219     if (ver != null) {
00220       int dots = 0;
00221       int i = 0;
00222       for ( ; i < ver.length(); i++) {
00223         char c = ver.charAt(i);
00224         if (Character.isDigit(c)) {
00225           continue;
00226         } else if (c == '.') {
00227           if (++dots < 3) {
00228             continue;
00229           }
00230         }
00231         break;
00232       }
00233       osVersion = ver.substring(0, i);
00234     }
00235         
00236     ProtectionDomain pd = null;
00237     if (System.getSecurityManager() != null) {
00238       try {
00239         pd = getClass().getProtectionDomain();
00240       } catch (Throwable t) {
00241         if(Debug.classLoader) {
00242           Debug.println("Failed to get protection domain: " + t);
00243         }
00244       }
00245       perm = new SecurePermissionOps(this);
00246     } else {
00247       perm = new PermissionOps();
00248     }
00249 
00250 
00251     Class storageImpl = Class.forName(whichStorageImpl);
00252     storage           = (BundleStorage)storageImpl.newInstance();
00253 
00254     dataStorage       = Util.getFileStorage("data");
00255     packages          = new Packages(this);
00256     
00257     listeners         = new Listeners(perm);
00258     services          = new Services(perm);
00259 
00260     systemBundle      = new SystemBundle(this, pd);
00261     systemBC          = new BundleContextImpl(systemBundle);
00262     bundles           = new Bundles(this);
00263 
00264     systemBundle.setBundleContext(systemBC);
00265 
00266     perm.registerService();
00267 
00268     String[] classes = new String [] { PackageAdmin.class.getName() };
00269     services.register(systemBundle,
00270                       classes,
00271                       new PackageAdminImpl(this),
00272                       null);
00273     
00274     registerStartLevel();
00275 
00276     urlStreamHandlerFactory = new ServiceURLStreamHandlerFactory(this);
00277     contentHandlerFactory   = new ServiceContentHandlerFactory(this);
00278 
00279     urlStreamHandlerFactory
00280       .setURLStreamHandler(BundleURLStreamHandler.PROTOCOL,
00281                            new BundleURLStreamHandler(bundles, perm));
00282     urlStreamHandlerFactory
00283       .setURLStreamHandler(ReferenceURLStreamHandler.PROTOCOL,
00284                            new ReferenceURLStreamHandler());
00285     
00286     // Install service based URL stream handler. This can be turned
00287     // off if there is need
00288     if(REGISTERSERVICEURLHANDLER) {
00289       try {
00290         URL.setURLStreamHandlerFactory(urlStreamHandlerFactory);
00291         
00292         URLConnection.setContentHandlerFactory(contentHandlerFactory);
00293       } catch (Throwable e) {
00294         Debug.println("Cannot set global URL handlers, continuing without OSGi service URL handler (" + e + ")");
00295         e.printStackTrace();
00296       }
00297     }
00298     bundles.load();
00299     
00300     mainHandle = m;
00301   }
00302 
00303 
00304   private void registerStartLevel(){
00305     String useStartLevel = System.getProperty(USESTARTLEVEL_PROP, TRUE);
00306 
00307     if(TRUE.equals(useStartLevel)) {
00308       if(Debug.startlevel) {
00309         Debug.println("[using startlevel service]");
00310       }
00311       startLevelService = new StartLevelImpl(this);
00312 
00313       // restoreState just reads from persistent storage
00314       // open() needs to be called to actually do the work
00315       // This is done after framework has been launched.
00316       startLevelService.restoreState();
00317 
00318       services.register(systemBundle,
00319                         new String [] { StartLevel.class.getName() },
00320                         startLevelService,
00321                         null);
00322     }
00323   }
00324 
00325   
00354   public void launch(long startBundle) throws BundleException {
00355     if (!active) {
00356       active = true;
00357       if (startBundle > 0) {
00358         startBundle(startBundle);
00359       } else {
00360         for (Iterator i = storage.getStartOnLaunchBundles().iterator(); i.hasNext(); ) {
00361           Bundle b = bundles.getBundle((String)i.next());
00362           try {
00363             b.start();
00364           } catch (BundleException be) {
00365             listeners.frameworkError(b, be);
00366           }
00367         }
00368       }
00369       systemBundle.systemActive();
00370 
00371       // start level open is delayed to this point to 
00372       // correctly work at restart
00373       if (startLevelService != null) {
00374         startLevelService.open();
00375       }
00376 
00377       listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.STARTED, systemBundle, null));
00378     }
00379   }
00380 
00381 
00400   public void shutdown() {
00401     if (active) {
00402       // No shuttingdown event specified
00403       // listeners.frameworkChanged(new FrameworkEvent(FrameworkEvent.SHUTTING_DOWN));
00404       active = false;
00405       List slist = storage.getStartOnLaunchBundles();
00406       shuttingdown = true;
00407       systemBundle.systemShuttingdown();
00408       if (startLevelService != null) {
00409         startLevelService.shutdown();
00410       }
00411       // Stop bundles, in reverse start order
00412       for (int i = slist.size()-1; i >= 0; i--) {
00413         Bundle b = bundles.getBundle((String)slist.get(i));
00414         try {
00415           if(b != null) {
00416             synchronized (b) {
00417               if (b.getState() == Bundle.ACTIVE) {
00418                 b.stop();
00419               }
00420             }
00421           }
00422         } catch (BundleException be) {
00423           listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.ERROR, b, be));
00424         }
00425       }
00426       shuttingdown = false; 
00427       // Purge any unrefreshed bundles
00428       List all = bundles.getBundles();
00429       for (Iterator i = all.iterator(); i.hasNext(); ) {
00430         ((BundleImpl)i.next()).purge();
00431       }
00432     }
00433 
00434     StringBuffer bootClasspath = new StringBuffer();
00435     StringBuffer frameworkClasspath = new StringBuffer();
00436     for (Iterator i = bundles.getFragmentBundles(systemBundle).iterator(); i.hasNext(); ) {
00437       BundleImpl eb = (BundleImpl)i.next();
00438       String path = eb.archive.getJarLocation();
00439       StringBuffer sb = eb.isBootClassPathExtension() ? bootClasspath : frameworkClasspath;
00440       sb.append(path);
00441       if (i.hasNext()) {
00442         sb.append(File.pathSeparator);
00443       }
00444     }
00445 
00446     try {
00447       FileTree storage = Util.getFileStorage(CLASSPATH_DIR);
00448       File bcpf = new File(storage, BOOT_CLASSPATH_FILE);
00449       File fcpf = new File(storage, FRAMEWORK_CLASSPATH_FILE);
00450       if (bootClasspath.length() > 0) {
00451         saveStringBuffer(bcpf, bootClasspath);
00452       } else {
00453         bcpf.delete();
00454       }
00455       if (frameworkClasspath.length() > 0) {
00456         saveStringBuffer(fcpf, frameworkClasspath);
00457       } else {
00458         fcpf.delete();
00459       }
00460     } catch (IOException e) {
00461       System.err.println("Could not save classpath " + e);
00462     }
00463   }
00464 
00465 
00466   private void saveStringBuffer(File f, StringBuffer content) throws IOException {
00467     PrintStream out = null;
00468     try {
00469       out = new PrintStream(new FileOutputStream(f));
00470       out.println(content.toString());
00471     } finally {
00472       if (out != null) {
00473         out.close();
00474       }
00475     }
00476   }
00477 
00478 
00487   public long installBundle(String location, InputStream in) throws BundleException {
00488     return bundles.install(location, in).id;
00489   }
00490 
00491 
00498   public void startBundle(long id) throws BundleException {
00499     Bundle b = bundles.getBundle(id);
00500     if (b != null) {
00501       b.start();
00502     } else {
00503       throw new BundleException("No such bundle: " + id);
00504     }
00505   }
00506 
00507 
00514   public void stopBundle(long id) throws BundleException {
00515     Bundle b = bundles.getBundle(id);
00516     if (b != null) {
00517       b.stop();
00518     } else {
00519       throw new BundleException("No such bundle: " + id);
00520     }
00521   }
00522 
00523 
00530   public void uninstallBundle(long id) throws BundleException {
00531     Bundle b = bundles.getBundle(id);
00532     if (b != null) {
00533       b.uninstall();
00534     } else {
00535       throw new BundleException("No such bundle: " + id);
00536     }
00537   }
00538 
00539 
00546   public void updateBundle(long id) throws BundleException {
00547     Bundle b = bundles.getBundle(id);
00548     if (b != null) {
00549       b.update();
00550     } else {
00551       throw new BundleException("No such bundle: " + id);
00552     }
00553   }
00554 
00555 
00564   public String getBundleLocation(long id) {
00565     Bundle b = bundles.getBundle(id);
00566     if (b != null) {
00567       return b.getLocation();
00568     } else {
00569       return null;
00570     }
00571   }
00572 
00581   public long getBundleId(String location) {
00582     Bundle b = bundles.getBundle(location);
00583     if (b != null) {
00584       return b.getBundleId();
00585     } else {
00586       return -1;
00587     }
00588   }
00589 
00593   public FileTree getDataStorage(long id) {
00594         if (dataStorage != null) {
00595           return new FileTree(dataStorage, Long.toString(id));
00596         }
00597         return null;
00598   }
00599 
00603   boolean isValidEE(String ee) {
00604     ee = ee.trim();
00605     if(ee == null || "".equals(ee)) {
00606       return true;
00607     }
00608 
00609     String fwEE = System.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
00610 
00611     if(fwEE == null) {
00612       // If EE is not set, allow everything
00613       return true;
00614     } else if (!fwEE.equals(eeCache)) {
00615       eeCacheSet.clear();
00616 
00617       String[] l = Util.splitwords(fwEE, ",");
00618       for(int i = 0 ; i < l.length; i++) {
00619         eeCacheSet.add(l[i]);
00620       }
00621       eeCache = fwEE;
00622     }
00623 
00624     String[] eel   = Util.splitwords(ee, ",");
00625     for(int i = 0 ; i < eel.length; i++) {
00626       if(eeCacheSet.contains(eel[i])) {
00627         return true;
00628       }
00629     }
00630     return false;
00631   }
00632 
00633   //
00634   // Static package methods
00635   //
00636 
00641   public static String getProperty(String key) {
00642     if (Constants.FRAMEWORK_VERSION.equals(key)) {
00643       // The version of the framework. 
00644       return SPEC_VERSION;
00645     } else if (Constants.FRAMEWORK_VENDOR.equals(key)) {
00646       // The vendor of this framework implementation. 
00647       return "Knopflerfish";
00648     } else if (Constants.FRAMEWORK_LANGUAGE.equals(key)) {
00649       // The language being used. See ISO 639 for possible values. 
00650       return Locale.getDefault().getLanguage();
00651     } else if (Constants.FRAMEWORK_OS_NAME.equals(key)) {
00652       // The name of the operating system of the hosting computer. 
00653       return osName;
00654     } else if (Constants.FRAMEWORK_OS_VERSION.equals(key)) {
00655       // The version number of the operating system of the hosting computer. 
00656       return osVersion;
00657     } else if (Constants.FRAMEWORK_PROCESSOR.equals(key)) {
00658       // The name of the processor of the hosting computer. 
00659       return osArch;
00660     } else if (Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE.equals(key)) {
00661       return TRUE;
00662     } else if (Constants.SUPPORTS_FRAMEWORK_FRAGMENT.equals(key)) {
00663       return TRUE;
00664     } else if (Constants.SUPPORTS_FRAMEWORK_EXTENSION.equals(key)) {
00665       return SUPPORTS_EXTENSION_BUNDLES ? TRUE : FALSE;
00666     } else if (Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION.equals(key)) {
00667       return SUPPORTS_EXTENSION_BUNDLES ? TRUE : FALSE;
00668     } else {
00669       return System.getProperty(key);
00670     }
00671   }
00672   
00673   public static Dictionary getProperties(){
00674     Dictionary props = System.getProperties();
00675     props.put(Constants.FRAMEWORK_VERSION, SPEC_VERSION);
00676     props.put(Constants.FRAMEWORK_VENDOR, "Knopflerfish");
00677     props.put(Constants.FRAMEWORK_LANGUAGE, Locale.getDefault().getLanguage());
00678     props.put(Constants.FRAMEWORK_OS_NAME, osName);
00679     props.put(Constants.FRAMEWORK_OS_VERSION, osVersion);
00680     props.put(Constants.FRAMEWORK_PROCESSOR, osArch);
00681     props.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, TRUE);
00682     props.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, TRUE);
00683     props.put(Constants.SUPPORTS_FRAMEWORK_EXTENSION, SUPPORTS_EXTENSION_BUNDLES ? TRUE : FALSE);
00684     props.put(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION, SUPPORTS_EXTENSION_BUNDLES ? TRUE : FALSE);
00685     return props;
00686   }
00687 
00691   public BundleContext getSystemBundleContext() {
00692     return systemBC;
00693   }
00694 }

Generated on Mon Jan 11 21:19:14 2010 for OpenMobileIS by  doxygen 1.5.4