View Javadoc
1   /*
2    * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions
6    * are met:
7    *
8    *   - Redistributions of source code must retain the above copyright
9    *     notice, this list of conditions and the following disclaimer.
10   *
11   *   - Redistributions in binary form must reproduce the above copyright
12   *     notice, this list of conditions and the following disclaimer in the
13   *     documentation and/or other materials provided with the distribution.
14   *
15   *   - Neither the name of Oracle nor the names of its
16   *     contributors may be used to endorse or promote products derived
17   *     from this software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  
32  /*
33   * This source code is provided to illustrate the usage of a given feature
34   * or technique and has been deliberately simplified. Additional steps
35   * required for a production-quality application, such as security checks,
36   * input validation and proper error handling, might not be present in
37   * this sample code.
38   */
39  
40  
41  package com.sun.jmx.examples.scandir.config;
42  
43  import java.io.File;
44  import java.io.FileFilter;
45  import java.util.ArrayList;
46  import java.util.Arrays;
47  import java.util.List;
48  import java.util.logging.Logger;
49  import javax.xml.bind.annotation.XmlAttribute;
50  import javax.xml.bind.annotation.XmlElement;
51  import javax.xml.bind.annotation.XmlElementRef;
52  import javax.xml.bind.annotation.XmlElementWrapper;
53  import javax.xml.bind.annotation.XmlList;
54  import javax.xml.bind.annotation.XmlRootElement;
55  
56  /**
57   * The <code>DirectoryScannerConfig</code> Java Bean is used to model
58   * the configuration of a {@link
59   * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}.
60   * <p>
61   * This class is annotated for XML binding.
62   * </p>
63   * @author Sun Microsystems, 2006 - All rights reserved.
64   */
65  @XmlRootElement(name="DirectoryScanner",
66          namespace=XmlConfigUtils.NAMESPACE)
67  public class DirectoryScannerConfig {
68  
69      //
70      // A logger for this class.
71      //
72      // private static final Logger LOG =
73      //        Logger.getLogger(DirectoryScannerConfig.class.getName());
74  
75      /**
76       * This enumeration is used to model the actions that a {@link
77       * com.sun.jmx.examples.scandir.DirectoryScannerMXBean
78       * DirectoryScannerMXBean} should take when a file matches its set
79       * of matching criteria.
80       **/
81      public enum Action {
82          /**
83           * Indicates that the {@code DirectoryScannerMXBean} should
84           * emit a {@code Notification} when a matching file is found.
85           */
86          NOTIFY,
87          /**
88           * Indicates that the {@code DirectoryScannerMXBean} should
89           * delete the matching files.
90           */
91          DELETE,
92          /**
93           * Indicates that the {@code DirectoryScannerMXBean} should
94           * log the actions that were taken on the matching files.
95           */
96          LOGRESULT };
97  
98      // A short name for the Directory Scanner
99      // This name is used for the value of the {@code name=} key in the
100     // {@code DirectoryScannerMXBean} ObjectName.
101     private String name;
102 
103     // The root directory of the Directory Scanner
104     private String rootDirectory;
105 
106     // List of filters identifying files that should be selected.
107     // A file is selected if at least one filter matches.
108     //
109     private final List<FileMatch> includeFiles =
110             new ArrayList<FileMatch>();
111 
112     // List of filters identifying files that should be excluded.
113     // A file is excluded if at least one filter matches.
114     //
115     private final List<FileMatch> excludeFiles =
116             new ArrayList<FileMatch>();
117 
118 
119     // The actions that this Directory Scanner should carry out when a
120     // file is selected. Default is NOTIFY and LOGRESULT.
121     //
122     private Action[] actions = { Action.NOTIFY, Action.LOGRESULT };
123 
124     /**
125      * Creates a new instance of {@code DirectoryScannerConfig}.
126      * We keep this empty constructor to make XML binding easier.
127      * You shouldn't use this constructor directly:
128      * use {@link #DirectoryScannerConfig(String)
129      * DirectoryScannerConfig(String name)} instead.
130      * @deprecated <p>Tagged deprecated so that a compiler warning is issued.
131      *             Use {@link #DirectoryScannerConfig(String)
132      *                  DirectoryScannerConfig(String name)} instead.
133      *             </p>
134      **/
135     public DirectoryScannerConfig() {
136         this(null);
137     }
138 
139     /**
140      * Creates a new instance of {@code DirectoryScannerConfig}.
141      * @param name A short name for the Directory Scanner. This name is used for
142      *        the value of the {@code name=} key in the
143      *        {@code DirectoryScannerMXBean} ObjectName.
144      **/
145     public DirectoryScannerConfig(String name) {
146         this.name = name;
147         rootDirectory = null;
148     }
149 
150     /**
151      * Gets the root directory configured for that Directory Scanner.
152      * @return the root directory at which the directory scanner should start
153      *         scanning.
154      **/
155     @XmlElement(name="RootDirectory",namespace=XmlConfigUtils.NAMESPACE)
156     public String getRootDirectory() {
157         return rootDirectory;
158     }
159 
160     /**
161      * Configures a root directory for that Directory Scanner.
162      * @param root The root directory at which the directory scanner should
163      *        start scanning.
164      **/
165     public void setRootDirectory(String root) {
166         rootDirectory=root;
167     }
168 
169 
170     /**
171      * Gets the short name of this directory scanner.
172      *
173      * <p>
174      * This name is used for the value of the {@code name=} key in the
175      * {@code DirectoryScannerMXBean} ObjectName.
176      * </p>
177      *
178      * @return the short name of this directory scanner.
179      **/
180     @XmlAttribute(name="name",required=true)
181     public String getName() {
182         return this.name;
183     }
184 
185     /**
186      * Setter for property {@link #getName() name}.
187      * Once set its value cannot change.
188      * @param name New value of property name.
189      * @throws IllegalArgumentException if {@code name} is already set to a
190      *         different non null value.
191      */
192     public void setName(String name) {
193         if (this.name == null)
194             this.name = name;
195         else if (name == null)
196             throw new IllegalArgumentException("name=null");
197         else if (!name.equals(this.name))
198             throw new IllegalArgumentException("name="+name);
199     }
200 
201     /**
202      * Getter for property includeFiles.
203      * This is an array of filters identifying files that should be selected.
204      * A file is selected if at least one filter matches.
205      * @return Value of property includeFiles.
206      */
207     @XmlElementWrapper(name="IncludeFiles",
208             namespace=XmlConfigUtils.NAMESPACE)
209     @XmlElementRef
210     public FileMatch[] getIncludeFiles() {
211         synchronized(includeFiles) {
212             return includeFiles.toArray(new FileMatch[0]);
213         }
214     }
215 
216     /**
217      * Adds a filter to the includeFiles property.
218      * A file is selected if at least one filter matches.
219      * @param include A filter identifying files that should be selected.
220      */
221     public void addIncludeFiles(FileMatch include) {
222         if (include == null)
223             throw new IllegalArgumentException("null");
224         synchronized (includeFiles) {
225             includeFiles.add(include);
226         }
227     }
228 
229     /**
230      * Setter for property includeFiles.
231      * @param includeFiles New value of property includeFiles.
232      *        This is an array of filters identifying files
233      *        that should be selected. A file is selected if at least
234      *        one filter matches.
235      */
236     public void setIncludeFiles(FileMatch[] includeFiles) {
237         synchronized (this.includeFiles) {
238             this.includeFiles.clear();
239             if (includeFiles == null) return;
240             this.includeFiles.addAll(Arrays.asList(includeFiles));
241         }
242     }
243 
244     /**
245      * Getter for property excludeFiles.
246      * This is an array of filters identifying files that should be excluded.
247      * A file is excluded if at least one filter matches.
248      * @return Value of property excludeFiles.
249      */
250     @XmlElementWrapper(name="ExcludeFiles",
251             namespace=XmlConfigUtils.NAMESPACE)
252     @XmlElementRef
253     public FileMatch[] getExcludeFiles() {
254         synchronized(excludeFiles) {
255             return excludeFiles.toArray(new FileMatch[0]);
256         }
257     }
258 
259     /**
260      * Setter for property excludeFiles.
261      * @param excludeFiles New value of property excludeFiles.
262      *        This is an array of filters identifying files
263      *        that should be excluded. A file is excluded if at least
264      *        one filter matches.
265      */
266     public void setExcludeFiles(FileMatch[] excludeFiles) {
267         synchronized (this.excludeFiles) {
268             this.excludeFiles.clear();
269             if (excludeFiles == null) return;
270             this.excludeFiles.addAll(Arrays.asList(excludeFiles));
271         }
272     }
273 
274     /**
275      * Adds a filter to the excludeFiles property.
276      * A file is excluded if at least one filter matches.
277      * @param exclude A filter identifying files that should be excluded.
278      */
279     public void addExcludeFiles(FileMatch exclude) {
280         if (exclude == null)
281             throw new IllegalArgumentException("null");
282         synchronized (excludeFiles) {
283             this.excludeFiles.add(exclude);
284         }
285     }
286 
287     /**
288      * Gets the list of actions that this Directory Scanner should carry
289      * out when a file is selected. Default is NOTIFY and LOGRESULT.
290 
291      * @return The list of actions that this Directory Scanner should carry
292      * out when a file is selected.
293      */
294     @XmlElement(name="Actions",namespace=XmlConfigUtils.NAMESPACE)
295     @XmlList
296     public Action[] getActions() {
297        return  (actions == null)?null:actions.clone();
298     }
299 
300     /**
301      * Sets the list of actions that this Directory Scanner should carry
302      * out when a file is selected. Default is NOTIFY and LOGRESULT.
303 
304      * @param actions The list of actions that this Directory Scanner should
305      * carry out when a file is selected.
306      */
307     public void setActions(Action[] actions) {
308         this.actions = (actions == null)?null:actions.clone();
309     }
310 
311     /**
312      * Builds a {@code FileFilter} from the {@link #getIncludeFiles
313      * includeFiles} and {@link #getExcludeFiles excludeFiles} lists.
314      * A file will be accepted if it is selected by at least one of
315      * the filters in {@link #getIncludeFiles includeFiles}, and is
316      * not excluded by any of the filters in {@link
317      * #getExcludeFiles excludeFiles}. If there's no filter in
318      * {@link #getIncludeFiles includeFiles}, then a file is accepted
319      * simply if it is not excluded by any of the filters in {@link
320      * #getExcludeFiles excludeFiles}.
321      *
322      * @return A new {@code FileFilter}  created from the current snapshot
323      *         of the {@link #getIncludeFiles
324      * includeFiles} and {@link #getExcludeFiles excludeFiles} lists.
325      *         Later modification of these lists will not affect the
326      *         returned {@code FileFilter}.
327      **/
328     public FileFilter buildFileFilter() {
329         final FileFilter[] ins = getIncludeFiles();
330         final FileFilter[] outs = getExcludeFiles();
331         final FileFilter filter = new FileFilter() {
332             public boolean accept(File f) {
333                 boolean result = false;
334                 // If no include filter, all files are included.
335                 if (ins != null) {
336                     for (FileFilter in: ins) {
337                         // if one filter accepts it, file is included
338                         if (!in.accept(f)) continue;
339 
340                         // file is accepted, include it
341                         result=true;
342                         break;
343                     }
344                 } else result= true;
345                 if (result == false) return false;
346 
347                 // The file is in the include list. Let's see if it's not
348                 // in the exclude list...
349                 //
350                 if (outs != null) {
351                     for (FileFilter out: outs) {
352                         // if one filter accepts it, file is excluded
353                         if (!out.accept(f)) continue;
354 
355                         // file is accepted, exclude it.
356                         result=false;
357                         break;
358                     }
359                 }
360                 return result;
361             }
362         };
363         return filter;
364     }
365 
366     // Used for equality - see equals().
367     private Object[] toArray() {
368         final Object[] thisconfig = {
369             name,rootDirectory,actions,excludeFiles,includeFiles
370         };
371         return thisconfig;
372     }
373 
374     @Override
375     public boolean equals(Object o) {
376         if (o == this) return true;
377         if (!(o instanceof DirectoryScannerConfig)) return false;
378         final DirectoryScannerConfig other = (DirectoryScannerConfig)o;
379         final Object[] thisconfig = toArray();
380         final Object[] otherconfig = other.toArray();
381         return Arrays.deepEquals(thisconfig,otherconfig);
382     }
383 
384     @Override
385     public int hashCode() {
386         final String key = name;
387         if (key == null) return 0;
388         else return key.hashCode();
389     }
390 
391 
392 }