KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > equinox > internal > app > AppPersistence


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.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 /**
28  * Manages all persistent data for ApplicationDescriptors (lock status,
29  * scheduled applications etc.)
30  */

31 public class AppPersistence implements ServiceTrackerCustomizer {
32     private static final String JavaDoc PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
33

34     private static final String JavaDoc FILTER_PREFIX = "(&(objectClass=org.eclipse.osgi.service.datalocation.Location)(type="; //$NON-NLS-1$
35
private static final String JavaDoc FILE_APPLOCKS = ".locks"; //$NON-NLS-1$
36
private static final String JavaDoc FILE_APPSCHEDULED = ".scheduled"; //$NON-NLS-1$
37
private static final String JavaDoc EVENT_HANDLER = "org.osgi.service.event.EventHandler"; //$NON-NLS-1$
38

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 JavaDoc 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(); // just incase
74
Filter filter = null;
75         try {
76             filter = context.createFilter(FILTER_PREFIX + PROP_CONFIG_AREA + "))"); //$NON-NLS-1$
77
} catch (InvalidSyntaxException e) {
78             // ignore this. It should never happen as we have tested the above format.
79
}
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     /**
91      * Used by {@link ApplicationDescriptor} to determine if an application is locked.
92      * @param desc the application descriptor
93      * @return true if the application is persistently locked.
94      */

95     public static boolean isLocked(ApplicationDescriptor desc) {
96         synchronized (locks) {
97             return locks.contains(desc.getApplicationId());
98         }
99     }
100
101     /**
102      * Used by {@link ApplicationDescriptor} to determine lock and unlock and application.
103      * @param desc the application descriptor
104      * @param locked the locked flag
105      */

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     /**
134      * Used by {@link ScheduledApplication} to persistently schedule an application launch
135      * @param descriptor
136      * @param arguments
137      * @param topic
138      * @param eventFilter
139      * @param recurring
140      * @return the scheduled application
141      * @throws InvalidSyntaxException
142      * @throws ApplicationException
143      */

144     public static ScheduledApplication addScheduledApp(ApplicationDescriptor descriptor, String JavaDoc scheduleId, Map arguments, String JavaDoc topic, String JavaDoc 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"); //$NON-NLS-1$
147
// check the event filter for correct syntax
148
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     // must call this method while holding the scheduledApps lock
159
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 JavaDoc[] {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 JavaDoc[] {ScheduledApplication.class.getName(), EVENT_HANDLER}, scheduledApp, serviceProps);
176         scheduledApp.setServiceRegistration(sr);
177     }
178
179     private static String JavaDoc getNextScheduledID(String JavaDoc 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); //$NON-NLS-1$
183
return scheduledId;
184         }
185         if (nextScheduledID == Integer.MAX_VALUE)
186             nextScheduledID = 0;
187         String JavaDoc result = new Integer JavaDoc(nextScheduledID++).toString();
188         while (scheduledApps.get(result) != null && nextScheduledID < Integer.MAX_VALUE)
189             result = new Integer JavaDoc(nextScheduledID++).toString();
190         if (nextScheduledID == Integer.MAX_VALUE)
191             throw new ApplicationException(ApplicationException.APPLICATION_DUPLICATE_SCHEDULE_ID, "Maximum number of scheduled applications reached"); //$NON-NLS-1$
192
return result;
193     }
194
195     private static boolean checkSchedulingSupport() {
196         // cannot support scheduling without the event admin package
197
try {
198             Class.forName(EVENT_HANDLER);
199             scheduling = true;
200             return true;
201         } catch (ClassNotFoundException JavaDoc e) {
202             scheduling = false;
203             return false;
204         }
205     }
206
207     private synchronized static boolean loadData(String JavaDoc 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); //$NON-NLS-1$
216
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); //$NON-NLS-1$
224
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 JavaDoc id = readString(in, false);
269                 String JavaDoc appPid = readString(in, false);
270                 String JavaDoc topic = readString(in, false);
271                 String JavaDoc 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 JavaDoc e) {
280             throw new IOException(e.getMessage());
281         } catch (ClassNotFoundException JavaDoc 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 JavaDoc 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 JavaDoc[] {fileName}, new String JavaDoc[] {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     // must call this while holding the locks lock
306
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 JavaDoc) iterLocks.next());
314         } finally {
315             if (out != null)
316                 out.close();
317         }
318     }
319
320     // must call this while holding the scheduledApps lock
321
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 JavaDoc(new AppTimer(), "app schedule timer"); //$NON-NLS-1$
344
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 JavaDoc {
354         public void run() {
355             int lastMin = -1;
356             while (!shutdown) {
357                 try {
358                     Thread.sleep(30000); // sleeping 30 secs instead of 60 to try to avoid skipping minutes
359
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 JavaDoc(cal.get(Calendar.YEAR)));
366                     props.put(ScheduledApplication.MONTH, new Integer JavaDoc(cal.get(Calendar.MONTH)));
367                     props.put(ScheduledApplication.DAY_OF_MONTH, new Integer JavaDoc(cal.get(Calendar.DAY_OF_MONTH)));
368                     props.put(ScheduledApplication.DAY_OF_WEEK, new Integer JavaDoc(cal.get(Calendar.DAY_OF_WEEK)));
369                     props.put(ScheduledApplication.HOUR_OF_DAY, new Integer JavaDoc(cal.get(Calendar.HOUR_OF_DAY)));
370                     props.put(ScheduledApplication.MINUTE, new Integer JavaDoc(minute));
371                     Event timerEvent = new Event(ScheduledApplication.TIMER_TOPIC, props);
372                     EclipseScheduledApplication[] apps = null;
373                     // poor mans implementation of dispatching events; the spec will not allow us to use event admin to dispatch the virtual timer events; boo!!
374
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 JavaDoc 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 JavaDoc t) {
386                             String JavaDoc 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 JavaDoc e) {
391                     // do nothing;
392
}
393             }
394         }
395     }
396
397     private static String JavaDoc 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 JavaDoc 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 JavaDoc addingService(ServiceReference reference) {
414         if (configLocation != null)
415             return null; // only care about one configuration
416
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 JavaDoc service) {
423         // don't care
424
}
425
426     public void removedService(ServiceReference reference, Object JavaDoc service) {
427         if (service == configLocation)
428             configLocation = null;
429     }
430 }
431
Popular Tags