Package net.xoetrope.xui.data

Source Code of net.xoetrope.xui.data.XRegisteredDataBindingFactory$XBindingMatch

package net.xoetrope.xui.data;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.build.BuildProperties;

/**
* A data binding factory that loads a specification of data bindings from an
* XML configuration file
* <p> Copyright (c) Xoetrope Ltd., 2002-2006. See license.txt for licensing
* details</p>
* @author luano
*/
public class XRegisteredDataBindingFactory extends XDataBindingFactory
{
  private static XRegisteredDataBindingFactory instance = null
 
  /**
   * Match bindings based on the target component class name
   */
  public static final int CLASS_MATCH = 0;

  /**
   * Match bindings based on implementation of a particular interface
   */
  public static final int INTERFACE_MATCH = 1;

  /**
   * Match bindings based on inheritance from a particular class
   */
  public static final int INSTANCE_MATCH = 2;
 
  /**
   * Match bindings based on the results of a user defined comparison
   */
  public static final int INSPECTOR_MATCH = 3;
  private static final int NUM_MATCH_MODES = 4;
 
 
  /**
   * The register of binding adapters for each component type
   */
  protected ArrayList[] bindingRegisters;

  /**
   * The config files used to build the set of component adapters. Stores the
   * file names
   */
  protected static Hashtable configFiles;

  /**
   * A counter for changes to the registry. Used to indicate if the registry
   * needs to be rebuilt
   */
  protected static int changeCounter;

  /**
   * Used for tracking changes to the registry spec.
   */
  protected int localChangeCounter = -1;
 
  private XProject currentProject;

  /**
   * Create the new component factory
   * @param project the owner project
   */
  private XRegisteredDataBindingFactory( XProject project )
  {
    super( project );
   
    if ( BuildProperties.DEBUG )
        DebugLogger.trace( "Setting up XRegisteredDataBindingFactory" );

    addConfigFile( "XUI", "net/xoetrope/xui/data/bindings.xml", false );
    currentProject = project;

    String projectRegistryFile = currentProject.getStartupParam( "BindingsRegistry" );
    if ( ( projectRegistryFile == null ) || ( projectRegistryFile.length() == 0 ) )
     projectRegistryFile = "bindings";
    if ( projectRegistryFile.indexOf( ".xml" ) < 0 )
      projectRegistryFile += ".xml";

    URL url = currentProject.findResource( projectRegistryFile );
    if ( url != null )
      addConfigFile( "Project", url, false );
  }
 
  /**
   * Register an instance of this binding factory.
   * @param currentProject the owner project
   */
  public static void register( XProject currentProject )
  {
    if ( instance == null )
      instance = new XRegisteredDataBindingFactory( currentProject );
   
    currentProject.registerBindingFactory( instance );
 
 
  /**
   * Try to get a binding factory to construct the binding
   * @param page the page that will own the binding
   * @param comp the target component
   * @param instanceConfig the attributes of the binding instance
   * @return the new binding if one could be constructed
   */
  public XDataBinding getBinding( PageSupport page, Object comp, Hashtable instanceConfig )
  {
    checkRegistration();
   
    String className = comp.getClass().getName();
    String type = (String)instanceConfig.get( "type" );
    Hashtable bindingConfig = new Hashtable();
    for ( int mode = 0; mode < NUM_MATCH_MODES; mode++ ) {
      int numRegistrations = bindingRegisters[ mode ].size();  
      for ( int i = 0; i < numRegistrations; i++ ) {
        XBindingMatch match = (XBindingMatch)bindingRegisters[ mode ].get( i );
        if ( match.matchMode == mode ) {
          if ( match.matches( mode, comp, className, type )) {
            try {
              XDataBinding db = (XDataBinding)Class.forName( match.className.trim()).newInstance();
              db.setup( currentProject, comp, bindingConfig, instanceConfig );
              return db;
            }
            catch ( Exception ex )
            {
              ex.printStackTrace();
            }
          }
        }
      }
    }
    return null;
 
 
  /**
   * Add a configuration file.
   * If the files have already been loaded then the new file will be loaded
   * @param key the name by which the configuration file is referenced
   * @param resource the name/path of the configuration file or the URL for the file
   * @param overwrite true to overwrite and existing entry matching the specified key
   */
  public static void addConfigFile( String key, Object resource, boolean overwrite )
  {
    if ( resource == null )
      return;

    if  ( configFiles == null )
      configFiles = new Hashtable();

    Object resourceObj = configFiles.get( key );
    // If the same file name is already used then ignore it.
    if (( resourceObj != null ) && resource.equals( resourceObj ))
      return;

    changeCounter++;
    if (( resourceObj != null ) || overwrite )
      configFiles.remove( key );

    configFiles.put( key, resource );
  }

  /**
   * Signal that the configuration has been updated.
   */
  public void updateConfig()
  {
    changeCounter++;
  }

  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   */
  protected void read()
  {
    bindingRegisters = new ArrayList[ NUM_MATCH_MODES ];
    for ( int i = 0; i < NUM_MATCH_MODES; i++ )
      bindingRegisters[ i ] = new ArrayList();

    Enumeration enumeration = configFiles.keys();
    while ( enumeration.hasMoreElements() ) {
      String key = ( String ) enumeration.nextElement();
      if ( !key.equals( "Project" ) )
        doRead( key, configFiles.get( key ) );
    }

    doRead( "Project", configFiles.get( "Project" ) );
  }

  /**
   * Read the component registry. The format is described in the components.xsd
   * schema. The config file is also registered.
   * @param configFile the name of the configuration file
   * @param key the name by which the configuration file is referenced
   */
  protected void read( String key, String configFile )
  {
    addConfigFile( key, configFile, true );
    doRead( key, configFile );
  }

  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   * @param configFile the name of the configuration file
   * @param key the name by which the configuration file is referenced
   */
  protected void doRead( String key, Object configFile )
  {
    if ( configFile == null )
      return;
    else if ( configFile instanceof URL )
      doRead( key, (URL)configFile );
    else
      doRead( key, (String)configFile );
  }

  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   * @param configFile the name of the configuration file
   * @param key the name by which the configuration file is referenced
   */
  protected void doRead( String key, String configFile )
  {
    if ( BuildProperties.DEBUG )
        DebugLogger.trace( "XRegisteredDataBindingFactory reading config file: " + configFile );

    try {
      String fileName = configFile;
      if ( fileName.indexOf( ".xml" ) < 0 )
        fileName += ".xml";
      Reader r = currentProject.getBufferedReader( fileName, null );
      if ( r != null )
        read( key, r );
    }
    catch ( Exception ex ) {
        ex.printStackTrace();
    }
  }

  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   * @param configFileURL the URL of the configuration file
   * @param key the name by which the configuration file is referenced
   */
  protected void doRead( String key, URL configFileURL )
  {
    if ( BuildProperties.DEBUG )
        DebugLogger.trace( "XRegisteredDataBindingFactory reading config file: " + configFileURL.toString() );

    try {
//      String file = configFileURL.getFile();
      Reader r = new BufferedReader( new InputStreamReader( configFileURL.openStream() ));
      if ( r != null )
        read( key, r );
    }
    catch ( Exception ex ) {
        ex.printStackTrace();
    }
  }


  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   * @param key the name by which the configuration file is referenced
   * @param reader the reader from which to read the file
   */
  public void read( String key, Reader reader )
  {
    try {
      XmlElement regRoot = XmlSource.read( reader );

      Vector registrationNodes = regRoot.getChildren();
      int numElements = registrationNodes.size();
      for ( int i = 0; i < numElements; i++ ) {
        XmlElement regElement = (XmlElement)registrationNodes.elementAt( i );
        String tag = regElement.getName();
        int mode = ( tag.equals( "InspectorBindings" ) ? INSPECTOR_MATCH :
                     tag.equals( "ClassBindings" ) ? CLASS_MATCH :
                     tag.equals( "InterfaceBindings" ) ? INTERFACE_MATCH :
                     INSTANCE_MATCH
                   );
        addBindingTypes( regElement, mode );
      }
    }
    catch ( Exception ex ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "Unable to setup the component registry" );
    }
  }
 
  /**
   * Read the component registry. The format is described in the components.xsd
   * schema.
   * @param regRoot the name by which the configuration file is referenced
   * @param mode the match mode for the new binding types
   */
  protected void addBindingTypes( XmlElement regRoot, int mode )
  {
    try {
      Vector registrationNodes = regRoot.getChildren();
      int numElements = registrationNodes.size();
      for ( int i = 0; i < numElements; i++ ) {
        XmlElement regElement = (XmlElement)registrationNodes.elementAt( i );
        XBindingMatch registration = new XBindingMatch();
        registration.matchMode = mode;
        registration.target = regElement.getAttribute( "target" );
        registration.className = regElement.getAttribute( "class" );
        registration.type = regElement.getAttribute( "type" );
        /** @todo store the extra attributes */
        bindingRegisters[ mode ].add( registration );
      }
    }
    catch ( Exception ex ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "Unable to setup the component registry" );
    }
  }

  /**
   * Check that all the registered components are loaded
   */
  public void checkRegistration()
  {
    if ( localChangeCounter != changeCounter ) {
      read();
      localChangeCounter = changeCounter;
    }
  } 
 
  class XBindingMatch
  {
    public int matchMode;
    public String target;
    public String className;
    public String type;
    private Class targetClass;
   
    public boolean matches( int mode, Object comp, String className, String instanceType )
    {
      if (( instanceType != null ) && ( instanceType.length() > 0 ) && !instanceType.equals( type ))
        return false;
       
      if ( mode == CLASS_MATCH ) {
        if ( target.equals( className ))
          return true;
       
        int pos = target.indexOf( '*' );
        if ( pos > 0 ) {
          if ( className.startsWith( target.substring( 0, pos )) && className.endsWith( target.substring( pos + 1 )))
            return true;
        }
      }
      else if ( mode == INTERFACE_MATCH ) {
        try {
          if ( targetClass == null )
            targetClass = Class.forName( target.trim());
         
          Class sc = comp.getClass();
          while ( sc != Object.class ) {
            Class[] interfaces = sc.getInterfaces();
            for ( int i = 0; i < interfaces.length; i++ ) {
              if ( interfaces[ i ] == targetClass )
                return true;
            }
           
            sc = sc.getSuperclass();
          }
        }
        catch ( ClassNotFoundException ex )
        {
          ex.printStackTrace();
        }
      }
      else if ( mode == INSTANCE_MATCH ) {
        try {
          if ( targetClass == null )
            targetClass = Class.forName( target.trim());
          Class sc = comp.getClass();
          while ( sc != Object.class ) {
            if ( sc == targetClass )
              return true;
            else
              sc = sc.getSuperclass();
          }
        }
        catch ( ClassNotFoundException ex )
        {
          ex.printStackTrace();
        }
      }
      else if ( mode == INSPECTOR_MATCH )
        return false;
     
      return false;
    }
  }
}
TOP

Related Classes of net.xoetrope.xui.data.XRegisteredDataBindingFactory$XBindingMatch

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.