KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensugar > cube > AbstractCube


1 /*
2  * JEFFREE: Java(TM) Embedded Framework FREE
3  * Copyright (C) 1999-2003 - Opensugar
4  *
5  * The contents of this file are subject to the Jeffree Public License,
6  * as defined by the file JEFFREE_LICENSE.TXT
7  *
8  * You may not use this file except in compliance with the License.
9  * You may obtain a copy of the License on the Objectweb web site
10  * (www.objectweb.org).
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14  * the specific terms governing rights and limitations under the License.
15  *
16  * The Original Code is JEFFREE, including the java package com.opensugar.cube,
17  * released January 1, 2003.
18  *
19  * The Initial Developer of the Original Code is Opensugar.
20  * The Original Code is Copyright Opensugar.
21  * All Rights Reserved.
22  *
23  * Initial developer(s): Pierre Scokaert (Opensugar)
24  * Contributor(s):
25  */

26
27 package com.opensugar.cube;
28
29 import com.opensugar.cube.java2.PackageHelper;
30 import com.opensugar.cube.packageAdmin.PackageAdminImpl;
31 import com.opensugar.cube.packageAdmin.PackageImport;
32 import com.opensugar.cube.serviceRegistry.ServiceRegistry;
33 import com.opensugar.cube.serviceRegistry.ServiceRegistryException;
34 import com.opensugar.cube.ldap.LDAPFilter;
35
36 import org.osgi.framework.Bundle;
37 import org.osgi.framework.BundleException;
38 import org.osgi.framework.FrameworkEvent;
39 import org.osgi.framework.ServiceEvent;
40 import org.osgi.framework.BundleEvent;
41 import org.osgi.framework.FrameworkListener;
42 import org.osgi.framework.ServiceListener;
43 import org.osgi.framework.BundleListener;
44 import org.osgi.framework.SynchronousBundleListener;
45 import org.osgi.framework.ServiceReference;
46 import org.osgi.framework.InvalidSyntaxException;
47 import org.osgi.framework.Constants;
48 import org.osgi.framework.ServicePermission;
49 import org.osgi.service.permissionadmin.PermissionAdmin;
50
51 import java.io.File;
52 import java.io.InputStream;
53 import java.io.FileOutputStream;
54 import java.io.FileInputStream;
55 import java.io.IOException;
56 import java.net.URL;
57 import java.util.Hashtable;
58 import java.util.Enumeration;
59 import java.util.Vector;
60 import java.util.Locale;
61 import java.util.Observer;
62
63 // Abstract engine.
64
// Cannot be instantiated.
65
// Should be sub-classed to define engines that are appropriate for different
66
// operating conditions.
67
public abstract class AbstractCube {
68
69    public static final String VERSION = "2.1.3";
70    public static final String VENDOR = "Opensugar S.A.";
71    public static final String OSGI_RELEASE = "2";
72
73    private static final String SYSTEM_PROPERTY_CUBE_VERSION = "com.opensugar.cube.version";
74    private static final String SYSTEM_PROPERTY_CUBE_DIR = "com.opensugar.cube.dir";
75 // private static final String SYSTEM_PROPERTY_PERMANENT_STORAGE_DIR = "com.opensugar.cube.permanentStorageDir";
76
private static final String SYSTEM_PROPERTY_SYSTEM_BUNDLE_JAR_FILE = "com.opensugar.cube.systemBundleJarFile";
77    private static final String SYSTEM_PROPERTY_CUBE_STARTED_FLAG_FILE = "com.opensugar.cube.startedFlagFile";
78
79    private static final String FLASH_URL_FILE = "flash.url";
80
81    private static final String defaultCubeDir = "osc/bs";
82    private static final String defaultPermanentStorageDir = "osc/.opensugar";
83    private static final String defaultSystemBundleJarFile = "systemBundle.jar";
84
85
86    protected static final String bundleDirNameBase = "b";
87    protected static final String bundleJarNameBase = "bundle";
88    protected static final String bundleJarNameExtension = ".jar";
89    protected static final String bundleLocationFileName = "location";
90    protected static final String bundleUninstalledFlagFileName = "uninstalled.flag";
91    protected static final String bundleStartedFlagFileName = "started.flag";
92    protected static final String bundleInnerFilesDirName = "inner";
93    protected static final String bundleDataDirName = "data";
94    protected static final String bundleIdFileName = ".bid";
95
96    // If an attempt is made to start or stop a bundle that is in the stating or
97
// stopping state, the bundle needs to wait until the bundle state changes.
98
// If this does not happen in a reasonable time however, the bundle must give up.
99
private int reasonableTimeToWait = 5000;
100
101    // list of bundles in this engine // bundle id --> bundle
102
private Hashtable id_bundle;
103    // package admin service for this cube
104
private PackageAdminImpl packageAdmin;
105    // service registry for this engine
106
private ServiceRegistry serviceRegistry;
107
108    // list of service event listeners
109
private ServiceListeners serviceListeners;
110    // list of synchrnous bundle listeners;
111
private BundleListeners bundleListeners;
112    // list of framework event listeners
113
private FrameworkListeners frameworkListeners;
114    // flag to determine whether or not framework is firing events
115
private boolean handlingEvents = false;
116
117    // the largest bundle id of any bundle that has been installed on the current run of the cube
118
private long largestBundleId = -1;
119
120    // hashtable of directories used by bundles to store inner files contained in the bundle jar file
121
private Hashtable bundleInnerFileDirectories;
122
123    // framework state
124
// can be * Bundle.RESOLVED before framework is started
125
// * Bundle.STARTING while the framework is staring
126
// * Bundle.ACTIVE while the framework is running
127
// * Bundle.STOPPING while the framework is shutting down
128
private int state = Bundle.RESOLVED;
129
130    // framework working directory
131
private File baseDirectory;
132
133 // *****************************************************************************
134
// Constructor, startup, shutdown, version
135
// *****************************************************************************
136

137    protected AbstractCube() {
138       this( null );
139    }
140
141    protected AbstractCube( File baseDirectory ) {
142       // Here, we do things that need to be done once only, at engine initialization
143
this.baseDirectory = baseDirectory;
144
145       System.out.println( "Opensugar cube " + VERSION );
146       System.out.println( "Implements OSGi Service Platform, Specification Release " + OSGI_RELEASE );
147
148       System.out.println( "Copyright (c) 2001, Opensugar S.A. All Rights Reserved." );
149       System.out.println( "Opensugar is a Registered Trademark." );
150       System.out.println( "" );
151
152       // Set cube vendor and version property
153
System.getProperties().put( Constants.FRAMEWORK_VENDOR, getProperty( Constants.FRAMEWORK_VENDOR ) );
154       System.getProperties().put( Constants.FRAMEWORK_VERSION, getProperty( Constants.FRAMEWORK_VERSION ) );
155
156       // Set cube version property
157
System.getProperties().put( SYSTEM_PROPERTY_CUBE_VERSION, VERSION );
158
159       // Set permanent storage dir property as it may be needed by bundles that want
160
// to store permanent data
161
// if ( System.getProperty( SYSTEM_PROPERTY_PERMANENT_STORAGE_DIR ) == null ) {
162
// System.getProperties().put( SYSTEM_PROPERTY_PERMANENT_STORAGE_DIR, defaultPermanentStorageDir );
163
// }
164

165       initLog();
166    }
167
168    public void flash( String flashURL ) throws IOException {
169       writeFile( new File( FLASH_URL_FILE ), flashURL );
170       shutdown( false );
171    }
172
173    public synchronized void startup( Observer progressListener ) {
174       // Here, we do things that need to be done on every engine startup
175

176       // clean-up from previous runs
177
deleteUninstalledBundleDirectories();
178       deleteObsoleteBundleFiles();
179
180       // Enable event handling
181
serviceListeners = new ServiceListeners();
182       bundleListeners = new BundleListeners();
183       frameworkListeners = new FrameworkListeners();
184       handlingEvents = true;
185
186       // enter starting state
187
state = Bundle.STARTING;
188
189       // Initialize hash table of bundle contexts
190
id_bundle = new Hashtable();
191
192       // Initialize hash table of bundle inner jar directories
193
bundleInnerFileDirectories = new Hashtable();
194
195       // Initialize package admin
196
packageAdmin = new PackageAdminImpl( this );
197
198       // Initialize service registry
199
serviceRegistry = new ServiceRegistry( this );
200
201       // Create engine base directory if it does not exists.
202
getBaseDirectory().mkdirs();
203       // Install system bundle
204
installSystemBundle( new File( System.getProperty( SYSTEM_PROPERTY_SYSTEM_BUNDLE_JAR_FILE, defaultSystemBundleJarFile ) ) );
205
206       // Reinstall bundles that were installed on last engine run
207
//
208
// OSGi 2 spec does not specify how to handle errors that may occur while
209
// reinstalling bundles
210
reinstallBundles();
211       // Refresh packages from all bundles (except system bundle) so that, no matter
212
// what order the bundles are installed in, we use the latest possible package
213
// versions, when the cube is restarted
214
Bundle[] bs = getBundles();
215       Vector v = new Vector();
216       for ( int i = 0; i < bs.length; i++ ) {
217          v.addElement( bs[ i ] );
218       }
219       v.removeElement( getBundle( (long)0 ) );
220       bs = new Bundle[ v.size() ];
221       v.copyInto( bs );
222       // refresh package synchronously
223
packageAdmin.doRefreshPackages( bs );
224       // Restart bundles that were active on last engine run
225
//
226
// OSGi 2 spec says that BundleException while restarting bundles should be
227
// broadcast as framework error events
228
restartBundles( progressListener );
229
230       // enter active state
231
state = Bundle.ACTIVE;
232
233       fireFrameworkStartedEvent();
234
235       System.out.println( "Cube started" );
236
237       String startedFlagFile = System.getProperty( SYSTEM_PROPERTY_CUBE_STARTED_FLAG_FILE );
238       if ( startedFlagFile != null ) {
239          File file = new File( startedFlagFile );
240          try {
241             writeFile( file, "" );
242          }
243          catch ( IOException e ) {
244             log( LOG_ERROR, "Unable to create started flag file: " + file.getAbsolutePath(), e );
245          }
246       }
247    }
248
249    public synchronized void shutdown( boolean exitJVM ) {
250       // enter stopping state
251
state = Bundle.STOPPING;
252
253       // suspend active bundles
254
//
255
// OSGi 2 spec says that BundleException while suspending bundles should be
256
// broadcast as framework error events
257
BundleImpl[] bundles = getBundles();
258       for ( int i = bundles.length - 1; i >= 0; i-- ) {
259          if ( bundles[ i ].getBundleId() != 0 && bundles[ i ].getState() == bundles[ i ].ACTIVE ) {
260             try {
261                bundles[ i ].stop( true );
262             }
263             catch( BundleException e ) {
264                fireFrameworkEvent( FrameworkEvent.ERROR, bundles[ i ], e );
265             }
266          }
267       }
268
269       // Disable event handling
270
handlingEvents = false;
271
272       state = Bundle.RESOLVED;
273
274       System.out.println( "Cube stopped" );
275
276       // Note: no data storage or updates to bundle directories are made in this method
277
// This is good because it means that if the engine is stopped brutally or crashed,
278
// the fact that shutdown() has not been called will not be a problem when the engine
279
// is restarted.
280

281       if ( exitJVM ) {
282          System.exit( 0 );
283       }
284    }
285
286    protected abstract boolean enforcesPermissions();
287
288 // *****************************************************************************
289
// Bundle operations
290
// *****************************************************************************
291

292    protected Bundle reinstallBundle( long id ) throws BundleException, IOException {
293       File jarFile = getCurrentBundleJarFile( id );
294       String location = readStoredBundleLocation( id );
295       return installBundle( id, location, jarFile );
296    }
297
298    public Bundle installBundle( String location ) throws BundleException {
299       Util.checkNullParameter( location, getClass().getName(), "installBundle", "location" );
300       return installBundle( location, null );
301    }
302
303    protected Bundle installBundle( String location, InputStream in ) throws BundleException {
304       Util.checkNullParameter( location, getClass().getName(), "installBundle", "location" );
305
306       // If a bundle with the same location string has already been installed
307
// into the framework, return that bundle
308
try {
309          Bundle bundle = getBundle( location );
310          if ( bundle != null && bundle.getState() != bundle.UNINSTALLED ) {
311             return getBundle( location );
312          }
313       }
314       catch( IllegalArgumentException ignore ) {
315          // bundle with this location has not already been installed
316
}
317
318       // Generate id for the bundle
319
long id = generateNewBundleId();
320
321       // With the new bundle id generated, we should be able to create a fresh directory.
322
// However there can be a problem (observed with windows NT)
323
// Start an engine, open a file explorer and look at the contents of the bundle with the
324
// largest id, b3 say.
325
// Then uninstall bundle 3, stop the engine and restart it.
326
// The directory for bundle b3 is deleted when the engine is restarted (since the bundle
327
// has been uninstalled). However the file explorer still has some sort of hook on that
328
// directory.
329
// When we create directory b3 now, it seems to be ok but when we call list() on the
330
// directory, we get null, and this causes exceptions.
331
// To avoid this problem, we test if this happens, and if it does, we just take another
332
// id.
333
File bundleDirectory = null;
334       while ( bundleDirectory == null ) {
335          // Create directory for bundle
336
bundleDirectory = createFreshBundleDirectory( id );
337          if ( bundleDirectory.list() == null ) {
338             bundleDirectory = null;
339             id++;
340          }
341       }
342
343       try {
344          // Retreive jar file and store in bundle directory
345
if ( in == null ) {
346             URL url = new URL( location );
347             in = url.openStream();
348          }
349          File bundleJar = getNewBundleJarFile( id );
350          Util.transferData( in, new FileOutputStream( bundleJar ) );
351
352          // Store bundle location in permanent storage
353
if ( id != 0 ) {
354             recordBundleLocation( id, location );
355          }
356
357          return installBundle( id, location, bundleJar );
358       }
359       catch( Exception e ) {
360          // Undo any work performed, and rethrow exception
361
if ( !Util.recursiveFileDelete( bundleDirectory ) ) {
362             log( LOG_WARNING, "Unable to delete bundle directory after bundle installation failure" );
363          }
364
365          if ( e instanceof BundleException ) {
366             throw (BundleException)e;
367          }
368          else {
369             throw new BundleException( "Unable to install bundle: " + location, e );
370          }
371       }
372    }
373
374    private Bundle installSystemBundle( File bundleJar ) {
375       try {
376          if ( !bundleJar.exists() ) {
377             throw new BundleException( "System bundle jar file not found: " + bundleJar.getAbsolutePath() );
378          }
379          return installBundle( (long)0, Constants.SYSTEM_BUNDLE_LOCATION, bundleJar );
380       }
381       catch( BundleException e ) {
382 // fireFrameworkErrorEvent( null, e );
383
Throwable rootCause = e;
384          if ( e.getNestedException() != null ) {
385             rootCause = e.getNestedException();
386          }
387          log( LOG_ERROR, "FATAL ERROR: System bundle could not be installed", rootCause );
388
389          System.exit( 1 );
390          return null;
391       }
392    }
393
394    // This method is called directly by the framework to install local copy of bundle
395
// on framework restarts.
396
// It is also called by this class's installBundle( location, in ) to complete a new
397
// bundle installation.
398
private Bundle installBundle( long id, String location, File bundleJar ) throws BundleException {
399       if ( id > largestBundleId ) {
400          largestBundleId = id;
401       }
402
403       try {
404          // Create bundle
405
// Allocate associated resources
406
// Set state to INSTALLED
407
// Resolve classpath and native code dependencies if any
408
BundleImpl bundle;
409          if ( id == 0 ) {
410             bundle = new SystemBundle( this, bundleJar );
411          }
412          else {
413             bundle = new BundleImpl( this, id, location, bundleJar );
414          }
415
416          // Broadcast bundle installed event
417
fireBundleEvent( BundleEvent.INSTALLED, bundle );
418
419          id_bundle.put( new Long( bundle.getBundleId() ), bundle );
420          packageAdmin.resolveBundles();
421
422          log( LOG_INFO, bundle.getLocation() + " installed (bundle id: " + bundle.getBundleId() + ")" );
423
424          // Return bundle
425
return bundle;
426       }
427       catch( Exception e ) {
428 e.printStackTrace();
429          throw new BundleException( "Unable to install bundle: " + location, e );
430       }
431    }
432
433    protected void bundleUninstalled( long id ) throws BundleException {
434       // don't remove bundle id
435
// leave bundle present on framework in uninstalled state
436
// (to completely remove all trace of the bundle from the framework, either stop and restart
437
// framework, or call this class's wipeUninstalledBundles() method)
438
// id_bundle.remove( new Long( id ) );
439

440       // no need to unresolve bundles because it is done in BundleImpl's uninitializeBundle() method
441
// unresolveBundles();
442

443       log( LOG_INFO, "Bundle " + id + " uninstalled" );
444    }
445
446    public void wipeUninstalledBundles( Bundle[] bundlesToCheck ) {
447       if ( bundlesToCheck == null ) {
448          bundlesToCheck = getBundles();
449       }
450
451       long bundleId;
452       for ( int i = 0; i < bundlesToCheck.length; i++ ) {
453          if ( bundlesToCheck[ i ].getState() == bundlesToCheck[ i ].UNINSTALLED ) {
454             bundleId = bundlesToCheck[ i ].getBundleId();
455             id_bundle.remove( new Long( bundleId ) );
456             deleteBundleDirectory( bundleId );
457          }
458       }
459    }
460
461 // *****************************************************************************
462

463    protected String getProperty( String key ) {
464       Util.checkNullParameter( key, getClass().getName(), "getProperty", "key" );
465
466       if ( key.equals( Constants.FRAMEWORK_LANGUAGE ) ) {
467          return Locale.getDefault().getLanguage();
468       }
469       else if ( key.equals( Constants.FRAMEWORK_OS_NAME ) ) {
470          String osName = System.getProperty( "os.name" );
471          if ( osName.equals( "OS/2" ) ) {
472             return "OS2";
473          }
474          else if ( osName.equals( "procnto" ) ) {
475             return "QNX";
476          }
477          else if ( osName.equals( "Win95" )
478                    || osName.equals( "Windows 95" ) ) {
479             return "Windows95";
480          }
481          else if ( osName.equals( "Win98" )
482                    || osName.equals( "Windows 98" ) ) {
483             return "Windows98";
484          }
485          else if ( osName.equals( "WinNT" )
486                    || osName.equals( "Windows NT" ) ) {
487             return "WindowsNT";
488          }
489          else if ( osName.equals( "WinCE" )
490                    || osName.equals( "Windows CE" ) ) {
491             return "WindowsCE";
492          }
493          else if ( osName.equals( "Win2000" )
494                    || osName.equals( "Windows 2000" ) ) {
495             return "Windows2000";
496          }
497          else if ( osName.equals( "Mac OS X" ) ) {
498             return "MacOS";
499          }
500          else {
501             return osName;
502          }
503       }
504       else if ( key.equals( Constants.FRAMEWORK_OS_VERSION ) ) {
505          return System.getProperty( "os.version" );
506       }
507       else if ( key.equals( Constants.FRAMEWORK_PROCESSOR ) ) {
508          String processorName = System.getProperty( "os.arch" );
509          if ( processorName.equals( "psc1k" ) ) {
510             return "Ignite";
511          }
512          else if ( processorName.equals( "power" )
513                    || processorName.equals( "ppc" ) ) {
514             return "PowerPC";
515          }
516          else if ( processorName.equals( "pentium" )
517                    || processorName.equals( "i386" )
518                    || processorName.equals( "i486" )
519                    || processorName.equals( "i586" )
520                    || processorName.equals( "i686" ) ) {
521             return "x86";
522          }
523          else {
524             return processorName;
525          }
526       }
527       else if ( key.equals( Constants.FRAMEWORK_VENDOR ) ) {
528          return VENDOR;
529       }
530       else if ( key.equals( Constants.FRAMEWORK_VERSION ) ) {
531          return VERSION;
532       }
533       else {
534          return null;
535       }
536    }
537
538    protected long generateNewBundleId() {
539       // create a new bundle id (bundle id values must never be reused)
540

541       // see if a bundle id file exists (in which we store the last bundle id generated)
542
long newBundleId = 0;
543       try {
544          newBundleId = Long.valueOf( readFile( getLastBundleIdFile() ) ).longValue() + 1;
545       }
546       catch ( Exception ignore ) {
547          // either the file is not there (we never generated a bundle id before) or it has
548
// been corrupted.
549
// In either case, do as if we never generated a bundle id before.
550

551          // if largest bundle id = 34, return 1001
552
// if largest bundle id = 254, return 1001
553
// if largest bundle id = 1234, return 2001
554
// if largest bundle id = 12455, return 13001
555
long thousands = largestBundleId / 1000 + 1;
556          newBundleId = thousands * 1000 + 1;
557       }
558
559       while ( id_bundle.get( new Long( newBundleId ) ) != null ) {
560          newBundleId++;
561       }
562
563       largestBundleId = newBundleId;
564       try {
565          writeFile( getLastBundleIdFile(), "" + largestBundleId );
566       }
567       catch ( IOException ignore ) {}
568
569       return newBundleId;
570 /*
571       long id = System.currentTimeMillis();
572       while ( id_bundle.get( new Long( id ) ) != null ) {
573          try {
574             Thread.sleep( 10 );
575          }
576          catch( InterruptedException ignore ) {}
577          id = System.currentTimeMillis();
578       }
579       return id;
580 */

581    }
582
583    public BundleImpl getBundle( String location ) {
584       Enumeration bundles = id_bundle.elements();
585       BundleImpl bundle;
586       while ( bundles.hasMoreElements() ) {
587          bundle = (BundleImpl)bundles.nextElement();
588          if ( bundle.getLocation().equals( location ) ) {
589             return bundle;
590          }
591       }
592       throw new IllegalArgumentException( "Bundle with requested location does not exist: " + location );
593    }
594
595    public BundleImpl getBundle( long id ) {
596       BundleImpl bundle = (BundleImpl)id_bundle.get( new Long( id ) );
597       if ( bundle == null ) {
598          throw new IllegalArgumentException( "Bundle with requested id does not exist: " + id );
599       }
600       return bundle;
601    }
602
603    public BundleImpl[] getBundles() {
604       Number[] ids = new Number[ id_bundle.size() ];
605       Enumeration enum = id_bundle.keys();
606       int i = 0;
607       while ( enum.hasMoreElements() ) {
608          ids[ i++ ] = (Long)enum.nextElement();
609       }
610       ids = Util.sortNumbers( ids );
611
612       BundleImpl[] bundles = new BundleImpl[ ids.length ];
613       for ( i = 0; i < ids.length; i++ ) {
614          bundles[ i ] = (BundleImpl)id_bundle.get( ids[ i ] );
615       }
616       return bundles;
617    }
618
619    public PackageAdminImpl getPackageAdmin() {
620       return packageAdmin;
621    }
622
623    public PermissionAdmin getPermissionAdmin() {
624       return null;
625    }
626
627    protected ServiceRegistry getServiceRegistry() {
628       return serviceRegistry;
629    }
630
631    protected File createFreshBundleDirectory( long id ) {
632       File bundleDirectory = generateBundleDirectory( id );
633
634       // If directory already exists, remove all it contains
635
if ( bundleDirectory.exists() ) {
636          if ( !Util.recursiveFileDelete( bundleDirectory ) ) {
637             log( LOG_WARNING, "Could not delete directory: " + bundleDirectory.getAbsolutePath() );
638          }
639       }
640
641       // Create bundle directory, and return
642
bundleDirectory.mkdirs();
643       return bundleDirectory;
644    }
645
646    public File getBundleInnerFilesDirectory( long id ) {
647       File bundleInnerFilesDirectory = (File)bundleInnerFileDirectories.get( new Long( id ) );
648       if ( bundleInnerFilesDirectory == null ) {
649          // this is the first time we get the directory
650
bundleInnerFilesDirectory = new File( generateBundleDirectory( id ), bundleInnerFilesDirName + getLargestBundleJarIndex( id ) );
651          bundleInnerFileDirectories.put( new Long( id ), bundleInnerFilesDirectory );
652          if ( bundleInnerFilesDirectory.exists() ) {
653             // clean up old stuff from previous engine runs
654
Util.recursiveFileDelete( bundleInnerFilesDirectory );
655          }
656          bundleInnerFilesDirectory.mkdirs();
657       }
658       return bundleInnerFilesDirectory;
659    }
660
661    public File getBundleDataDirectory( long id ) {
662       File dataDirectory = new File( generateBundleDirectory( id ), bundleDataDirName );
663       if ( !dataDirectory.exists() ) {
664          dataDirectory.mkdirs();
665       }
666       return dataDirectory;
667    }
668
669    protected int getLargestBundleJarIndex( long id ) {
670       File bundleDir = generateBundleDirectory( id );
671       String[] listing = bundleDir.list();
672       String indexString;
673       int index;
674       int largestBundleJarIndex = -1;
675       for ( int i = 0; i < listing.length; i++ ) {
676          if ( listing[ i ].startsWith( bundleJarNameBase ) && listing[ i ].endsWith( bundleJarNameExtension ) ) {
677             indexString = listing[ i ].substring( bundleJarNameBase.length(), listing[ i ].length() - bundleJarNameExtension.length() );
678             try {
679                index = Integer.valueOf( indexString ).intValue();
680                if ( largestBundleJarIndex < index ) {
681                   largestBundleJarIndex = index;
682                }
683             }
684             catch( NumberFormatException ignore ) {}
685          }
686       }
687       if ( largestBundleJarIndex > -1 ) {
688          return largestBundleJarIndex;
689       }
690       throw new IllegalArgumentException( "No bundle jar file found for requested bundle id: " + id );
691    }
692
693    protected File getCurrentBundleJarFile( long id ) {
694       int jarIndex = getLargestBundleJarIndex( id );
695       return new File( generateBundleDirectory( id ), bundleJarNameBase + jarIndex + bundleJarNameExtension );
696    }
697
698    protected File getNewBundleJarFile( long id ) {
699       int index;
700       try {
701          int jarIndex = getLargestBundleJarIndex( id );
702          index = jarIndex + 1;
703       }
704       catch( IllegalArgumentException e ) {
705          index = 0;
706       }
707
708       return new File( generateBundleDirectory( id ), bundleJarNameBase + index + bundleJarNameExtension );
709    }
710
711    // Called to delete jar file that was created during an unsuccessful bundle update.
712
protected boolean deleteBundleJarFile( File file ) {
713       if ( file.exists() ) {
714          return file.delete();
715       }
716       return true;
717    }
718
719    protected boolean deleteBundleDirectory( long id ) {
720       File bundleDir = generateBundleDirectory( id );
721       return bundleDir.delete();
722    }
723
724    protected void setBundleUninstalled( long id ) throws IOException {
725       File uninstalledFlagFile = generateBundleUninstalledFlagFile( id );
726       writeFile( uninstalledFlagFile, "" );
727    }
728
729    protected void registerBundleAsStarted( long bundleId ) throws IOException {
730       File startedFlagFile = generateBundleStartedFlagFile( bundleId );
731       writeFile( startedFlagFile, "" );
732    }
733
734    protected void recordBundleLocation( long bundleId, String location ) throws IOException {
735       File file = generateBundleLocationFile( bundleId );
736       writeFile( file, location );
737    }
738
739    protected String readStoredBundleLocation( long id ) throws IOException {
740       File file = generateBundleLocationFile( id );
741       if ( !file.exists() ) {
742          throw new IllegalArgumentException( "No location file found for bundle: " + id );
743       }
744
745       return readFile( file );
746    }
747
748    protected boolean unregisterBundleAsStarted( Bundle bundle ) {
749       File startedFlagFile = generateBundleStartedFlagFile( bundle.getBundleId() );
750       if ( !startedFlagFile.exists() ) {
751          return true;
752       }
753       else {
754          return startedFlagFile.delete();
755       }
756    }
757
758    protected int getReasonableTimeToWait() {
759       return reasonableTimeToWait;
760    }
761
762 // *****************************************************************************
763
// Security
764
// *****************************************************************************
765

766    public abstract void checkAdminPermission() throws SecurityException;
767    public abstract void checkFilePermission( String file, String permissionToCheck ) throws SecurityException;
768    public abstract void checkPackagePermission( NamedPropertySet[] packages, String permissionToCheck, Object codeSource ) throws SecurityException;
769    public abstract void checkPropertyPermission( String property, String permissionToCheck ) throws SecurityException;
770    public abstract void checkServicePermission( String className, String permissionToCheck ) throws SecurityException;
771    // Throw a security exception if the check fails on one ore more of the classes
772
public abstract void checkServicePermissionForAll( String[] classNames, String permissionToCheck ) throws SecurityException;
773    // Throw a security exception if all the checks fail
774
public abstract void checkServicePermissionForAtLeastOne( String[] classNames, String permissionToCheck ) throws SecurityException;
775    protected abstract boolean hasPermission( BundleImpl bundle, Object permission );
776    protected abstract BundleClassLoader createClassLoaderForBundle( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibraries, NamedPropertySet[] classPath ) throws IOException;
777
778
779 // *****************************************************************************
780
// Events
781
// *****************************************************************************
782

783    protected void addServiceListener( BundleImpl bundle, ServiceListener serviceListener, String filterString ) throws InvalidSyntaxException {
784       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " adding a service listener" );
785       if ( filterString == null ) {
786          addServiceListener( bundle, serviceListener );
787       }
788       else {
789          // use filter that use case-insensitive keys (service property names are case-insensitive)
790
serviceListeners.addListener( bundle, serviceListener, new LDAPFilter( filterString, false ) );
791       }
792    }
793
794    protected void addServiceListener( BundleImpl bundle, ServiceListener serviceListener ) {
795       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " adding a service listener" );
796       serviceListeners.addListener( bundle, serviceListener );
797    }
798
799    protected void removeServiceListener( BundleImpl bundle, ServiceListener serviceListener ) {
800       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing a service listener" );
801       serviceListeners.removeListener( bundle, serviceListener );
802    }
803
804    protected void removeServiceListenersRegisteredBy( BundleImpl bundle ) {
805       int n = serviceListeners.getListenersRegisteredBy( bundle ).length;
806       if ( n > 0 ) {
807          log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing " + n + " service listener(s)" );
808       }
809       serviceListeners.removeAllListenersRegisteredBy( bundle );
810    }
811
812    protected void addBundleListener( BundleImpl bundle, BundleListener bundleListener ) {
813       if ( bundleListener instanceof SynchronousBundleListener ) {
814          // adding a synchronous bundle listener requires admin permission
815
checkAdminPermission();
816       }
817       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " adding a bundle listener" );
818       bundleListeners.addListener( bundle, bundleListener );
819    }
820
821    protected void removeBundleListener( BundleImpl bundle, BundleListener bundleListener ) {
822       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing a bundle listener" );
823       bundleListeners.removeListener( bundle, bundleListener );
824    }
825
826    protected void removeBundleListenersRegisteredBy( BundleImpl bundle ) {
827       int n = bundleListeners.getListenersRegisteredBy( bundle ).length;
828       if ( n > 0 ) {
829       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing " + n + " bundle listener(s)" );
830       }
831       bundleListeners.removeAllListenersRegisteredBy( bundle );
832    }
833
834    protected void addFrameworkListener( BundleImpl bundle, FrameworkListener frameworkListener ) {
835       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " adding a framework listener" );
836       frameworkListeners.addListener( bundle, frameworkListener );
837    }
838
839    protected void removeFrameworkListener( BundleImpl bundle, FrameworkListener frameworkListener ) {
840       log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing a framework listeners" );
841       frameworkListeners.removeListener( bundle, frameworkListener );
842    }
843
844    protected void removeFrameworkListenersRegisteredBy( BundleImpl bundle ) {
845       int n = frameworkListeners.getListenersRegisteredBy( bundle ).length;
846       if ( n > 0 ) {
847          log( LOG_DEBUG, bundle.getLocationWithoutAdminPermissionCheck() + " removing " + n + " framework listener(s)" );
848       }
849       frameworkListeners.removeAllListenersRegisteredBy( bundle );
850    }
851
852    protected void fireServiceEvent( int type, ServiceReference serviceReference ) {
853       if ( handlingEvents ) {
854          final ServiceEvent event = new ServiceEvent( type, serviceReference );
855          String[] serviceObjectClasses = (String[])serviceReference.getProperty( Constants.OBJECTCLASS );
856          ServicePermission[] permissions = new ServicePermission[ serviceObjectClasses.length ];
857          for ( int i = 0; i < serviceObjectClasses.length; i++ ) {
858             permissions[ i ] = new ServicePermission( serviceObjectClasses[ i ], ServicePermission.GET );
859          }
860
861          Enumeration bundles = serviceListeners.getBundles();
862          BundleImpl bundle;
863          boolean permissionOk;
864          Object[] bundleListeners;
865          Vector listeners = new Vector();
866          while ( bundles.hasMoreElements() ) {
867             bundle = (BundleImpl)bundles.nextElement();
868             // check if bundle has GET service permission for at least one of the classes
869
// under which the service was registered
870
permissionOk = false;
871             for ( int i = 0; i < permissions.length; i++ ) {
872                if ( hasPermission( bundle, permissions[ i ] ) ) {
873                   permissionOk = true;
874                   break;
875                }
876             }
877             if ( permissionOk ) {
878                // Only notify listeners if their bundle has GET service permission for
879
// at least one of the classes under which the service was registered
880
bundleListeners = serviceListeners.getListenersRegisteredBy( bundle );
881                for ( int i = 0; i < bundleListeners.length; i++ ) {
882                   LDAPFilter filter = serviceListeners.getFilter( bundleListeners[ i ] );
883                   if ( filter == null || filter.match( serviceReference ) ) {
884                      // Only notify listener if the filter it registered with is passed by the service
885
listeners.addElement( bundleListeners[ i ] );
886                   }
887                }
888             }
889          }
890
891          // synchronous event delivery
892
// OSGi 2.0 spec says service event delivery should occur synchronously
893
// (i.e. in the same thread that caused the event to be fired
894
for ( int i = 0; i < listeners.size(); i++ ) {
895             try {
896                doServiceEventCallback( (ServiceListener)listeners.elementAt( i ), event );
897             }
898             catch ( Throwable e ) {
899                log( LOG_WARNING, "A service listener threw an exception while being notified of an event" );
900             }
901          }
902       }
903    }
904
905    protected void fireBundleEvent( int type, Bundle bundle ) {
906       if ( handlingEvents ) {
907          SynchronousBundleListener[] synchronousTargets = bundleListeners.getSynchronousBundleListeners();
908          final BundleListener[] nonSynchronousTargets = bundleListeners.getNonSynchronousBundleListeners();
909          final BundleEvent event = new BundleEvent( type, bundle );
910          // synchronous event delivery to synchronous listeners
911
for ( int i = 0; i < synchronousTargets.length; i++ ) {
912             try {
913                doBundleEventCallback( synchronousTargets[ i ], event );
914             }
915             catch ( Throwable e ) {
916                log( LOG_WARNING, "A bundle listener threw an exception while being notified of an event" );
917             }
918          }
919          // asynchronous event delivery to other listeners
920
new Thread( ( new Runnable() {
921             public void run() {
922                for ( int i = 0; i < nonSynchronousTargets.length; i++ ) {
923                   try {
924                      doBundleEventCallback( nonSynchronousTargets[ i ], event );
925                   }
926                   catch ( Throwable e ) {
927                      log( LOG_WARNING, "A bundle listener threw an exception while being notified of an event" );
928                   }
929                }
930             }
931          } ) ).start();
932       }
933    }
934
935    public void fireFrameworkEvent( int type, Bundle bundle, Throwable throwable ) {
936       if ( type == FrameworkEvent.ERROR ) {
937          log( LOG_ERROR, "Framework error" );
938          if ( bundle != null ) {
939             log( LOG_ERROR, "Bundle: " + bundle.getLocation() + " (Id: " + bundle.getBundleId() + ")" );
940          }
941          if ( throwable != null ) {
942             StringBuffer sb = new StringBuffer( "Exception: " + throwable.toString() );
943             if ( throwable instanceof BundleException ) {
944                Throwable nested = ( (BundleException)throwable ).getNestedException();
945                if ( nested != null ) {
946                   sb.append( "\nNested excpetion: " + nested.toString() );
947                }
948             }
949             log( LOG_ERROR, sb.toString() );
950          }
951       }
952
953       if ( handlingEvents ) {
954          final Enumeration targets = frameworkListeners.getAllListeners();
955          final FrameworkEvent event = new FrameworkEvent( type, bundle, throwable );
956          // asynchronous event delivery to all listeners
957
new Thread( ( new Runnable() {
958             public void run() {
959                while ( targets.hasMoreElements() ) {
960                   try {
961                      doFrameworkEventCallback( (FrameworkListener)targets.nextElement(), event );
962                   }
963                   catch ( Throwable e ) {
964                      log( LOG_WARNING, "A framework listener threw an exception while being notified of an event" );
965                   }
966                }
967             }
968          } ) ).start();
969       }
970    }
971
972    protected void fireFrameworkErrorEvent( Bundle bundle, Throwable exception ) {
973       log( LOG_ERROR, "Framework error" );
974       log( LOG_ERROR, "Exception: " + exception.toString() );
975
976       if ( handlingEvents ) {
977          final Enumeration targets = frameworkListeners.getAllListeners();
978          final FrameworkEvent event = new FrameworkEvent( FrameworkEvent.ERROR, bundle, exception );
979          // asynchronous event delivery
980
new Thread( ( new Runnable() {
981             public void run() {
982                while ( targets.hasMoreElements() ) {
983                   try {
984                      doFrameworkEventCallback( (FrameworkListener)targets.nextElement(), event );
985                   }
986                   catch ( Throwable e ) {
987                      log( LOG_WARNING, "A framework listener threw an exception while being notified of an event" );
988                   }
989                }
990             }
991          } ) ).start();
992       }
993    }
994
995    private void fireFrameworkStartedEvent() {
996       if ( handlingEvents ) {
997          final Enumeration targets = frameworkListeners.getAllListeners();
998          final FrameworkEvent event = new FrameworkEvent( FrameworkEvent.STARTED, getBundle( 0 ), null );
999          // asynchronous event delivery
1000
new Thread( ( new Runnable() {
1001            public void run() {
1002               while ( targets.hasMoreElements() ) {
1003                  try {
1004                     doFrameworkEventCallback( (FrameworkListener)targets.nextElement(), event );
1005                  }
1006                  catch ( Throwable e ) {
1007                     log( LOG_WARNING, "A framework listener threw an exception while being notified of an event" );
1008                  }
1009               }
1010            }
1011         } ) ).start();
1012      }
1013   }
1014
1015   public void doServiceEventCallback( ServiceListener listener, ServiceEvent event ) {
1016      listener.serviceChanged( event );
1017   }
1018
1019   public void doBundleEventCallback( BundleListener listener, BundleEvent event ) {
1020      listener.bundleChanged( event );
1021   }
1022
1023   public void doFrameworkEventCallback( FrameworkListener listener, FrameworkEvent event ) {
1024      listener.frameworkEvent( event );
1025   }
1026
1027// *****************************************************************************
1028
// Low level framework logging
1029
// *****************************************************************************
1030

1031   public static final String LOG_INFO = "INFO: ";
1032   public static final String LOG_DEBUG = "DEBUG: ";
1033   public static final String LOG_WARNING = "WARNING: ";
1034   public static final String LOG_ERROR = "ERROR: ";
1035
1036   private Hashtable logTypes = new Hashtable();
1037
1038   private void initLog() {
1039      // log errors by default
1040
if ( ( "" + false ).equals( System.getProperty( "com.opensugar.cube.lowLevelLog.showErrors" ) ) ) {
1041         setLogging( LOG_ERROR, false );
1042      }
1043      else {
1044         setLogging( LOG_ERROR, true );
1045      }
1046      // log warnings by default
1047
if ( ( "" + false ).equals( System.getProperty( "com.opensugar.cube.lowLevelLog.showWarnings" ) ) ) {
1048         setLogging( LOG_WARNING, false );
1049      }
1050      else {
1051         setLogging( LOG_WARNING, true );
1052      }
1053      // do not log infos by default
1054
if ( ( "" + true ).equals( System.getProperty( "com.opensugar.cube.lowLevelLog.showInfos" ) ) ) {
1055         setLogging( LOG_INFO, true );
1056      }
1057      else {
1058         setLogging( LOG_INFO, false );
1059      }
1060   }
1061
1062   protected void setLogging( String logType, boolean logging ) {
1063      if ( logging ) {
1064         logTypes.put( logType, "" );
1065      }
1066      else {
1067         logTypes.remove( logType );
1068      }
1069   }
1070
1071   public void log( String logType, String message ) {
1072      log( logType, message, null );
1073   }
1074
1075   public void log( String logType, String message, Throwable exception ) {
1076      if ( logTypes.get( logType ) != null ) {
1077         System.out.println( logType + message );
1078         if ( logType.equals( LOG_ERROR ) && exception != null ) {
1079            if ( exception instanceof BundleException && ( (BundleException)exception ).getNestedException() != null ) {
1080               ( (BundleException) exception ).getNestedException().printStackTrace();
1081            }
1082            else {
1083               exception.printStackTrace();
1084            }
1085         }
1086      }
1087   }
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100// *****************************************************************************
1101
// Files and directories
1102
// *****************************************************************************
1103

1104   protected File getBaseDirectory() {
1105      if ( baseDirectory == null ) {
1106         baseDirectory = new File( System.getProperty( SYSTEM_PROPERTY_CUBE_DIR, defaultCubeDir ) );
1107      }
1108      return baseDirectory;
1109   }
1110
1111   private File getLastBundleIdFile() {
1112      return new File( getBaseDirectory(), bundleIdFileName );
1113   }
1114
1115   private File generateBundleDirectory( long id ) {
1116      return new File( getBaseDirectory(), bundleDirNameBase + id );
1117   }
1118
1119   private File generateBundleStartedFlagFile( long id ) {
1120      return new File( generateBundleDirectory( id ), bundleStartedFlagFileName );
1121   }
1122
1123   private File generateBundleUninstalledFlagFile( long id ) {
1124      return new File( generateBundleDirectory( id ), bundleUninstalledFlagFileName );
1125   }
1126
1127   private File generateBundleLocationFile( long id ) {
1128      return new File( generateBundleDirectory( id ), bundleLocationFileName );
1129   }
1130
1131   private String readFile( File file ) throws IOException {
1132      FileInputStream fis = null;
1133      try {
1134         fis = new FileInputStream( file );
1135         int n = fis.available();
1136         byte[] data = new byte[ n ];
1137         fis.read( data );
1138         return new String( data );
1139      }
1140      catch( IOException e ) {
1141         throw e;
1142      }
1143      finally {
1144         try {
1145            fis.close();
1146         }
1147         catch( Exception ignore ) {}
1148      }
1149   }
1150
1151   private void writeFile( File file, String contents ) throws IOException {
1152      FileOutputStream fos = null;
1153      try {
1154         fos = new FileOutputStream( file );
1155         fos.write( contents.getBytes() );
1156      }
1157      catch( IOException e ) {
1158         throw e;
1159      }
1160      finally {
1161         try {
1162            fos.close();
1163         }
1164         catch( Exception ignore ) {}
1165      }
1166   }
1167
1168// *****************************************************************************
1169
// deleteUninstalledBundleDirectories()
1170
// deleteObsoleteBundleJars()
1171
// reinstallBundles()
1172
// restartBundles()
1173
// *****************************************************************************
1174

1175   // When a bundle is uninstalled, it may not be possible to delete the bundle's
1176
// directory. That is the case if the bundle's stop method does not release all
1177
// the files that it is using. (I think the bundle is badly coded if it does that
1178
// but we want to be robust against this sort of behavior.)
1179
// If a bundle is uninstalled and its directory is not deleted, the engine records
1180
// the fact that this directory should have been deleted by creating an uninstalled
1181
// flag file in the directory. This way, next time the engine is started it can
1182
// delete the directories of uninstalled bundles.
1183
// Here we check all the bundle directories, and delete any directory that contains
1184
// an uninstalled flag file.
1185
private void deleteUninstalledBundleDirectories() {
1186      File[] bundleDirs = getBundleDirectories();
1187      if ( bundleDirs == null ) {
1188         return;
1189      }
1190
1191      for ( int i = 0; i < bundleDirs.length; i++ ) {
1192         if ( !isInstalled( bundleDirs[ i ] ) ) {
1193            if ( !Util.recursiveFileDelete( bundleDirs[ i ] ) ) {
1194               log( LOG_WARNING, "Unable to delete bundle directory: " + bundleDirs[ i ] );
1195            }
1196         }
1197      }
1198   }
1199
1200   // Check if the specified directory contains an uninstalled flag file.
1201
private boolean isInstalled( File bundleDir ) {
1202      File uninstalledFlagFile = new File( bundleDir, AbstractCube.bundleUninstalledFlagFileName );
1203      if ( uninstalledFlagFile.exists() ) {
1204         return false;
1205      }
1206      return true;
1207   }
1208
1209   // Check if the specified directory contains a started flag file.
1210
private boolean isStarted( File bundleDir ) {
1211      File startedFlagFile = new File( bundleDir, AbstractCube.bundleStartedFlagFileName );
1212      if ( startedFlagFile.exists() ) {
1213         return true;
1214      }
1215      return false;
1216   }
1217
1218   // When a bundle is updated, it may not be possible to delete the old version of
1219
// the bundle's jar file (and the directory in which inner files are stored).
1220
// That is the case if the bundle's stop method does not
1221
// release all the files that it is using. (I think the bundle is badly coded if it
1222
// does that but we want to be robust against this sort of behavior.)
1223
// That is also be the case if the cube needs to continue exporting classes that are
1224
// in the old bundle jar file but not in the new one. (Note that if the cube continues
1225
// to export the packages of a bundle after it is updated or uninstalled, it must stop
1226
// doing so next time it is started. Therefore deletion of the bundle jar here is the
1227
// correct behavior.)
1228
// If a bundle is updated and its old jar file is not deleted, the cube stores the
1229
// new jar file next to the old jar file, with an index number one higher than the index
1230
// of the old jar file. When the engine is restarted it should delete the obsolete jar
1231
// files, i.e. all jar files in the bundle directory except that with the highest index
1232
// number.
1233
// Also, when a problem occurs during installation of a bundle, a directory for the bundle
1234
// can be created that does not contain the required files. If directories exist that do
1235
// not contain all required files, they should be deleted so the engine does not try to
1236
// restart the bundle.
1237
//
1238
// Here we check all the bundle directories, and delete any jar file and inner file directory
1239
// with index number smaller than the index number of the jar file that has the highest index
1240
// number in the same directory.
1241
//
1242
// (If bundle jar name base is "bundle" and bundle jar name extension is .jar, names of jar
1243
// files take the form: bundle0.jar, bundle1.jar, bundle2.jar, and if the bundle inner file
1244
// directory base is "inner", then inner file directories take the form: inner0, inner1,
1245
// inner2, etc.
1246
private void deleteObsoleteBundleFiles() {
1247      File[] invalidBundleDirs = getInvalidBundleDirectories();
1248      for ( int i = 0; i < invalidBundleDirs.length; i++ ) {
1249         if ( !invalidBundleDirs[ i ].delete() ) {
1250            log( LOG_ERROR, "Unable to delete invalid bundle directory: " + invalidBundleDirs[ i ] );
1251            System.exit( 1 );
1252         }
1253      }
1254
1255
1256      File[] bundleDirs = getBundleDirectories();
1257      if ( bundleDirs == null ) {
1258         return;
1259      }
1260
1261      File[] obsoleteBundleFiles;
1262      for ( int i = 0; i < bundleDirs.length; i++ ) {
1263         obsoleteBundleFiles = getObsoleteBundleFiles( bundleDirs[ i ] );
1264         if ( obsoleteBundleFiles == null ) {
1265            continue;
1266         }
1267         for ( int j = 0; j < obsoleteBundleFiles.length; j++ ) {
1268            if ( !Util.recursiveFileDelete( obsoleteBundleFiles[ j ] ) ) {
1269               log( LOG_WARNING, "Unable to delete obsolete bundle file: " + obsoleteBundleFiles[ j ].getPath() );
1270            }
1271         }
1272      }
1273   }
1274
1275   // Return a list of all invalid bundle directories.
1276
// Invalid bundle directories are bundle directories that do not contain the files
1277
// that are required in a bundle directory.
1278
// The files that are required in a bundle directory are the bundle jar file and the
1279
// location file.
1280
private File[] getInvalidBundleDirectories() {
1281      File[] bundleDirs = getBundleDirectories();
1282      if ( bundleDirs == null ) {
1283         return new File[ 0 ];
1284      }
1285      String[] listing;
1286      Vector v = new Vector();
1287      for ( int i = 0; i < bundleDirs.length; i++ ) {
1288         listing = bundleDirs[ i ].list();
1289         boolean bundleJarFileFound = false;
1290         boolean locationFileFound = false;
1291         for ( int j = 0; j < listing.length; j++ ) {
1292            try {
1293               getBundleJarFileIndex( listing[ j ] );
1294               bundleJarFileFound = true;
1295            }
1296            catch( Exception e ) {
1297               // not a bundle directory
1298
}
1299
1300            if ( listing[ j ].equals( AbstractCube.bundleLocationFileName ) ) {
1301               locationFileFound = true;
1302            }
1303         }
1304         if ( !bundleJarFileFound || !locationFileFound ) {
1305            v.addElement( bundleDirs[ i ] );
1306         }
1307      }
1308
1309      File[] invalidBundleDirs = new File[ v.size() ];
1310      v.copyInto( invalidBundleDirs );
1311      return invalidBundleDirs;
1312   }
1313
1314   // Return a list of all the bundle directories.
1315
// Bundle directories are direct subdirectories of the engine directory.
1316
// If the bundle directory name base is "b", the name of the bundle directories
1317
// take the form b1, b2, b3, etc, where the integer after the base name is the
1318
// bundle id.
1319
private File[] getBundleDirectories() {
1320      File baseDir = getBaseDirectory();
1321      if ( !baseDir.exists() ) {
1322         return null;
1323      }
1324
1325      String[] listing = baseDir.list();
1326      Vector vec = new Vector();
1327      String bundleId;
1328      for ( int i = 0; i < listing.length; i++ ) {
1329         try {
1330            // Check if directory is a bundle directory
1331
getBundleId( listing[ i ] );
1332            // If so add it to the list.
1333
vec.addElement( new File( baseDir, listing[ i ] ) );
1334         }
1335         catch( IllegalArgumentException ignore ) {
1336            // Directory is not a bundle directory
1337
}
1338      }
1339
1340      File[] bundleDirs = new File[ vec.size() ];
1341      vec.copyInto( bundleDirs );
1342      return bundleDirs;
1343   }
1344
1345
1346   // Return the bundle id corresponding to the specified bundle directory.
1347
// If the bundle directory name base is "b", the name of the bundle directories
1348
// take the form b1, b2, b3, etc, where the integer after the base name is the
1349
// bundle id.
1350
private long getBundleId( String bundleDirName ) throws IllegalArgumentException {
1351      if ( !bundleDirName.startsWith( AbstractCube.bundleDirNameBase ) ) {
1352         throw new IllegalArgumentException( "Directory name is not a valid bundle directory name" );
1353      }
1354      String idString = bundleDirName.substring( AbstractCube.bundleDirNameBase.length(), bundleDirName.length() );
1355      try {
1356         Long id = Long.valueOf( idString );
1357         return id.longValue();
1358      }
1359      catch( NumberFormatException e ) {
1360         throw new IllegalArgumentException( "Directory name is not a valid bundle directory name" );
1361      }
1362   }
1363
1364   // Return a list of all the old (obsolete) bundle files in a given directory.
1365
// Obsolete bundle files are obsolete bundle jar files and obsolete bundle inner jar file
1366
// directories.
1367
// (See comments of method deleteObsoleteBundleJars()
1368
//
1369
// (If bundle jar name base is "bundle" and bundle jar name extension is .jar, names of jar
1370
// files take the form: bundle0.jar, bundle1.jar, bundle2.jar, etc
1371
// If bundle inner jar file directory name is "inner", names of inner jar file directories
1372
// take the form: inner0, inner1, inner2, etc
1373
private File[] getObsoleteBundleFiles( File bundleDir ) {
1374      if ( bundleDir == null ) {
1375         return null;
1376      }
1377
1378      // Collect index number of all jar files.
1379
String[] listing = bundleDir.list();
1380      if ( listing == null ) {
1381         // bundleDir is in some weird state
1382
return null;
1383      }
1384
1385      Vector indices = new Vector();
1386      for ( int i = 0; i < listing.length; i++ ) {
1387         try {
1388            indices.addElement( new Integer( getBundleJarFileIndex( listing[ i ] ) ) );
1389         }
1390         catch( Exception e ) {
1391            // not a bundle jar file
1392
}
1393      }
1394
1395      // If no index has been collected, no jar file is in this directory.
1396
if ( indices.size() == 0 ) {
1397         log( LOG_WARNING, "No bundle jar file in directory: " + bundleDir );
1398         return null;
1399      }
1400
1401      // If a single index has been collected, no obsolete jar file is in this directory.
1402
if ( indices.size() == 1 ) {
1403         return null;
1404      }
1405
1406      // Find max bundle jar index.
1407
int maxIndex = -1;
1408      int index;
1409      for ( int i = 0; i < indices.size(); i++ ) {
1410         index = ( (Integer)indices.elementAt( i ) ).intValue();
1411         if ( maxIndex < index ) {
1412            maxIndex = index;
1413         }
1414      }
1415
1416      // Remove max index from list to get list of obsolete jar indices.
1417
indices.removeElement( new Integer( maxIndex ) );
1418
1419      // Create the list of bundle jar files and bundle inner jar file directories to return
1420
//
1421
// Assume that an inner file directory with a given index exists only if a bundle
1422
// jar file with that index exists.
1423
Vector tmp = new Vector();
1424      File innerFilesDirectory;
1425      for ( int i = 0; i < indices.size(); i++ ) {
1426         index = ( (Integer)indices.elementAt( i ) ).intValue();
1427         tmp.addElement( new File( bundleDir, AbstractCube.bundleJarNameBase + index + AbstractCube.bundleJarNameExtension ) );
1428         innerFilesDirectory = new File( bundleDir, AbstractCube.bundleInnerFilesDirName + index );
1429         if ( innerFilesDirectory.exists() ) {
1430            tmp.addElement( innerFilesDirectory );
1431         }
1432      }
1433
1434      File[] obsoleteBundleFiles = new File[ tmp.size() ];
1435      tmp.copyInto( obsoleteBundleFiles );
1436      return obsoleteBundleFiles;
1437   }
1438
1439   private int getBundleJarFileIndex( String bundleJarFileName ) throws NumberFormatException, IllegalArgumentException {
1440      if ( bundleJarFileName.startsWith( AbstractCube.bundleJarNameBase ) && bundleJarFileName.endsWith( AbstractCube.bundleJarNameExtension ) ) {
1441         String indexString = bundleJarFileName.substring( AbstractCube.bundleJarNameBase.length(), bundleJarFileName.length() - AbstractCube.bundleJarNameExtension.length() );
1442         return Integer.valueOf( indexString ).intValue();
1443      }
1444      else {
1445         throw new IllegalArgumentException( "Invalid bundle jar file name" );
1446      }
1447   }
1448
1449   // Install bundles that were installed last time the engine was run.
1450
//
1451
// OSGi 2 spec does not specify how to handle errors that may occur while
1452
// reinstalling bundles
1453
private void reinstallBundles() {
1454      File[] bundleDirs = getBundleDirectories();
1455      if ( bundleDirs == null ) {
1456         return;
1457      }
1458
1459      long bundleId;
1460      for ( int i = 0; i < bundleDirs.length; i++ ) {
1461         if ( isInstalled( bundleDirs[ i ] ) ) {
1462            bundleId = getBundleId( bundleDirs[ i ].getName() );
1463            try {
1464               reinstallBundle( bundleId );
1465            }
1466            catch( BundleException e ) {
1467               log( LOG_ERROR, "Could not reinstall bundle " + bundleId, e );
1468            }
1469            catch( IOException e ) {
1470               log( LOG_ERROR, "Could not reinstall bundle " + bundleId, e );
1471            }
1472         }
1473      }
1474   }
1475
1476   // Start bundles that were active last time the engine was run.
1477
//
1478
// OSGi 2 spec says that BundleException while restarting bundles should be
1479
// broadcast as framework error events
1480
private void restartBundles( Observer progressListener ) {
1481      File[] bundleDirs = getBundleDirectories();
1482      if ( bundleDirs == null ) {
1483         return;
1484      }
1485
1486      // order bundles that need to be started in increasing bundle id order
1487
long bundleId, id;
1488      Vector vec = new Vector();
1489      for ( int i = 0; i < bundleDirs.length; i++ ) {
1490         if ( isStarted( bundleDirs[ i ] ) ) {
1491            bundleId = getBundleId( bundleDirs[ i ].getName() );
1492            int index = vec.size();
1493            for ( int j = 0; j < vec.size(); j++ ) {
1494               id = ( (Long)vec.elementAt( j ) ).longValue();
1495               if ( bundleId < id ) {
1496                  index = j;
1497                  break;
1498               }
1499            }
1500            vec.insertElementAt( new Long( bundleId ), index );
1501         }
1502      }
1503
1504      int fudgeSleepTime = 0;
1505      try {
1506         fudgeSleepTime = Integer.valueOf( System.getProperty( "com.opensugar.cube.fudgeSleep" ) ).intValue();
1507      }
1508      catch ( Exception ignore ) {}
1509
1510                        int percent = 0;
1511                        String percentString = percent + " %";
1512                        System.out.print( percentString );
1513                        if ( progressListener != null ) {
1514                           progressListener.update( null, new Integer( percent ) );
1515                        }
1516      for ( int i = 0; i < vec.size(); i++ ) {
1517         bundleId = ( (Long)vec.elementAt( i ) ).longValue();
1518         BundleImpl bundle = getBundle( bundleId );
1519         try {
1520                        for ( int j = 0; j < percentString.length(); j++ ) {
1521                           System.out.print( "\b" );
1522                        }
1523                        percent = (int)( ( i + 0.5 ) / vec.size() * 100 );
1524                        percentString = percent + " %";
1525                        System.out.print( percentString );
1526                        if ( progressListener != null ) {
1527                           progressListener.update( null, new Integer( percent ) );
1528                        }
1529            // check bundle is resolved before attempting to start it
1530
// (bundle could have been running last time the cube was shut down, using stale
1531
// packages exported by an updated or uninstalled bundle. If that is the case,
1532
// the stale packages are no longer available now that the cube is being restarted
1533
// - unless another bundle provides those packages), therefore the bundle cannot
1534
// be started
1535
if ( bundle.getState() == bundle.RESOLVED ) {
1536               bundle.start();
1537            }
1538            else {
1539               log( LOG_WARNING, "\nCould not restart bundle " + bundleId + " because it is not resolved" );
1540               PackageImport[] unsatisfiedImports = packageAdmin.getUnsatisfiedImports( bundle );
1541               System.out.println( "Missing packages:" );
1542               for ( int j = 0; j < unsatisfiedImports.length; j++ ) {
1543                  System.out.print( "\t" + unsatisfiedImports[ j ].getName() );
1544                  if ( unsatisfiedImports[ j ].getSpecificationVersion() != null ) {
1545                     System.out.print( " - v" + unsatisfiedImports[ j ].getSpecificationVersion() );
1546                  }
1547                  System.out.print( "\n" );
1548               }
1549            }
1550            if ( fudgeSleepTime > 0 ) {
1551               try {
1552                  Thread.sleep( fudgeSleepTime );
1553               }
1554               catch ( InterruptedException ignore ) {}
1555            }
1556                        for ( int j = 0; j < percentString.length(); j++ ) {
1557                           System.out.print( "\b" );
1558                        }
1559                        percent = (int)( ( i + 1.0 ) / vec.size() * 100 );
1560                        percentString = percent + " %";
1561                        System.out.print( percentString );
1562                        if ( progressListener != null ) {
1563                           progressListener.update( null, new Integer( percent ) );
1564                        }
1565         }
1566         catch( Throwable e ) {
1567            fireFrameworkEvent( FrameworkEvent.ERROR, bundle, e );
1568            log( LOG_ERROR, "\nCould not restart bundle " + bundleId, e );
1569e.printStackTrace();
1570         }
1571      }
1572                        for ( int j = 0; j < percentString.length(); j++ ) {
1573                           System.out.print( "\b" );
1574                        }
1575                        if ( progressListener != null ) {
1576                           progressListener.update( null, new Integer( percent ) );
1577                        }
1578   }
1579
1580}
1581
Popular Tags