001/*
002 * JPPF.
003 * Copyright (C) 2005-2016 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.node.policy;
020
021import java.io.*;
022import java.util.regex.*;
023
024import org.jppf.utils.PropertiesCollection;
025
026/**
027 * An execution policy rule that encapsulates a test of type <i>property_value matches regular_expression</i>.
028 * The expression syntax must follow the one specified for {@link java.util.regex.Pattern Pattern}.
029 * The test applies to string values only.
030 * @author Laurent Cohen
031 */
032public class RegExp extends ExecutionPolicy {
033  /**
034   * Explicit serialVersionUID.
035   */
036  private static final long serialVersionUID = 1L;
037  /**
038   * The name of the property to compare.
039   */
040  private String propertyName = null;
041  /**
042   * A regular expression to match the property value against.
043   */
044  private String regExp = null;
045  /**
046   * The pattern object to compile from the regular expression.
047   */
048  private transient Pattern pattern = null;
049
050  /**
051   * Define an equality comparison between the string value of a property and another string value.
052   * @param propertyName the name of the property to compare.
053   * @param regExp a regular expression to match the property value against.
054   * @throws PatternSyntaxException if the syntax of expression is invalid
055   */
056  public RegExp(final String propertyName, final String regExp) throws PatternSyntaxException {
057    this.propertyName = propertyName;
058    // compiled at creation time to ensure any syntax problem in the expression is known on the client side.
059    pattern = Pattern.compile(regExp);
060    this.regExp = regExp;
061  }
062
063  /**
064   * Determines whether this policy accepts the specified node.
065   * @param info system information for the node on which the tasks will run if accepted.
066   * @return true if the node is accepted, false otherwise.
067   */
068  @Override
069  public boolean accepts(final PropertiesCollection info) {
070    if (regExp == null) return false;
071    String s = getProperty(info, propertyName);
072    if (s == null) return false;
073    return pattern.matcher(s).matches();
074  }
075
076  /**
077   * Print this object to a string.
078   * @return an XML string representation of this object
079   */
080  @Override
081  public String toString() {
082    if (computedToString == null) {
083      synchronized (ExecutionPolicy.class) {
084        StringBuilder sb = new StringBuilder();
085        sb.append(indent()).append("<RegExp>\n");
086        toStringIndent++;
087        sb.append(indent()).append("<Property>").append(propertyName).append("</Property>\n");
088        sb.append(indent()).append("<Value>").append(regExp).append("</Value>\n");
089        toStringIndent--;
090        sb.append(indent()).append("</RegExp>\n");
091        computedToString = sb.toString();
092      }
093    }
094    return computedToString;
095  }
096
097  /**
098   * Save the state of the {@code JPPFJob} instance to a stream (i.e.,serialize it).
099   * @param out the output stream to which to write the job. 
100   * @throws IOException if any I/O error occurs.
101   * @since 5.2
102   */
103  private void writeObject(final ObjectOutputStream out) throws IOException {
104    out.defaultWriteObject();
105  }
106
107  /**
108   * Reconstitute the {@code TreeMap} instance from a stream (i.e., deserialize it).
109   * @param in the input stream from which to read the job. 
110   * @throws IOException if any I/O error occurs.
111   * @throws ClassNotFoundException if the class of an object in the object graph can not be found.
112   * @since 5.2
113   */
114  private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
115    in.defaultReadObject();
116    pattern = Pattern.compile(regExp);
117  }
118}