/* * © Copyright FOCONIS AG, 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * */ package org.openntf.formula; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Valueholder to hold single or multiple values. * * When evaluating a formula, every String/int/double value is wrapped in a "ValueHolder". The holder has several get-methods to return the * different types. You always must check the datatype before calling one of the getters, because a ValueHolder that contains Strings cannot * return * * The code itself might look strange, but this was done to be as fast as possible * * @author Roland Praml, Foconis AG * */ public class ValueHolderObject<T> extends ValueHolder implements Serializable { private static final long serialVersionUID = 8290517470597891417L; private final Object values[]; ValueHolderObject(final int size) { values = new Object[size]; } /** * Returns the object @ * */ @SuppressWarnings("unchecked") @Override public T getObject(final int i) { switch (dataType) { case _UNSET: return null; case ERROR: case BOOLEAN: case DOUBLE: case INTEGER: throw new IllegalStateException(dataType + " is not supported here"); default: if (i < size) return (T) values[i]; return (T) values[size - 1]; } } /** * Returns the object as String */ @Override public String getString(final int i) { switch (dataType) { case KEYWORD_STRING: case STRING: if (i < size) return (String) values[i]; return (String) values[size - 1]; default: throw new ClassCastException("STRING expected. Got '" + dataType + "'"); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#getDateTime(int) */ @Override public DateTime getDateTime(final int i) { switch (dataType) { case DATETIME: if (i < size) return (DateTime) values[i]; return (DateTime) values[size - 1]; default: throw new ClassCastException("DATETIME expected. Got '" + dataType + "'"); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#add(java.lang.String) */ @Override public boolean add(final String obj) { switch (dataType) { case _UNSET: dataType = DataType.STRING; case KEYWORD_STRING: case STRING: case OBJECT: values[size++] = obj; return true; default: return super.add(obj); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#add(org.openntf.domino.ISimpleDateTime) */ @Override public boolean add(final DateTime dateTime) { switch (dataType) { case _UNSET: dataType = DataType.DATETIME; case DATETIME: case OBJECT: values[size++] = dateTime; return true; default: return super.add(dateTime); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#add(java.lang.Object) */ @Deprecated @Override public boolean add(final Object obj) { if (obj instanceof String) return add((String) obj); if (obj instanceof DateTime) return add((DateTime) obj); switch (dataType) { case _UNSET: dataType = DataType.OBJECT; case OBJECT: values[size++] = obj; return true; default: return super.add(obj); } } @Override public boolean addAll(final ValueHolder other) { checkImmutable(); //System.out.println("Adding " + other.dataType + " to " + dataType); switch (other.dataType) { case _UNSET: return false; // we do not add unset case DOUBLE: case INTEGER: case BOOLEAN: return super.addAll(other); default: if (dataType == DataType._UNSET) dataType = other.dataType; if (dataType == DataType.OBJECT || dataType == other.dataType) { @SuppressWarnings("unchecked") ValueHolderObject<T> toAdd = (ValueHolderObject<T>) other; System.arraycopy(toAdd.values, 0, values, size, toAdd.size); size += other.size; return true; } return super.addAll(other); } } @Override public List<Object> toList() throws EvaluateException { throwError(); List<Object> ret = new ArrayList<Object>(size); for (int i = 0; i < size; i++) { ret.add(values[i]); } return ret; } @Override public ValueHolder newInstance(final int size) { return new ValueHolderObject<Object>(size); } @Override public void swap(final int i, final int j) { Object tmp = values[i]; values[i] = values[j]; values[j] = tmp; } @Override public String quoteValue() { StringBuilder sb = new StringBuilder(); if (dataType == DataType.KEYWORD_STRING) { sb.append(getString(0)); for (int i = 1; i < values.length; i++) { sb.append(':'); sb.append(getString(i)); } } else { sb.append(quote(getString(0))); for (int i = 1; i < values.length; i++) { sb.append(':'); sb.append(quote(getString(i))); } } return sb.toString(); } // TODO: is this really correct private String quote(String s) { s = s.replace("\\", "\\\\"); return "\"" + s.replace("\"", "\\\"") + "\""; } }