KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > internal > baseadaptor > BaseStorage


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 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
12 package org.eclipse.osgi.internal.baseadaptor;
13
14 import java.io.*;
15 import java.lang.reflect.InvocationTargetException JavaDoc;
16 import java.lang.reflect.Method JavaDoc;
17 import java.net.*;
18 import java.util.*;
19 import org.eclipse.core.runtime.adaptor.EclipseStarter;
20 import org.eclipse.core.runtime.adaptor.LocationManager;
21 import org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMsg;
22 import org.eclipse.osgi.baseadaptor.*;
23 import org.eclipse.osgi.baseadaptor.bundlefile.*;
24 import org.eclipse.osgi.baseadaptor.hooks.*;
25 import org.eclipse.osgi.framework.adaptor.*;
26 import org.eclipse.osgi.framework.debug.Debug;
27 import org.eclipse.osgi.framework.debug.FrameworkDebugOptions;
28 import org.eclipse.osgi.framework.internal.core.*;
29 import org.eclipse.osgi.framework.internal.core.Constants;
30 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
31 import org.eclipse.osgi.framework.util.KeyedHashSet;
32 import org.eclipse.osgi.service.datalocation.Location;
33 import org.eclipse.osgi.service.resolver.*;
34 import org.eclipse.osgi.storagemanager.ManagedOutputStream;
35 import org.eclipse.osgi.storagemanager.StorageManager;
36 import org.eclipse.osgi.util.ManifestElement;
37 import org.eclipse.osgi.util.NLS;
38 import org.osgi.framework.*;
39
40 public class BaseStorage implements SynchronousBundleListener {
41     private static final String JavaDoc RUNTIME_ADAPTOR = FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + "/eclipseadaptor"; //$NON-NLS-1$
42
private static final String JavaDoc OPTION_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/debug/platformadmin"; //$NON-NLS-1$
43
private static final String JavaDoc OPTION_PLATFORM_ADMIN_RESOLVER = RUNTIME_ADAPTOR + "/debug/platformadmin/resolver"; //$NON-NLS-1$
44
private static final String JavaDoc OPTION_MONITOR_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/resolver/timing"; //$NON-NLS-1$
45
private static final String JavaDoc OPTION_RESOLVER_READER = RUNTIME_ADAPTOR + "/resolver/reader/timing"; //$NON-NLS-1$
46
private static final String JavaDoc PROP_FRAMEWORK_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
47
private static final String JavaDoc PROP_BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$
48
// The name of the bundle data directory
49
static final String JavaDoc DATA_DIR_NAME = "data"; //$NON-NLS-1$
50
static final String JavaDoc LIB_TEMP = "libtemp"; //$NON-NLS-1$
51
// System property used to determine whether State saver needs to be enabled
52
private static final String JavaDoc PROP_ENABLE_STATE_SAVER = "eclipse.enableStateSaver"; //$NON-NLS-1$
53
static final String JavaDoc BUNDLEFILE_NAME = "bundlefile"; //$NON-NLS-1$
54
// System property used to clean the osgi configuration area
55
private static final String JavaDoc PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$
56

57     /** The current bundle data version */
58     public static final byte BUNDLEDATA_VERSION = 18;
59     /**
60      * flag to indicate a framework extension is being intialized
61      */

62     public static final byte EXTENSION_INITIALIZE = 0x01;
63     /**
64      * flag to indicate a framework extension is being installed
65      */

66     public static final byte EXTENSION_INSTALLED = 0x02;
67     /**
68      * flag to indicate a framework extension is being uninstalled
69      */

70     public static final byte EXTENSION_UNINSTALLED = 0x04;
71     /**
72      * flag to indicate a framework extension is being updated
73      */

74     public static final byte EXTENSION_UPDATED = 0x08;
75
76     /**
77      * the file name for the delete flag. If this file exists in one a directory
78      * under the bundle store area then it will be removed during the
79      * compact operation.
80      */

81     public static final String JavaDoc DELETE_FLAG = ".delete"; //$NON-NLS-1$
82
private static final String JavaDoc PERM_DATA_FILE = ".permdata"; //$NON-NLS-1$
83
private static final byte PERMDATA_VERSION = 1;
84
85     private BaseAdaptor adaptor;
86     // assume a file: installURL
87
private String JavaDoc installPath;
88     private StorageManager storageManager;
89     private StateManager stateManager;
90     // no need to synchronize on storageHooks because the elements are statically set in initialize
91
private KeyedHashSet storageHooks = new KeyedHashSet(5, false);
92     private BundleContext context;
93     private SynchronousBundleListener extensionListener;
94
95     /**
96      * The add URL method used to support framework extensions
97      */

98     private Method JavaDoc addURLMethod;
99     /**
100      * The list of configured framework extensions
101      */

102     private String JavaDoc[] configuredExtensions;
103
104     private long timeStamp = 0;
105     private int initialBundleStartLevel = 1;
106     private long nextId = 1;
107     /**
108      * directory containing installed bundles
109      */

110     private File bundleStoreRoot;
111
112     private BasePermissionStorage permissionStorage;
113     private StateSaver stateSaver;
114     private boolean invalidState;
115     private boolean storageManagerClosed;
116
117     BaseStorage() {
118         // make constructor package private
119
}
120
121     public void initialize(BaseAdaptor adaptor) throws IOException {
122         this.adaptor = adaptor;
123         setDebugOptions();
124         if (Boolean.valueOf(FrameworkProperties.getProperty(BaseStorage.PROP_CLEAN)).booleanValue())
125             cleanOSGiCache();
126         // initialize the addURLMethod to support framework extensions
127
ClassLoader JavaDoc fwloader = BaseStorage.class.getClassLoader();
128         if (fwloader != null)
129             addURLMethod = findaddURLMethod(fwloader.getClass());
130         // we need to set the install path as soon as possible so we can determine
131
// the absolute location of install relative URLs
132
Location installLoc = LocationManager.getInstallLocation();
133         if (installLoc != null) {
134             URL installURL = installLoc.getURL();
135             // assume install URL is file: based
136
installPath = installURL.getPath();
137         }
138         boolean readOnlyConfiguration = LocationManager.getConfigurationLocation().isReadOnly();
139         storageManager = initFileManager(LocationManager.getOSGiConfigurationDir(), readOnlyConfiguration ? "none" : null, readOnlyConfiguration); //$NON-NLS-1$
140
storageManagerClosed = false;
141         // initialize the storageHooks
142
StorageHook[] hooks = adaptor.getHookRegistry().getStorageHooks();
143         for (int i = 0; i < hooks.length; i++)
144             storageHooks.add(hooks[i]);
145     }
146
147     private void setDebugOptions() {
148         FrameworkDebugOptions options = FrameworkDebugOptions.getDefault();
149         // may be null if debugging is not enabled
150
if (options == null)
151             return;
152         StateManager.DEBUG = options != null;
153         StateManager.DEBUG_READER = options.getBooleanOption(OPTION_RESOLVER_READER, false);
154         StateManager.MONITOR_PLATFORM_ADMIN = options.getBooleanOption(OPTION_MONITOR_PLATFORM_ADMIN, false);
155         StateManager.DEBUG_PLATFORM_ADMIN = options.getBooleanOption(OPTION_PLATFORM_ADMIN, false);
156         StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER = options.getBooleanOption(OPTION_PLATFORM_ADMIN_RESOLVER, false);
157     }
158
159     protected StorageManager initFileManager(File baseDir, String JavaDoc lockMode, boolean readOnly) {
160         StorageManager sManager = new StorageManager(baseDir, lockMode, readOnly);
161         try {
162             sManager.open(!readOnly);
163         } catch (IOException ex) {
164             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
165                 Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$
166
Debug.printStackTrace(ex);
167             }
168             String JavaDoc message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR, ex.getMessage());
169             FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, ex, null);
170             adaptor.getFrameworkLog().log(logEntry);
171         }
172         return sManager;
173     }
174
175     public boolean isReadOnly() {
176         return storageManager.isReadOnly();
177     }
178
179     public void compact() throws IOException {
180         if (!isReadOnly())
181             compact(getBundleStoreRoot());
182     }
183
184     private void compact(File directory) {
185         if (Debug.DEBUG && Debug.DEBUG_GENERAL)
186             Debug.println("compact(" + directory.getPath() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
187
String JavaDoc list[] = directory.list();
188         if (list == null)
189             return;
190
191         int len = list.length;
192         for (int i = 0; i < len; i++) {
193             if (BaseStorage.DATA_DIR_NAME.equals(list[i]))
194                 continue; /* do not examine the bundles data dir. */
195             File target = new File(directory, list[i]);
196             // if the file is a directory
197
if (!target.isDirectory())
198                 continue;
199             File delete = new File(target, BaseStorage.DELETE_FLAG);
200             // and the directory is marked for delete
201
if (delete.exists()) {
202                 // if rm fails to delete the directory and .delete was removed
203
if (!AdaptorUtil.rm(target) && !delete.exists()) {
204                     try {
205                         // recreate .delete
206
FileOutputStream out = new FileOutputStream(delete);
207                         out.close();
208                     } catch (IOException e) {
209                         if (Debug.DEBUG && Debug.DEBUG_GENERAL)
210                             Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
211
}
212                 }
213             } else {
214                 compact(target); /* descend into directory */
215             }
216         }
217     }
218
219     public long getFreeSpace() throws IOException {
220         // cannot implement this without native code!
221
return -1;
222     }
223
224     public File getDataFile(BaseData data, String JavaDoc path) {
225         BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY);
226         if (storageHook == null)
227             return null;
228         return storageHook.getDataFile(path);
229     }
230
231     BaseAdaptor getAdaptor() {
232         return adaptor;
233     }
234
235     public void installNativeCode(BaseData data, String JavaDoc[] nativepaths) throws BundleException {
236         if (nativepaths.length > 0) {
237             BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY);
238             if (storageHook != null)
239                 storageHook.installNativePaths(nativepaths);
240         }
241     }
242
243     public Dictionary loadManifest(BaseData data) throws BundleException {
244         return loadManifest(data, false);
245     }
246
247     public Dictionary loadManifest(BaseData bundleData, boolean firstTime) throws BundleException {
248         Dictionary result = null;
249         StorageHook[] dataStorageHooks = bundleData.getStorageHooks();
250         for (int i = 0; i < dataStorageHooks.length && result == null; i++)
251             result = dataStorageHooks[i].getManifest(firstTime);
252         if (result == null)
253             result = AdaptorUtil.loadManifestFrom(bundleData);
254         if (result == null)
255             throw new BundleException(NLS.bind(AdaptorMsg.MANIFEST_NOT_FOUND_EXCEPTION, Constants.OSGI_BUNDLE_MANIFEST, bundleData.getLocation()));
256         return result;
257     }
258
259     public File getExtractFile(BaseData data, String JavaDoc path) {
260         BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY);
261         if (storageHook == null)
262             return null;
263         // first check the child generation dir
264
File childGenDir = storageHook.getGenerationDir();
265         if (childGenDir != null) {
266             File childPath = new File(childGenDir, path);
267             if (childPath.exists())
268                 return childPath;
269         }
270         // now check the parent
271
File parentGenDir = storageHook.getParentGenerationDir();
272         if (parentGenDir != null) {
273             // there is a parent generation check if the file exists
274
File parentPath = new File(parentGenDir, path);
275             if (parentPath.exists())
276                 // only use the parent generation file if it exists; do not extract there
277
return parentPath;
278         }
279         // did not exist in both locations; create a file for extraction.
280
File bundleGenerationDir = storageHook.createGenerationDir();
281         /* if the generation dir exists, then we have place to cache */
282         if (bundleGenerationDir != null && bundleGenerationDir.exists())
283             return new File(bundleGenerationDir, path);
284         return null;
285     }
286
287     public BaseData[] getInstalledBundles() {
288         return readBundleDatas();
289     }
290
291     private BaseData[] readBundleDatas() {
292         InputStream bundleDataStream = findStorageStream(LocationManager.BUNDLE_DATA_FILE);
293         if (bundleDataStream == null)
294             return null;
295         try {
296             DataInputStream in = new DataInputStream(new BufferedInputStream(bundleDataStream));
297             try {
298                 byte version = in.readByte();
299                 if (version != BUNDLEDATA_VERSION)
300                     return null;
301                 timeStamp = in.readLong();
302                 initialBundleStartLevel = in.readInt();
303                 nextId = in.readLong();
304
305                 int numStorageHooks = in.readInt();
306                 StorageHook[] storageHooks = adaptor.getHookRegistry().getStorageHooks();
307                 if (numStorageHooks != storageHooks.length)
308                     return null; // must have the same number of storagehooks to properly read the data
309
for (int i = 0; i < numStorageHooks; i++) {
310                     Object JavaDoc storageKey = storageHooks[i].getKey();
311                     int storageVersion = storageHooks[i].getStorageVersion();
312                     if (!storageKey.equals(in.readUTF()) || storageVersion != in.readInt())
313                         return null; // some storage hooks have changed must throw the data away.
314
}
315
316                 int bundleCount = in.readInt();
317                 ArrayList result = new ArrayList(bundleCount);
318                 long id = -1;
319                 boolean bundleDiscarded = false;
320                 for (int i = 0; i < bundleCount; i++) {
321                     boolean error = false;
322                     BaseData data = null;
323                     try {
324                         id = in.readLong();
325                         if (id != 0) {
326                             data = loadBaseData(id, in);
327                             data.getBundleFile();
328                             StorageHook[] dataStorageHooks = data.getStorageHooks();
329                             for (int j = 0; j < dataStorageHooks.length; j++)
330                                 dataStorageHooks[j].validate();
331                             if (Debug.DEBUG && Debug.DEBUG_GENERAL)
332                                 Debug.println("BundleData created: " + data); //$NON-NLS-1$
333
processExtension(data, EXTENSION_INITIALIZE);
334                             result.add(data);
335                         }
336                     } catch (IllegalArgumentException JavaDoc e) {
337                         // may be from data.getBundleFile()
338
bundleDiscarded = true;
339                         error = true;
340                     } catch (BundleException e) {
341                         // should never happen
342
bundleDiscarded = true;
343                         error = true;
344                     } catch (IOException e) {
345                         bundleDiscarded = true;
346                         error = true;
347                         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
348                             Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$
349
Debug.printStackTrace(e);
350                         }
351                     }
352                     if (error && data != null) {
353                         BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY);
354                         storageHook.delete(true, BaseStorageHook.DEL_BUNDLE_STORE);
355                     }
356                 }
357                 if (bundleDiscarded)
358                     FrameworkProperties.setProperty(EclipseStarter.PROP_REFRESH_BUNDLES, "true"); //$NON-NLS-1$
359
return (BaseData[]) result.toArray(new BaseData[result.size()]);
360             } finally {
361                 in.close();
362             }
363         } catch (IOException e) {
364             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
365                 Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$
366
Debug.printStackTrace(e);
367             }
368         }
369         return null;
370     }
371
372     private void saveAllData(boolean shutdown) {
373         if (storageManagerClosed)
374             try {
375                 storageManager.open(!LocationManager.getConfigurationLocation().isReadOnly());
376                 storageManagerClosed = false;
377             } catch (IOException e) {
378                 String JavaDoc message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR, e.getMessage());
379                 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null);
380                 adaptor.getFrameworkLog().log(logEntry);
381             }
382         saveBundleDatas();
383         saveStateData(shutdown);
384         savePermissionStorage();
385         if (shutdown)
386             stateManager.stopDataManager();
387     }
388
389     private BasePermissionStorage readPermissionData() {
390         BasePermissionStorage result = new BasePermissionStorage(this);
391         InputStream permDataStream = findStorageStream(PERM_DATA_FILE);
392         if (permDataStream == null)
393             return result;
394         try {
395             DataInputStream in = new DataInputStream(new BufferedInputStream(permDataStream));
396             try {
397                 if (PERMDATA_VERSION != in.readByte())
398                     return result;
399                 // read the default permissions first
400
int numPerms = in.readInt();
401                 if (numPerms > 0) {
402                     String JavaDoc[] perms = new String JavaDoc[numPerms];
403                     for (int i = 0; i < numPerms; i++)
404                         perms[i] = in.readUTF();
405                     result.setPermissionData(null, perms);
406                 }
407                 int numLocs = in.readInt();
408                 if (numLocs > 0)
409                     for (int i = 0; i < numLocs; i++) {
410                         String JavaDoc loc = in.readUTF();
411                         numPerms = in.readInt();
412                         String JavaDoc[] perms = new String JavaDoc[numPerms];
413                         for (int j = 0; j < numPerms; j++)
414                             perms[j] = in.readUTF();
415                         result.setPermissionData(loc, perms);
416                     }
417                 int numCondPerms = in.readInt();
418                 if (numCondPerms > 0) {
419                     String JavaDoc[] condPerms = new String JavaDoc[numCondPerms];
420                     for (int i = 0; i < numCondPerms; i++)
421                         condPerms[i] = in.readUTF();
422                     result.saveConditionalPermissionInfos(condPerms);
423                 }
424                 result.setDirty(false);
425             } finally {
426                 in.close();
427             }
428         } catch (IOException e) {
429             adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e));
430         }
431         return result;
432     }
433
434     private void savePermissionStorage() {
435         if (permissionStorage == null || isReadOnly() || !permissionStorage.isDirty())
436             return;
437         try {
438             ManagedOutputStream fmos = storageManager.getOutputStream(PERM_DATA_FILE);
439             DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fmos));
440             boolean error = true;
441             try {
442                 out.writeByte(PERMDATA_VERSION);
443                 // always write the default permissions first
444
String JavaDoc[] defaultPerms = permissionStorage.getPermissionData(null);
445                 out.writeInt(defaultPerms == null ? 0 : defaultPerms.length);
446                 if (defaultPerms != null)
447                     for (int i = 0; i < defaultPerms.length; i++)
448                         out.writeUTF(defaultPerms[i]);
449                 String JavaDoc[] locations = permissionStorage.getLocations();
450                 out.writeInt(locations == null ? 0 : locations.length);
451                 if (locations != null)
452                     for (int i = 0; i < locations.length; i++) {
453                         out.writeUTF(locations[i]);
454                         String JavaDoc[] perms = permissionStorage.getPermissionData(locations[i]);
455                         out.writeInt(perms == null ? 0 : perms.length);
456                         if (perms != null)
457                             for (int j = 0; j < perms.length; j++)
458                                 out.writeUTF(perms[j]);
459                     }
460                 String JavaDoc[] condPerms = permissionStorage.getConditionalPermissionInfos();
461                 out.writeInt(condPerms == null ? 0 : condPerms.length);
462                 if (condPerms != null)
463                     for (int i = 0; i < condPerms.length; i++)
464                         out.writeUTF(condPerms[i]);
465                 out.close();
466                 permissionStorage.setDirty(false);
467                 error = false;
468             } finally {
469                 // if something happens, don't close a corrupt file
470
if (error) {
471                     fmos.abort();
472                     try {
473                         out.close();
474                     } catch (IOException e) {/*ignore*/
475                     }
476                 }
477             }
478         } catch (IOException e) {
479             adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e));
480             return;
481         }
482     }
483
484     private void saveBundleDatas() {
485         // the cache and the state match
486
if (stateManager == null || isReadOnly() || (timeStamp == stateManager.getSystemState().getTimeStamp() && !stateManager.saveNeeded()))
487             return;
488         try {
489             ManagedOutputStream fmos = storageManager.getOutputStream(LocationManager.BUNDLE_DATA_FILE);
490             DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fmos));
491             boolean error = true;
492             try {
493                 out.writeByte(BUNDLEDATA_VERSION);
494                 out.writeLong(stateManager.getSystemState().getTimeStamp());
495                 out.writeInt(initialBundleStartLevel);
496                 out.writeLong(nextId);
497
498                 StorageHook[] storageHooks = adaptor.getHookRegistry().getStorageHooks();
499                 out.writeInt(storageHooks.length);
500                 for (int i = 0; i < storageHooks.length; i++) {
501                     out.writeUTF((String JavaDoc) storageHooks[i].getKey());
502                     out.writeInt(storageHooks[i].getStorageVersion());
503                 }
504
505                 Bundle[] bundles = context.getBundles();
506                 out.writeInt(bundles.length);
507                 for (int i = 0; i < bundles.length; i++) {
508                     long id = bundles[i].getBundleId();
509                     out.writeLong(id);
510                     if (id != 0) {
511                         BundleData data = ((org.eclipse.osgi.framework.internal.core.AbstractBundle) bundles[i]).getBundleData();
512                         saveBaseData((BaseData) data, out);
513                     }
514                 }
515                 out.close();
516                 // update the 'timeStamp' after the changed Meta data is saved.
517
timeStamp = stateManager.getSystemState().getTimeStamp();
518                 error = false;
519             } finally {
520                 // if something happens, don't close a corrupt file
521
if (error) {
522                     fmos.abort();
523                     try {
524                         out.close();
525                     } catch (IOException e) {/*ignore*/
526                     }
527                 }
528             }
529         } catch (IOException e) {
530             adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e));
531             return;
532         }
533     }
534
535     private void saveStateData(boolean shutdown) {
536         if (stateManager == null || isReadOnly() || !stateManager.saveNeeded())
537             return;
538         try {
539             File stateTmpFile = File.createTempFile(LocationManager.STATE_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$
540
File lazyTmpFile = File.createTempFile(LocationManager.LAZY_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$
541
if (shutdown)
542                 stateManager.shutdown(stateTmpFile, lazyTmpFile);
543             else
544                 synchronized (stateManager) {
545                     stateManager.update(stateTmpFile, lazyTmpFile);
546                 }
547             storageManager.lookup(LocationManager.STATE_FILE, true);
548             storageManager.lookup(LocationManager.LAZY_FILE, true);
549             storageManager.update(new String JavaDoc[] {LocationManager.STATE_FILE, LocationManager.LAZY_FILE}, new String JavaDoc[] {stateTmpFile.getName(), lazyTmpFile.getName()});
550         } catch (IOException e) {
551             adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e));
552         }
553     }
554
555     public PermissionStorage getPermissionStorage() throws IOException {
556         if (permissionStorage == null)
557             permissionStorage = readPermissionData();
558         return permissionStorage;
559     }
560
561     public int getInitialBundleStartLevel() {
562         return initialBundleStartLevel;
563     }
564
565     public void setInitialBundleStartLevel(int value) {
566         this.initialBundleStartLevel = value;
567         requestSave();
568     }
569
570     public void save(BaseData data) throws IOException {
571         if (data.isDirty()) {
572             timeStamp--; // Change the value of the timeStamp, as a marker that something changed.
573
requestSave();
574             data.setDirty(false);
575         }
576     }
577
578     public BundleOperation installBundle(String JavaDoc location, URLConnection source) {
579         BaseData data = createBaseData(getNextBundleId(), location);
580         return new BundleInstall(data, source, this);
581     }
582
583     public BundleOperation updateBundle(BaseData data, URLConnection source) {
584         return new BundleUpdate(data, source, this);
585     }
586
587     public BundleOperation uninstallBundle(BaseData data) {
588         return new BundleUninstall(data, this);
589     }
590
591     protected Object JavaDoc getBundleContent(BaseData bundledata) throws IOException {
592         BaseStorageHook storageHook = (BaseStorageHook) bundledata.getStorageHook(BaseStorageHook.KEY);
593         if (storageHook == null)
594             throw new IllegalStateException JavaDoc();
595         return storageHook.isReference() ? new File(storageHook.getFileName()) : new File(storageHook.getGenerationDir(), storageHook.getFileName());
596     }
597
598     public BundleFile createBundleFile(Object JavaDoc content, BaseData data) throws IOException {
599         boolean base = false;
600         if (content == null) {
601             // this must be a request for the base bundlefile
602
base = true;
603             // get the content of this bundle
604
content = getBundleContent(data);
605         }
606         BundleFile result = null;
607         // Ask factories before doing the default behavior
608
BundleFileFactoryHook[] factories = adaptor.getHookRegistry().getBundleFileFactoryHooks();
609         for (int i = 0; i < factories.length && result == null; i++)
610             result = factories[i].createBundleFile(content, data, base);
611
612         // No factories configured or they declined to create the bundle file; do default
613
if (result == null && content instanceof File) {
614             File file = (File) content;
615             if (file.isDirectory())
616                 result = new DirBundleFile(file);
617             else
618                 result = new ZipBundleFile(file, data);
619         }
620
621         if (result == null && content instanceof String JavaDoc) {
622             // here we assume the content is a path offset into the base bundle file; create a NestedDirBundleFile
623
result = new NestedDirBundleFile(data.getBundleFile(), (String JavaDoc) content);
624         }
625         if (result == null)
626             // nothing we can do; must throw exception for the content
627
throw new IOException("Cannot create bundle file for content of type: " + content.getClass().getName()); //$NON-NLS-1$
628

629         // try creating a wrapper bundlefile out of it.
630
BundleFileWrapperFactoryHook[] wrapperFactories = adaptor.getHookRegistry().getBundleFileWrapperFactoryHooks();
631         for (int i = 0; i < wrapperFactories.length; i++) {
632             BundleFile wrapperBundle = wrapperFactories[i].wrapBundleFile(result, content, data, base);
633             if (wrapperBundle != null)
634                 result = wrapperBundle;
635         }
636         return result;
637     }
638
639     public synchronized StateManager getStateManager() {
640         if (stateManager != null)
641             return stateManager;
642         stateManager = readStateData();
643         checkSystemState(stateManager.getSystemState());
644         return stateManager;
645     }
646
647     private void checkSystemState(State state) {
648         BundleDescription[] bundles = state.getBundles();
649         if (bundles == null)
650             return;
651         boolean removedBundle = false;
652         for (int i = 0; i < bundles.length; i++) {
653             if (context.getBundle(bundles[i].getBundleId()) == null) {
654                 state.removeBundle(bundles[i]);
655                 removedBundle = true;
656             }
657         }
658         if (removedBundle)
659             state.resolve(false); // do a full resolve
660
BundleDescription systemBundle = state.getBundle(0);
661         if (systemBundle == null || !systemBundle.isResolved()) {
662             ResolverError[] errors = systemBundle == null ? new ResolverError[0] : state.getResolverErrors(systemBundle);
663             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
664             for (int i = 0; i < errors.length; i++) {
665                 sb.append(errors[i].toString());
666                 if (i < errors.length - 1)
667                     sb.append(", "); //$NON-NLS-1$
668
}
669             // this would be a bug in the framework
670
throw new IllegalStateException JavaDoc(NLS.bind(AdaptorMsg.SYSTEMBUNDLE_NOTRESOLVED, sb.toString()));
671         }
672     }
673
674     private StateManager readStateData() {
675         File[] stateFiles = findStorageFiles(new String JavaDoc[] {LocationManager.STATE_FILE, LocationManager.LAZY_FILE});
676         File stateFile = stateFiles[0];
677         File lazyFile = stateFiles[1];
678
679         stateManager = new StateManager(stateFile, lazyFile, context, timeStamp);
680         State systemState = null;
681         if (!invalidState) {
682             systemState = stateManager.readSystemState();
683             if (systemState != null)
684                 return stateManager;
685         }
686         systemState = stateManager.createSystemState();
687         Bundle[] installedBundles = context.getBundles();
688         if (installedBundles == null)
689             return stateManager;
690         StateObjectFactory factory = stateManager.getFactory();
691         for (int i = 0; i < installedBundles.length; i++) {
692             AbstractBundle toAdd = (AbstractBundle) installedBundles[i];
693             try {
694                 // make sure we get the real manifest as if this is the first time.
695
Dictionary toAddManifest = loadManifest((BaseData) toAdd.getBundleData(), true);
696                 BundleDescription newDescription = factory.createBundleDescription(systemState, toAddManifest, toAdd.getLocation(), toAdd.getBundleId());
697                 systemState.addBundle(newDescription);
698             } catch (BundleException be) {
699                 // just ignore bundle datas with invalid manifests
700
}
701         }
702         // we do not set the cached timestamp here because we want a new one to be used from the new system state object (bug 132978)
703
// we need the state resolved
704
systemState.resolve();
705         invalidState = false;
706         return stateManager;
707     }
708
709     private File[] findStorageFiles(String JavaDoc[] fileNames) {
710         File[] storageFiles = new File[fileNames.length];
711         try {
712             for (int i = 0; i < storageFiles.length; i++)
713                 storageFiles[i] = storageManager.lookup(fileNames[i], false);
714         } catch (IOException ex) {
715             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
716                 Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$
717
Debug.printStackTrace(ex);
718             }
719         }
720         boolean success = true;
721         for (int i = 0; i < storageFiles.length; i++)
722             if (storageFiles[i] == null || !storageFiles[i].isFile()) {
723                 success = false;
724                 break;
725             }
726         if (success)
727             return storageFiles;
728         //if it does not exist, try to read it from the parent
729
Location parentConfiguration = null;
730         Location currentConfiguration = LocationManager.getConfigurationLocation();
731         if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) {
732             try {
733                 File stateLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME);
734                 StorageManager newFileManager = initFileManager(stateLocationDir, "none", true); //$NON-NLS-1$);
735
for (int i = 0; i < storageFiles.length; i++)
736                     storageFiles[i] = newFileManager.lookup(fileNames[i], false);
737                 newFileManager.close();
738             } catch (IOException ex) {
739                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
740                     Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$
741
Debug.printStackTrace(ex);
742                 }
743             }
744         } else {
745             try {
746                 //it did not exist in either place, so create it in the original location
747
if (!isReadOnly()) {
748                     for (int i = 0; i < storageFiles.length; i++)
749                         storageFiles[i] = storageManager.lookup(fileNames[i], true);
750                 }
751             } catch (IOException ex) {
752                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
753                     Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$
754
Debug.printStackTrace(ex);
755                 }
756             }
757         }
758         return storageFiles;
759     }
760
761     public void frameworkStart(BundleContext fwContext) throws BundleException {
762         this.context = fwContext;
763         // System property can be set to enable state saver or not.
764
if (Boolean.valueOf(FrameworkProperties.getProperty(BaseStorage.PROP_ENABLE_STATE_SAVER, "true")).booleanValue()) //$NON-NLS-1$
765
stateSaver = new StateSaver();
766
767     }
768
769     public void frameworkStop(BundleContext fwContext) throws BundleException {
770         if (stateSaver != null)
771             stateSaver.shutdown();
772         saveAllData(true);
773         storageManager.close();
774         storageManagerClosed = true;
775         if (extensionListener != null)
776             context.removeBundleListener(extensionListener);
777     }
778
779     public void frameworkStopping(BundleContext fwContext) {
780         // do nothing in storage
781
}
782
783     public void addProperties(Properties properties) {
784         // set the extension support if we found the addURL method
785
if (addURLMethod != null)
786             properties.put(Constants.SUPPORTS_FRAMEWORK_EXTENSION, "true"); //$NON-NLS-1$
787
// store bundleStore back into adaptor properties for others to see
788
properties.put(BaseStorage.PROP_BUNDLE_STORE, getBundleStoreRoot().getAbsolutePath());
789     }
790
791     private InputStream findStorageStream(String JavaDoc fileName) {
792         InputStream storageStream = null;
793         try {
794             storageStream = storageManager.getInputStream(fileName);
795         } catch (IOException ex) {
796             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
797                 Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$
798
Debug.printStackTrace(ex);
799             }
800         }
801         if (storageStream == null) {
802             Location currentConfiguration = LocationManager.getConfigurationLocation();
803             Location parentConfiguration = null;
804             if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) {
805                 try {
806                     File bundledataLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME);
807                     StorageManager newStorageManager = initFileManager(bundledataLocationDir, "none", true); //$NON-NLS-1$
808
storageStream = newStorageManager.getInputStream(fileName);
809                     newStorageManager.close();
810                 } catch (MalformedURLException e1) {
811                     // This will not happen since all the URLs are derived by us
812
// and we are GODS!
813
} catch (IOException e1) {
814                     // That's ok we will regenerate the .bundleData
815
}
816             }
817         }
818         return storageStream;
819     }
820
821     protected void saveBaseData(BaseData bundledata, DataOutputStream out) throws IOException {
822         StorageHook[] hooks = bundledata.getStorageHooks();
823         out.writeInt(hooks.length);
824         for (int i = 0; i < hooks.length; i++) {
825             out.writeUTF((String JavaDoc) hooks[i].getKey());
826             hooks[i].save(out);
827         }
828     }
829
830     protected BaseData loadBaseData(long id, DataInputStream in) throws IOException {
831         BaseData result = new BaseData(id, adaptor);
832         int numHooks = in.readInt();
833         StorageHook[] hooks = new StorageHook[numHooks];
834         for (int i = 0; i < numHooks; i++) {
835             String JavaDoc hookKey = in.readUTF();
836             StorageHook storageHook = (StorageHook) storageHooks.getByKey(hookKey);
837             if (storageHook == null)
838                 throw new IOException();
839             hooks[i] = storageHook.load(result, in);
840         }
841         result.setStorageHooks(hooks);
842         return result;
843     }
844
845     protected BaseData createBaseData(long id, String JavaDoc location) {
846         BaseData result = new BaseData(id, adaptor);
847         result.setLocation(location);
848         return result;
849     }
850
851     public String JavaDoc getInstallPath() {
852         return installPath;
853     }
854
855     private void cleanOSGiCache() {
856         File osgiConfig = LocationManager.getOSGiConfigurationDir();
857         if (!AdaptorUtil.rm(osgiConfig)) {
858             // TODO log error?
859
}
860     }
861
862     /**
863      * Processes an extension bundle
864      * @param bundleData the extension bundle data
865      * @param type the type of extension bundle
866      * @throws BundleException on any errors or if the extension bundle type is not supported
867      */

868     protected void processExtension(BaseData bundleData, byte type) throws BundleException {
869         if ((bundleData.getType() & BundleData.TYPE_FRAMEWORK_EXTENSION) != 0) {
870             validateExtension(bundleData);
871             processFrameworkExtension(bundleData, type);
872         } else if ((bundleData.getType() & BundleData.TYPE_BOOTCLASSPATH_EXTENSION) != 0) {
873             validateExtension(bundleData);
874             processBootExtension(bundleData, type);
875         }
876     }
877
878     /**
879      * Validates the extension bundle metadata
880      * @param bundleData the extension bundle data
881      * @throws BundleException if the extension bundle metadata is invalid
882      */

883     private void validateExtension(BundleData bundleData) throws BundleException {
884         Dictionary extensionManifest = bundleData.getManifest();
885         if (extensionManifest.get(Constants.IMPORT_PACKAGE) != null)
886             throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_IMPORT_ERROR, bundleData.getLocation()));
887         if (extensionManifest.get(Constants.REQUIRE_BUNDLE) != null)
888             throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_REQUIRE_ERROR, bundleData.getLocation()));
889         if (extensionManifest.get(Constants.BUNDLE_NATIVECODE) != null)
890             throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_NATIVECODE_ERROR, bundleData.getLocation()));
891     }
892
893     /**
894      * Processes a framework extension bundle
895      * @param bundleData the extension bundle data
896      * @param type the type of extension bundle
897      * @throws BundleException on errors or if framework extensions are not supported
898      */

899     protected void processFrameworkExtension(BaseData bundleData, byte type) throws BundleException {
900         if (addURLMethod == null)
901             throw new BundleException("Framework extensions are not supported.", new UnsupportedOperationException JavaDoc()); //$NON-NLS-1$
902
if ((type & (EXTENSION_UNINSTALLED | EXTENSION_UPDATED)) != 0)
903             // if uninstalled or updated then do nothing framework must be restarted.
904
return;
905
906         // first make sure this BundleData is not on the pre-configured osgi.framework.extensions list
907
String JavaDoc[] extensions = getConfiguredExtensions();
908         for (int i = 0; i < extensions.length; i++)
909             if (extensions[i].equals(bundleData.getSymbolicName()))
910                 return;
911         if ((type & EXTENSION_INSTALLED) != 0) {
912             if (extensionListener == null) {
913                 // add bundle listener to wait for extension to be resolved
914
extensionListener = this;
915                 context.addBundleListener(extensionListener);
916             }
917             return;
918         }
919         File[] files = getExtensionFiles(bundleData);
920         if (files == null)
921             return;
922         ClassLoader JavaDoc cl = getClass().getClassLoader();
923         for (int i = 0; i < files.length; i++) {
924             if (files[i] == null)
925                 continue;
926             Throwable JavaDoc exceptionLog = null;
927             try {
928                 addURLMethod.invoke(cl, new Object JavaDoc[] {files[i].toURL()});
929             } catch (InvocationTargetException JavaDoc e) {
930                 exceptionLog = e.getTargetException();
931             } catch (Throwable JavaDoc t) {
932                 exceptionLog = t;
933             } finally {
934                 if (exceptionLog != null)
935                     adaptor.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundleData.getBundle(), exceptionLog);
936             }
937         }
938         try {
939             cl.loadClass("thisIsNotAClass"); // initialize the new urls //$NON-NLS-1$
940
} catch (ClassNotFoundException JavaDoc e) {
941             // do nothing
942
}
943     }
944
945     /**
946      * Returns a list of configured extensions
947      * @return a list of configured extensions
948      */

949     protected String JavaDoc[] getConfiguredExtensions() {
950         if (configuredExtensions != null)
951             return configuredExtensions;
952         String JavaDoc prop = FrameworkProperties.getProperty(BaseStorage.PROP_FRAMEWORK_EXTENSIONS);
953         if (prop == null || prop.trim().length() == 0)
954             configuredExtensions = new String JavaDoc[0];
955         else
956             configuredExtensions = ManifestElement.getArrayFromList(prop);
957         return configuredExtensions;
958     }
959
960     /**
961      * Processes a boot extension bundle
962      * @param bundleData the extension bundle data
963      * @param type the type of extension bundle
964      * @throws BundleException on errors or if boot extensions are not supported
965      */

966     protected void processBootExtension(BundleData bundleData, byte type) throws BundleException {
967         throw new BundleException("Boot classpath extensions are not supported.", new UnsupportedOperationException JavaDoc()); //$NON-NLS-1$
968
}
969
970     private void initBundleStoreRoot() {
971         File configurationLocation = LocationManager.getOSGiConfigurationDir();
972         if (configurationLocation != null)
973             bundleStoreRoot = new File(configurationLocation, LocationManager.BUNDLES_DIR);
974         else
975             // last resort just default to "bundles"
976
bundleStoreRoot = new File(LocationManager.BUNDLES_DIR);
977     }
978
979     public File getBundleStoreRoot() {
980         if (bundleStoreRoot == null)
981             initBundleStoreRoot();
982         return bundleStoreRoot;
983     }
984
985     /**
986      * Returns a list of classpath files for an extension bundle
987      * @param bundleData the bundle data for an extension bundle
988      * @return a list of classpath files for an extension bundle
989      */

990     protected File[] getExtensionFiles(BaseData bundleData) {
991         File[] files = null;
992         try {
993             String JavaDoc[] paths = bundleData.getClassPath();
994             // TODO need to be smarter about dev path here
995
if (FrameworkProperties.getProperty("osgi.dev") != null) { //$NON-NLS-1$
996
String JavaDoc[] origPaths = paths;
997                 paths = new String JavaDoc[origPaths.length + 1];
998                 System.arraycopy(origPaths, 0, paths, 0, origPaths.length);
999                 paths[paths.length - 1] = "bin"; //$NON-NLS-1$
1000
}
1001            ArrayList results = new ArrayList(paths.length);
1002            for (int i = 0; i < paths.length; i++) {
1003                if (".".equals(paths[i])) //$NON-NLS-1$
1004
results.add(bundleData.getBundleFile().getBaseFile());
1005                else {
1006                    File result = bundleData.getBundleFile().getFile(paths[i], false);
1007                    if (result != null)
1008                        results.add(result);
1009                }
1010            }
1011            return (File[]) results.toArray(new File[results.size()]);
1012        } catch (BundleException e) {
1013            adaptor.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundleData.getBundle(), e);
1014        }
1015        return files;
1016    }
1017
1018    void requestSave() {
1019        // Only when the State saver is enabled will the stateSaver be started.
1020
if (stateSaver == null)
1021            return;
1022        stateSaver.requestSave();
1023    }
1024
1025    /**
1026     * Updates the state mananager with an updated/installed/uninstalled bundle
1027     * @param bundleData the modified bundle
1028     * @param type the type of modification
1029     * @throws BundleException
1030     */

1031    public void updateState(BundleData bundleData, int type) throws BundleException {
1032        if (stateManager == null) {
1033            invalidState = true;
1034            return;
1035        }
1036        State systemState = stateManager.getSystemState();
1037        switch (type) {
1038            case BundleEvent.UPDATED :
1039                systemState.removeBundle(bundleData.getBundleID());
1040                // fall through to INSTALLED
1041
case BundleEvent.INSTALLED :
1042                BundleDescription newDescription = stateManager.getFactory().createBundleDescription(systemState, bundleData.getManifest(), bundleData.getLocation(), bundleData.getBundleID());
1043                systemState.addBundle(newDescription);
1044                break;
1045            case BundleEvent.UNINSTALLED :
1046                systemState.removeBundle(bundleData.getBundleID());
1047                break;
1048        }
1049    }
1050
1051    private static Method JavaDoc findaddURLMethod(Class JavaDoc clazz) {
1052        if (clazz == null)
1053            return null; // ends the recursion when getSuperClass returns null
1054
try {
1055            Method JavaDoc result = clazz.getDeclaredMethod("addURL", new Class JavaDoc[] {URL.class}); //$NON-NLS-1$
1056
result.setAccessible(true);
1057            return result;
1058        } catch (NoSuchMethodException JavaDoc e) {
1059            // do nothing look in super class below
1060
} catch (SecurityException JavaDoc e) {
1061            // if we do not have the permissions then we will not find the method
1062
}
1063        return findaddURLMethod(clazz.getSuperclass());
1064    }
1065
1066    private class StateSaver implements Runnable JavaDoc {
1067        private long delay_interval = 30000; // 30 seconds.
1068
private long max_total_delay_interval = 1800000; // 30 minutes.
1069
private boolean shutdown = false;
1070        private long lastSaveTime = 0;
1071        private Thread JavaDoc runningThread = null;
1072
1073        StateSaver() {
1074            String JavaDoc prop = FrameworkProperties.getProperty("eclipse.stateSaveDelayInterval"); //$NON-NLS-1$
1075
if (prop != null) {
1076                try {
1077                    long val = Long.parseLong(prop);
1078                    if (val >= 1000 && val <= 1800000) {
1079                        delay_interval = val;
1080                        max_total_delay_interval = val * 60;
1081                    }
1082                } catch (NumberFormatException JavaDoc e) {
1083                    // ignore
1084
}
1085            }
1086        }
1087
1088        public void run() {
1089            State systemState = adaptor.getState();
1090            synchronized (systemState) {
1091                long firstSaveTime = lastSaveTime;
1092                long curSaveTime = 0;
1093                long delayTime;
1094                do {
1095                    do {
1096                        if ((System.currentTimeMillis() - firstSaveTime) > max_total_delay_interval) {
1097                            curSaveTime = lastSaveTime;
1098                            // Waiting time has been too long, so break to start saving State data to file.
1099
break;
1100                        }
1101                        delayTime = Math.min(delay_interval, lastSaveTime - curSaveTime);
1102                        curSaveTime = lastSaveTime;
1103                        // wait for other save requests
1104
try {
1105                            if (!shutdown)
1106                                systemState.wait(delayTime);
1107                        } catch (InterruptedException JavaDoc ie) {
1108                            // force break from do/while loops
1109
curSaveTime = lastSaveTime;
1110                            break;
1111                        }
1112                        // Continue the loop if 'lastSaveTime' is increased again during waiting.
1113
} while (!shutdown && curSaveTime < lastSaveTime);
1114                    // Save State and Meta data.
1115
saveAllData(false);
1116                    // Continue the loop if Saver is asked again during saving State data to file.
1117
} while (!shutdown && curSaveTime < lastSaveTime);
1118                runningThread = null; // clear runningThread
1119
}
1120        }
1121
1122        void shutdown() {
1123            State systemState = adaptor.getState();
1124            Thread JavaDoc joinWith = null;
1125            synchronized (systemState) {
1126                shutdown = true;
1127                joinWith = runningThread;
1128                systemState.notifyAll(); // To wakeup sleeping thread.
1129
}
1130            try {
1131                if (joinWith != null)
1132                    // There should be no deadlock when 'shutdown' is true.
1133
joinWith.join();
1134            } catch (InterruptedException JavaDoc ie) {
1135                if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
1136                    Debug.println("Error shutdowning StateSaver: " + ie.getMessage()); //$NON-NLS-1$
1137
Debug.printStackTrace(ie);
1138                }
1139            }
1140        }
1141
1142        void requestSave() {
1143            State systemState = adaptor.getState();
1144            synchronized (systemState) {
1145                lastSaveTime = System.currentTimeMillis();
1146                if (runningThread == null) {
1147                    runningThread = new Thread JavaDoc(this, "State Saver"); //$NON-NLS-1$
1148
runningThread.start();
1149                }
1150            }
1151        }
1152    }
1153
1154    public long getNextBundleId() {
1155        return nextId++;
1156    }
1157
1158    public void bundleChanged(BundleEvent event) {
1159        if (event.getType() != BundleEvent.RESOLVED)
1160            return;
1161        BaseData data = (BaseData) ((AbstractBundle) event.getBundle()).getBundleData();
1162        try {
1163        if ((data.getType() & BundleData.TYPE_FRAMEWORK_EXTENSION) != 0)
1164            processFrameworkExtension(data, EXTENSION_INITIALIZE);
1165        else if ((data.getType() & BundleData.TYPE_BOOTCLASSPATH_EXTENSION) != 0)
1166            processBootExtension(data, EXTENSION_INITIALIZE);
1167        } catch (BundleException e) {
1168            // do nothing;
1169
}
1170    }
1171
1172    public String JavaDoc copyToTempLibrary(BaseData data, String JavaDoc absolutePath) throws IOException {
1173        File storageRoot = getBundleStoreRoot();
1174        File libTempDir = new File(storageRoot, LIB_TEMP);
1175        // we assume the absolutePath is a File path
1176
File realLib = new File(absolutePath);
1177        String JavaDoc libName = realLib.getName();
1178        // find a temp dir for the bundle data and the library;
1179
File bundleTempDir = null;
1180        File libTempFile = null;
1181        // We need a somewhat predictable temp dir for the libraries of a given bundle;
1182
// This is not strictly necessary but it does help scenarios where one native library loads another native library without using java.
1183
// On some OSes this causes issues because the second library is cannot be found.
1184
// This has been worked around by the bundles loading the libraries in a particular order (and setting some LIB_PATH env).
1185
// The one catch is that the libraries need to be in the same directory and they must use their original lib names.
1186
//
1187
// This bit of code attempts to do that by using the bundle ID as an ID for the temp dir along with an incrementing ID
1188
// in cases where the temp dir may already exist.
1189
Long JavaDoc bundleID = new Long JavaDoc(data.getBundleID());
1190        for (int i = 0; i < Integer.MAX_VALUE; i++) {
1191            bundleTempDir = new File(libTempDir, bundleID.toString() + "_" + new Integer JavaDoc(i).toString()); //$NON-NLS-1$
1192
libTempFile = new File(bundleTempDir, libName);
1193            if (bundleTempDir.exists()) {
1194                if (libTempFile.exists())
1195                    continue; // to to next temp file
1196
break;
1197            }
1198            break;
1199        }
1200        if (!bundleTempDir.exists()) {
1201            bundleTempDir.mkdirs();
1202            bundleTempDir.deleteOnExit();
1203            // This is just a safeguard incase the VM is terminated unexpectantly, it also looks like deleteOnExit cannot really work because
1204
// the VM likely will still have a lock on the lib file at the time of VM exit.
1205
File deleteFlag = new File(libTempDir, BaseStorage.DELETE_FLAG);
1206            if (!deleteFlag.exists()) {
1207                // need to create a delete flag to force removal the temp libraries
1208
try {
1209                    FileOutputStream out = new FileOutputStream(deleteFlag);
1210                    out.close();
1211                } catch (IOException e) {
1212                    // do nothing; that would mean we did not make the temp dir successfully
1213
}
1214            }
1215        }
1216        // copy the library file
1217
InputStream in = new FileInputStream(realLib);
1218        AdaptorUtil.readFile(in, libTempFile);
1219        // set permissions if needed
1220
BundleFile.setPermissions(libTempFile);
1221        libTempFile.deleteOnExit(); // this probably will not work because the VM will probably have the lib locked at exit
1222
// return the temporary path
1223
return libTempFile.getAbsolutePath();
1224    }
1225
1226}
1227
Popular Tags