Package org.pentaho.reporting.tools.configeditor.model

Source Code of org.pentaho.reporting.tools.configeditor.model.ModuleNodeFactory$ModuleSorter

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors.  All rights reserved.
*/

package org.pentaho.reporting.tools.configeditor.model;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.libraries.base.boot.Module;
import org.pentaho.reporting.libraries.base.boot.PackageManager;
import org.pentaho.reporting.tools.configeditor.Messages;
import org.xml.sax.SAXException;

/**
* The module node factory is used to build the lists of modules and their assigned keys for the ConfigTreeModel.
*
* @author Thomas Morgner
*/
public class ModuleNodeFactory
{
  private static class ConfigTreeModuleNodeComparator implements Comparator
  {
    public int compare(final Object o1, final Object o2)
    {
      final ConfigTreeModuleNode n1 = (ConfigTreeModuleNode) o1;
      final ConfigTreeModuleNode n2 = (ConfigTreeModuleNode) o2;
      return (n1.getName().compareTo(n2.getName()));
    }
  }

  /**
   * Sorts the given modules by their class package names.
   *
   * @author Thomas Morgner
   */
  private static class ModuleSorter implements Comparator, Serializable
  {
    /**
     * DefaultConstructor.
     */
    protected ModuleSorter()
    {
    }

    /**
     * Compares its two arguments for order.  Returns a negative integer, zero, or a positive integer as the first
     * argument is less than, equal to, or greater than the second.<p>
     *
     * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater
     *         than the second.
     * @throws ClassCastException if the arguments' types prevent them from being compared by this Comparator.
     */
    public int compare(final Object o1, final Object o2)
    {
      final String name1;
      final String name2;

      if (o1.getClass().getPackage() == null || o2.getClass().getPackage() == null)
      {
        name1 = ModuleNodeFactory.getPackage(o1.getClass());
        name2 = ModuleNodeFactory.getPackage(o2.getClass());
      }
      else
      {
        name1 = o1.getClass().getPackage().getName();
        name2 = o2.getClass().getPackage().getName();
      }
      return name1.compareTo(name2);
    }
  }

  private static final Log logger = LogFactory.getLog(ModuleNodeFactory.class);

  /**
   * Provides access to externalized strings
   */
  private final Messages messages;

  /**
   * All known modules as known at construction time.
   */
  private final Module[] activeModules;
  /**
   * A list of global module nodes.
   */
  private final ArrayList globalNodes;
  /**
   * A list of local module nodes.
   */
  private final ArrayList localNodes;
  /**
   * A hashtable of all defined config description entries.
   */
  private final HashMap configEntryLookup;

  /**
   * Create a new and uninitialized module node factory.
   */
  public ModuleNodeFactory(final PackageManager packageManager)
  {
    messages = Messages.getInstance();
    activeModules = packageManager.getAllModules();
    Arrays.sort(activeModules, new ModuleSorter());
    globalNodes = new ArrayList();
    localNodes = new ArrayList();
    configEntryLookup = new HashMap();

  }

  /**
   * Creates a new module node factory and initializes the factory from the given input stream. The stream will be used
   * to build a ConfigDescription model and should contain suitable XML content.
   *
   * @param in the input stream from where to read the model content.
   * @throws IOException if an error occured while reading the stream.
   */
  public ModuleNodeFactory(final PackageManager packageManager, final InputStream in)
      throws IOException
  {
    this(packageManager);
    load(in, false);
  }

  public void load(final InputStream in, final boolean append)
      throws IOException
  {
    if (append == false)
    {
      configEntryLookup.clear();
    }
    final ConfigDescriptionModel model = new ConfigDescriptionModel();
    try
    {
      model.load(in);
    }
    catch (SAXException saxException)
    {
      final String error = messages.getString("ModuleNodeFactory.ERROR_0001_PARSE_FAILURE",
          saxException.getMessage()); //$NON-NLS-1$
      ModuleNodeFactory.logger.error(error, saxException);
      throw new IOException(error);
    }
    catch (ParserConfigurationException pE)
    {
      final String error = messages.getString("ModuleNodeFactory.ERROR_0002_PARSER_CONFIG_ERROR",
          pE.getMessage()); //$NON-NLS-1$
      ModuleNodeFactory.logger.error(error, pE);
      throw new IOException(error);
    }

    final ConfigDescriptionEntry[] entries = model.toArray();
    for (int i = 0; i < entries.length; i++)
    {
      //Log.debug ("Entry: " + entries[i].getKeyName() + " registered");
      configEntryLookup.put(entries[i].getKeyName(), entries[i]);
    }
  }


  /**
   * (Re)Initializes the factory from the given report configuration. This will assign all keys frmo the report
   * configuration to the model and assignes the definition from the configuration description if possible.
   */
  public void init()
  {
    globalNodes.clear();
    localNodes.clear();

    //Iterator enum = config.findPropertyKeys("");
    final Iterator keys = configEntryLookup.keySet().iterator();
    while (keys.hasNext())
    {
      final String key = (String) keys.next();
      processKey(key);
    }
  }

  /**
   * Processes a single report configuration key and tries to find a definition for that key.
   *
   * @param key the name of the report configuration key
   */
  private void processKey(final String key)
  {
    ConfigDescriptionEntry cde = (ConfigDescriptionEntry) configEntryLookup.get(key);

    //Log.debug ("ActiveModule: " + mod.getClass() + " for key " + key);
    if (cde == null)
    {
      // check whether the system properties define such an key.
      // if they do, then we can assume, that it is just a sys-prop
      // and we ignore the key.
      //
      // if this is no system property, then this is a new entry, we'll
      // assume that it is a local text key.
      //
      // Security restrictions are handled as if the key is not defined
      // in the system properties. It is safer to add too much than to add
      // less properties ...
      try
      {
        if (System.getProperties().containsKey(key))
        {
          ModuleNodeFactory.logger.debug("Ignored key from the system properties: " + key); //$NON-NLS-1$
          return;
        }
        else
        {
          ModuleNodeFactory.logger.debug("Undefined key added on the fly: " + key); //$NON-NLS-1$
          cde = new TextConfigDescriptionEntry(key);
        }
      }
      catch (final SecurityException se)
      {
        ModuleNodeFactory.logger.debug("Unsafe key-definition due to security restrictions: " + key, se); //$NON-NLS-1$
        cde = new TextConfigDescriptionEntry(key);
      }
    }

    // We ignore hidden keys.
    if (cde.isHidden())
    {
      return;
    }

    final Module mod = lookupModule(key);
    if (mod == null)
    {
      return;
    }
    if (cde.isGlobal() == false)
    {
      ConfigTreeModuleNode node = lookupNode(mod, localNodes);
      if (node == null)
      {
        node = new ConfigTreeModuleNode(mod);
        localNodes.add(node);
      }
      node.addAssignedKey(cde);
    }

    // The global configuration provides defaults for the local
    // settings...
    ConfigTreeModuleNode node = lookupNode(mod, globalNodes);
    if (node == null)
    {
      node = new ConfigTreeModuleNode(mod);
      globalNodes.add(node);
    }
    node.addAssignedKey(cde);
  }

  /**
   * Tries to find a module node for the given module in the given list.
   *
   * @param key      the module that is searched.
   * @param nodeList the list with all known modules.
   * @return the node containing the given module, or null if not found.
   */
  private ConfigTreeModuleNode lookupNode(final Module key, final ArrayList nodeList)
  {
    if (key == null)
    {
      return null;
    }
    for (int i = 0; i < nodeList.size(); i++)
    {
      final ConfigTreeModuleNode node = (ConfigTreeModuleNode) nodeList.get(i);
      if (key == node.getModule())
      {
        return node;
      }
    }
    return null;
  }

  /**
   * Returns the name of the package for the given class. This is a workaround for the classloader behaviour of JDK1.2.2
   * where no package objects are created.
   *
   * @param c the class for which we search the package.
   * @return the name of the package, never null.
   */
  public static String getPackage(final Class c)
  {
    final String className = c.getName();
    final int idx = className.lastIndexOf('.');
    if (idx <= 0)
    {
      // the default package
      return ""; //$NON-NLS-1$
    }
    else
    {
      return className.substring(0, idx);
    }
  }

  /**
   * Looks up the module for the given key. If no module is responsible for the key, then it will be assigned to the
   * core module.
   * <p/>
   * If the core is not defined, then a ConfigTreeModelException is thrown. The core is the base for all modules, and is
   * always defined in a sane environment.
   *
   * @param key the name of the configuration key
   * @return the module that most likely defines that key
   */
  private Module lookupModule(final String key)
  {
    Module retval = null;
    int confidence = -1;
    for (int i = 0; i < activeModules.length; i++)
    {
      final String modPackage = ModuleNodeFactory.getPackage(activeModules[i].getClass());
      // Log.debug ("Module package: " + modPackage + " for " + activeModules[i].getClass());
      if (key.startsWith(modPackage))
      {
        if (confidence < modPackage.length())
        {
          confidence = modPackage.length();
          retval = activeModules[i];
        }
      }
    }
    return retval;
  }

  /**
   * Returns all global nodes. You have to initialize the factory before using this method.
   *
   * @return the list of all global nodes.
   */
  public ConfigTreeModuleNode[] getGlobalNodes()
  {
    final ConfigTreeModuleNode[] retval = (ConfigTreeModuleNode[])
        globalNodes.toArray(new ConfigTreeModuleNode[globalNodes.size()]);
    Arrays.sort(retval, new ConfigTreeModuleNodeComparator());
    return retval;
  }

  /**
   * Returns all local nodes. You have to initialize the factory before using this method.
   *
   * @return the list of all global nodes.
   */
  public ConfigTreeModuleNode[] getLocalNodes()
  {
    final ConfigTreeModuleNode[] retval = (ConfigTreeModuleNode[])
        localNodes.toArray(new ConfigTreeModuleNode[localNodes.size()]);
    Arrays.sort(retval, new ConfigTreeModuleNodeComparator());
    return retval;
  }

  /**
   * Returns the entry for the given key or null, if the key has no metadata.
   *
   * @param key the name of the key
   * @return the entry or null if not found.
   */
  public ConfigDescriptionEntry getEntryForKey(final String key)
  {
    return (ConfigDescriptionEntry) configEntryLookup.get(key);
  }
}
TOP

Related Classes of org.pentaho.reporting.tools.configeditor.model.ModuleNodeFactory$ModuleSorter

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.
ore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');