1 11 12 package org.eclipse.equinox.internal.app; 13 14 import java.io.*; 15 import java.util.*; 16 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 17 import org.eclipse.osgi.service.datalocation.Location; 18 import org.eclipse.osgi.storagemanager.StorageManager; 19 import org.eclipse.osgi.util.NLS; 20 import org.osgi.framework.*; 21 import org.osgi.service.application.*; 22 import org.osgi.service.event.Event; 23 import org.osgi.service.event.EventConstants; 24 import org.osgi.util.tracker.ServiceTracker; 25 import org.osgi.util.tracker.ServiceTrackerCustomizer; 26 27 31 public class AppPersistence implements ServiceTrackerCustomizer { 32 private static final String PROP_CONFIG_AREA = "osgi.configuration.area"; 34 private static final String FILTER_PREFIX = "(&(objectClass=org.eclipse.osgi.service.datalocation.Location)(type="; private static final String FILE_APPLOCKS = ".locks"; private static final String FILE_APPSCHEDULED = ".scheduled"; private static final String EVENT_HANDLER = "org.osgi.service.event.EventHandler"; 39 private static final int DATA_VERSION = 2; 40 private static final byte NULL = 0; 41 private static final int OBJECT = 1; 42 43 private static BundleContext context; 44 private static ServiceTracker configTracker; 45 private static Location configLocation; 46 private static Collection locks = new ArrayList(); 47 private static Map scheduledApps = new HashMap(); 48 static ArrayList timerApps = new ArrayList(); 49 private static StorageManager storageManager; 50 private static boolean scheduling = false; 51 static boolean shutdown = false; 52 private static int nextScheduledID = 1; 53 private static Thread timerThread; 54 55 static void start(BundleContext bc) { 56 context = bc; 57 shutdown = false; 58 initConfiguration(); 59 } 60 61 static void stop() { 62 shutdown = true; 63 stopTimer(); 64 if (storageManager != null) { 65 storageManager.close(); 66 storageManager = null; 67 } 68 closeConfiguration(); 69 context = null; 70 } 71 72 private static void initConfiguration() { 73 closeConfiguration(); Filter filter = null; 75 try { 76 filter = context.createFilter(FILTER_PREFIX + PROP_CONFIG_AREA + "))"); } catch (InvalidSyntaxException e) { 78 } 80 configTracker = new ServiceTracker(context, filter, new AppPersistence()); 81 configTracker.open(); 82 } 83 84 private static void closeConfiguration() { 85 if (configTracker != null) 86 configTracker.close(); 87 configTracker = null; 88 } 89 90 95 public static boolean isLocked(ApplicationDescriptor desc) { 96 synchronized (locks) { 97 return locks.contains(desc.getApplicationId()); 98 } 99 } 100 101 106 public static void saveLock(ApplicationDescriptor desc, boolean locked) { 107 synchronized (locks) { 108 if (locked) { 109 if (!locks.contains(desc.getApplicationId())) { 110 locks.add(desc.getApplicationId()); 111 saveData(FILE_APPLOCKS); 112 } 113 } else if (locks.remove(desc.getApplicationId())) { 114 saveData(FILE_APPLOCKS); 115 } 116 } 117 } 118 119 static void removeScheduledApp(EclipseScheduledApplication scheduledApp) { 120 boolean removed; 121 synchronized (scheduledApps) { 122 removed = scheduledApps.remove(scheduledApp.getScheduleId()) != null; 123 if (removed) { 124 saveData(FILE_APPSCHEDULED); 125 } 126 } 127 if (removed) 128 synchronized (timerApps) { 129 timerApps.remove(scheduledApp); 130 } 131 } 132 133 144 public static ScheduledApplication addScheduledApp(ApplicationDescriptor descriptor, String scheduleId, Map arguments, String topic, String eventFilter, boolean recurring) throws InvalidSyntaxException, ApplicationException { 145 if (!scheduling && !checkSchedulingSupport()) 146 throw new ApplicationException(ApplicationException.APPLICATION_SCHEDULING_FAILED, "Cannot support scheduling without org.osgi.service.event package"); context.createFilter(eventFilter); 149 EclipseScheduledApplication result; 150 synchronized (scheduledApps) { 151 result = new EclipseScheduledApplication(context, getNextScheduledID(scheduleId), descriptor.getApplicationId(), arguments, topic, eventFilter, recurring); 152 addScheduledApp(result); 153 saveData(FILE_APPSCHEDULED); 154 } 155 return result; 156 } 157 158 private static void addScheduledApp(EclipseScheduledApplication scheduledApp) { 160 if (ScheduledApplication.TIMER_TOPIC.equals(scheduledApp.getTopic())) { 161 synchronized (timerApps) { 162 timerApps.add(scheduledApp); 163 if (timerThread == null) 164 startTimer(); 165 } 166 } 167 scheduledApps.put(scheduledApp.getScheduleId(), scheduledApp); 168 Hashtable serviceProps = new Hashtable(); 169 if (scheduledApp.getTopic() != null) 170 serviceProps.put(EventConstants.EVENT_TOPIC, new String [] {scheduledApp.getTopic()}); 171 if (scheduledApp.getEventFilter() != null) 172 serviceProps.put(EventConstants.EVENT_FILTER, scheduledApp.getEventFilter()); 173 serviceProps.put(ScheduledApplication.SCHEDULE_ID, scheduledApp.getScheduleId()); 174 serviceProps.put(ScheduledApplication.APPLICATION_PID, scheduledApp.getAppPid()); 175 ServiceRegistration sr = context.registerService(new String [] {ScheduledApplication.class.getName(), EVENT_HANDLER}, scheduledApp, serviceProps); 176 scheduledApp.setServiceRegistration(sr); 177 } 178 179 private static String getNextScheduledID(String scheduledId) throws ApplicationException { 180 if (scheduledId != null) { 181 if (scheduledApps.get(scheduledId) != null) 182 throw new ApplicationException(ApplicationException.APPLICATION_DUPLICATE_SCHEDULE_ID, "Duplicate scheduled ID: " + scheduledId); return scheduledId; 184 } 185 if (nextScheduledID == Integer.MAX_VALUE) 186 nextScheduledID = 0; 187 String result = new Integer (nextScheduledID++).toString(); 188 while (scheduledApps.get(result) != null && nextScheduledID < Integer.MAX_VALUE) 189 result = new Integer (nextScheduledID++).toString(); 190 if (nextScheduledID == Integer.MAX_VALUE) 191 throw new ApplicationException(ApplicationException.APPLICATION_DUPLICATE_SCHEDULE_ID, "Maximum number of scheduled applications reached"); return result; 193 } 194 195 private static boolean checkSchedulingSupport() { 196 try { 198 Class.forName(EVENT_HANDLER); 199 scheduling = true; 200 return true; 201 } catch (ClassNotFoundException e) { 202 scheduling = false; 203 return false; 204 } 205 } 206 207 private synchronized static boolean loadData(String fileName) { 208 try { 209 Location location = configLocation; 210 if (location == null) 211 return false; 212 File theStorageDir = new File(location.getURL().getPath() + '/' + Activator.PI_APP); 213 if (storageManager == null) { 214 boolean readOnly = location.isReadOnly(); 215 storageManager = new StorageManager(theStorageDir, readOnly ? "none" : null, readOnly); storageManager.open(!readOnly); 217 } 218 File dataFile = storageManager.lookup(fileName, false); 219 if (dataFile == null || !dataFile.isFile()) { 220 Location parent = location.getParentLocation(); 221 if (parent != null) { 222 theStorageDir = new File(parent.getURL().getPath() + '/' + Activator.PI_APP); 223 StorageManager tmp = new StorageManager(theStorageDir, "none", true); tmp.open(false); 225 dataFile = tmp.lookup(fileName, false); 226 tmp.close(); 227 } 228 } 229 if (dataFile == null || !dataFile.isFile()) 230 return true; 231 if (FILE_APPLOCKS.equals(fileName)) 232 loadLocks(dataFile); 233 else if (FILE_APPSCHEDULED.equals(fileName)) 234 loadSchedules(dataFile); 235 } catch (IOException e) { 236 return false; 237 } 238 return true; 239 } 240 241 private static void loadLocks(File locksData) throws IOException { 242 ObjectInputStream in = null; 243 try { 244 in = new ObjectInputStream(new FileInputStream(locksData)); 245 int dataVersion = in.readInt(); 246 if (dataVersion != DATA_VERSION) 247 return; 248 int numLocks = in.readInt(); 249 synchronized (locks) { 250 for (int i = 0; i < numLocks; i++) 251 locks.add(in.readUTF()); 252 } 253 } finally { 254 if (in != null) 255 in.close(); 256 } 257 } 258 259 private static void loadSchedules(File schedulesData) throws IOException { 260 ObjectInputStream in = null; 261 try { 262 in = new ObjectInputStream(new FileInputStream(schedulesData)); 263 int dataVersion = in.readInt(); 264 if (dataVersion != DATA_VERSION) 265 return; 266 int numScheds = in.readInt(); 267 for (int i = 0; i < numScheds; i++) { 268 String id = readString(in, false); 269 String appPid = readString(in, false); 270 String topic = readString(in, false); 271 String eventFilter = readString(in, false); 272 boolean recurring = in.readBoolean(); 273 Map args = (Map) in.readObject(); 274 EclipseScheduledApplication schedApp = new EclipseScheduledApplication(context, id, appPid, args, topic, eventFilter, recurring); 275 addScheduledApp(schedApp); 276 } 277 } catch (InvalidSyntaxException e) { 278 throw new IOException(e.getMessage()); 279 } catch (NoClassDefFoundError e) { 280 throw new IOException(e.getMessage()); 281 } catch (ClassNotFoundException e) { 282 throw new IOException(e.getMessage()); 283 } finally { 284 if (in != null) 285 in.close(); 286 } 287 } 288 289 private synchronized static void saveData(String fileName) { 290 if (storageManager == null || storageManager.isReadOnly()) 291 return; 292 try { 293 File data = storageManager.createTempFile(fileName); 294 if (FILE_APPLOCKS.equals(fileName)) 295 saveLocks(data); 296 else if (FILE_APPSCHEDULED.equals(fileName)) 297 saveSchedules(data); 298 storageManager.lookup(fileName, true); 299 storageManager.update(new String [] {fileName}, new String [] {data.getName()}); 300 } catch (IOException e) { 301 Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.ERROR, 0, NLS.bind(Messages.persistence_error_saving, fileName), 0, e, null)); 302 } 303 } 304 305 private static void saveLocks(File locksData) throws IOException { 307 ObjectOutputStream out = null; 308 try { 309 out = new ObjectOutputStream(new FileOutputStream(locksData)); 310 out.writeInt(DATA_VERSION); 311 out.writeInt(locks.size()); 312 for (Iterator iterLocks = locks.iterator(); iterLocks.hasNext();) 313 out.writeUTF((String ) iterLocks.next()); 314 } finally { 315 if (out != null) 316 out.close(); 317 } 318 } 319 320 private static void saveSchedules(File schedulesData) throws IOException { 322 ObjectOutputStream out = null; 323 try { 324 out = new ObjectOutputStream(new FileOutputStream(schedulesData)); 325 out.writeInt(DATA_VERSION); 326 out.writeInt(scheduledApps.size()); 327 for (Iterator apps = scheduledApps.values().iterator(); apps.hasNext();) { 328 EclipseScheduledApplication app = (EclipseScheduledApplication) apps.next(); 329 writeStringOrNull(out, app.getScheduleId()); 330 writeStringOrNull(out, app.getAppPid()); 331 writeStringOrNull(out, app.getTopic()); 332 writeStringOrNull(out, app.getEventFilter()); 333 out.writeBoolean(app.isRecurring()); 334 out.writeObject(app.getArguments()); 335 } 336 } finally { 337 if (out != null) 338 out.close(); 339 } 340 } 341 342 private static void startTimer() { 343 timerThread = new Thread (new AppTimer(), "app schedule timer"); timerThread.start(); 345 } 346 347 private static void stopTimer() { 348 if (timerThread != null) 349 timerThread.interrupt(); 350 timerThread = null; 351 } 352 353 static class AppTimer implements Runnable { 354 public void run() { 355 int lastMin = -1; 356 while (!shutdown) { 357 try { 358 Thread.sleep(30000); Calendar cal = Calendar.getInstance(); 360 int minute = cal.get(Calendar.MINUTE); 361 if (minute == lastMin) 362 continue; 363 lastMin = minute; 364 Hashtable props = new Hashtable(); 365 props.put(ScheduledApplication.YEAR, new Integer (cal.get(Calendar.YEAR))); 366 props.put(ScheduledApplication.MONTH, new Integer (cal.get(Calendar.MONTH))); 367 props.put(ScheduledApplication.DAY_OF_MONTH, new Integer (cal.get(Calendar.DAY_OF_MONTH))); 368 props.put(ScheduledApplication.DAY_OF_WEEK, new Integer (cal.get(Calendar.DAY_OF_WEEK))); 369 props.put(ScheduledApplication.HOUR_OF_DAY, new Integer (cal.get(Calendar.HOUR_OF_DAY))); 370 props.put(ScheduledApplication.MINUTE, new Integer (minute)); 371 Event timerEvent = new Event(ScheduledApplication.TIMER_TOPIC, props); 372 EclipseScheduledApplication[] apps = null; 373 synchronized (timerApps) { 375 if (timerApps.size() == 0) 376 continue; 377 apps = (EclipseScheduledApplication[]) timerApps.toArray(new EclipseScheduledApplication[timerApps.size()]); 378 } 379 for (int i = 0; i < apps.length; i++) { 380 try { 381 String filterString = apps[i].getEventFilter(); 382 Filter filter = filterString == null ? null : FrameworkUtil.createFilter(filterString); 383 if (filter == null || filter.match(props)) 384 apps[i].handleEvent(timerEvent); 385 } catch (Throwable t) { 386 String message = NLS.bind(Messages.scheduled_app_launch_error, apps[i].getAppPid()); 387 Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.WARNING, 0, message, 0, t, null)); 388 } 389 } 390 } catch (InterruptedException e) { 391 } 393 } 394 } 395 } 396 397 private static String readString(ObjectInputStream in, boolean intern) throws IOException { 398 byte type = in.readByte(); 399 if (type == NULL) 400 return null; 401 return intern ? in.readUTF().intern() : in.readUTF(); 402 } 403 404 private static void writeStringOrNull(ObjectOutputStream out, String string) throws IOException { 405 if (string == null) 406 out.writeByte(NULL); 407 else { 408 out.writeByte(OBJECT); 409 out.writeUTF(string); 410 } 411 } 412 413 public Object addingService(ServiceReference reference) { 414 if (configLocation != null) 415 return null; configLocation = (Location) context.getService(reference); 417 loadData(FILE_APPLOCKS); 418 loadData(FILE_APPSCHEDULED); 419 return configLocation; 420 } 421 422 public void modifiedService(ServiceReference reference, Object service) { 423 } 425 426 public void removedService(ServiceReference reference, Object service) { 427 if (service == configLocation) 428 configLocation = null; 429 } 430 } 431
| Popular Tags
|