net.sf.eclipsecs.core.config.CheckConfigurationWorkingCopy.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.eclipsecs.core.config.CheckConfigurationWorkingCopy.java

Source

//============================================================================
//
// Copyright (C) 2002-2014  David Schneider, Lars Kdderitzsch
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//============================================================================

package net.sf.eclipsecs.core.config;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.eclipsecs.core.CheckstylePlugin;
import net.sf.eclipsecs.core.Messages;
import net.sf.eclipsecs.core.config.configtypes.IConfigurationType;
import net.sf.eclipsecs.core.util.CheckstylePluginException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.util.NLS;
import org.xml.sax.InputSource;

/**
 * This class acts as wrapper around check configurations to add editing aspects. Check configurations by themself are
 * not editable.
 *
 * @author Lars Kdderitzsch
 */
public class CheckConfigurationWorkingCopy implements ICheckConfiguration, Cloneable {

    /** The source check configuration of the working copy. */
    private final ICheckConfiguration mCheckConfiguration;

    /** The working set this working copy belongs to. */
    private final ICheckConfigurationWorkingSet mWorkingSet;

    /** The edited name of the configuration. */
    private String mEditedName;

    /** The edited location of the configuration. */
    private String mEditedLocation;

    /** The edited description of the configuration. */
    private String mEditedDescription;

    /** The list of resolvable properties. */
    private List<ResolvableProperty> mProperties = new ArrayList<ResolvableProperty>();

    /** The map of additional data for this configuration. */
    private Map<String, String> mAdditionalData = new HashMap<String, String>();

    /** flags if the configuration is dirty. */
    private boolean mHasConfigChanged;

    /**
     * Creates a new working copy from an existing check configuration.
     *
     * @param checkConfigToEdit
     *            the existing check configuration
     * @param workingSet
     *            the working set this working copy belongs to
     */
    public CheckConfigurationWorkingCopy(ICheckConfiguration checkConfigToEdit,
            ICheckConfigurationWorkingSet workingSet) {
        mCheckConfiguration = checkConfigToEdit;
        mWorkingSet = workingSet;

        mAdditionalData.putAll(checkConfigToEdit.getAdditionalData());

        List<ResolvableProperty> props = checkConfigToEdit.getResolvableProperties();
        for (ResolvableProperty prop : props) {
            mProperties.add(prop.clone());
        }
    }

    /**
     * Creates a working copy for a new check configuration.
     *
     * @param configType
     *            the type of the new configuration
     * @param workingSet
     *            the working set this working copy belongs to
     * @param global
     *            <code>true</code> if the new configuration is a global configuration
     */
    public CheckConfigurationWorkingCopy(IConfigurationType configType, ICheckConfigurationWorkingSet workingSet,
            boolean global) {

        mWorkingSet = workingSet;
        mCheckConfiguration = new CheckConfiguration(null, null, null, configType, global, null, null);
    }

    /**
     * Returns the source check configuration of this working copy.
     *
     * @return the source check configuration
     */
    public ICheckConfiguration getSourceCheckConfiguration() {
        return mCheckConfiguration;
    }

    /**
     * Changes the name of the check configuration.
     *
     * @param name
     *            the new name
     * @throws CheckstylePluginException
     *             if name is <code>null</code> or empty or a name collision with an existing check configuration exists
     */
    public void setName(String name) throws CheckstylePluginException {

        if (name == null || name.trim().length() == 0) {
            throw new CheckstylePluginException(Messages.errorConfigNameEmpty);
        }

        String oldName = getName();
        if (!name.equals(oldName)) {

            mEditedName = name;

            // Check if the new name is in use
            if (mWorkingSet.isNameCollision(this)) {
                mEditedName = oldName;
                throw new CheckstylePluginException(NLS.bind(Messages.errorConfigNameInUse, name));
            }
        }
    }

    /**
     * Changes the location of the Checkstyle configuration file.
     *
     * @param location
     *            the new location of Checkstyle configuration file
     * @throws CheckstylePluginException
     *             if location is <code>null</code> or empty or the Checkstyle configuration file cannot be resolved
     */
    public void setLocation(String location) throws CheckstylePluginException {
        if (location == null || location.trim().length() == 0) {
            throw new CheckstylePluginException(Messages.errorLocationEmpty);
        }

        String oldLocation = getLocation();
        if (!location.equals(oldLocation)) {

            try {
                mEditedLocation = location;

                // test if configuration file exists
                getCheckstyleConfiguration();
            } catch (Exception e) {
                mEditedLocation = oldLocation;
                CheckstylePluginException.rethrow(e,
                        NLS.bind(Messages.errorResolveConfigLocation, location, e.getLocalizedMessage()));
            }
        }
    }

    /**
     * Sets a new description for the check configuration.
     *
     * @param description
     *            the new description
     */
    public void setDescription(String description) {
        String oldDescription = getDescription();
        if (description == null || !description.equals(oldDescription)) {
            mEditedDescription = description;
        }
    }

    /**
     * Flags if the working copy changed compared to the original check configuration and needs to be saved.
     *
     * @return <code>true</code> if the working copy has changes over the original check configuration
     */
    public boolean isDirty() {
        return !this.equals(mCheckConfiguration);
    }

    /**
     * Determines if the checkstyle configuration of this working copy changed. This is used to determine if specific
     * projects need to rebuild afterwards.
     *
     * @return <code>true</code> if the checkstyle configuration changed.
     */
    public boolean hasConfigurationChanged() {
        return mHasConfigChanged || !(new EqualsBuilder().append(getLocation(), mCheckConfiguration.getLocation())
                .append(getResolvableProperties(), mCheckConfiguration.getResolvableProperties())
                .append(getAdditionalData(), mCheckConfiguration.getAdditionalData()).isEquals());
    }

    /**
     * Reads the Checkstyle configuration file and builds the list of configured modules. Elements are of type
     * <code>net.sf.eclipsecs.core.config.Module</code>.
     *
     * @return the list of configured modules in this Checkstyle configuration
     * @throws CheckstylePluginException
     *             error when reading the Checkstyle configuration file
     */
    public List<Module> getModules() throws CheckstylePluginException {
        List<Module> result = null;

        InputSource in = null;

        try {
            in = getCheckstyleConfiguration().getCheckConfigFileInputSource();
            result = ConfigurationReader.read(in);
        } finally {
            IOUtils.closeQuietly(in.getByteStream());
        }

        return result;
    }

    /**
     * Stores the (edited) list of modules to the Checkstyle configuration file.
     *
     * @param modules
     *            the list of modules to store into the Checkstyle configuration file
     * @throws CheckstylePluginException
     *             error storing the Checkstyle configuration
     */
    public void setModules(List<Module> modules) throws CheckstylePluginException {

        OutputStream out = null;
        ByteArrayOutputStream byteOut = null;
        try {

            // First write to a byte array outputstream
            // because otherwise in an error case the original
            // file would be destroyed
            byteOut = new ByteArrayOutputStream();

            ConfigurationWriter.write(byteOut, modules, this);

            // all went ok, write to the file
            File configFile = FileUtils.toFile(getResolvedConfigurationFileURL());
            out = new BufferedOutputStream(new FileOutputStream(configFile));
            out.write(byteOut.toByteArray());

            // refresh the files if within the workspace
            // Bug 1251194 - Resource out of sync after performing changes to
            // config
            IPath path = new Path(configFile.toString());
            IFile[] files = CheckstylePlugin.getWorkspace().getRoot().findFilesForLocation(path);
            for (int i = 0; i < files.length; i++) {
                try {
                    files[i].refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
                } catch (CoreException e) {
                    // NOOP - just ignore
                }
            }

            mHasConfigChanged = true;

            // throw away the cached Checkstyle configurations
            CheckConfigurationFactory.refresh();
        } catch (IOException e) {
            CheckstylePluginException.rethrow(e);
        } finally {
            IOUtils.closeQuietly(byteOut);
            IOUtils.closeQuietly(out);
        }
    }

    //
    // Implementation of ICheckConfiguration
    //

    /**
     * {@inheritDoc}
     */
    public String getName() {
        return mEditedName != null ? mEditedName : getSourceCheckConfiguration().getName();
    }

    /**
     * {@inheritDoc}
     */
    public String getDescription() {
        return mEditedDescription != null ? mEditedDescription : getSourceCheckConfiguration().getDescription();
    }

    /**
     * {@inheritDoc}
     */
    public String getLocation() {
        return mEditedLocation != null ? mEditedLocation : getSourceCheckConfiguration().getLocation();
    }

    /**
     * {@inheritDoc}
     */
    public IConfigurationType getType() {
        return getSourceCheckConfiguration().getType();
    }

    /**
     * {@inheritDoc}
     */
    public Map<String, String> getAdditionalData() {
        return mAdditionalData;
    }

    /**
     * {@inheritDoc}
     */
    public List<ResolvableProperty> getResolvableProperties() {
        return mProperties;
    }

    /**
     * {@inheritDoc}
     */
    public URL getResolvedConfigurationFileURL() throws CheckstylePluginException {
        return getType().getResolvedConfigurationFileURL(this);
    }

    /**
     * {@inheritDoc}
     */
    public CheckstyleConfigurationFile getCheckstyleConfiguration() throws CheckstylePluginException {
        return getType().getCheckstyleConfiguration(this);
    }

    /**
     * {@inheritDoc}
     */
    public boolean isEditable() {
        return getType().isEditable();
    }

    /**
     * {@inheritDoc}
     */
    public boolean isConfigurable() {
        return getType().isConfigurable(this);
    }

    /**
     * {@inheritDoc}
     */
    public boolean isGlobal() {
        return mCheckConfiguration.isGlobal();
    }

    /**
     * {@inheritDoc}
     */
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof ICheckConfiguration)) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        ICheckConfiguration rhs = (ICheckConfiguration) obj;
        return new EqualsBuilder().append(getName(), rhs.getName()).append(getLocation(), rhs.getLocation())
                .append(getDescription(), rhs.getDescription()).append(getType(), rhs.getType())
                .append(isGlobal(), rhs.isGlobal()).append(getResolvableProperties(), rhs.getResolvableProperties())
                .append(getAdditionalData(), rhs.getAdditionalData()).isEquals();
    }

    /**
     * {@inheritDoc}
     */
    public int hashCode() {
        return new HashCodeBuilder(928729, 1000003).append(getName()).append(getLocation()).append(getDescription())
                .append(getType()).append(isGlobal()).append(getResolvableProperties()).append(getAdditionalData())
                .toHashCode();
    }

    /**
     * {@inheritDoc}
     */
    public CheckConfigurationWorkingCopy clone() {

        CheckConfigurationWorkingCopy clone = null;

        try {
            clone = (CheckConfigurationWorkingCopy) super.clone();

            clone.mAdditionalData = new HashMap<String, String>();
            clone.mAdditionalData.putAll(this.mAdditionalData);

            clone.mProperties = new ArrayList<ResolvableProperty>();

            for (ResolvableProperty prop : mProperties) {
                clone.mProperties.add(prop.clone());
            }
        } catch (CloneNotSupportedException e) {
            throw new InternalError(); // this should never happen
        }
        return clone;
    }
}