Package org.formulacompiler.spreadsheet.internal.util

Source Code of org.formulacompiler.spreadsheet.internal.util.EngineBuilderImpl$Factory

/*
* Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
* All rights reserved.
*
* This file is part of the Abacus Formula Compiler (AFC).
*
* For commercial licensing, please contact sales(at)formulacompiler.com.
*
* AFC 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 3 of the License, or
* (at your option) any later version.
*
* AFC 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 AFC.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.formulacompiler.spreadsheet.internal.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.formulacompiler.compiler.CallFrame;
import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.NumericType;
import org.formulacompiler.compiler.SaveableEngine;
import org.formulacompiler.runtime.Computation;
import org.formulacompiler.runtime.ComputationMode;
import org.formulacompiler.runtime.EngineException;
import org.formulacompiler.spreadsheet.ConstantExpressionOptimizationListener;
import org.formulacompiler.spreadsheet.EngineBuilder;
import org.formulacompiler.spreadsheet.Spreadsheet;
import org.formulacompiler.spreadsheet.SpreadsheetBinder;
import org.formulacompiler.spreadsheet.SpreadsheetByNameBinder;
import org.formulacompiler.spreadsheet.SpreadsheetCompiler;
import org.formulacompiler.spreadsheet.SpreadsheetException;
import org.formulacompiler.spreadsheet.SpreadsheetLoader;
import org.formulacompiler.spreadsheet.SpreadsheetNameCreator;
import org.formulacompiler.spreadsheet.SpreadsheetToEngineCompiler;
import org.formulacompiler.spreadsheet.SpreadsheetBinder.Config;


public class EngineBuilderImpl implements EngineBuilder
{
  private Spreadsheet spreadsheet;
  private NumericType numericType = SpreadsheetCompiler.DEFAULT_NUMERIC_TYPE;
  private ComputationMode computationMode = null;
  private Class inputClass;
  private Class outputClass;
  private Class factoryClass;
  private Method factoryMethod;
  private boolean fullCaching;
  private Computation.Config compileTimeConfig;
  private SpreadsheetBinder binder;
  private SpreadsheetByNameBinder byNameBinder;
  private ClassLoader parentClassLoaderForEngine = ClassLoader.getSystemClassLoader();
  private boolean compileToReadableCode = false;
  private boolean computationListenerEnabled = false;
  private ConstantExpressionOptimizationListener constExprOptListener;


  public static final class Factory implements EngineBuilder.Factory
  {
    public EngineBuilder newInstance()
    {
      return new EngineBuilderImpl();
    }
  }


  // ------------------------------------------------ Numeric Type


  public NumericType getNumericType()
  {
    return this.numericType;
  }

  public void setNumericType( NumericType _type )
  {
    this.numericType = _type;
  }


  // ------------------------------------------------ Computation Mode


  public ComputationMode getComputationMode()
  {
    return this.computationMode;
  }

  public void setComputationMode( final ComputationMode _computationMode )
  {
    this.computationMode = _computationMode;
  }


  // ------------------------------------------------ Spreadsheet


  public Spreadsheet getSpreadsheet()
  {
    return this.spreadsheet;
  }

  public void setSpreadsheet( Spreadsheet _sheet )
  {
    failIfBinderExists();
    this.spreadsheet = _sheet;
  }


  private boolean loadAllCellValues = false;

  public void setLoadAllCellValues( boolean _value )
  {
    this.loadAllCellValues = _value;
  }


  public void loadSpreadsheet( File _file ) throws FileNotFoundException, IOException, SpreadsheetException
  {
    final SpreadsheetLoader.Config cfg = new SpreadsheetLoader.Config();
    cfg.loadAllCellValues = this.loadAllCellValues;
    setSpreadsheet( SpreadsheetCompiler.loadSpreadsheet( _file.getName(), new FileInputStream( _file ), cfg ) );
  }


  // ------------------------------------------------ Classes


  public Class getInputClass()
  {
    return this.inputClass;
  }

  public void setInputClass( Class _inputClass )
  {
    failIfBinderExists();
    this.inputClass = _inputClass;
  }

  public Class getOutputClass()
  {
    return this.outputClass;
  }

  public void setOutputClass( Class _outputClass )
  {
    failIfBinderExists();
    this.outputClass = _outputClass;
  }

  public Class getFactoryClass()
  {
    return this.factoryClass;
  }

  public void setFactoryClass( Class _class )
  {
    failIfBinderExists();
    this.factoryClass = _class;
  }

  public Method getFactoryMethod()
  {
    return this.factoryMethod;
  }

  public void setFactoryMethod( Method _factoryMethod )
  {
    failIfBinderExists();
    this.factoryMethod = _factoryMethod;
  }

  protected void configureClasses() throws CompilerException
  {
    if (this.factoryMethod != null) {
      if (this.factoryClass == null) {
        this.factoryClass = this.factoryMethod.getDeclaringClass();
      }
    }
    else if (this.factoryClass != null) {
      if (this.inputClass == null || this.outputClass == null) {
        this.factoryMethod = determineFactoryMethod( this.factoryClass );
      }
      else {
        this.factoryMethod = determineFactoryMethod( this.factoryClass, this.inputClass, this.outputClass );
      }
    }
    if (this.inputClass == null && this.factoryMethod != null && this.factoryMethod.getParameterTypes().length == 1) {
      this.inputClass = this.factoryMethod.getParameterTypes()[ 0 ];
    }
    if (this.outputClass == null && this.factoryMethod != null) {
      this.outputClass = this.factoryMethod.getReturnType();
    }
  }

  /**
   * Look for a method with a signature "(any)any". Return the first abstract one, or else the last
   * one that matches.
   *
   * @throws CompilerException
   */
  private Method determineFactoryMethod( Class _factoryClass ) throws CompilerException
  {
    final Method[] methods = _factoryClass.getMethods();
    Method candidate = null;
    for (Method method : methods) {
      final int mod = method.getModifiers();
      if (Modifier.isPublic( mod ) && !Modifier.isStatic( mod ) && !Modifier.isFinal( mod )) {
        if (method.getReturnType() != null && method.getParameterTypes().length == 1) {
          candidate = method;
          if (Modifier.isAbstract( mod )) {
            return candidate;
          }
        }
      }
    }
    if (candidate != null) return candidate;
    throw new CompilerException.FactoryMethodMissing( _factoryClass );
  }

  /**
   * Look for a method with the signature "(input)output". Return the first abstract one, or else
   * the last one that matches. Fail if none found.
   *
   * @throws CompilerException
   */
  private Method determineFactoryMethod( Class _factoryClass, Class _inputClass, Class _outputClass )
      throws CompilerException
  {
    final Method[] methods = _factoryClass.getMethods();
    Method candidate = null;
    for (Method method : methods) {
      final int mod = method.getModifiers();
      if (Modifier.isPublic( mod ) && !Modifier.isStatic( mod ) && !Modifier.isFinal( mod )) {
        if (method.getReturnType() == _outputClass) {
          Class[] params = method.getParameterTypes();
          if (params.length == 1 && params[ 0 ] == _inputClass) {
            candidate = method;
            if (Modifier.isAbstract( method.getModifiers() )) {
              return candidate;
            }
          }
        }
      }
    }
    if (candidate != null) return candidate;
    throw new CompilerException.FactoryMethodMissing( _factoryClass, _inputClass, _outputClass );
  }


  private void validateClasses()
  {
    if (this.inputClass == null) throw new IllegalStateException( "InputClass not specified" );
    if (this.outputClass == null) throw new IllegalStateException( "OutputClass not specified" );
    if (this.factoryClass != null) {
      if (this.factoryMethod == null) throw new IllegalStateException( "FactoryMethod not specified" );
    }
  }


  // ------------------------------------------------ Caching


  public boolean getFullCaching()
  {
    return this.fullCaching;
  }

  public void setFullCaching( boolean _enabled )
  {
    this.fullCaching = _enabled;
  }


  // ------------------------------------------------ Compile-time configuration


  public Computation.Config getCompileTimeConfig()
  {
    if (this.compileTimeConfig == null) {
      this.compileTimeConfig = new Computation.Config();
    }
    return this.compileTimeConfig;
  }

  public void setCompileTimeConfig( Computation.Config _value )
  {
    this.compileTimeConfig = _value;
  }


  // ------------------------------------------------ Name creation


  public boolean areAnyNamesDefined()
  {
    return (getSpreadsheet().getRangeNames().size() > 0);
  }


  public void createCellNamesFromRowTitles()
  {
    final SpreadsheetNameCreator creator = SpreadsheetCompiler.newSpreadsheetCellNameCreator( getSpreadsheet()
        .getSheets()[ 0 ] );
    creator.createCellNamesFromRowTitles();
  }


  // ------------------------------------------------ Binding


  protected SpreadsheetBinder getBinder() throws CompilerException
  {
    if (this.binder == null) this.binder = makeBinder();
    return this.binder;
  }

  private SpreadsheetBinder makeBinder() throws CompilerException
  {
    configureClasses();
    validateClasses();
    final Config cfg = new SpreadsheetBinder.Config();
    cfg.spreadsheet = this.spreadsheet;
    cfg.inputClass = this.inputClass;
    cfg.outputClass = this.outputClass;
    cfg.compileTimeConfig = this.compileTimeConfig;
    return SpreadsheetCompiler.newSpreadsheetBinder( cfg );
  }

  private void failIfBinderExists()
  {
    if (this.binder != null) throw new IllegalStateException( "Binder already exists" );
  }

  public SpreadsheetBinder.Section getRootBinder() throws CompilerException
  {
    return getBinder().getRoot();
  }

  public CallFrame newCallFrame( Method _method, Object... _args )
  {
    return SpreadsheetCompiler.newCallFrame( _method, _args );
  }

  public SpreadsheetByNameBinder getByNameBinder() throws CompilerException
  {
    if (this.byNameBinder == null) this.byNameBinder = makeByNameBinder();
    return this.byNameBinder;
  }

  private SpreadsheetByNameBinder makeByNameBinder() throws CompilerException
  {
    return SpreadsheetCompiler.newSpreadsheetByNameBinder( getBinder() );
  }


  public void bindAllByName() throws CompilerException
  {
    // ---- bindAllByName
    if (!areAnyNamesDefined()) {
      createCellNamesFromRowTitles();
    }
    SpreadsheetByNameBinder bn = getByNameBinder();
    bn.outputs().bindAllMethodsToNamedCells();
    bn.inputs().bindAllNamedCellsToMethods();
    // ---- bindAllByName
  }

  public void failIfByNameBindingLeftNamedCellsUnbound() throws CompilerException
  {
    getByNameBinder().failIfCellNamesAreStillUnbound();
  }


  public void bindAllByName( String _inputPrefix, String _outputPrefix ) throws CompilerException
  {
    // ---- bindAllByNamePrefixed
    if (!areAnyNamesDefined()) {
      createCellNamesFromRowTitles();
    }
    SpreadsheetByNameBinder bn = getByNameBinder();
    bn.outputs().bindAllMethodsToPrefixedNamedCells( _outputPrefix );
    bn.inputs().bindAllPrefixedNamedCellsToMethods( _inputPrefix );
    // ---- bindAllByNamePrefixed
  }

  public void failIfByNameBindingLeftNamedCellsUnbound( String _inputPrefix, String _outputPrefix )
      throws CompilerException
  {
    getByNameBinder().inputs().failIfCellNamesAreStillUnbound( _inputPrefix );
    getByNameBinder().outputs().failIfCellNamesAreStillUnbound( _outputPrefix );
  }


  // ------------------------------------------------ Compilation


  public ClassLoader getParentClassLoaderForEngine()
  {
    return this.parentClassLoaderForEngine;
  }

  public void setParentClassLoaderForEngine( ClassLoader _value )
  {
    this.parentClassLoaderForEngine = _value;
  }


  public boolean getCompileToReadableCode()
  {
    return this.compileToReadableCode;
  }

  public void setCompileToReadableCode( boolean _value )
  {
    this.compileToReadableCode = _value;
  }


  public boolean getComputationListenerEnabled()
  {
    return this.computationListenerEnabled;
  }

  public void setComputationListenerEnabled( boolean _enabled )
  {
    this.computationListenerEnabled = _enabled;
  }


  public ConstantExpressionOptimizationListener getConstantExpressionOptimizationListener()
  {
    return this.constExprOptListener;
  }

  public void setConstantExpressionOptimizationListener( ConstantExpressionOptimizationListener _listener )
  {
    this.constExprOptListener = _listener;
  }


  public SaveableEngine compile() throws CompilerException, EngineException
  {
    final SpreadsheetToEngineCompiler.Config cfg = new SpreadsheetToEngineCompiler.Config();
    cfg.binding = getBinder().getBinding();
    cfg.numericType = this.numericType;
    cfg.computationMode = this.computationMode;
    cfg.factoryClass = this.factoryClass;
    cfg.factoryMethod = this.factoryMethod;
    cfg.fullCaching = this.fullCaching;
    cfg.parentClassLoader = this.parentClassLoaderForEngine;
    cfg.compileToReadableCode = this.compileToReadableCode;
    cfg.computationListenerEnabled = this.computationListenerEnabled;
    cfg.constantExpressionOptimizationListener = this.constExprOptListener;
    return SpreadsheetCompiler.newSpreadsheetCompiler( cfg ).compile();
  }


}
TOP

Related Classes of org.formulacompiler.spreadsheet.internal.util.EngineBuilderImpl$Factory

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.