00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 package org.knopflerfish.framework;
00036
00037 import org.osgi.framework.*;
00038 import org.osgi.service.startlevel.*;
00039 import java.util.Vector;
00040 import java.util.List;
00041 import java.util.Iterator;
00042
00043 import java.io.File;
00044
00045
00050 public class StartLevelImpl implements StartLevel, Runnable {
00051 Thread wc;
00052 long wcDelay = 2000;
00053 boolean bRun = false;
00054 Queue jobQueue = new Queue(100);
00055
00056 final static int START_MIN = 0;
00057 final static int START_MAX = Integer.MAX_VALUE;
00058
00059 final static String LEVEL_FILE = "currentlevel";
00060
00061 int currentLevel = 0;
00062 int initStartLevel = 1;
00063 int targetStartLevel = currentLevel;
00064 boolean acceptChanges = true;
00065
00066 Framework framework;
00067
00068 FileTree storage;
00069
00070
00071
00072 boolean bCompat ;
00073
00074 public static final String SPEC_VERSION = "1.0";
00075
00076
00077 public StartLevelImpl(Framework framework) {
00078 this.framework = framework;
00079
00080 storage = Util.getFileStorage("startlevel");
00081 }
00082
00083 void open() {
00084
00085 if(Debug.startlevel) {
00086 Debug.println("startlevel: open");
00087 }
00088
00089 if (jobQueue.isEmpty()) {
00090 setStartLevel0(1, false, false, true);
00091 }
00092 Runnable firstJob = (Runnable)jobQueue.firstElement();
00093 wc = new Thread(this, "startlevel job thread");
00094 synchronized (firstJob) {
00095 bRun = true;
00096 wc.start();
00097 if (!acceptChanges) {
00098 acceptChanges = true;
00099 restoreState();
00100 }
00101
00102 try {
00103 firstJob.wait();
00104 } catch (InterruptedException _ignore) { }
00105 }
00106 }
00107
00120 void restoreState() {
00121 if (Debug.startlevel) {
00122 Debug.println("startlevel: restoreState");
00123 }
00124
00125
00126 if (!Framework.bIsMemoryStorage) {
00127 try {
00128 String s = Util.getContent(new File(storage, LEVEL_FILE));
00129 if (s != null) {
00130 int oldStartLevel = Integer.parseInt(s);
00131 if (oldStartLevel != -1) {
00132 setStartLevel0(oldStartLevel, false, false, true);
00133 }
00134 }
00135 } catch (Exception _ignored) { }
00136 }
00137 }
00138
00139
00140 void close() {
00141 if (Debug.startlevel) {
00142 Debug.println("*** closing startlevel service");
00143 }
00144
00145 bRun = false;
00146 if(wc != null) {
00147 try {
00148 wc.join(wcDelay * 2);
00149 } catch (Exception ignored) {
00150 }
00151 wc = null;
00152 }
00153 }
00154
00155 void shutdown() {
00156 acceptChanges = false;
00157 setStartLevel0(0, false, true, false);
00158 while (currentLevel > 1) {
00159 synchronized (wc) {
00160 try { wc.wait(); } catch (Exception e) {}
00161 }
00162 }
00163 close();
00164 }
00165
00166 public void run() {
00167 while(bRun) {
00168 try {
00169 Runnable job = (Runnable)jobQueue.removeWait((float)(wcDelay / 1000.0));
00170 if (job != null) {
00171 job.run();
00172 synchronized (job) {
00173 job.notify();
00174 }
00175 }
00176 } catch (Exception ignored) {
00177 ignored.printStackTrace();
00178 }
00179 }
00180 }
00181
00182
00183 public int getStartLevel() {
00184 return currentLevel;
00185 }
00186
00187
00188 public void setStartLevel(final int startLevel) {
00189 framework.perm.checkStartLevelAdminPerm();
00190 if(startLevel <= 0) {
00191 throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel);
00192 }
00193 if (acceptChanges) {
00194 setStartLevel0(startLevel, framework.active, false, true);
00195 }
00196 }
00197
00198
00199 private void setStartLevel0(final int startLevel, final boolean notifyFw, final boolean notifyWC, final boolean storeLevel) {
00200 if (Debug.startlevel) {
00201 Debug.println("startlevel: setStartLevel " + startLevel);
00202 }
00203
00204 jobQueue.insert(new Runnable() {
00205 public void run() {
00206 int sl = bCompat ? 1 : startLevel;
00207 targetStartLevel = sl;
00208
00209 while (targetStartLevel > currentLevel) {
00210 increaseStartLevel();
00211 }
00212
00213 while (targetStartLevel < currentLevel) {
00214 decreaseStartLevel();
00215 }
00216
00217
00218
00219 if (storeLevel && !Framework.bIsMemoryStorage) {
00220 try {
00221 Util.putContent(new File(storage, LEVEL_FILE),
00222 Integer.toString(currentLevel));
00223 } catch (Exception e) {
00224 e.printStackTrace();
00225 }
00226 }
00227 if (notifyFw) {
00228 notifyFramework();
00229 }
00230 if (notifyWC && wc != null) {
00231 synchronized (wc) {
00232 wc.notifyAll();
00233 }
00234 }
00235 }
00236 });
00237 }
00238
00239
00240 Object lock = new Object();
00241
00242
00243 void increaseStartLevel() {
00244 synchronized(lock) {
00245
00246 currentLevel++;
00247
00248 if (Debug.startlevel) {
00249 Debug.println("startlevel: increaseStartLevel currentLevel=" + currentLevel);
00250 }
00251 Vector set = new Vector();
00252
00253 List bundles = framework.bundles.getBundles();
00254
00255 for (Iterator i = bundles.iterator(); i.hasNext(); ) {
00256 BundleImpl bs = (BundleImpl)i.next();
00257
00258 if (canStart(bs)) {
00259 if (bs.getStartLevel() == currentLevel) {
00260 if (bs.archive.isPersistent()) {
00261 set.addElement(bs);
00262 }
00263 }
00264 } else {
00265
00266 }
00267 }
00268
00269 Util.sort(set, BSComparator, false);
00270
00271 for(int i = 0; i < set.size(); i++) {
00272 BundleImpl bs = (BundleImpl)set.elementAt(i);
00273 try {
00274 if (bs.archive.isPersistent()) {
00275 if (Debug.startlevel) {
00276 Debug.println("startlevel: start " + bs);
00277 }
00278 bs.start();
00279 }
00280 } catch (Exception e) {
00281 framework.listeners.frameworkError(bs, e);
00282 }
00283 }
00284 }
00285 }
00286
00287
00288 void decreaseStartLevel() {
00289 synchronized(lock) {
00290 currentLevel--;
00291
00292 Vector set = new Vector();
00293
00294 List bundles = framework.bundles.getBundles();
00295
00296 for (Iterator i = bundles.iterator(); i.hasNext(); ) {
00297 BundleImpl bs = (BundleImpl)i.next();
00298
00299 if (bs.getState() == Bundle.ACTIVE) {
00300 if (bs.getStartLevel() == currentLevel + 1) {
00301 set.addElement(bs);
00302 }
00303 }
00304 }
00305
00306 Util.sort(set, BSComparator, true);
00307
00308 for (int i = 0; i < set.size(); i++) {
00309 BundleImpl bs = (BundleImpl)set.elementAt(i);
00310 BundleException saved = null;
00311 synchronized (bs) {
00312 if (bs.getState() == Bundle.ACTIVE) {
00313 if (Debug.startlevel) {
00314 Debug.println("startlevel: stop " + bs);
00315 }
00316 saved = bs.stop0(false);
00317 }
00318 }
00319 if (saved != null) {
00320 framework.listeners.frameworkError(bs, saved);
00321 }
00322 }
00323 }
00324 }
00325
00326
00327 boolean canStart(BundleImpl b) {
00328 return b.getState() != Bundle.UNINSTALLED;
00329 }
00330
00331
00332 static final Util.Comparator BSComparator = new Util.Comparator() {
00333 public int compare(Object o1, Object o2) {
00334 BundleImpl b1 = (BundleImpl)o1;
00335 BundleImpl b2 = (BundleImpl)o2;
00336
00337 int res = b1.getStartLevel() - b2.getStartLevel();
00338 if (res == 0) {
00339 res = (int)(b1.getBundleId() - b2.getBundleId());
00340 }
00341 return res;
00342 }
00343 };
00344
00345
00346 public int getBundleStartLevel(Bundle bundle) {
00347 if(bundle.getBundleId() == 0) {
00348 return 0;
00349 }
00350 BundleImpl bs = (BundleImpl)bundle;
00351 return bs.getStartLevel();
00352 }
00353
00354
00355 public void setBundleStartLevel(Bundle bundle, final int startLevel) {
00356 framework.perm.checkExecuteAdminPerm(bundle);
00357
00358 if(startLevel <= 0) {
00359 throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel);
00360 }
00361
00362 if(bundle.getBundleId() == 0) {
00363 throw new IllegalArgumentException("System bundle start level cannot be changed");
00364 }
00365
00366 final BundleImpl bs = (BundleImpl)bundle;
00367
00368 if(bs.getState() == Bundle.UNINSTALLED) {
00369 throw new IllegalArgumentException("uninstalled bundle start level cannot be changed");
00370 }
00371
00372 jobQueue.insert(new Runnable() {
00373 public void run() {
00374 int sl = bCompat ? 1 : startLevel;
00375
00376 bs.setStartLevel(sl);
00377 syncStartLevel(bs);
00378 }
00379 });
00380 }
00381
00382
00383 void syncStartLevel(BundleImpl bs) {
00384 synchronized(lock) {
00385
00386 if (bs.getStartLevel() <= currentLevel) {
00387 if (canStart(bs)) {
00388 if (bs.archive.isPersistent() || (bs.getState() == Bundle.RESOLVED)) {
00389 try {
00390 if (Debug.startlevel) {
00391 Debug.println("startlevel: start " + bs);
00392 }
00393 bs.start();
00394 } catch (Exception e) {
00395 framework.listeners.frameworkError(bs, e);
00396 }
00397 } else {
00398 bs.bDelayedStart = true;
00399 }
00400 }
00401 } else if (bs.getStartLevel() > currentLevel) {
00402 BundleException saved = null;
00403 synchronized (bs) {
00404 if (bs.getState() == Bundle.ACTIVE) {
00405 if (Debug.startlevel) {
00406 Debug.println("startlevel: stop " + bs);
00407 }
00408 saved = bs.stop0(false);
00409 }
00410 }
00411 if (saved != null) {
00412 framework.listeners.frameworkError(bs, saved);
00413 }
00414 }
00415 }
00416 }
00417
00418
00419 public int getInitialBundleStartLevel() {
00420 return initStartLevel;
00421 }
00422
00423
00424 public void setInitialBundleStartLevel(int startLevel) {
00425 framework.perm.checkStartLevelAdminPerm();
00426
00427 if(startLevel <= 0) {
00428 throw new IllegalArgumentException("Initial start level must be > 0, is " + startLevel);
00429 }
00430 initStartLevel = bCompat ? 1 : startLevel;
00431 }
00432
00433
00434 public boolean isBundlePersistentlyStarted(Bundle bundle) {
00435 return ((BundleImpl)bundle).isPersistent();
00436 }
00437
00438
00439 private void notifyFramework() {
00440 framework.listeners.frameworkEvent(new FrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, framework.systemBundle, null));
00441 }
00442 }
00443
00444