/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.scripting.solutionmodel;
import java.util.Arrays;
import org.mozilla.javascript.annotations.JSFunction;
import org.mozilla.javascript.annotations.JSGetter;
import org.mozilla.javascript.annotations.JSSetter;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.dataprocessing.FoundSetManager;
import com.servoy.j2db.documentation.ServoyDocumented;
import com.servoy.j2db.persistence.RepositoryException;
import com.servoy.j2db.persistence.ScriptCalculation;
import com.servoy.j2db.persistence.ScriptNameValidator;
import com.servoy.j2db.persistence.TableNode;
import com.servoy.j2db.scripting.IJavaScriptType;
import com.servoy.j2db.scripting.TableScope;
import com.servoy.j2db.solutionmodel.ISMCalculation;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.ServoyException;
import com.servoy.j2db.util.UUID;
@SuppressWarnings("nls")
@ServoyDocumented(category = ServoyDocumented.RUNTIME)
public class JSCalculation implements IJavaScriptType, ISMCalculation
{
private ScriptCalculation scriptCalculation;
private final IApplication application;
private boolean isCopy;
private final JSDataSourceNode parent;
public JSCalculation(JSDataSourceNode parent, ScriptCalculation scriptCalculation, IApplication application, boolean isNew)
{
this.parent = parent;
this.scriptCalculation = scriptCalculation;
this.application = application;
this.isCopy = isNew;
}
private void checkModification()
{
if (!isCopy)
{
try
{
TableNode tableNode = application.getFlattenedSolution().getSolutionCopyTableNode(parent.getDataSource());
ScriptCalculation sc = tableNode.getScriptCalculation(scriptCalculation.getName());
if (sc == null)
{
sc = (ScriptCalculation)scriptCalculation.clonePersist();
tableNode.addChild(sc);
scriptCalculation = sc;
}
isCopy = true;
}
catch (RepositoryException e)
{
Debug.error(e);
throw new RuntimeException("Can't alter ScriptCalculation " + scriptCalculation.getName() + ", clone failed", e);
}
}
}
/**
* Get or set the sql type of this variable.
* Type should be one of JSVariable.DATETIME, JSVariable.TEXT, JSVariable.NUMBER , JSVariable.INTEGER or JSVariable.MEDIA.
*
* @sample
* var calc = solutionModel.getDataSourceNode("db:/example_data/customers").getCalculation("myCalculation");
* calc.variableType = JSVariable.DATETIME;
*/
@JSGetter
public int getVariableType()
{
return scriptCalculation.getDataProviderType();
}
@JSSetter
public void setVariableType(int type)
{
if (isStored()) throw new RuntimeException("Can't alter variable type of the stored calculation " + scriptCalculation.getName());
checkModification();
scriptCalculation.setTypeAndCheck(type, application);
TableScope tableScope;
try
{
tableScope = (TableScope)application.getScriptEngine().getTableScope(scriptCalculation.getTable());
if (tableScope != null)
{
tableScope.put(scriptCalculation, scriptCalculation);
((FoundSetManager)application.getFoundSetManager()).flushSQLSheet(scriptCalculation.getTable().getDataSource());
}
}
catch (RepositoryException e)
{
Debug.error(e);
}
}
/**
* This method returns the name of the stored calculation.
*
* @sample
* var calc = solutionModel.newCalculation("function myCalculation() { return 123; }", JSVariable.INTEGER, "db:/example_data/customers");
* application.output(calc.getName());
*
* @return the name of the stored calculation
*/
@JSFunction
public String getName()
{
return scriptCalculation.getName();
}
/**
* Returns whether this calculation is a stored one or not.
*
* @sample
* var calc = solutionModel.getDataSourceNode("db:/example_data/customers").newCalculation("function myCalculation() { return 123; }", JSVariable.INTEGER);
* if (calc.isStored()) application.output("The calculation is stored");
* else application.output("The calculation is not stored");
*
* @return true if the calculation is stored, false otherwise
*/
@JSFunction
public boolean isStored()
{
try
{
return scriptCalculation.getTable().getColumn(scriptCalculation.getName()) != null;
}
catch (RepositoryException e)
{
Debug.error(e);
}
return false;
}
/**
* @clonedesc com.servoy.j2db.persistence.AbstractScriptProvider#getDeclaration()
*
* @sample
* var calc = solutionModel.getDataSourceNode("db:/example_data/customers").getCalculation("myCalculation");
* calc.code = "function myCalculation() { return 123; }";
*/
@JSGetter
public String getCode()
{
return scriptCalculation.getDeclaration();
}
@JSSetter
public void setCode(String code)
{
checkModification();
String name = JSMethod.parseName(code);
if (!name.equals(scriptCalculation.getName()))
{
try
{
scriptCalculation.updateName(new ScriptNameValidator(application.getFlattenedSolution()), name);
}
catch (RepositoryException e)
{
throw new RuntimeException("Error updating the name from " + scriptCalculation.getName() + " to " + name, e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
scriptCalculation.setDeclaration(code);
try
{
TableScope tableScope = (TableScope)application.getScriptEngine().getTableScope(scriptCalculation.getTable());
if (tableScope != null)
{
tableScope.put(scriptCalculation, scriptCalculation);
String dataSource = scriptCalculation.getTable().getDataSource();
FoundSetManager fsm = (FoundSetManager)application.getFoundSetManager();
fsm.flushSQLSheet(dataSource);
fsm.getRowManager(dataSource).clearCalcs(null, Arrays.asList(scriptCalculation.getName()));
}
}
catch (ServoyException e)
{
Debug.error(e);
}
}
@Override
public String toString()
{
return "JSCalculation[name:" + scriptCalculation.getName() + ",type:" + scriptCalculation.getTypeAsString() + ']';
}
/**
* Returns the UUID of the calculation.
*
* @sample
* var calc = solutionModel.getDataSourceNode("db:/example_data/customers").newCalculation("function myCalculation() { return 123; }", JSVariable.INTEGER);
* application.output(calc.getUUID().toString());
*/
@JSFunction
public UUID getUUID()
{
return scriptCalculation.getUUID();
}
/**
* Check a flag of the calculation.
* The flags are a bit pattern consisting of 1 or more of the following bits:
* - JSColumn.UUID_COLUMN
*
* @sample
* var datasourceNode = solutionModel.getDataSourceNode('db:/example_data/orders')
* var calculation = datasourceNode.getCalculation('mycalculation')
* if (calculation.hasFlag(JSColumn.UUID_COLUMN))
* {
* // calculation was typed as UUID
* }
*
* @param flag
*
* @return boolean whether flag is set.
*/
@JSFunction
public boolean hasFlag(int flag)
{
return (scriptCalculation.getFlags() & flag) != 0;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((scriptCalculation == null) ? 0 : scriptCalculation.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
JSCalculation other = (JSCalculation)obj;
if (scriptCalculation == null)
{
if (other.scriptCalculation != null) return false;
}
else if (!scriptCalculation.getUUID().equals(other.scriptCalculation.getUUID())) return false;
return true;
}
}