package org.springframework.roo.file.monitor; import static org.springframework.roo.file.monitor.event.FileOperation.CREATED; import static org.springframework.roo.file.monitor.event.FileOperation.DELETED; import static org.springframework.roo.file.monitor.event.FileOperation.RENAMED; import static org.springframework.roo.file.monitor.event.FileOperation.UPDATED; import java.beans.PropertyEditor; import java.beans.PropertyEditorSupport; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.springframework.roo.file.monitor.event.FileOperation; /** * A {@link PropertyEditor} for {@link MonitoringRequest}s. * <p> * The syntax expected by the editor is as follows: * <p> * <code>fullyQualifiedName + "," + fileOperationCodes + {"," + "**"}<code> * * <p> * Where: * <ul> * <li>fullyQualifiedName is a {@link File}-resolvable name (required)</li> * <li>fileOperationCodes is one or more of characters "C" (for create), "R" (for rename), * "U" (for update) and "D" (for delete), as per {@link FileOperation} (required)</li> * <li>literal "**" indicates to watch the subtree, which is only valid if the * fullyQualifiedName is an existing directory (optional, but can only be used * for a directory)</li> * </ul> * * @author Ben Alex * @since 1.0 */ public class MonitoringRequestEditor extends PropertyEditorSupport { private static final FileOperation[] MONITORED_OPERATIONS = {CREATED, RENAMED, UPDATED, DELETED}; private static final String SUBTREE_WILDCARD = "**"; /** * @return this object in accordance with the string specification given in * the JavaDocs (or null if the object null) */ @Override public String getAsText() { final MonitoringRequest req = getValue(); if (req == null) { return null; } final StringBuilder text = new StringBuilder(); try { text.append(req.getFile().getCanonicalPath()); } catch (final IOException ioe) { throw new IllegalStateException("Failure retrieving path for request '" + req + "'", ioe); } text.append(","); for (final FileOperation fileOperation : MONITORED_OPERATIONS) { if (req.getNotifyOn().contains(fileOperation)) { text.append(fileOperation.name().charAt(0)); } } if (req instanceof DirectoryMonitoringRequest) { final DirectoryMonitoringRequest dmr = (DirectoryMonitoringRequest) req; if (dmr.isWatchSubtree()) { text.append(",").append(SUBTREE_WILDCARD); } } return text.toString(); } @Override public MonitoringRequest getValue() { return (MonitoringRequest) super.getValue(); } private Collection<FileOperation> parseFileOperations(final String fileOperationCodes) { final Set<FileOperation> fileOperations = new HashSet<FileOperation>(); for (final FileOperation fileOperation : MONITORED_OPERATIONS) { if (fileOperationCodes.contains(fileOperation.name().substring(0, 1))) { fileOperations.add(fileOperation); } } return fileOperations; } @Override public void setAsText(final String text) throws IllegalArgumentException { if (StringUtils.isBlank(text)) { setValue(null); return; } final String[] segments = StringUtils.split(text, ","); Validate.isTrue(segments.length == 2 || segments.length == 3, "Text '%s' is invalid for a MonitoringRequest", text); final File file = new File(segments[0]); Validate.isTrue(file.exists(), "File '%s' does not exist", file); final Collection<FileOperation> fileOperations = parseFileOperations(segments[1]); Validate.notEmpty(fileOperations, "One or more valid operation codes ('CRUD') required for file '%s'", file); if (file.isFile()) { Validate.isTrue(segments.length == 2, "Can only have two values for file '%s'", file); setValue(new FileMonitoringRequest(file, fileOperations)); } else { setValueToDirectoryMonitoringRequest(segments, file, fileOperations); } } private void setValueToDirectoryMonitoringRequest(final String[] segments, final File file, final Collection<FileOperation> fileOperations) { if (segments.length == 3) { Validate .isTrue( SUBTREE_WILDCARD.equals(segments[2]), "The third value for directory '%s' can only be '%s' (or completely remove the third parameter if you do not want to watch the subtree)", file, SUBTREE_WILDCARD); setValue(new DirectoryMonitoringRequest(file, true, fileOperations)); } else { setValue(new DirectoryMonitoringRequest(file, false, fileOperations)); } } }