/*
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.persistence;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.StringTokenizer;
import org.mozilla.javascript.NativeDate;
import org.mozilla.javascript.Wrapper;
import com.servoy.base.scripting.annotations.ServoyClientSupport;
import com.servoy.j2db.documentation.ServoyDocumented;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.ScopesUtils;
import com.servoy.j2db.util.UUID;
import com.servoy.j2db.util.Utils;
/**
* A so called script variable used as global under solution and as form variable used under form objects
*
* @author jblok
*/
@ServoyDocumented(category = ServoyDocumented.DESIGNTIME, publicName = "Variable", typeCode = IRepository.SCRIPTVARIABLES)
@ServoyClientSupport(mc = true, wc = true, sc = true)
public class ScriptVariable extends AbstractBase implements IVariable, IDataProvider, ISupportUpdateableName, ISupportHTMLToolTipText, ISupportContentEquals,
IPersistCloneable, ICloneable, ISupportScope, ISupportDeprecatedAnnotation
{
private static final long serialVersionUID = 1L;
private String prefixedName = null;
public static final String GLOBAL_SCOPE = "globals"; //$NON-NLS-1$
public static final String GLOBALS_DOT_PREFIX = GLOBAL_SCOPE + '.';
public static final String SCOPES = "scopes"; //$NON-NLS-1$
public static final String SCOPES_DOT_PREFIX = SCOPES + '.';
/**
* Constructor I
*/
ScriptVariable(ISupportChilds parent, int element_id, UUID uuid)
{
super(IRepository.SCRIPTVARIABLES, parent, element_id, uuid);
}
/*
* _____________________________________________________________ Methods from this class
*/
/**
* update the name
*
* @param arg the name
*/
public void setName(String arg)
{
setTypedProperty(StaticContentSpecLoader.PROPERTY_NAME, arg);
prefixedName = null;
}
/**
* Set the name
*
* @param arg the name
*/
public void updateName(IValidateName validator, String arg) throws RepositoryException
{
validator.checkName(arg, getID(), new ValidatorSearchContext(getScopeName() != null ? getScopeName() : getRootObject(), IRepository.SCRIPTVARIABLES),
false);
setTypedProperty(StaticContentSpecLoader.PROPERTY_NAME, arg);
prefixedName = null;
getRootObject().getChangeHandler().fireIPersistChanged(this);
}
/**
* @clonedesc com.servoy.base.solutionmodel.IBaseSMVariable#getName()
*/
public String getName()
{
return getTypedProperty(StaticContentSpecLoader.PROPERTY_NAME);
}
/**
* Property for setting and getting the jsdoc text (comment) of the script variable.
*
* @return the value of the jsdoc text (comment) of the script variable
*/
public String getComment()
{
return getTypedProperty(StaticContentSpecLoader.PROPERTY_COMMENT);
}
/**
* @param arg the jsdoc text value for the script variable
*/
public void setComment(String arg)
{
setTypedProperty(StaticContentSpecLoader.PROPERTY_COMMENT, arg);
}
/**
* The name of the scope.
*/
public String getScopeName()
{
String value = getTypedProperty(StaticContentSpecLoader.PROPERTY_SCOPENAME);
if (value == null && getParent() instanceof Solution)
{
// scope name is a bit strange, has 2 default values: null for non direct solution children (handled through ContentSpec) and "globals" for direct solution children...
// it needs to be interpreted as "globals" if not available for solution children (for importing solutions from older versions before scopes were introduced - otherwise a "null.js" gets created)
value = ScriptVariable.GLOBAL_SCOPE;
}
return value;
}
public void setScopeName(String scopeName)
{
setTypedProperty(StaticContentSpecLoader.PROPERTY_SCOPENAME, scopeName);
}
/**
* Set the variableType
*
* @param arg the variableType
*/
@SuppressWarnings("nls")
public void setVariableType(int arg)
{
int variableType = arg;
if (variableType == Types.FLOAT) variableType = IColumnTypes.NUMBER;
boolean hit = false;
int[] types = Column.allDefinedTypes;
for (int element : types)
{
if (variableType == element)
{
hit = true;
break;
}
}
if (!hit)
{
Debug.error("unknown variable type " + variableType + " for variable " + getName() + " reverting to previous or MEDIA type",
new RuntimeException());
if (getVariableType() == 0)
{
variableType = IColumnTypes.MEDIA;
}
else
{
return;
}
}
setTypedProperty(StaticContentSpecLoader.PROPERTY_VARIABLETYPE, variableType);
}
/**
* @clonedesc com.servoy.base.solutionmodel.IBaseSMVariable#getVariableType()
*/
public int getVariableType()
{
return getTypedProperty(StaticContentSpecLoader.PROPERTY_VARIABLETYPE).intValue();
}
@Override
public String toString()
{
return getDataProviderID();
}
public void setDefaultValue(String arg)
{
setTypedProperty(StaticContentSpecLoader.PROPERTY_DEFAULTVALUE, "".equals(arg) ? null : arg);
}
/**
* @clonedesc com.servoy.base.solutionmodel.IBaseSMVariable#getDefaultValue()
*/
public String getDefaultValue()
{
String value = getTypedProperty(StaticContentSpecLoader.PROPERTY_DEFAULTVALUE);
return "".equals(value) ? null : value;
}
@SuppressWarnings("nls")
public Object getInitValue()
{
String defaultValue = getDefaultValue();
switch (Column.mapToDefaultType(getVariableType()))
{
case IColumnTypes.DATETIME :
if ("now".equalsIgnoreCase(defaultValue))
{
return new java.util.Date();
}
if (defaultValue != null)
{
return parseDate(defaultValue);
}
return null;
case IColumnTypes.TEXT :
{
if ("null".equalsIgnoreCase(defaultValue))
{
return null;
}
return (defaultValue == null ? "" : defaultValue); //$NON-NLS-1$
}
case IColumnTypes.NUMBER :
try
{
double number = Utils.getAsDouble(defaultValue, true);
return ("null".equalsIgnoreCase(defaultValue) ? null : new Double(number)); //$NON-NLS-1$
}
catch (RuntimeException e)
{
return defaultValue;
}
case IColumnTypes.INTEGER :
try
{
int number = Utils.getAsInteger(defaultValue, true);
return ("null".equalsIgnoreCase(defaultValue) ? null : new Integer(number)); //$NON-NLS-1$
}
catch (RuntimeException e)
{
return defaultValue;
}
case IColumnTypes.MEDIA :
if ("null".equalsIgnoreCase(defaultValue))
{
return null;
}
return defaultValue;
default :
return null;
}
}
public String toHTML()
{
StringBuffer sb = new StringBuffer();
sb.append("<html>"); //$NON-NLS-1$
sb.append("<b>"); //$NON-NLS-1$
sb.append(getName());
sb.append("</b> "); //$NON-NLS-1$
sb.append(Column.getDisplayTypeString(getVariableType()));
sb.append(" defaultvalue: "); //$NON-NLS-1$
sb.append(getDefaultValue());
sb.append("</html>"); //$NON-NLS-1$
return sb.toString();
}
/*
* _____________________________________________________________ Methods from IDataProvider
*/
public String getDataProviderID()
{
if (prefixedName == null)
{
if (getParent() instanceof Solution)
{
prefixedName = ScopesUtils.getScopeString(this);
}
else
{
prefixedName = getName();
}
}
return prefixedName;
}
public int getDataProviderType()
{
return getVariableType();
}
// public String[] getDependentDataProviderIDs()
// {
// return null;
// }
public ColumnWrapper getColumnWrapper()
{
return null;
}
public int getLength()
{
return -1;
}
public boolean isEditable()
{
return true;
}
public int getFlags()
{
return Column.NORMAL_COLUMN;
}
//the repository element id can differ!
public boolean contentEquals(Object obj)
{
if (obj instanceof ScriptVariable)
{
ScriptVariable other = (ScriptVariable)obj;
return (getDataProviderID().equals(other.getDataProviderID()) && getVariableType() == other.getVariableType() &&
Utils.equalObjects(getDefaultValue(), other.getDefaultValue()));
}
return false;
}
@SuppressWarnings("nls")
private static Date parseDate(String dateString)
{
if (dateString == null) return null;
if (!dateString.toLowerCase().startsWith("new date(")) return null;
String value = dateString.substring(9, dateString.lastIndexOf(')'));
if (value.trim().length() == 0) return new Date();
Object[] args = null;
if (value.startsWith("\"") || value.startsWith("'"))
{
args = new Object[] { value.substring(1, value.length() - 1) };
}
else
{
ArrayList<String> al = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(value, ",");
while (st.hasMoreTokens())
{
al.add(st.nextToken());
}
args = al.toArray();
}
Wrapper wrapper = (Wrapper)NativeDate.jsConstructor(args);
return (Date)wrapper.unwrap();
}
/**
* @return
*/
public boolean isPrivate()
{
return getComment() != null && getComment().indexOf("@private") != -1;
}
public boolean isPublic()
{
return getComment() != null && getComment().indexOf("@public") != -1;
}
public boolean isDeprecated()
{
return getComment() != null && getComment().indexOf("@deprecated") != -1;
}
public int getLineNumberOffset()
{
return getTypedProperty(StaticContentSpecLoader.PROPERTY_LINENUMBEROFFSET).intValue();
}
public void setLineNumberOffset(int arg)
{
setTypedProperty(StaticContentSpecLoader.PROPERTY_LINENUMBEROFFSET, arg);
}
/**
* @return
*/
public boolean isEnum()
{
return getComment() != null && getComment().indexOf("@enum") != -1;
}
}