/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.common.utils; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.util.Arrays; import java.util.regex.Pattern; /** * Common utility methods for handling and visualising literal values. * * @author Tuukka Lehtonen * * PROBLEMS: * - ProCore does not support zero length vectors at the moment * - String[] literals could be parsed from a String assuming a StringMemento String serialization. */ public final class Literals { final private static Pattern comma = Pattern.compile(","); private static int precision = 8; // public static final boolean[] FALSE = { false }; // // public static final boolean[] TRUE = { true }; public static int getPrecision() { return precision; } public static void setPrecision(int precision) { Literals.precision = precision; } private static String formattedDouble(double a) { try { BigDecimal dec = new BigDecimal(String.valueOf(a), new MathContext(precision, RoundingMode.HALF_UP)); dec = dec.stripTrailingZeros(); if(dec.scale() < 1) dec = dec.setScale(1); return dec.toString(); } catch (NumberFormatException e) { return "Invalid Value"; } } public static String toString(double[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { b.append(formattedDouble(a[i])); if (i == iMax) return b.append(']').toString(); b.append(", "); } } /** * Convert a literal object (of any allowed type) into to a String. * * @param literal * @return * @throws IllegalArgumentException */ public static String literalToString(Object literal) throws IllegalArgumentException { Class literalClass = literal.getClass(); if (literalClass == String.class) { return (String)literal; } else if (literalClass == Double.class) { return literal.toString(); } else if (literalClass == Float.class) { return literal.toString(); } else if (literalClass == Long.class) { return literal.toString(); } else if (literalClass == Integer.class) { return literal.toString(); } else if (literalClass == Byte.class) { return literal.toString(); } else if (literalClass == Boolean.class) { return literal.toString(); } else if (literalClass == String[].class) { return literalToString((String[]) literal); } else if (literalClass == double[].class) { return literalToString((double[]) literal); } else if (literalClass == float[].class) { return literalToString((float[]) literal); } else if (literalClass == long[].class) { return literalToString((long[]) literal); } else if (literalClass == int[].class) { return literalToString((int[]) literal); } else if (literalClass == byte[].class) { return literalToString((byte[]) literal); } else if (literalClass == boolean[].class) { return literalToString((boolean[]) literal); } throw new IllegalArgumentException(String.format("Literal object type not recognized: %s", literal.getClass().getName())); } public static String shortString(Object original) { if(original.toString().length() > 100) return original.toString().substring(0, 99) + "..."; else return original.toString(); } public static String literalToString(boolean[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(byte[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(int[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(long[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(float[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(double[] l) throws IllegalArgumentException { return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } public static String literalToString(String[] l) throws IllegalArgumentException { // FIXME BEWARE!!! THIS BREAKS UP WITH STRINGS CONTAINING ',' CHARACTERS return l.length == 1 ? String.valueOf(l[0]) : Arrays.toString(l); } // /** // * Convert a literal object (of any allowed type) into to a String. // * // * @param literal a literal as string // * @return the same literal as its native type // * @throws IllegalArgumentException // */ // public static Object stringToLiteral(Graph g, Resource property, String literal) throws IllegalArgumentException, ResourceNotFoundException { // if (property == null) // throw new IllegalArgumentException("null property"); // if (literal == null) // throw new IllegalArgumentException("null literal string"); // // // Attempt to parse the property value by its type. // if (g.isInstanceOf(property, g.getBuiltins().Double)) { // return parseDoubleLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().Float)) { // return parseFloatLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().Long)) { // return parseLongLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().Integer)) { // return parseIntegerLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().Byte)) { // return parseByteLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().Boolean)) { // return parseBooleanLiteral(literal); // } else if (g.isInstanceOf(property, g.getBuiltins().String)) { // return parseStringLiteral(literal); // } // // throw new IllegalArgumentException("unrecognized property type for resource"); // } /** * @param literal * @return * @throws IllegalArgumentException if the parsing fails */ public static boolean[] parseBooleanLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); boolean[] result = new boolean[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Boolean.parseBoolean(parts[i]); return result; } catch(NumberFormatException e) { throw new IllegalArgumentException("Invalid boolean value: " + literal, e); } } /** * @param literal * @return * @throws IllegalArgumentException if the parsing fails */ public static double[] parseDoubleLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); // " " would be more common delimiter for primitive arrays since // it is also default delimiter in XML documents double result[] = new double[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Double.parseDouble(parts[i]); return result; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid double value: " + literal, e); } } /** * @param literal * @return * @throws IllegalArgumentException if the parsing fails */ public static int[] parseIntegerLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); int result[] = new int[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Integer.parseInt(parts[i]); return result; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid integer value: " + literal, e); } } public static byte[] parseByteLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); byte result[] = new byte[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Byte.parseByte(parts[i]); return result; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid byte value: " + literal, e); } } public static long[] parseLongLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); long result[] = new long[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Long.parseLong(parts[i]); return result; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid long value: " + literal, e); } } public static float[] parseFloatLiteral(String literal) { literal = trimLiteralString(literal); try { String parts[] = comma.split(literal); float result[] = new float[parts.length]; for (int i = 0; i < parts.length; i++) result[i] = Float.parseFloat(parts[i]); return result; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid float value: " + literal, e); } } private static String[] parseStringLiteral(String literal) { // TODO: support StringMemento serialized literals! return new String[] {literal}; } private static String trimLiteralString(String literal) { // First trim the literal to make the input more canonical. // Also remove possible '[' and ']' prefix and suffix. literal = literal.trim(); if (literal.startsWith("[")) literal = literal.substring(1); if (literal.endsWith("]")) literal = literal.substring(0, literal.length() - 1); return literal; } }