/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.mappingsmodel.query.relational;
import java.text.NumberFormat;
import java.util.List;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWTypeDeclaration;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.tools.workbench.utility.node.Problem;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.expressions.ConstantExpression;
import org.eclipse.persistence.internal.helper.ConversionManager;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
/**
* An MWLiteralArgument is only used as the right hand side of a MWBinaryExpression
* The user chooses a type and then enters a value in the correct format of the chosen type.
*
* If the type is changed, the value is changed appropriately to fit the new format.
*/
public final class MWLiteralArgument extends MWArgument {
private volatile MWTypeDeclaration type;
public final static String TYPE_PROPERTY = "type";
private volatile String value;
public final static String VALUE_PROPERTY = "value";
/**
* Default constructor - for TopLink use only.
*/
private MWLiteralArgument()
{
super();
}
MWLiteralArgument(MWBasicExpression expression, MWTypeDeclaration type, String value)
{
super(expression);
this.type = type;
this.value = value;
}
MWLiteralArgument(MWBasicExpression expression)
{
super(expression);
}
protected void initialize(Node parent)
{
super.initialize(parent);
this.type = new MWTypeDeclaration(this, typeNamed("java.lang.String"));
this.value = "";
}
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.type);
}
private MWBasicExpression getBasicExpression() {
return (MWBasicExpression) getParent();
}
public String getType() {
return LITERAL_TYPE;
}
//certain operators only can only take a String for the type (Like, Not Like)
public void operatorTypeChanged()
{
if (getBasicExpression().operatorIsStringType())
setType(new MWTypeDeclaration(this, typeNamed("java.lang.String")));
}
public MWTypeDeclaration getLiteralType()
{
return this.type;
}
public Object getValue()
{
return this.value;
}
public void undoChange(String propertyName, Object oldValue, Object newValue)
{
if (propertyName == TYPE_PROPERTY)
setType((MWTypeDeclaration) oldValue);
else if (propertyName == VALUE_PROPERTY)
setValue((String) oldValue);
}
public void setType(MWTypeDeclaration type)
{
MWTypeDeclaration oldType = getLiteralType();
this.type = type;
firePropertyChanged(TYPE_PROPERTY, oldType, getLiteralType());
getBasicExpression().getRootCompoundExpression().propertyChanged(this, TYPE_PROPERTY, oldType, type);
}
public void setValue(String value)
{
Object oldValue = getValue();
this.value = value;
firePropertyChanged(VALUE_PROPERTY, oldValue, getValue());
getBasicExpression().getRootCompoundExpression().propertyChanged(this, VALUE_PROPERTY, oldValue, value);
}
public String displayString()
{
return "\"" + getValue() +"\"";
}
public void toString(StringBuffer sb)
{
super.toString(sb);
sb.append("type = ");
sb.append(getLiteralType().typeName());
sb.append(", value = ");
sb.append(getValue());
}
//Persistence
public static XMLDescriptor buildDescriptor()
{
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWLiteralArgument.class);
descriptor.getInheritancePolicy().setParentClass(MWArgument.class);
// 1:1 - type
XMLCompositeObjectMapping typeMapping = new XMLCompositeObjectMapping();
typeMapping.setAttributeName("type");
typeMapping.setReferenceClass(MWTypeDeclaration.class);
typeMapping.setXPath("type");
descriptor.addMapping(typeMapping);
// DTF Object value
XMLDirectMapping valueMapping = (XMLDirectMapping)descriptor.addDirectMapping("value", "value/text()");
valueMapping.setNullValue("");
return descriptor;
}
//Conversion to Runtime
Expression runtimeExpression(ExpressionBuilder builder) {
return new ConstantExpression(value(), builder);
}
private Object value() {
Class nullClass = null;
try {
nullClass = Class.forName(getLiteralType().typeName());
}
catch (ClassNotFoundException cnfe) {
// can't do anything with it, just don't do anything
return null;
}
ConversionManager cm = ConversionManager.getDefaultManager();
try {
return cm.convertObject(this.value, nullClass);
}
catch (ConversionException ce) {
// can't do anything with it, just don't do anything
return null;
}
}
static MWLiteralArgument convertFromRuntime(MWBasicExpression bldrExpression, ConstantExpression runtimeExpression) {
Object value = runtimeExpression.getValue();
MWClass type = bldrExpression.typeNamed(value.getClass().getName());
MWLiteralArgument argument = new MWLiteralArgument(bldrExpression);
argument.setType(new MWTypeDeclaration(argument, type));
argument.setValue((String) value);
return argument;
}
protected void addProblemsTo(List currentProblems) {
super.addProblemsTo(currentProblems);
Class literalTypeClass = null;
try {
literalTypeClass = Class.forName(getLiteralType().typeName());
}
catch (ClassNotFoundException cnfe) {
//this should never happen, the list of types are all java classes
}
ConversionManager cm = ConversionManager.getDefaultManager();
try {
cm.convertObject(this.value, literalTypeClass);
}
catch (ConversionException ce) {
currentProblems.add(buildProblemForConversionException(literalTypeClass));
//add a problem, value is not in the correct format for the given type.
//should have a separate problem message for every type
}
}
private Problem buildProblemForConversionException(Class javaClass) {
String javaClassName = javaClass.getName();
String lineNumber = getBasicExpression().getIndex();
String queryName = getBasicExpression().getParentQuery().getName();
if (javaClass == Boolean.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_BOOLEAN_FORMAT,
lineNumber,
queryName,
javaClassName);
}
else if (javaClass == Character.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_CHARACTER_FORMAT,
lineNumber,
queryName,
javaClassName);
}
else if (javaClass == Short.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_NUMBER_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Short.MIN_VALUE),
NumberFormat.getInstance().format(Short.MAX_VALUE)});
}
else if (javaClass == Byte.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_BYTE_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Byte.MIN_VALUE),
NumberFormat.getInstance().format(Byte.MAX_VALUE)});
}
else if (javaClass == Float.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_NUMBER_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Float.MIN_VALUE),
NumberFormat.getInstance().format(Float.MAX_VALUE)});
}
else if (javaClass == Double.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_NUMBER_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Double.MIN_VALUE),
NumberFormat.getInstance().format(Double.MAX_VALUE)});
}
else if (javaClass == Integer.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_NUMBER_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Integer.MIN_VALUE),
NumberFormat.getInstance().format(Integer.MAX_VALUE)});
}
else if (javaClass == Long.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_NUMBER_FORMAT,
new Object[] {lineNumber,
queryName,
javaClassName,
NumberFormat.getInstance().format(Long.MIN_VALUE),
NumberFormat.getInstance().format(Long.MAX_VALUE)});
}
else if (javaClass == String.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_STRING_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.math.BigDecimal.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_BIGDECIMAL_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.math.BigInteger.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_BIGINTEGER_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.sql.Date.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_SQLDATE_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.sql.Time.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_SQLTIME_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.sql.Timestamp.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_SQLTIMESTAMP_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.util.Date.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_UTILDATE_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == java.util.Calendar.class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_UTILCALENDAR_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == byte[].class || javaClass == Byte[].class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_BYTEARRAY_FORMAT, lineNumber, queryName, javaClassName);
}
else if (javaClass == char[].class || javaClass == Character[].class) {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_CHARARRAY_FORMAT, lineNumber, queryName, javaClassName);
}
else {
return buildProblem(ProblemConstants.LITERAL_ARGUMENT_ILLEGAL_GENERIC_FORMAT, lineNumber, queryName);
}
}
}