/*******************************************************************************
* 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.internal.expressions;
import java.io.*;
import java.util.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
/**
* Used for wrapping constant values.
*/
public class ConstantExpression extends Expression {
protected Object value;
protected Expression localBase;
public ConstantExpression() {
super();
}
public ConstantExpression(Object newValue, Expression baseExpression) {
super();
value = newValue;
localBase = baseExpression;
}
/**
* INTERNAL:
* Return if the expression is equal to the other.
* This is used to allow dynamic expression's SQL to be cached.
*/
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!super.equals(object)) {
return false;
}
ConstantExpression expression = (ConstantExpression) object;
return ((getValue() == expression.getValue()) || ((getValue() != null) && getValue().equals(expression.getValue())));
}
/**
* INTERNAL:
* Compute a consistent hash-code for the expression.
* This is used to allow dynamic expression's SQL to be cached.
*/
public int computeHashCode() {
int hashCode = super.computeHashCode();
if (getValue() != null) {
hashCode = hashCode + getValue().hashCode();
}
return hashCode;
}
/**
* INTERNAL:
* Used for debug printing.
*/
public String descriptionOfNodeType() {
return "Constant";
}
/**
* Return the expression builder which is the ultimate base of this expression, or
* null if there isn't one (shouldn't happen if we start from a root)
*/
public ExpressionBuilder getBuilder() {
if(this.localBase != null) {
return this.localBase.getBuilder();
} else {
return null;
}
}
public Expression getLocalBase() {
return localBase;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public boolean isConstantExpression() {
return true;
}
/**
* INTERNAL:
*/
public boolean isValueExpression() {
return true;
}
/**
* INTERNAL:
* Normalize collection of values if they are expressions.
* or collection of collection expressions.
*/
public Expression normalize(ExpressionNormalizer normalizer) {
super.normalize(normalizer);
if (value == null)
return this;
if (value instanceof Collection) {
normalizeValueList(normalizer, (Collection)value);
}
return this;
}
private void normalizeValueList(ExpressionNormalizer normalizer, Collection valueCollection) {
for (Object obj : valueCollection) {
if (obj instanceof Collection) {
normalizeValueList(normalizer, (Collection)obj);
} else if (obj instanceof Expression) {
((Expression)obj).normalize(normalizer);
}
}
}
/**
* INTERNAL:
* Used for cloning.
*/
protected void postCopyIn(Map alreadyDone) {
super.postCopyIn(alreadyDone);
localBase = localBase.copiedVersionFrom(alreadyDone);
}
/**
* INTERNAL:
* Print SQL onto the stream, using the ExpressionPrinter for context
*/
public void printSQL(ExpressionSQLPrinter printer) {
Object value = getLocalBase().getFieldValue(getValue(), getSession());
if(value == null) {
printer.printNull(this);
} else {
printer.printPrimitive(value);
}
}
/**
* INTERNAL:
* Print java for project class generation
*/
public void printJava(ExpressionJavaPrinter printer) {
printer.printJava(getValue());
}
/**
* INTERNAL:
* This expression is built on a different base than the one we want. Rebuild it and
* return the root of the new tree
*/
public Expression rebuildOn(Expression newBase) {
Expression result = (ConstantExpression)clone();
result.setLocalBase(getLocalBase().rebuildOn(newBase));
return result;
}
/**
* INTERNAL:
* Search the tree for any expressions (like SubSelectExpressions) that have been
* built using a builder that is not attached to the query. This happens in case of an Exists
* call using a new ExpressionBuilder(). This builder needs to be replaced with one from the query.
*/
public void resetPlaceHolderBuilder(ExpressionBuilder queryBuilder){
return;
}
public void setLocalBase(Expression e) {
localBase = e;
}
/**
* INTERNAL:
* Rebuild myself against the base, with the values of parameters supplied by the context
* expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping)
* into part of some larger expression. You normally would not call this directly, instead calling twist
* See the comment there for more details"
*/
@Override
public Expression twistedForBaseAndContext(Expression newBase, Expression context, Expression oldBase) {
return this;
}
/**
* INTERNAL:
* Return the value for in memory comparison.
* This is only valid for valueable expressions.
*/
public Object valueFromObject(Object object, AbstractSession session, AbstractRecord translationRow, int valueHolderPolicy, boolean isObjectUnregistered) {
// PERF: direct-access.
return this.localBase.getFieldValue(this.value, session);
}
/**
* INTERNAL:
* Used to print a debug form of the expression tree.
*/
public void writeDescriptionOn(BufferedWriter writer) throws IOException {
writer.write(String.valueOf(getValue()));
}
/**
* INTERNAL:
* Append the constant value into the printer
*/
@Override
public void writeFields(ExpressionSQLPrinter printer, Vector newFields, SQLSelectStatement statement) {
if (printer.getPlatform().isDynamicSQLRequiredForFunctions()) {
printer.getCall().setUsesBinding(false);
}
//print ", " before each selected field except the first one
if (printer.isFirstElementPrinted()) {
printer.printString(", ");
} else {
printer.setIsFirstElementPrinted(true);
}
// This field is a constant value, so any name can be used.
newFields.addElement(new DatabaseField("*"));
printSQL(printer);
}
}