Package net.sf.jeters.componentInterface

Source Code of net.sf.jeters.componentInterface.ComponentManager

/*
* JETERS – Java Extensible Text Replacement System
* Copyright (C) 2006–2008  Tobias Knerr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
*/

package net.sf.jeters.componentInterface;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import net.sf.jeters.configuration.Configuration;
import net.sf.jeters.configuration.io.ConfigurationReader;
import net.sf.jeters.configuration.io.ConfigurationStorage;
import net.sf.jeters.core.ComponentClassLoader;
import net.sf.jeters.internationalization.Translatable;
import net.sf.jeters.internationalization.TranslationReader;

/**
* class that manages components. It will make sure configurations and
* translations are applied to components when being initialized.
* For other classes, it provides get and set methods to access components and
* to change which components are currently in use.
*
* Note that neither set nor get methods clone the components, modifying them
* (e.g. by setting configurations) will affect the active component.
*
* @author Tobias Knerr
*/
public class ComponentManager {
   
  /** manifest entry name specifying the component class contained in a jar */
  private static final String MANIFEST_CLASS_ENTRY = "JETERS-Class";

  /** entry for localized component names in resource bundles */
  private static final String LOCALIZED_NAME_ENTRY = "displayName";

  /** directory containing the components */
  private File componentDirectory;
 
  /** the class loader that will load the components and .properties files */
  private ComponentClassLoader classLoader;

  /** permanent storage for configurations */
  private ConfigurationStorage configurationStorage;
 
  /**
   * objects that read and write the configurations of components,
   * with increasing priority (conflict => earlier one is overwritten)
   */
  private ConfigurationReader[] configurationReaders;
 
  /** reader for translations for components */
  private TranslationReader translationReader;
 
  /** the components available to the component manager */
  private List<Class<? extends Component>> availableComponentClasses;
 
  /** map storing the current configuration for each component class */
  private final Map<Class<? extends Component>, Configuration> configurationMap;
 
  /** map storing the .jar file a component is based on */
  private final Map<Class<? extends Component>, File> jarFileMap;
 
  /** collection of weak references to the instances of component classes
   *  created by this manager */
  private final Collection<WeakReference<Component>> instances =
    new LinkedList<WeakReference<Component>>();
 
  /** the currently used UI component */
  private UIComponent uiComponent; 
  /** the currently used input component */
  private InputComponent<?> inputComponent;
  /** the currently used output component */
  private OutputComponent<?> outputComponent;
  /** the currently used replacer components */
  private List<ReplacerComponent<?,?>> replacerComponents =
    new ArrayList<ReplacerComponent<?,?>>()

  /**
   * constructor creating a component manager using a given directory as
   * component source
   *
   * @param componentDirectory  directory containing components (classes/jars)
   * @param configurationStorage  storage for base configurations; may be null
   * @param configurationReaders  objects reading additional configuration options.
   *                              They will not be used to store configurations,
   *                              but will temporarily overwrite information from
   *                              configurationStorage. Ordered with increasing priority.
   *                              (conflicting values => earlier one is overwritten)
   * @param translationReader  reader providing language-specific Strings for
   *                           components implementing Translatable
   */
  public ComponentManager(File componentDirectory,
                    ConfigurationStorage configurationStorage,
                      ConfigurationReader[] configurationReaders,
                      TranslationReader translationReader) {
   
    this.componentDirectory = componentDirectory;
    this.configurationStorage = configurationStorage;
    this.configurationReaders = configurationReaders;
    this.translationReader = translationReader;
   
    try {
      classLoader = new ComponentClassLoader(componentDirectory);
    } catch (MalformedURLException e) {
      throw new IllegalArgumentException("creation of ComponentClassLoader for directory " +
          componentDirectory + " resulted in MalformedURLException", e);
    }

    this.jarFileMap = new HashMap<Class<? extends Component>, File>();
   
    loadAvailableComponentClasses();
   
    this.configurationMap = new HashMap<Class<? extends Component>, Configuration>();
   
    readAllComponentConfigurations();
       
  }
 
  /**
   * returns the current input component
   *
   * @return  current input component
   */
  public UIComponent getUIComponent() {
    return uiComponent;   
  }
 
  /**
   * returns the current input component
   *
   * @return  current input component
   */
  public InputComponent<?> getInputComponent() {
    return inputComponent;   
  }
 
  /**
   * returns the current output component
   *
   * @return  current input component
   */
  public OutputComponent<?> getOutputComponent() {
    return outputComponent;   
  }
 
  /**
   * returns a list of the current replacer components;
   * modifying of the list will not affect the component manager, modifying
   * the components, however, will modify the originals.
   *
   * @return  list of current replacer components;
   *          guaranteed to be non-null (can, however, be empty)
   */
  public List<ReplacerComponent<?,?>> getReplacerComponents() {
    List<ReplacerComponent<?,?>> listClone =
      new ArrayList<ReplacerComponent<?,?>>(replacerComponents);
    return listClone;
  }
 
  /**
   * creates a new UI component from the given class
   * and sets it as active UI component
   *
   * @param uiCompClass  class that will be instantiated to create the
   *                        component; must implement UIComponent, not null,
   *                        a call to newInstance must not cause an
   *                        InstantiationException or IllegalAccessException
   */
  public void setUIComponent(Class<? extends UIComponent> uiCompClass) {   
   
    UIComponent component;
   
    try {
      component = createComponent(uiCompClass);
    } catch (InstantiationException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    } catch (IllegalAccessException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    }
   
    configureComponent(component);
    setTranslation(component);
    uiComponent = component;
       
  }
 
  /**
   * creates a new input component from the given class
   * and sets it as active input component
   *
   * @param componentClass  class that will be instantiated to create the
   *                        component; must implement InputComponent,
   *                        not null, a call to newInstance must not cause an
   *                        InstantiationException or IllegalAccessException
   */
  public void setInputComponent(Class<? extends InputComponent<?>> componentClass) {
   
    InputComponent<?> component;
   
    try {
      component = createComponent(componentClass);
    } catch (InstantiationException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    } catch (IllegalAccessException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    }
   
    configureComponent(component);
    setTranslation(component);
    inputComponent = component;
       
  }
 
  /**
   * creates a new output component from the given class
   * and sets it as active output component
   *
   * @param componentClass  class that will be instantiated to create the
   *                        component; must implement OutputComponent,
   *                        not null, a call to newInstance must not cause an
   *                        InstantiationException or IllegalAccessException
   */
  public void setOutputComponent(Class<? extends OutputComponent<?>> componentClass) {   
       
    OutputComponent<?> component;
   
    try {
      component = createComponent(componentClass);
    } catch (InstantiationException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    } catch (IllegalAccessException e) {
      throw new IllegalArgumentException(
          "instantiation of componentClass failed: " + e);
    }
   
    configureComponent(component);
    setTranslation(component);
    outputComponent = component;
       
  }
 
  /**
   * creates new replacer components from the given classes
   * and sets it as active replacer components
   *
   * @param componentClasses  collection of classes that will be instantiated
   *                          to create the components; every class must
   *                          implement ReplacerComponent, neither the list
   *                          nor its element may be null, a call to
   *                          newInstance for a class must not cause an
   *                          InstantiationException or IllegalAccessException
   */
  public void setReplacerComponent(Collection<Class<? extends ReplacerComponent<?,?>>> componentClasses) {   
   
    List<ReplacerComponent<?,?>> newReplacerComponents =
      new ArrayList<ReplacerComponent<?,?>>();
   
    for (Class<? extends ReplacerComponent<?,?>> componentClass : componentClasses) {

      Component component;

      try {
        component = createComponent(componentClass);
        configureComponent(component);
        setTranslation(component);
      } catch (InstantiationException e) {
        throw new IllegalArgumentException(
            "instantiation of componentClass failed: " + e);
      } catch (IllegalAccessException e) {
        throw new IllegalArgumentException(
            "instantiation of componentClass failed: " + e);
      }

      newReplacerComponents.add((ReplacerComponent<?,?>)component);
   
    }   
   
    replacerComponents = newReplacerComponents;   
  }
 
  /**
   * returns the available components classes, can be limited to those
   * components that are instances of given classes/interfaces.
   *
   * Examples:
   * If you want to get only UI components, call:<br/>
   * <code>getAvailableComponentClasses(UIComponent.class)</code><br/>
   * For all configurable input components, use:<br/>
   * <code>getAvailableComponentClasses(Configurable.class,
   *                                    InputComponent.class)</code><br/>
   * If you simply want all components, you should call<br/>
   * <code>getAvailableComponents()</code>
   *
   * @param classes  classes/interfaces the component classes must be
   *                 subtypes of (a vararg parameter)
   * @return         list of all avaliable component classes
   *                 that are subtypes of the classes given as parameter
   */
  public List<Class<? extends Component>> getAvailableComponentClasses(Class<?>... classes) {
       
    List<Class<? extends Component>> matchingComponentClasses =
      new ArrayList<Class<? extends Component>>();

    for (Class<? extends Component> componentClass : availableComponentClasses) {

      boolean instanceOfClasses = true;
     
      for (Class<?> c : classes) {
        if (!c.isAssignableFrom(componentClass)) {
          instanceOfClasses = false;
          break;
        }
      }

      if (instanceOfClasses) {       
        matchingComponentClasses.add(componentClass);
      }   

    }   

    return matchingComponentClasses;
  }
 
  /**
   * returns the full names of the available components classes, can be
   * limited to those components that are instances of given
   * classes/interfaces. For details and examples, see
   * {@link #getAvailableComponentClasses(Class[])}
   *
   * @param classes  classes/interfaces the component classes must be
   *                 subtypes of (a vararg parameter)
   * @return         list of the names of all avaliable component classes
   *                 that are subtypes of the classes given as parameter
   */
  public List<String> getNamesOfAvailableComponentClasses(Class<?>... classes) {
   
    List<String> componentClassNames = new ArrayList<String>();
   
    List<Class<? extends Component>> componentClasses =
      getAvailableComponentClasses(classes);

    for (Class<? extends Component> componentClass : componentClasses) {
      componentClassNames.add(componentClass.getName());
    }   

    return componentClassNames;
 
 
  /**
   * returns the component class for the given name
   *
   * @param name  the full name of the component class
   * @return  a class implementing the Component interface
   *          or null if no component class with the given name exists
   */
  public Class<? extends Component> getComponentClassForName(String name) {
   
    try{
     
      Class<?> loadedClass = classLoader.loadClass(name);

      if (isValidComponentClass(loadedClass)) {
       
        @SuppressWarnings("unchecked")
        Class<? extends Component> componentClass =
          (Class<? extends Component>) loadedClass;
       
        return componentClass;
       
      } else {
        return null;
      }
     
    } catch (ClassNotFoundException e) {
      return null;
    } catch (NoClassDefFoundError e) {
      return null
    }
   
  }
 
  /**
   * reads the configuration for all component classes using the configurationReaders
   * and writes the result to the configurationMap.
   * Existing instances are reconfigured.
   */
  private void readAllComponentConfigurations() {
   
    for (Class<? extends Component> componentClass : availableComponentClasses) {
      readComponentConfiguration(componentClass);     
    }
   
  }
 
  private void readComponentConfiguration(Class <? extends Component> componentClass) {
   
    Configuration classConf = retrieveBaseConfiguration(componentClass);
 
    for (ConfigurationReader configReader : configurationReaders) {
      Configuration newClassConf = configReader.read(componentClass);
      if (newClassConf != null) {
        classConf.setValuesFrom(newClassConf);
      }
    }
   
    configurationMap.put(componentClass, classConf);

    //reconfigure existing instances of componentClass   
    for (WeakReference<Component> instanceReference : instances) {
      Component instance = instanceReference.get();
      if (instance != null && componentClass.isInstance(instance)) {
        classConf.applyTo(instance);
      }
    }
   
  }
 
  /**
   * reads the configuration from the {@link #configurationStorage};
   * uses defaults where necessary
   */
  private Configuration retrieveBaseConfiguration(Class <? extends Component> componentClass) {
   
    //get defaults
    Configuration baseConf;
    try {
      baseConf = new Configuration((Class<Component>)componentClass, (Component)componentClass.newInstance());
    } catch (InstantiationException e) {
      throw new Error(e);
    } catch (IllegalAccessException e) {
      throw new Error(e);
    }
   
    //get values from component storage and overwrite defaults 
    if (configurationStorage != null) {
      Configuration confFromStorage = configurationStorage.read(componentClass);
      if (confFromStorage != null) {
        baseConf.setValuesFrom(confFromStorage);
      } else if (baseConf.getConfigurableFields().size() > 0) {
        System.out.println("no configuration found for " + componentClass.getSimpleName());
      }
    }
       
    return baseConf;
   
  }
 
  /**
   * stores the base configurations of all component classes,
   * also adds defaults if some fields are not part of the current configuration
   * in the configuration storage
   */
  public void writeAllComponentBaseConfigurations() {
   
    for (Class<? extends Component> componentClass : availableComponentClasses) {
      Configuration baseConf = retrieveBaseConfiguration(componentClass);
      writeComponentConfiguration(baseConf);
    }
   
  }
 
  /**
   * stores a configuration
   *
   * @param configuration  configuration to be stored, must not be null
   */
  public void writeComponentConfiguration(Configuration configuration) {
   
    assert configuration != null;

    configurationStorage.write(configuration);

  }
 
  /**
   * "installs" a component by copying its .jar into the component directory
   * @param jarFile  file to copy to component directory; != null
   * @throws IOException
   */
  public void installComponent(File jarFile) throws IOException {

    File target = new File(componentDirectory + File.separator + jarFile.getName());
   
    System.out.println(target);
   
    InputStream in = new FileInputStream(jarFile);
    OutputStream out = new FileOutputStream(target);

    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0){
      out.write(buf, 0, len);
    }
   
    in.close();
    out.close();
 
    loadAvailableComponentClasses();
   
  }
   
  /**
   * "uninstalls" a component by removing its .jar from the component directory
   * @param componentClass  class whose jar is to be deleted; != null
   * @return true if the file was successfully deleted
   */
  public boolean uninstallComponent(Class<? extends Component> componentClass) {

    File file = jarFileMap.get(componentClass);
   
    if (file != null) {
     
      boolean success = file.delete();
     
      if (success) {
        loadAvailableComponentClasses();
      }
     
      return success;
     
    } else {
      return false;
    }   
   
  }
 
  /**
   * returns true if the file can be removed (it needs to be a .jar file for this)
   */
  public boolean canUninstall(Class<? extends Component> componentClass) {
    return jarFileMap.containsKey(componentClass);
  }
 
  /**
   * finds all available component classes
   * and creates the availableComponentClasses list
   */
  private void loadAvailableComponentClasses() {
   
    availableComponentClasses = new LinkedList<Class<? extends Component>>();
   
    availableComponentClasses.addAll(getComponentClassesFromClassFiles());
    availableComponentClasses.addAll(getComponentClassesFromJarFiles());
       
  }
 
  /**
   * returns a collection of all valid components classes that exist as
   * class files in the component directory.
   *
   * @return  classes as collection, guaranteed to be component classes
   */
  private Collection<Class<? extends Component>> getComponentClassesFromClassFiles() {
   
    Collection<Class<? extends Component>> componentClasses =
      new LinkedList<Class<? extends Component>>();
   
    //get all filenames from the directory that end with ".class"
    String[] fileNames = listFilesEndingWith(componentDirectory, ".class");
       
    if (fileNames != null) {
     
      for (String fileName : fileNames) {

        //get the name of the class (remove ".class")                         
        String className = fileName.substring(0,
            fileName.length() - ".class".length());         

        /* get and add the class itself (the method will return
         * null if the class cannot be loaded or is not a valid
         * component class)                                     */
       
        Class<? extends Component> componentClass = getComponentClassForName(className);

        if (componentClass != null) {
          componentClasses.add(componentClass);
        }

      }
     
    }
       
    return componentClasses; 
  }
   
  /**
   * returns a collection of all valid components classes that exist in
   * jar files in the component directory. The class for loading is
   * determined by the manifest's MANIFEST_CLASS_ENTRY value.
   *
   * @return  classes as collection, guaranteed to be component classes
   */ 
  private Collection<Class<? extends Component>> getComponentClassesFromJarFiles() {
     
    Collection<Class<? extends Component>> componentClasses =
      new LinkedList<Class<? extends Component>>();

    //get all filenames from the directory that end with ".jar"
    String[] fileNames = listFilesEndingWith(componentDirectory, ".jar");
   
    if (fileNames != null) {
   
      for (String fileName : fileNames) {

        String className = null;

        File file = null;
       
        try{
          //create a JarFile-object 
          file = new File(componentDirectory, fileName);
          JarFile jarFile = new JarFile(file);     

          //find out which class is the component
          Manifest m = jarFile.getManifest();   
          className =
            m.getMainAttributes().getValue(MANIFEST_CLASS_ENTRY);

        } catch(IOException e){
          /* TODO: log "Error accessing the component jar \"" +
                       fileName + "\": " + ioe.toString()       */
        }

        if (className != null) {

          /* get and add the class itself (the method will return
           * null if the class cannot be loaded or is not a valid
           * component class)                                     */
         
          Class<? extends Component> componentClass =
            getComponentClassForName(className);

          if (componentClass != null) {
            componentClasses.add(componentClass);
            jarFileMap.put(componentClass, file);
          }

        }
         
      }
     
    }
       
    return componentClasses;
  }
     
  /**
   * instantiates a component class and returns the created component
   *
   * @param <C>  component subtype to create
   *
   * @param c  class to instantiate, must implement component class; not null
   * @return   true for valid component classes, otherwise false
   *
   * @throws InstantiationException  may be thrown on creating an instance of c
   * @throws IllegalAccessException  may be thrown on creating an instance of c
   */
  private <C extends Component> C createComponent(Class<C> c)
          throws InstantiationException, IllegalAccessException {
       
    if (c == null) {
      throw new NullPointerException("class must not be null");
    }
     
    C componentInstance = c.newInstance();
   
    cleanInstancesCollection();
    instances.add(new WeakReference<Component>(componentInstance));
   
    return componentInstance;

  }

  /**
   * removes all weak references to components from {@link #instances}
   * that don't exist anymore
   */

  private void cleanInstancesCollection() {
   
    for (Iterator<WeakReference<Component>> iterator = instances.iterator(); iterator.hasNext();) {
      WeakReference<Component> instanceReference = (WeakReference<Component>) iterator.next();
      if (instanceReference.get() == null) {
        iterator.remove();
      }
    }
   
  }

  /**
   * loads and sets configuration for a component
   *
   * @param component  component to set configurations for, not null; may
   *                   be a component that is not configurable (=> no action)
   */
  private void configureComponent(Component component) {

    assert component != null;

    Configuration configuration = configurationMap.get(component.getClass());
    if (configuration != null) {
      configuration.applyTo(component);
    }
   
  }
 
  /**
   * returns the base configuration for a component class.
   * This provides the configuration as permanently stored for that class,
   * <em>without</em> influences by the temporary configuration readers
   * that were also set in the constructor.
   *
   * @param componentClass  class to get configuration for; != null
   */
  public Configuration getComponentClassBaseConfiguration(Class<? extends Component> componentClass) {
   
    assert componentClass != null;
   
    return retrieveBaseConfiguration(componentClass);
   
  }
 
  /**
   * changes the current base configuration for a component class;
   * see also {@link #getComponentClassBaseConfiguration(Class)}
   *
   * @param componentClass  class to set configuration for; != null
   * @param configuration   new base configuration for componentClass; != null
   */
  public void setComponentClassBaseConfiguration(
      Class<? extends Component> componentClass,
      Configuration configuration) {
   
    assert componentClass != null && configuration != null;
    assert configuration.getClass().equals(componentClass);

    if (configurationStorage != null) {   
      configurationStorage.write(configuration);
    }
   
    readComponentConfiguration(componentClass);   
   
  }

  /**
   * loads and sets the translation for a component
   * using the current translatationReader.
   *
   * @param component  component whose translation is to be set,
   *                   not null; may be an object that is not translatable
   *                   (=> no action)
   */
  public void setTranslation(Object component) {

    if (component == null) {
      throw new NullPointerException("component must not be null");
    }
       
    if (component instanceof Translatable) {

      ResourceBundle langRB = loadTranslation(component.getClass());

      ((Translatable)component).setLanguageResourceBundle(langRB);     
     
    }
   
  }

  private ResourceBundle loadTranslation(Class<?> componentClass) {

    assert componentClass != null;
   
    String componentSimpleName = componentClass.getSimpleName();

    return translationReader.readTranslation(componentSimpleName,
                                       classLoader);
  }
 
  /** reloads translations for all active components */
  private void reloadTranslations() {

    for (Component component : activeComponents()) {
      setTranslation(component);
    }
   
  }
 
 
  /**
   * returns the localized component name for a component;
   * this name is determined from its resource bundle for the current locale
   * (if it exists)
   *
   * @param componentClass  component class to get localized name for, != null
   * @return  localized name or null (if no localized name exists)
   */
  public String getLocalizedComponentName(Class<? extends Component> componentClass) {

    if (componentClass == null) {
      throw new NullPointerException("componentClass must not be null");
    }
   
    if (!Translatable.class.isAssignableFrom(componentClass)) {
      return null;
    }   
   
    ResourceBundle langRB = loadTranslation(componentClass);
   
    if (langRB != null && langRB.containsKey(LOCALIZED_NAME_ENTRY)) {
      return langRB.getString(LOCALIZED_NAME_ENTRY);
    } else {
      return null;
    }
 
  }
 

  /**
   * returns a list of all components currently active
   * (i.e. inputComp., outputComp., uiComp. and the replacerComp.s
   * to ease performing operations on all of them
   */
  private List<? extends Component> activeComponents() {
   
    List<Component> activeComponents = new LinkedList<Component>();
   
    activeComponents.add(inputComponent);
    activeComponents.add(outputComponent);
    activeComponents.add(uiComponent);
   
    for (ReplacerComponent<?,?> replacerComponent : replacerComponents) {
      activeComponents.add(replacerComponent);
    }
   
    return activeComponents;   
  }
 
  /**
   * lists all files in a directory that end with a given string
   *
   * @param dir  directory to list contents of
   * @param str  String all returned filenames must end with
   * @return     list of filenames ending with s; null if this abstract
   *             pathname does not denote a directory, or if an I/O error
   *             occurs (compare java.io.File's list(FilenameFilter) method)
   */
  private static final String[] listFilesEndingWith(File dir,
                                                final String str) {
 
    FilenameFilter filter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        return name.endsWith(str);
      }     
    };
   
    return dir.list(filter);
  }
 
  /**
   * checks whether a class is a valid component class, i.e. implementing
   * Component, public and not abstract
   *
   * @param c  class to check
   * @return   true for valid component classes, otherwise false
   */
  private static final boolean isValidComponentClass(Class<?> c) {
 
    return Component.class.isAssignableFrom(c)
           && Modifier.isPublic(c.getModifiers())
           && !java.lang.reflect.Modifier.isAbstract(c.getModifiers());
   
  }
 
}
TOP

Related Classes of net.sf.jeters.componentInterface.ComponentManager

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.