KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > examples > scandir > ScanDirConfig


1 /*
2  * ScanDirConfig.java
3  *
4  * Created on July 12, 2006, 7:43 PM
5  *
6  * @(#)ScanDirConfig.java 1.2 06/08/02
7  *
8  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * -Redistribution of source code must retain the above copyright notice, this
14  * list of conditions and the following disclaimer.
15  *
16  * -Redistribution in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  *
20  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
21  * be used to endorse or promote products derived from this software without
22  * specific prior written permission.
23  *
24  * This software is provided "AS IS," without a warranty of any kind. ALL
25  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
26  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
27  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
28  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
29  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
30  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
31  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
32  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
33  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
34  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
35  *
36  * You acknowledge that this software is not designed, licensed or intended
37  * for use in the design, construction, operation or maintenance of any
38  * nuclear facility.
39  */

40
41 package com.sun.jmx.examples.scandir;
42
43 import static com.sun.jmx.examples.scandir.ScanManager.getNextSeqNumber;
44 import static com.sun.jmx.examples.scandir.ScanDirConfigMXBean.SaveState.*;
45 import com.sun.jmx.examples.scandir.config.XmlConfigUtils;
46 import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig;
47 import com.sun.jmx.examples.scandir.config.FileMatch;
48 import com.sun.jmx.examples.scandir.config.ScanManagerConfig;
49 import java.io.File JavaDoc;
50 import java.io.IOException JavaDoc;
51 import java.io.InputStream JavaDoc;
52 import java.io.OutputStream JavaDoc;
53 import java.util.Date JavaDoc;
54 import java.util.logging.Level JavaDoc;
55 import java.util.logging.Logger JavaDoc;
56 import javax.management.*;
57 import javax.xml.bind.JAXBException;
58
59 /**
60  * <p>The <code>ScanDirConfig</code> MBean is in charge of the
61  * <i>scandir</i> application configuration.
62  * </p>
63  * <p>The <code>ScanDirConfig</code> MBean is able to
64  * load and save the <i>scandir</i> application configuration to and from an
65  * XML file.
66  * </p>
67  * <p>
68  * It will let you also interactively modify that configuration, which you
69  * can later save to the file, by calling {@link #save}, or discard, by
70  * reloading the file without saving - see {@link #load}.
71  * </p>
72  * <p>
73  * There can be as many <code>ScanDirConfigMXBean</code> registered
74  * in the MBeanServer as you like, but only one of them will be identified as
75  * the current configuration of the {@link ScanManagerMXBean}.
76  * You can switch to another configuration by calling {@link
77  * ScanManagerMXBean#setConfigurationMBean
78  * ScanManagerMXBean.setConfigurationMBean}.
79  * </p>
80  * <p>
81  * Once the current configuration has been loaded (by calling {@link #load})
82  * or modified (by calling one of {@link #addDirectoryScanner
83  * addDirectoryScanner}, {@link #removeDirectoryScanner removeDirectoryScanner}
84  * or {@link #setConfiguration setConfiguration}) it can be pushed
85  * to the {@link ScanManagerMXBean} by calling {@link
86  * ScanManagerMXBean#applyConfiguration
87  * ScanManagerMXBean.applyConfiguration(true)} -
88  * <code>true</code> means that we apply the configuration from memory,
89  * without first reloading the file.
90  * </p>
91  * <p>
92  * The <code>ScanDirConfig</code> uses the XML annotated Java Beans defined
93  * in the {@link com.sun.jmx.examples.scandir.config} package.
94  * </p>
95  * <p>
96  * <u>Note:</u> The <code>ScanDirConfig</code> should probably use
97  * {@code java.nio.channels.FileLock} and lock its configuration file so that
98  * two <code>ScanDirConfig</code> object do not share the same file, but it
99  * doesn't. Feel free to improve the application in that way.
100  * </p>
101  * @author Sun Microsystems, 2006 - All rights reserved.
102  */

103 public class ScanDirConfig extends NotificationBroadcasterSupport
104         implements ScanDirConfigMXBean, MBeanRegistration {
105     
106     /**
107      * A logger for this class.
108      **/

109     private static final Logger JavaDoc LOG =
110             Logger.getLogger(ScanDirConfig.class.getName());
111     
112     // We will emit a notification when the save state of this object
113
// chenges. We use directly the base notification class, with a
114
// notification type that indicates the new state at which the
115
// object has arrived.
116
//
117
// All these notification types will have the same prefix, which is
118
// 'com.sun.jmx.examples.scandir.config'.
119
//
120
private final static String JavaDoc NOTIFICATION_PREFIX =
121             ScanManagerConfig.class.getPackage().getName();
122     
123     /**
124      * The <i>com.sun.jmx.examples.scandir.config.saved</i> notification
125      * indicates that the configuration data was saved.
126      **/

127     public final static String JavaDoc NOTIFICATION_SAVED =
128             NOTIFICATION_PREFIX+".saved";
129     /**
130      * The <i>com.sun.jmx.examples.scandir.config.loaded</i> notification
131      * indicates that the configuration data was loaded.
132      **/

133     public final static String JavaDoc NOTIFICATION_LOADED =
134             NOTIFICATION_PREFIX+".loaded";
135     
136     /**
137      * The <i>com.sun.jmx.examples.scandir.config.modified</i> notification
138      * indicates that the configuration data was modified.
139      **/

140     public final static String JavaDoc NOTIFICATION_MODIFIED =
141             NOTIFICATION_PREFIX+".modified";
142     
143     // The array of MBeanNotificationInfo that will be exposed in the
144
// ScanDirConfigMXBean MBeanInfo.
145
// We will pass this array to the NotificationBroadcasterSupport
146
// constructor.
147
//
148
private static MBeanNotificationInfo[] NOTIFICATION_INFO = {
149         new MBeanNotificationInfo(
150                 new String JavaDoc[] {NOTIFICATION_SAVED},
151                 Notification.class.getName(),
152                 "Emitted when the configuration is saved"),
153         new MBeanNotificationInfo(
154                 new String JavaDoc[] {NOTIFICATION_LOADED},
155                 Notification.class.getName(),
156                 "Emitted when the configuration is loaded"),
157         new MBeanNotificationInfo(
158                 new String JavaDoc[] {NOTIFICATION_MODIFIED},
159                 Notification.class.getName(),
160                 "Emitted when the configuration is modified"),
161     };
162
163      // The ScanDirConfigMXBean configuration data.
164
private volatile ScanManagerConfig config;
165     
166     // The name of the configuration file
167
private String JavaDoc filename = null;
168     
169     // The name of this configuration. This is usually both equal to
170
// config.getName() and objectName.getKeyProperty(name).
171
private volatile String JavaDoc configname = null;
172     
173     // This object save state. CREATED is the initial state.
174
//
175
private volatile SaveState status = CREATED;
176     
177     /**
178      * Creates a new {@link ScanDirConfigMXBean}.
179      * <p>{@code ScanDirConfigMXBean} can be created by the {@link
180      * ScanManagerMXBean}, or directly by a remote client, using
181      * {@code createMBean} or {@code registerMBean}.
182      * </p>
183      * <p>{@code ScanDirConfigMXBean} created by the {@link
184      * ScanManagerMXBean} will be unregistered by the
185      * {@code ScanManagerMXBean}. {@code ScanDirConfigMXBean} created
186      * directly by a remote client will not be unregistered by the
187      * {@code ScanManagerMXBean} - this will remain to the responsibility of
188      * the code/client that created them.
189      * </p>
190      * <p>This object is created empty, you should call load() if you want it
191      * to load its data from the configuration file.
192      * </p>
193      * @param filename The configuration file used by this MBean.
194      * Can be null (in which case load() and save() will fail).
195      * Can point to a file that does not exists yet (in which case
196      * load() will fail if called before save(), and save() will
197      * attempt to create that file). Can point to an existing file,
198      * in which case load() will load that file and save() will save
199      * to that file.
200      *
201      **/

202     public ScanDirConfig(String JavaDoc filename) {
203         this(filename,null);
204     }
205
206     /**
207      * Create a new ScanDirConfig MBean with an initial configuration.
208      * @param filename The name of the configuration file.
209      * @param initialConfig an initial configuration.
210      **/

211     public ScanDirConfig(String JavaDoc filename, ScanManagerConfig initialConfig) {
212         super(NOTIFICATION_INFO);
213         this.filename = filename;
214         this.config = initialConfig;
215     }
216
217     
218     // see ScanDirConfigMXBean
219
public void load() throws IOException JavaDoc {
220         if (filename == null)
221             throw new UnsupportedOperationException JavaDoc("load");
222          
223         synchronized(this) {
224             config = new XmlConfigUtils(filename).readFromFile();
225             if (configname != null) config = config.copy(configname);
226             else configname = config.getName();
227         
228             status=LOADED;
229         }
230         sendNotification(NOTIFICATION_LOADED);
231     }
232     
233     // see ScanDirConfigMXBean
234
public void save() throws IOException JavaDoc {
235         if (filename == null)
236             throw new UnsupportedOperationException JavaDoc("load");
237         synchronized (this) {
238             new XmlConfigUtils(filename).writeToFile(config);
239             status = SAVED;
240         }
241         sendNotification(NOTIFICATION_SAVED);
242     }
243         
244     // see ScanDirConfigMXBean
245
public ScanManagerConfig getConfiguration() {
246         synchronized (this) {
247             return XmlConfigUtils.xmlClone(config);
248         }
249     }
250
251    
252     // sends a notification indicating the new save state.
253
private void sendNotification(String JavaDoc type) {
254         final Object JavaDoc source = (objectName==null)?this:objectName;
255         final Notification n = new Notification(type,source,
256                 getNextSeqNumber(),
257                 "The configuration is "+
258                 type.substring(type.lastIndexOf('.')+1));
259         sendNotification(n);
260     }
261     
262
263     /**
264      * Allows the MBean to perform any operations it needs before being
265      * registered in the MBean server. If the name of the MBean is not
266      * specified, the MBean can provide a name for its registration. If
267      * any exception is raised, the MBean will not be registered in the
268      * MBean server.
269      * @param server The MBean server in which the MBean will be registered.
270      * @param name The object name of the MBean. This name is null if the
271      * name parameter to one of the createMBean or registerMBean methods in
272      * the MBeanServer interface is null. In that case, this method will
273      * try to guess its MBean name by examining its configuration data.
274      * If its configuration data is null (nothing was provided in the
275      * constructor) or doesn't contain a name, this method returns {@code null},
276      * and registration will fail.
277      * <p>
278      * Otherwise, if {@code name} wasn't {@code null} or if a default name could
279      * be constructed, the name of the configuration will be set to
280      * the value of the ObjectName's {@code name=} key, and the configuration
281      * data will always be renamed to reflect this change.
282      * </p>
283      *
284      * @return The name under which the MBean is to be registered.
285      * @throws Exception This exception will be caught by the MBean server and
286      * re-thrown as an MBeanRegistrationException.
287      */

288     public ObjectName preRegister(MBeanServer server, ObjectName name)
289         throws Exception JavaDoc {
290         if (name == null) {
291             if (config == null) return null;
292             if (config.getName() == null) return null;
293             name = ScanManager.
294                     makeMBeanName(ScanDirConfigMXBean.class,config.getName());
295         }
296         objectName = name;
297         mbeanServer = server;
298         synchronized (this) {
299             configname = name.getKeyProperty("name");
300             if (config == null) config = new ScanManagerConfig(configname);
301             else config = config.copy(configname);
302         }
303         return name;
304     }
305
306     /**
307      * Allows the MBean to perform any operations needed after having
308      * been registered in the MBean server or after the registration has
309      * failed.
310      * <p>This implementation does nothing</p>
311      * @param registrationDone Indicates whether or not the MBean has been
312      * successfully registered in the MBean server. The value false means
313      * that the registration has failed.
314      */

315     public void postRegister(Boolean JavaDoc registrationDone) {
316         // Nothing to do here.
317
}
318
319     /**
320      * Allows the MBean to perform any operations it needs before being
321      * unregistered by the MBean server.
322      * <p>This implementation does nothing</p>
323      * @throws Exception This exception will be caught by the MBean server and
324      * re-thrown as an MBeanRegistrationException.
325      */

326     public void preDeregister() throws Exception JavaDoc {
327         // Nothing to do here.
328
}
329
330     /**
331      * Allows the MBean to perform any operations needed after having been
332      * unregistered in the MBean server.
333      * <p>This implementation does nothing</p>
334      */

335     public void postDeregister() {
336         // Nothing to do here.
337
}
338
339     // see ScanDirConfigMXBean
340
public String JavaDoc getConfigFilename() {
341         return filename;
342     }
343
344     // see ScanDirConfigMXBean
345
public void setConfiguration(ScanManagerConfig config) {
346         synchronized (this) {
347             if (config == null) {
348                 this.config = null;
349                 return;
350             }
351         
352             if (configname == null)
353                 configname = config.getName();
354         
355             this.config = config.copy(configname);
356             status = MODIFIED;
357         }
358         sendNotification(NOTIFICATION_MODIFIED);
359     }
360     
361     // see ScanDirConfigMXBean
362
public DirectoryScannerConfig
363             addDirectoryScanner(String JavaDoc name, String JavaDoc dir, String JavaDoc filePattern,
364                                 long sizeExceedsMaxBytes, long sinceLastModified) {
365          final DirectoryScannerConfig scanner =
366                  new DirectoryScannerConfig(name);
367          scanner.setRootDirectory(dir);
368          if (filePattern!=null||sizeExceedsMaxBytes>0||sinceLastModified>0) {
369             final FileMatch filter = new FileMatch();
370             filter.setFilePattern(filePattern);
371             filter.setSizeExceedsMaxBytes(sizeExceedsMaxBytes);
372             if (sinceLastModified > 0)
373                 filter.setLastModifiedBefore(new Date JavaDoc(new Date JavaDoc().getTime()
374                                                 -sinceLastModified));
375             scanner.addIncludeFiles(filter);
376          }
377          synchronized (this) {
378             config.putScan(scanner);
379             status = MODIFIED;
380          }
381          LOG.fine("config: "+config);
382          sendNotification(NOTIFICATION_MODIFIED);
383          return scanner;
384     }
385
386     // see ScanDirConfigMXBean
387
public DirectoryScannerConfig removeDirectoryScanner(String JavaDoc name)
388         throws IOException JavaDoc, InstanceNotFoundException {
389         final DirectoryScannerConfig scanner;
390         synchronized (this) {
391             scanner = config.removeScan(name);
392             if (scanner == null)
393                 throw new IllegalArgumentException JavaDoc(name+": scanner not found");
394             status = MODIFIED;
395         }
396         sendNotification(NOTIFICATION_MODIFIED);
397         return scanner;
398     }
399
400     // see ScanDirConfigMXBean
401
public SaveState getSaveState() {
402         return status;
403     }
404     
405     // These methods are used by ScanManager to guess a configuration name from
406
// a configuration filename.
407
//
408
static String JavaDoc DEFAULT = "DEFAULT";
409     
410     private static String JavaDoc getBasename(String JavaDoc name) {
411         final int dot = name.indexOf('.');
412         if (dot<0) return name;
413         if (dot==0) return getBasename(name.substring(1));
414         return name.substring(0,dot);
415     }
416     
417     static String JavaDoc guessConfigName(String JavaDoc configFileName,String JavaDoc defaultFile) {
418         try {
419             if (configFileName == null) return DEFAULT;
420             final File JavaDoc f = new File JavaDoc(configFileName);
421             if (f.canRead()) {
422                 final String JavaDoc confname = XmlConfigUtils.read(f).getName();
423                 if (confname != null && confname.length()>0) return confname;
424             }
425             final File JavaDoc f2 = new File JavaDoc(defaultFile);
426             if (f.equals(f2)) return DEFAULT;
427             final String JavaDoc guess = getBasename(f.getName());
428             if (guess == null) return DEFAULT;
429             if (guess.length()==0) return DEFAULT;
430             return guess;
431         } catch (Exception JavaDoc x) {
432             return DEFAULT;
433         }
434     }
435     
436     // Set by preRegister()
437
private volatile MBeanServer mbeanServer;
438     private volatile ObjectName objectName;
439     
440 }
441
442
443
Popular Tags