/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * DefaultValueNodeTransformer.java * Creation date: (19/07/01 1:14:39 PM) * By: Michael Cheng */ package org.openquark.cal.valuenode; import java.text.ParseException; import org.openquark.cal.compiler.PreludeTypeConstants; import org.openquark.cal.compiler.TypeExpr; import com.ibm.icu.text.DateFormat; /** * Default ValueNodeTransformer used to transform (transfer data) between ValueNodes. * Creation date: (19/07/01 1:14:39 PM) * @author Michael Cheng */ public class DefaultValueNodeTransformer implements ValueNodeTransformer { /** * DefaultValueNodeTransformer constructor. */ public DefaultValueNodeTransformer() { super(); } /** * Will return a new ValueNode ideally suited for handling targetTypeExpr. * If the sourceVN and the returned ValueNode are of a recognized 'data transferable' * combination, then the sourceVN's data value will be moved to the returned ValueNode * (perhaps with some minor mutations like rounding numbers). * Note: It is assumed that Int and Double types will always be handled by LiteralValueNode. * Currently, we recognize the following: * LiteralValueNode (double) -> LiteralValueNode (int) * LiteralValueNode (int) -> LiteralValueNode (double) * RelativeDateTimeValueNode -> RelativeDateValueNode * RelativeDateTimeValueNode -> RelativeTimeValueNode * Also, we do some conversions involving Strings. * @param valueNodeBuilderHelper * @param sourceVN * @param destTypeExpr * @return ValueNode */ public ValueNode transform(ValueNodeBuilderHelper valueNodeBuilderHelper, ValueNode sourceVN, TypeExpr destTypeExpr) { TypeExpr sourceTypeExpr = sourceVN.getTypeExpr(); // check if we're "transforming" to the same type if (sourceTypeExpr.sameType(destTypeExpr)) { return sourceVN.copyValueNode(destTypeExpr); } Object newValue = null; Class<? extends ValueNode> handlerClass = valueNodeBuilderHelper.getValueNodeClass(destTypeExpr); PreludeTypeConstants typeConstants = valueNodeBuilderHelper.getPreludeTypeConstants(); if (handlerClass.equals(ListOfCharValueNode.class) || destTypeExpr.sameType(typeConstants.getStringType())) { if (sourceVN instanceof ListValueNode && sourceVN.getTypeExpr().sameType(typeConstants.getCharListType())) { // Converting a List to a List of Char: we convert each of the list values ListValueNode listValueNode = (ListValueNode)sourceVN; StringBuilder sb = new StringBuilder(); int nElements = listValueNode.getNElements(); for (int i = 0; i < nElements; i++) { sb.append(listValueNode.getValueAt(i).getCALValue()); } newValue = sb.toString(); } else { newValue = sourceVN.getTextValue(); } } else if (destTypeExpr.sameType(typeConstants.getCharType())) { // Just take the first character of the text value (if any) String textValue = sourceVN.getTextValue(); if (textValue.length() != 0) { newValue = Character.valueOf(textValue.charAt(0)); } } if (sourceVN instanceof LiteralValueNode && !sourceVN.getTypeExpr().sameType(typeConstants.getStringType())) { LiteralValueNode sourceLiteralVN = (LiteralValueNode) sourceVN; if (sourceTypeExpr.sameType(typeConstants.getDoubleType()) && destTypeExpr.sameType(typeConstants.getIntType())) { newValue = Integer.valueOf((int) Math.round(sourceLiteralVN.getDoubleValue().doubleValue())); } else if (sourceTypeExpr.sameType(typeConstants.getIntType()) && destTypeExpr.sameType(typeConstants.getDoubleType())) { newValue = Double.valueOf(sourceLiteralVN.getIntegerValue().intValue()); } } else if (sourceVN instanceof RelativeDateTimeValueNode) { RelativeDateTimeValueNode sourceDateTimeVN = (RelativeDateTimeValueNode) sourceVN; if (handlerClass.equals(RelativeDateValueNode.class) || handlerClass.equals(RelativeTimeValueNode.class)) { // TEMP: May need to copy. newValue = sourceDateTimeVN.getDateTimeValue(); } } else if (sourceVN instanceof ListOfCharValueNode || sourceVN.getTypeExpr().sameType(typeConstants.getStringType())) { String stringVal = sourceVN instanceof ListOfCharValueNode ? ((ListOfCharValueNode)sourceVN).getStringValue() : ((LiteralValueNode)sourceVN).getStringValue(); if (handlerClass.equals(RelativeDateValueNode.class)) { DateFormat dateFormat = RelativeTemporalValueNode.getDateFormat(DateFormat.FULL, -1); try { newValue = dateFormat.parse(stringVal); } catch (ParseException pe) { // Okay, can't parse. Don't transform. } } else if (handlerClass.equals(RelativeTimeValueNode.class)) { DateFormat timeFormat = RelativeTemporalValueNode.getDateFormat(-1, DateFormat.MEDIUM); try { newValue = timeFormat.parse(stringVal); } catch (ParseException pe) { // Okay, can't parse. Don't transform. } } else if (handlerClass.equals(RelativeDateTimeValueNode.class)) { DateFormat dateTimeFormat = RelativeTemporalValueNode.getDateFormat(DateFormat.FULL, DateFormat.MEDIUM); try { newValue = dateTimeFormat.parse(stringVal); } catch (ParseException pe) { // Okay, can't parse. Don't transform. } } else if (handlerClass.equals(LiteralValueNode.class)) { if (destTypeExpr.sameType(typeConstants.getDoubleType())) { try { newValue = Double.valueOf(stringVal); } catch (NumberFormatException e) { // Okay, can't parse. Don't transform. } } else if (destTypeExpr.sameType(typeConstants.getIntType())) { try { Double unRoundedVal = Double.valueOf(stringVal); newValue = Integer.valueOf(unRoundedVal.intValue()); } catch (NumberFormatException e) { // Okay, can't parse. Don't transform. } } else if (destTypeExpr.sameType(typeConstants.getCharType())) { // Only transform when there's only 1 character in stringVal. if (stringVal.length() == 1) { newValue = Character.valueOf(stringVal.charAt(0)); } } else if (destTypeExpr.sameType(typeConstants.getBooleanType())) { // Let's be forgiving, and allow case insensitivity. if (stringVal.equalsIgnoreCase("True")) { newValue = Boolean.TRUE; } else if (stringVal.equalsIgnoreCase("False")) { newValue = Boolean.FALSE; } } } } return valueNodeBuilderHelper.buildValueNode(newValue, null, destTypeExpr); } }