Package org.apache.tools.ant.types.selectors.modifiedselector

Source Code of org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector$ComparatorName

/*
* Copyright  2003-2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package org.apache.tools.ant.types.selectors.modifiedselector;


// Java
import java.util.Comparator;
import java.util.Vector;
import java.util.Iterator;
import java.io.File;

// Ant
import org.apache.tools.ant.Project;
import org.apache.tools.ant.IntrospectionHelper;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Parameter;
import org.apache.tools.ant.types.selectors.BaseExtendSelector;


/**
* <p>Selector class that uses <i>Algorithm</i>, <i>Cache</i> and <i>Comparator</i>
* for its work.
* The <i>Algorithm</i> is used for computing a hashvalue for a file.
* The <i>Comparator</i> decides whether to select or not.
* The <i>Cache</i> stores the other value for comparison by the <i>Comparator</i>
* in a persistent manner.</p>
*
* <p>The ModifiedSelector is implemented as a <b>CoreSelector</b> and uses default
* values for all its attributes therefore the simpliest example is <pre>
*   <copy todir="dest">
*       <filelist dir="src">
*           <modified/>
*       </filelist>
*   </copy>
* </pre></p>
*
* <p>The same example rewritten as CoreSelector with setting the all values
* (same as defaults are) would be <pre>
*   <copy todir="dest">
*       <filelist dir="src">
*           <modified update="true"
*                     cache="propertyfile"
*                     algorithm="digest"
*                     comparator="equal">
*               <param name="cache.cachefile"     value="cache.properties"/>
*               <param name="algorithm.algorithm" value="MD5"/>
*           </modified>
*       </filelist>
*   </copy>
* </pre></p>
*
* <p>And the same rewritten as CustomSelector would be<pre>
*   <copy todir="dest">
*       <filelist dir="src">
*           <custom class="org.apache.tools.ant.type.selectors.ModifiedSelector">
*               <param name="update"     value="true"/>
*               <param name="cache"      value="propertyfile"/>
*               <param name="algorithm"  value="digest"/>
*               <param name="comparator" value="equal"/>
*               <param name="cache.cachefile"     value="cache.properties"/>
*               <param name="algorithm.algorithm" value="MD5"/>
*           </custom>
*       </filelist>
*   </copy>
* </pre></p>
*
* <p>All these three examples copy the files from <i>src</i> to <i>dest</i>
* using the ModifiedSelector. The ModifiedSelector uses the <i>PropertyfileCache
* </i>, the <i>DigestAlgorithm</i> and the <i>EqualComparator</i> for its
* work. The PropertyfileCache stores key-value-pairs in a simple java
* properties file. The filename is <i>cache.properties</i>. The <i>update</i>
* flag lets the selector update the values in the cache (and on first call
* creates the cache). The <i>DigestAlgorithm</i> computes a hashvalue using the
* java.security.MessageDigest class with its MD5-Algorithm and its standard
* provider. The new computed hashvalue and the stored one are compared by
* the <i>EqualComparator</i> which returns 'true' (more correct a value not
* equals zero (1)) if the values are not the same using simple String
* comparison.</p>
*
* <p>A useful scenario for this selector is inside a build environment
* for homepage generation (e.g. with <a href="http://xml.apache.org/forrest/">
* Apache Forrest</a>). <pre>
* <target name="generate-and-upload-site">
*     <echo> generate the site using forrest </echo>
*     <antcall target="site"/>
*
*     <echo> upload the changed files </echo>
*     <ftp server="${ftp.server}" userid="${ftp.user}" password="${ftp.pwd}">
*         <fileset dir="htdocs/manual">
*             <modified/>
*         </fileset>
*     </ftp>
* </target>
* </pre> Here all <b>changed</b> files are uploaded to the server. The
* ModifiedSelector saves therefore much upload time.</p>
*
* <p>This selector supports the following nested param's:
* <table>
* <tr><th>name</th><th>values</th><th>description</th><th>required</th></tr>
* <tr>
*     <td> cache </td>
*     <td> propertyfile </td>
*     <td> which cache implementation should be used <ul>
*          <li><b>propertyfile</b> - using java.util.Properties </li>
*     </td>
*     <td> no, defaults to 'propertyfile' </td>
* </tr>
* <tr>
*     <td> algorithm </td>
*     <td> hashvalue | digest </td>
*     <td> which algorithm implementation should be used
*          <li><b>hashvalue</b> - loads the file content into a String and
*                                 uses its hashValue() method </li>
*          <li><b>digest</b> - uses java.security.MessageDigest class </i>
*     </td>
*     <td> no, defaults to digest </td>
* </tr>
* <tr>
*     <td> comparator </td>
*     <td> equal | role </td>
*     <td> which comparator implementation should be used
*          <li><b>equal</b> - simple comparison using String.equals() </li>
*          <li><b>role</b> - uses java.text.RuleBasedCollator class </i>
*     </td>
*     <td> no, defaults to equal </td>
* </tr>
* <tr>
*     <td> update </td>
*     <td> true | false </td>
*     <td> If set to <i>true</i>, the cache will be stored, otherwise the values
*          will be lost. </td>
*     <td> no, defaults to true </td>
* </tr>
* <tr>
*     <td> seldirs </td>
*     <td> true | false </td>
*     <td> If set to <i>true</i>, directories will be selected otherwise not </td>
*     <td> no, defaults to true </td>
* </tr>
* <tr>
*     <td> cache.* </td>
*     <td> depends on used cache </td>
*     <td> value is stored and given to the Cache-Object for initialisation </td>
*     <td> depends on used cache </td>
* </tr>
* <tr>
*     <td> algorithm.* </td>
*     <td> depends on used algorithm </td>
*     <td> value is stored and given to the Algorithm-Object for initialisation </td>
*     <td> depends on used algorithm </td>
* </tr>
* <tr>
*     <td> comparator.* </td>
*     <td> depends on used comparator </td>
*     <td> value is stored and given to the Comparator-Object for initialisation </td>
*     <td> depends on used comparator </td>
* </tr>
* </table>
* If another name is used a BuildException "Invalid parameter" is thrown. </p>
*
* <p>This selector uses reflection for setting the values of its three interfaces
* (using org.apache.tools.ant.IntrospectionHelper) therefore no special
* 'configuration interfaces' has to be implemented by new caches, algorithms or
* comparators. All present <i>set</i>XX methods can be used. E.g. the DigestAlgorithm
* can use a specified provider for computing its value. For selecting this
* there is a <i>setProvider(String providername)</i> method. So you can use
* a nested <i><param name="algorithm.provider" value="MyProvider"/></i>.
*
*
* @author Jan Mat\u00e8rne
* @version 2003-09-13
* @since  Ant 1.6
*/
public class ModifiedSelector extends BaseExtendSelector {


    // -----  member variables - configuration


    /** The Cache containing the old values. */
    private Cache cache = null;

    /** Algorithm for computing new values and updating the cache. */
    private Algorithm algorithm = null;

    /** How should the cached value and the new one compared? */
    private Comparator comparator = null;

    /** Should the cache be updated? */
    private boolean update = true;

    /** Are directories selected? */
    private boolean selectDirectories = true;


    // -----  member variables - internal use


    /** Flag whether this object is configured. Configuration is only done once. */
    private boolean isConfigured = false;

    /** Algorithm name for later instantiation. */
    private AlgorithmName algoName = null;

    /** Cache name for later instantiation. */
    private CacheName cacheName = null;

    /** Comparator name for later instantiation. */
    private ComparatorName compName = null;


    /**
     * Parameter vector with parameters for later initialization.
     * @see #configure
     */
    private Vector configParameter = new Vector();

    /**
     * Parameter vector with special parameters for later initialization.
     * The names have the pattern '*.*', e.g. 'cache.cachefile'.
     * These parameters are used <b>after</b> the parameters with the pattern '*'.
     * @see #configure
     */
    private Vector specialParameter = new Vector();


    // -----  constructors  -----


    /** Bean-Constructor. */
    public ModifiedSelector() {
    }


    // ----- configuration  -----


    /** Overrides BaseSelector.verifySettings(). */
    public void verifySettings() {
        configure();
        if (cache == null) {
            setError("Cache must be set.");
        } else if (algorithm == null) {
            setError("Algorithm must be set.");
        } else if (!cache.isValid()) {
            setError("Cache must be proper configured.");
        } else if (!algorithm.isValid()) {
            setError("Algorithm must be proper configured.");
        }
    }


    /**
     * Configures this Selector.
     * Does this work only once per Selector object.
     * <p>Because some problems while configuring from <custom>Selector
     * the configuration is done in the following order:<ol>
     * <li> collect the configuration data </li>
     * <li> wait for the first isSelected() call </li>
     * <li> set the default values </li>
     * <li> set values for name pattern '*': update, cache, algorithm, comparator </li>
     * <li> set values for name pattern '*.*: cache.cachefile, ... </li>
     * </ol></p>
     * <p>This configuration algorithm is needed because you don't know
     * the order of arriving config-data. E.g. if you first set the
     * <i>cache.cachefilename</i> and after that the <i>cache</i> itself,
     * the default value for cachefilename is used, because setting the
     * cache implies creating a new Cache instance - with its defaults.</p>
     */
    public void configure() {
        //
        // -----  The "Singleton"  -----
        //
        if (isConfigured) {
            return;
        }
        isConfigured = true;

        //
        // -----  Set default values  -----
        //
        org.apache.tools.ant.Project project = getProject();
        String filename = "cache.properties";
        File cachefile = null;
        if (project != null) {
            // normal use inside Ant
            cachefile = new File(project.getBaseDir(), filename);
        } else {
            // no reference to project - e.g. during JUnit tests
            cachefile = new File(filename);
        }
        cache = new PropertiesfileCache(cachefile);
        algorithm = new DigestAlgorithm();
        comparator = new EqualComparator();
        update = true;
        selectDirectories = true;


        //
        // -----  Set the main attributes, pattern '*'  -----
        //
        for (Iterator itConfig = configParameter.iterator(); itConfig.hasNext();) {
            Parameter par = (Parameter) itConfig.next();
            if (par.getName().indexOf(".") > 0) {
                // this is a *.* parameter for later use
                specialParameter.add(par);
            } else {
                useParameter(par);
            }
        }
        configParameter = new Vector();

        //
        // -----  Instantiate the interfaces  -----
        //
        String className = null;
        String pkg = "org.apache.tools.ant.types.selectors.cacheselector";

        // the algorithm
        if (algorithm == null) {
            if ("hashvalue".equals(algoName.getValue())) {
                className = pkg + ".HashvalueAlgorithm";
            } else if ("digest".equals(algoName.getValue())) {
                className = pkg + ".DigestAlgorithm";
            }
            if (className != null) {
                try {
                    // load the specified Algorithm, save the reference and configure it
                    algorithm = (Algorithm) Class.forName(className).newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // the cache
        if (cache == null) {
            if ("propertyfile".equals(cacheName.getValue())) {
                className = pkg + ".PropertiesfileCache";
            }
            if (className != null) {
                try {
                    // load the specified Cache, save the reference and configure it
                    cache = (Cache) Class.forName(className).newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // the comparator
        if (comparator == null) {
            if ("equal".equals(compName.getValue())) {
                className = pkg + ".EqualComparator";
            } else if ("role".equals(compName.getValue())) {
                className = "java.text.RuleBasedCollator";
            }
            if (className != null) {
                try {
                    // load the specified Cache, save the reference and configure it
                    comparator = (Comparator) Class.forName(className).newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        //
        // -----  Set the special attributes, pattern '*.*'  -----
        //
        for (Iterator itSpecial = specialParameter.iterator(); itSpecial.hasNext();) {
            Parameter par = (Parameter) itSpecial.next();
            useParameter(par);
        }
        specialParameter = new Vector();
    }


    // -----  the selection work  -----


    /**
     * Implementation of BaseExtendSelector.isSelected().
     * @param basedir as described in BaseExtendSelector
     * @param filename as described in BaseExtendSelector
     * @param file as described in BaseExtendSelector
     * @return as described in BaseExtendSelector
     */
    public boolean isSelected(File basedir, String filename, File file) {
        validate();
        File f = new File(basedir, filename);

        // You can not compute a value for a directory
        if (f.isDirectory()) {
            return selectDirectories;
        }

        // Get the values and do the comparison
        String cachedValue = String.valueOf(cache.get(f.getAbsolutePath()));
        String newValue    = algorithm.getValue(f);
        boolean rv = (comparator.compare(cachedValue, newValue) != 0);

        // Maybe update the cache
        if (update && !cachedValue.equals(newValue)) {
            cache.put(f.getAbsolutePath(), newValue);
            cache.save();
        }

        return rv;
    }


    // -----  attribute and nested element support  -----


    /**
     * Support for <i>update</i> attribute.
     * @param update new value
     */
    public void setUpdate(boolean update) {
        this.update = update;
    }


    /**
     * Support for <i>seldirs</i> attribute.
     * @param seldirs new value
     */
    public void setSeldirs(boolean seldirs) {
        selectDirectories = seldirs;
    }


    /**
     * Support for nested &lt;param&gt; tags.
     * @param key the key of the parameter
     * @param value the value of the parameter
     */
    public void addParam(String key, Object value) {
        Parameter par = new Parameter();
        par.setName(key);
        par.setValue(String.valueOf(value));
        configParameter.add(par);
    }


    /**
     * Support for nested &lt;param&gt; tags.
     * @param parameter the parameter object
     */
    public void addParam(Parameter parameter) {
        configParameter.add(parameter);
    }


    /**
     * Defined in org.apache.tools.ant.types.Parameterizable.
     * Overwrite implementation in superclass because only special
     * parameters are valid.
     * @see #addParam(String,String).
     */
    public void setParameters(Parameter[] parameters) {
        if (parameters != null) {
            for (int i = 0; i < parameters.length; i++) {
                configParameter.add(parameters[i]);
            }
        }
    }


    /**
     * Support for nested <param name="" value=""/> tags.
     * Parameter named <i>cache</i>, <i>algorithm</i>,
     * <i>comparator</i> or <i>update</i> are mapped to
     * the respective set-Method.
     * Parameter which names starts with <i>cache.</i> or
     * <i>algorithm.</i> or <i>comparator.</i> are tried
     * to set on the appropriate object via its set-methods.
     * Other parameters are invalid and an BuildException will
     * be thrown.
     *
     * @param parameter  Key and value as parameter object
     */
    public void useParameter(Parameter parameter) {
        String key = parameter.getName();
        String value = parameter.getValue();
        if ("cache".equals(key)) {
            CacheName cn = new CacheName();
            cn.setValue(value);
            setCache(cn);
        } else if ("algorithm".equals(key)) {
            AlgorithmName an = new AlgorithmName();
            an.setValue(value);
            setAlgorithm(an);
        } else if ("comparator".equals(key)) {
            ComparatorName cn = new ComparatorName();
            cn.setValue(value);
            setComparator(cn);
        } else if ("update".equals(key)) {
            boolean updateValue =
                ("true".equalsIgnoreCase(value))
                ? true
                : false;
            setUpdate(updateValue);
        } else if ("seldirs".equals(key)) {
            boolean sdValue =
                ("true".equalsIgnoreCase(value))
                ? true
                : false;
            setSeldirs(sdValue);
        } else if (key.startsWith("cache.")) {
            String name = key.substring(6);
            tryToSetAParameter(cache, name, value);
        } else if (key.startsWith("algorithm.")) {
            String name = key.substring(10);
            tryToSetAParameter(algorithm, name, value);
        } else if (key.startsWith("comparator.")) {
            String name = key.substring(11);
            tryToSetAParameter(comparator, name, value);
        } else {
            setError("Invalid parameter " + key);
        }
    }


    /**
     * Try to set a value on an object using reflection.
     * Helper method for easier access to IntrospectionHelper.setAttribute().
     * @param obj the object on which the attribute should be set
     * @param name the attributename
     * @param value the new value
     */
    protected void tryToSetAParameter(Object obj, String name, String value) {
        Project prj = (getProject() != null) ? getProject() : new Project();
        IntrospectionHelper iHelper
            = IntrospectionHelper.getHelper(prj, obj.getClass());

        try {
            iHelper.setAttribute(prj, obj, name, value);
        } catch (org.apache.tools.ant.BuildException e) {
            // no-op
        }
    }


    // ----- 'beautiful' output -----


    /**
     * Override Object.toString().
     * @return information about this selector
     */
    public String toString() {
        StringBuffer buf = new StringBuffer("{modifiedselector");
        buf.append(" update=").append(update);
        buf.append(" seldirs=").append(selectDirectories);
        buf.append(" cache=").append(cache);
        buf.append(" algorithm=").append(algorithm);
        buf.append(" comparator=").append(comparator);
        buf.append("}");
        return buf.toString();
    }


    // The EnumeratedAttributes for the three interface implementations.
    // Name-Classname mapping is done in the configure() method.


    public Cache getCache() { return cache; }
    public void setCache(CacheName name) {
        cacheName = name;
    }
    public static class CacheName extends EnumeratedAttribute {
        public String[] getValues() {
            return new String[] {"propertyfile" };
        }
    }


    public Algorithm getAlgorithm() { return algorithm; }
    public void setAlgorithm(AlgorithmName name) {
        algoName = name;
    }
    public static class AlgorithmName extends EnumeratedAttribute {
        public String[] getValues() {
            return new String[] {"hashvalue", "digest" };
        }
    }


    public Comparator getComparator() { return comparator; }
    public void setComparator(ComparatorName name) {
        compName = name;
    }
    public static class ComparatorName extends EnumeratedAttribute {
        public String[] getValues() {
            return new String[] {"equal", "rule" };
        }
    }

}
TOP

Related Classes of org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector$ComparatorName

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.