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 } 393