Ptidej-v5.2-master/POM Tests/data/ArgoUML_0.28/src/org/argouml/moduleloader/ModuleLoader2.java
// $Id: ModuleLoader2.java 15682 2008-09-06 22:24:52Z tfmorris $
// Copyright (c) 2004-2008 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies.  This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason.  IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package org.argouml.moduleloader;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.log4j.Logger;
import org.argouml.application.api.AbstractArgoJPanel;
import org.argouml.application.api.Argo;
import org.argouml.i18n.Translator;


/**
 * This is the module loader that loads modules implementing the
 * ModuleInterface.<p>
 *
 * This is a singleton. There are convenience functions that are static
 * to access the module.<p>
 *
 * @stereotype singleton
 * @author Linus Tolke
 * @since 0.15.4
 */
public final class ModuleLoader2 {
    /**
     * Logger.
     */
    private static final Logger LOG = Logger.getLogger(ModuleLoader2.class);

    /**
     * This map contains the module loader information about the module.<p>
     *
     * The keys is the list of available modules.
     */
    private Map<ModuleInterface, ModuleStatus> moduleStatus;
    
    /**
     * List of locations that we've searched and/or loaded modules
     * from.  This is for information purposes only to allow it to 
     * be displayed in the settings Environment tab.
     */
    private List<String> extensionLocations = new ArrayList<String>();

    /**
     * The module loader object.
     */
    private static final ModuleLoader2 INSTANCE = new ModuleLoader2();

    /**
     * The prefix in URL:s that are files.
     */
    private static final String FILE_PREFIX = "file:";

    /**
     * The prefix in URL:s that are jars.
     */
    private static final String JAR_PREFIX = "jar:";

    /**
     * Class file suffix.
     */
    public static final String CLASS_SUFFIX = ".class";

    /**
     * Constructor for this object.
     */
    private ModuleLoader2() {
	moduleStatus = new HashMap<ModuleInterface, ModuleStatus>();
        computeExtensionLocations();
    }

    /**
     * Get hold of the instance of this object.
     *
     * @return the instance
     */
    public static ModuleLoader2 getInstance() {
	return INSTANCE;
    }

    /**
     * @return a list of Details panel tabs
     */
    List<AbstractArgoJPanel> getDetailsTabs() {
        List<AbstractArgoJPanel> result = new ArrayList<AbstractArgoJPanel>();
        for (ModuleInterface module : getInstance().availableModules()) {
            ModuleStatus status = moduleStatus.get(module);
            if (status == null) {
                continue;
            }
            if (status.isEnabled()) {
                if (module instanceof DetailsTabProvider) {
                    result.addAll(
                            ((DetailsTabProvider) module).getDetailsTabs());
                }
            }
        }
        return result;
    }
    /**
     * Return a collection of all available modules.
     *
     * @return A Collection of all available modules.
     */
    private Collection<ModuleInterface> availableModules() {
	return Collections.unmodifiableCollection(moduleStatus.keySet());
    }

    // Access methods for program infrastructure.
    /**
     * Enables all selected modules and disabling all modules not selected.<p>
     *
     * In short this attempts to make the modules obey their selection.<p>
     *
     * @param failingAllowed is <code>true</code> if enabling or disabling of
     *                       some of the modules is allowed to fail.
     */
    public static void doLoad(boolean failingAllowed) {
	getInstance().doInternal(failingAllowed);
    }

    // Access methods for modules that need to query about the status of
    // other modules.
    /**
     * Gets the loaded status for some other module.
     *
     * @return true if the module exists and is enabled.
     * @param name is the module name of the queried module
     */
    public static boolean isEnabled(String name) {
	return getInstance().isEnabledInternal(name);
    }

    // Access methods for the GUI that the user uses to enable and disable
    // modules.

    /**
     * Get a Collection with all the names.
     *
     * @return all the names.
     */
    public static Collection<String> allModules() {
	Collection<String> coll = new HashSet<String>();

	for (ModuleInterface mf : getInstance().availableModules()) {
	    coll.add(mf.getName());
	}

	return coll;
    }

    /**
     * Get the selected.
     *
     * @param name The name of the module.
     * @return <code>true</code> if the module is selected.
     */
    public static boolean isSelected(String name) {
	return getInstance().isSelectedInternal(name);
    }

    /**
     * Get the selected.
     *
     * @see #isSelected(String)
     * @param name The name of the module.
     * @return <code>true</code> if the module is selected.
     */
    private boolean isSelectedInternal(String name) {
	Map.Entry<ModuleInterface, ModuleStatus> entry = findModule(name);

	if (entry != null) {
	    ModuleStatus status = entry.getValue();

	    if (status == null) {
		return false;
	    }

	    return status.isSelected();
	}
	return false;
    }

    /**
     * Set the selected value.
     *
     * @param name The name of the module.
     * @param value Selected or not.
     */
    public static void setSelected(String name, boolean value) {
	getInstance().setSelectedInternal(name, value);
    }

    /**
     * Set the selected value.
     *
     * @see #setSelected(String, boolean)
     * @param name The name of the module.
     * @param value Selected or not.
     */
    private void setSelectedInternal(String name, boolean value) {
	Map.Entry<ModuleInterface, ModuleStatus> entry = findModule(name);

	if (entry != null) {
	    ModuleStatus status = entry.getValue();

	    status.setSelected(value);
	}
    }

    /**
     * Create a description of the module based on the information provided
     * by the module itself.
     *
     * @param name The name of the module.
     * @return The description.
     */
    public static String getDescription(String name) {
        return getInstance().getDescriptionInternal(name);
    }

    /**
     * Create a description of the module based on the information provided
     * by the module itself.
     *
     * @see #getDescription(String)
     * @param name The name of the module.
     * @return The description.
     */
    private String getDescriptionInternal(String name) {
	Map.Entry<ModuleInterface, ModuleStatus> entry = findModule(name);

	if (entry == null) {
	    throw new IllegalArgumentException("Module does not exist.");
	}

	ModuleInterface module = entry.getKey();
        StringBuffer sb = new StringBuffer();
        String desc = module.getInfo(ModuleInterface.DESCRIPTION);
        if (desc != null) {
            sb.append(desc);
            sb.append("\n\n");
        }
        String author = module.getInfo(ModuleInterface.AUTHOR);
        if (author != null) {
            sb.append("Author: ").append(author);
            sb.append("\n");
        }
        String version = module.getInfo(ModuleInterface.VERSION);
        if (version != null) {
            sb.append("Version: ").append(version);
            sb.append("\n");
        }
        return sb.toString();
    }


    // Access methods for the program infrastructure
    /**
     * Enables all selected modules.
     *
     * @param failingAllowed is true if this is not the last attempt at
     * turning on.
     */
    private void doInternal(boolean failingAllowed) {
	huntForModules();

	boolean someModuleSucceeded;
	do {
	    someModuleSucceeded = false;

	    for (ModuleInterface module : getInstance().availableModules()) {

		ModuleStatus status = moduleStatus.get(module);

		if (status == null) {
		    continue;
		}

		if (!status.isEnabled() && status.isSelected()) {
		    try {
		        if (module.enable()) {
		            someModuleSucceeded = true;
		            status.setEnabled();
		        }
		    }
		    // Catch all exceptions and errors, however severe
		    catch (Throwable e) {                       
		        LOG.error("Exception or error while trying to "
                                + "enable module " + module.getName(), e);
		    }
		} else if (status.isEnabled() && !status.isSelected()) {
		    try { 
		        if (module.disable()) {
		            someModuleSucceeded = true;
		            status.setDisabled();
		        }
		    }
                    // Catch all exceptions and errors, however severe
		    catch (Throwable e) {
		        LOG.error("Exception or error while trying to "
                                + "disable module " + module.getName(), e);
		    }
		}
	    }
	} while (someModuleSucceeded);

	if (!failingAllowed) {
	    // Notify the user that the modules in the list that are selected
	    // but not enabled were not possible to enable and that are not
	    // selected that we cannot disable.
	    //
	    // Currently we just log this.
	    //
	    // TODO: We could eventually pop up some warning window.
	    //
	    for (ModuleInterface module : getInstance().availableModules()) {

		ModuleStatus status = moduleStatus.get(module);

		if (status == null) {
		    continue;
		}

		if (status.isEnabled() && status.isSelected()) {
		    continue;
		}

		if (!status.isEnabled() && !status.isSelected()) {
		    continue;
		}

		if (status.isSelected()) {
		    LOG.warn("ModuleLoader was not able to enable module "
		             + module.getName());
		} else {
		    LOG.warn("ModuleLoader was not able to disable module "
		             + module.getName());
		}
	    }
	}
    }

    /**
     * Gets the loaded status for some other module.
     *
     * @return true if the module exists and is enabled.
     * @param name is the module name of the queried module
     */
    private boolean isEnabledInternal(String name) {
	Map.Entry<ModuleInterface, ModuleStatus> entry = findModule(name);

	if (entry != null) {
	    ModuleStatus status = entry.getValue();

	    if (status == null) {
		return false;
	    }

	    return status.isEnabled();
	}
	return false;
    }


    /**
     * Return the ModuleInterface, ModuleStatus pair for the module
     * with the given name or <code>null</code> if there isn't any.
     *
     * @param name The given name.
     * @return A pair (Map.Entry).
     */
    private Map.Entry<ModuleInterface, ModuleStatus> findModule(String name) {
        for (Map.Entry<ModuleInterface, ModuleStatus> entry : moduleStatus
                .entrySet()) {
            ModuleInterface module = entry.getKey();
            if (name.equalsIgnoreCase(module.getName())) {
                return entry;
            }
        }
	return null;
    }

    /**
     * Tries to find as many available modules as possible.<p>
     *
     * As the modules are found they are appended to {@link #moduleStatus}.<p>
     */
    private void huntForModules() {
        huntForModulesFromExtensionDir();
        // TODO: huntForModulesFromJavaWebStart();

        // Load modules specified by a System property.
        // Modules specified by a system property is for
        // running modules from within Eclipse and running
        // from Java Web Start.
        String listOfClasses = System.getProperty("argouml.modules");
        if (listOfClasses != null) {
            StringTokenizer si = new StringTokenizer(listOfClasses, ";");
            while (si.hasMoreTokens()) {
                String className = si.nextToken();
                try {
                    addClass(className);
                } catch (ClassNotFoundException e) {
                    LOG.error("Could not load module from class " + className);
                }
            }
        }
    }
    
    /**
     * Find and enable modules from our "ext" directory and from the
     * directory specified in "argo.ext.dir".<p>
     */
    private void huntForModulesFromExtensionDir() {
        for (String location : extensionLocations) {
            huntModulesFromNamedDirectory(location);            
        }
    }

    /**
     * This does a calculation of where our "ext" directory is.
     * TODO: We should eventually make sure that this calculation is
     *       only present in one place in the code and not several.
     */
    private void computeExtensionLocations() {
        // Use a little trick to find out where Argo is being loaded from.
        // TODO: Use a different resource here. ARGOINI is unused and deprecated
        String extForm = getClass().getResource(Argo.ARGOINI).toExternalForm();
        String argoRoot =
            extForm.substring(0,
                              extForm.length() - Argo.ARGOINI.length());

        // If it's a jar, clean it up and make it look like a file url
        if (argoRoot.startsWith(JAR_PREFIX)) {
            argoRoot = argoRoot.substring(JAR_PREFIX.length());
            if (argoRoot.endsWith("!")) {
                argoRoot = argoRoot.substring(0, argoRoot.length() - 1);
            }
        }

        String argoHome = null;

        if (argoRoot != null) {
            LOG.info("argoRoot is " + argoRoot);
            if (argoRoot.startsWith(FILE_PREFIX)) {
                argoHome =
                    new File(argoRoot.substring(FILE_PREFIX.length()))
                        .getAbsoluteFile().getParent();
            } else {
                argoHome = new File(argoRoot).getAbsoluteFile().getParent();
            }

            try {
                argoHome = java.net.URLDecoder.decode(argoHome, 
                        Argo.getEncoding());
            } catch (UnsupportedEncodingException e) {
                LOG.warn("Encoding " 
                        + Argo.getEncoding() 
                        + " is unknown.");
            }

            LOG.info("argoHome is " + argoHome);
        }

        if (argoHome != null) {
            String extdir;
            if (argoHome.startsWith(FILE_PREFIX)) {
                extdir = argoHome.substring(FILE_PREFIX.length())
                        + File.separator + "ext";
            } else {
                extdir = argoHome + File.separator + "ext";
            }
            extensionLocations.add(extdir);
        }

        String extdir = System.getProperty("argo.ext.dir");
        if (extdir != null) {
            extensionLocations.add(extdir);
        }
    }
    
    /**
     * Get the list of locations that we've loaded extension modules from.
     * @return A list of the paths we've loaded from.
     */
    public List<String> getExtensionLocations() {
        return Collections.unmodifiableList(extensionLocations);
    }

    /**
     * Find and enable a module from a given directory.
     *
     * @param dirname The name of the directory.
     */
    private void huntModulesFromNamedDirectory(String dirname) {
	File extensionDir = new File(dirname);
	if (extensionDir.isDirectory()) {
	    File[] files = extensionDir.listFiles(new JarFileFilter());
	    for (File file : files) {
		JarFile jarfile = null;
		// Try-catch only the JarFile instantiation so we
		// don't accidentally mask anything in ArgoJarClassLoader
		// or processJarFile.
		try {
		    jarfile = new JarFile(file);
		    if (jarfile != null) {
		        // TODO: Should we be delegating to a different
		        // classloader than the default here? - - tfm
	                ClassLoader classloader =
			    new URLClassLoader(new URL[] {
				file.toURI().toURL(),
			    });
	                try {
	                    processJarFile(classloader, file);
	                } catch (ClassNotFoundException e) {
	                    LOG.error("The class is not found.", e);
	                    return;
	                }
		    }
		} catch (IOException ioe) {
		    LOG.error("Cannot open Jar file " + file, ioe);
		}
	    }
	}
    }

    /**
     * Check a jar file for an ArgoUML extension/module.<p>
     *
     * If there isn't a manifest or it isn't readable, we fall back to using
     * the raw JAR entries.
     *
     * @param classloader The classloader to use.
     * @param file The file to process.
     * @throws ClassNotFoundException if the manifest file contains a class
     *         that doesn't exist.
     */
    private void processJarFile(ClassLoader classloader, File file)
        throws ClassNotFoundException {

	LOG.info("Opening jar file " + file);
        JarFile jarfile;
	try {
	    jarfile = new JarFile(file);
	} catch (IOException e) {
	    LOG.error("Unable to open " + file, e);
            return;
	}

        Manifest manifest;
        try {
            manifest = jarfile.getManifest();
            if (manifest == null) {
                // We expect all extensions to have a manifest even though we
                // can operate without one if necessary.
                LOG.warn(file + " does not have a manifest");
            }
        } catch (IOException e) {
            LOG.error("Unable to read manifest of " + file, e);
            return;
        }
        
        // TODO: It is a performance drain to load all classes at startup time.
        // They should be lazy loaded when needed.  Instead of scanning all
        // classes for ones which implement our loadable module interface, we 
        // should use a manifest entry or a special name/name pattern that we
        // look for to find the single main module class to load here.  - tfm
	
        boolean loadedClass = false;
        if (manifest == null) {
            Enumeration<JarEntry> jarEntries = jarfile.entries();
            while (jarEntries.hasMoreElements()) {
                JarEntry entry = jarEntries.nextElement();
                loadedClass =
                        loadedClass
                                | processEntry(classloader, entry.getName());
            }
        } else {
            Map<String, Attributes> entries = manifest.getEntries();
            for (String key : entries.keySet()) {
                // Look for our specification
                loadedClass =
                    loadedClass
                            | processEntry(classloader, key);
            }
        }

        // Add this to search list for I18N properties
        // (Done for both modules & localized property file sets)
        Translator.addClassLoader(classloader);
        
        // If it didn't have a loadable module class and it doesn't look like
        // a localized property set, warn the user that something funny is in
        // their extension directory
        if (!loadedClass && !file.getName().contains("argouml-i18n-")) {
            LOG.error("Failed to find any loadable ArgoUML modules in jar "
                    + file);
        }
    }

    /**
     * Process a JAR file entry, attempting to load anything that looks like a
     * Java class.
     * 
     * @param classloader
     *            the classloader to use when loading the class
     * @param cname
     *            the class name
     * @throws ClassNotFoundException
     * @return true if class was a module class and loaded successfully
     */
    private boolean processEntry(ClassLoader classloader, String cname)
        throws ClassNotFoundException {
        if (cname.endsWith(CLASS_SUFFIX)) {
            int classNamelen = cname.length() - CLASS_SUFFIX.length();
            String className = cname.substring(0, classNamelen);
            className = className.replace('/', '.');
            return addClass(classloader, className);
        }
        return false;
    }

    /**
     * Add a class from the current class loader.
     *
     * @param classname The name of the class (including package).
     * @throws ClassNotFoundException if the class classname is not found.
     */
    public static void addClass(String classname)
        throws ClassNotFoundException {

        getInstance().addClass(ModuleLoader2.class.getClassLoader(),
			       classname);
    }

    /**
     * Try to load a module from the given ClassLoader.<p>
     *
     * Only add it as a module if it is a module (i.e. it implements the
     * {@link ModuleInterface} interface.
     *
     * @param classLoader The ClassLoader to load from.
     * @param classname The name.
     * @throws ClassNotFoundException if the class classname is not found.
     */
    private boolean addClass(ClassLoader classLoader, String classname)
        throws ClassNotFoundException {

        LOG.info("Loading module " + classname);
        Class moduleClass;
        try {
            moduleClass = classLoader.loadClass(classname);
        } catch (UnsupportedClassVersionError e) {
            LOG.error("Unsupported Java class version for " + classname);
            return false;
        } catch (NoClassDefFoundError e) {
            LOG.error("Unable to find required class while loading "
                    + classname + " - may indicate an obsolete"
                    + " extension module or an unresolved dependency", e);
            return false;
        } catch (Throwable e) {
            if (e instanceof ClassNotFoundException) {
                throw (ClassNotFoundException) e;
            }
            LOG.error("Unexpected error while loading " + classname, e);
            return false;
        }
        
        if (!ModuleInterface.class.isAssignableFrom(moduleClass)) {
            LOG.debug("The class " + classname + " is not a module.");
            return false;
        }

        Constructor defaultConstructor;
        try {
            defaultConstructor =
                    moduleClass.getDeclaredConstructor(new Class[] {});
        } catch (SecurityException e) {
            LOG.error("The default constructor for class " + classname
                      + " is not accessable.",
                      e);
            return false;
        } catch (NoSuchMethodException e) {
            LOG.error("The default constructor for class " + classname
                      + " is not found.", e);
            return false;
        } catch (NoClassDefFoundError e) {
            LOG.error("Unable to find required class while loading "
                    + classname + " - may indicate an obsolete"
                    + " extension module or an unresolved dependency", e);
            return false;
        } catch (Throwable e) {
            LOG.error("Unexpected error while loading " + classname, e);
            return false;
        }

        if (!Modifier.isPublic(defaultConstructor.getModifiers())) {
            LOG.error("The default constructor for class " + classname
                    + " is not public.  Not loaded.");
            return false;
        }
        Object moduleInstance;
        try {
            moduleInstance = defaultConstructor.newInstance(new Object[]{});
        } catch (IllegalArgumentException e) {
            LOG.error("The constructor for class " + classname
                    + " is called with incorrect argument.", e);
            return false;
        } catch (InstantiationException e) {
            LOG.error("The constructor for class " + classname
                    + " threw an exception.", e);
            return false;
        } catch (IllegalAccessException e) {
            LOG.error("The constructor for class " + classname
                    + " is not accessible.", e);
            return false;
        } catch (InvocationTargetException e) {
            LOG.error("The constructor for class " + classname
                    + " cannot be called.", e);
            return false;
        } catch (NoClassDefFoundError e) {
            LOG.error("Unable to find required class while instantiating "
                    + classname + " - may indicate an obsolete"
                    + " extension module or an unresolved dependency", e);
            return false;
        } catch (Throwable e) {
            LOG.error("Unexpected error while instantiating " + classname, e);
            return false;
        }

        // The following check should have been satisfied before we
        // instantiated the module, but double check again
        if (!(moduleInstance instanceof ModuleInterface)) {
            LOG.error("The class " + classname + " is not a module.");
            return false;
        }
        ModuleInterface mf = (ModuleInterface) moduleInstance;

        addModule(mf);
        LOG.info("Succesfully loaded module " + classname);
        return true;
    }

    /**
     * Add a newly found module to {@link #moduleStatus}. If we already
     * know about it, don't add it.
     *
     * @param mf The module to add.
     */
    private void addModule(ModuleInterface mf) {
	// Since there is no way to compare the objects as equal,
	// we have to search through the list at this point.
        for (ModuleInterface foundMf : moduleStatus.keySet()) {
	    if (foundMf.getName().equals(mf.getName())) {
		return;
	    }
	}

	// We havn't found it. Add it.
	ModuleStatus ms = new ModuleStatus();

	// Enable it.
	// TODO: This by default selects all modules that are found.
	//       Eventually we would rather obey a default either from the
	//       modules themselves, from how they are found, and also
	//       have information on what modules are selected from the
	//       configuration.
	ms.setSelected();

	moduleStatus.put(mf, ms);
    }


    /**
     * The file filter that selects Jar files.
     */
    static class JarFileFilter implements FileFilter {
	/*
	 * @see java.io.FileFilter#accept(java.io.File)
	 */
	public boolean accept(File pathname) {
	    return (pathname.canRead()
		    && pathname.isFile()
		    && pathname.getPath().toLowerCase().endsWith(".jar"));
	}
    }
}


/**
 * Status for each of the available modules. This is created in one copy per
 * available module.
 */
class ModuleStatus {
    /**
     * If the module is enabled.
     */
    private boolean enabled;

    /**
     * If the module is selected.
     */
    private boolean selected;

    /**
     * Tells if the module is enabled or not.
     *
     * @return true if the module is enabled.
     */
    public boolean isEnabled() {
	return enabled;
    }

    /**
     * Setter for enabled.
     */
    public void setEnabled() {
	enabled = true;
    }

    /**
     * Setter for enabled.
     */
    public void setDisabled() {
	enabled = false;
    }

    /**
     * Tells if the module is selected by the user or not.
     *
     * @return true if it is selected.
     */
    public boolean isSelected() {
	return selected;
    }


    /**
     * Setter for selected.
     */
    public void setSelected() {
	selected = true;
    }

    /**
     * Setter for selected.
     */
    public void setUnselect() {
	selected = false;
    }

    /**
     * Setter for selected.
     *
     * @param value The value to set.
     */
    public void setSelected(boolean value) {
	if (value) {
	    setSelected();
	} else {
	    setUnselect();
	}
    }
}
