All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.xma.mdl.Atom Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * 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:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: Atom.java 2298 2008-01-30 08:49:08Z s3460 $
package at.spardat.xma.mdl;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;

import at.spardat.enterprise.fmt.IFmt;
import at.spardat.enterprise.util.DateUtil;
import at.spardat.enterprise.util.NumberUtil;
import at.spardat.enterprise.util.StringUtil;
import at.spardat.enterprise.util.TimeStampUtil;
import at.spardat.enterprise.util.Types;
import at.spardat.xma.mdl.util.DNode;
import at.spardat.xma.mdl.util.Descriptive;
import at.spardat.xma.serializer.XmaInput;
import at.spardat.xma.serializer.XmaOutput;
import at.spardat.xma.test.TestUtil;

/**
 * This class is an immutable implementation of the {@link IAtomic} interface.
 * Sinces is immutable, this class provides a set of type specific constructors
 * and a set of static objects that may be used for empty Atom of the
 * various types.
 *
 * @author YSD, 12.04.2003 22:37:08
 */
public class Atom implements Comparable, Descriptive, IAtomic {

    /**
     * Empty Atom of type T_STRING
     */
    public static final Atom        EMPTY_STRING = new Atom (Types.T_STRING);

    /**
     * Empty Atom of type T_BCD
     */
    public static final Atom        EMPTY_BCD = new Atom (Types.T_BCD);

    /**
     * Empty Atom of type T_DATE
     */
    public static final Atom        EMPTY_DATE = new Atom (Types.T_DATE);

    /**
     * Empty Atom of type T_TIMESTAMP
     */
    public static final Atom        EMPTY_TIMESTAMP = new Atom (Types.T_TIMESTAMP);

    /**
     * Empty Atom of type T_BOOLEAN
     */
    public static final Atom        EMPTY_BOOLEAN = new Atom (Types.T_BOOLEAN);

    /**
     * Empty Atom of type T_DOM
     */
    public static final Atom        EMPTY_DOM = new Atom (Types.T_DOM);

    /**
     * One of the type codes in enterprise.util.Types.
     */
    protected byte                  type_;

    /**
     * A string encoded value of a particular type. This instance is never null.
     */
    protected String                value_ = "";






    /**
     * Constructor for internal use. Do not call it!!!!
     */
    public Atom () {
    }

    /**
     * Internal constructor to get an empty Atom.
     *
     * @param type see {@link at.spardat.enterprise.util.Types Types}
     */
    private Atom (byte type) {
        type_ = type;
    }

    /**
     * Constructs an Atom with type T_STRING and the provided value.
     *
     * @param s the value to set
     * @exception IllegalArgumentException if argument null
     */
    public Atom (String s) {
        if (s == null) throw new IllegalArgumentException();
        type_ = Types.T_STRING;
        value_ = s;
        if (s == null) value_ = "";
    }

    /**
     * Constructs an atom by providing its instance variables. 

* * You may only use this method if you are working with formatters * at.spardat.enterprise.fmt.IFmt and need to construct * an Atom from an formatter-internal encoding. * * @param type the type code * @param internalValue the internally stored string encoding of the type. * @return newly created Atom */ public static Atom newInstance (byte type, String internalValue) { Atom toReturn = new Atom (type); toReturn.value_ = internalValue; return toReturn; } /** * Constructs an atom from various java types. * * @param o must be of the types String, Boolean, Folat, Double, Date, * Byte, Short, Integer, Long * @return Atom of type T_STRING, T_BOOLEAN, T_BCD or T_DATE * @exception IllegalArgumentException if Object is of unsupported type */ public static Atom newInstance (Object o) { if (o == null) throw new IllegalArgumentException(); if (o instanceof String) return new Atom ((String)o); if (o instanceof Boolean) return new Atom (((Boolean)o).booleanValue()); if (o instanceof Double) return new Atom (((Double)o).doubleValue()); if (o instanceof Timestamp) return new Atom (Types.T_TIMESTAMP, (Timestamp)o); if (o instanceof Date) return new Atom (Types.T_DATE, (Date)o); if (o instanceof Byte) return new Atom ((int)(((Byte)o).byteValue())); // important: do not call the byte constructor; that just sets the type if (o instanceof Short) return new Atom (((Short)o).shortValue()); if (o instanceof Integer) return new Atom (((Integer)o).intValue()); if (o instanceof Long) return new Atom (((Long)o).longValue()); if (o instanceof Float) return new Atom (((Float)o).doubleValue()); if (o instanceof BigDecimal) return new Atom (((BigDecimal)o)); if (o instanceof Atom) return (Atom)o; throw new IllegalArgumentException(o.getClass().getName()); } /** * Randomly contructs an Atom and returns it. */ public static Atom newRandomInstance () { int type = TestUtil.randomInt(0, 4); switch (type) { case 0: if (TestUtil.draw(0.1)) return EMPTY_STRING; else return new Atom (TestUtil.randomString(TestUtil.randomInt(0, 10))); case 1: if (TestUtil.draw(0.1)) return EMPTY_BOOLEAN; if (TestUtil.draw(0.5)) return new Atom (true); return new Atom(false); case 2: if (TestUtil.draw(0.1)) return EMPTY_BCD; if (TestUtil.draw(0.2)) return new Atom (0.0); else return new Atom (TestUtil.randomDouble(-100000.0, 100000.0) / Math.pow(10.0, TestUtil.randomInt(0, 5))); case 3: if (TestUtil.draw(0.1)) return EMPTY_DATE; else return new Atom (Types.T_DATE, new java.util.Date()); case 4: if (TestUtil.draw(0.1)) return EMPTY_TIMESTAMP; else return new Atom (Types.T_TIMESTAMP, new java.util.Date()); } return null; } /** * Constructs a T_BCD Atom. * * @param value the numeric value to set. * @param numNK number of digits after the comma to be used * when the provided double is converted to a String * (which has to be done since Atoms are * string encoded). If numNK * equals -1, the number of the resulting places * after the comma is unknown. */ public Atom (double value, int numNK) { type_ = Types.T_BCD; if (Double.isInfinite(value) || Double.isNaN(value)) value_ = ""; else { BigDecimal bigDec = new BigDecimal(value); if (numNK != -1 && numNK >= 0) { // round the value to numNK places after the comma bigDec = bigDec.setScale(numNK, BigDecimal.ROUND_HALF_UP); value_ = bigDec.toString(); } else { value_ = NumberUtil.double2String(value); } } } /** * Constructs a T_BCD Atom from a double. The resulting value * of this is empty if value is NaN or Infinity. * If the provided value cannot trivially be converted to * a string, because its numeric (binary coded) value would * result in a very long (decimally coded) String, * digits after the comma are reduced so that the total number of * significant digits does not exceed 15 digits. * * @param value the input double value */ public Atom (double value) { type_ = Types.T_BCD; value_ = NumberUtil.double2String(value); } /** * Constructs an T_BCD Atom from an BigDecimal. * * @param value the BigDecimal providing the numeric value. */ public Atom (BigDecimal value) { type_ = Types.T_BCD; if (value == null) { value_ = ""; } else { value_ = value.toString(); } } /** * Constructs a T_BCD Atom from an int. The resulting value * of this is never empty. * * @param value */ public Atom (int value) { type_ = Types.T_BCD; value_ = String.valueOf (value); } /** * Constructs a T_BCD Atom from a long. The resulting value * of this is never empty. * * @param value */ public Atom (long value) { type_ = Types.T_BCD; value_ = String.valueOf (value); } /** * Constructs a T_DATE or T_TIMESTAMP Atom. * * @param type may be T_DATE or T_TIMESTAMP * @param date the value of the Atom * @exception IllegalArgumentException if argument null */ public Atom (byte type, Date date) { if (date == null) throw new IllegalArgumentException(); if (type == Types.T_DATE) { type_ = Types.T_DATE; value_ = DateUtil.date2Internal(date); } else if (type == Types.T_TIMESTAMP) { type_ = Types.T_TIMESTAMP; if (date instanceof java.sql.Timestamp) value_ = TimeStampUtil.timestamp2Internal((Timestamp)date); else value_ = TimeStampUtil.date2Internal(date); } else throw new IllegalArgumentException(); } /** * Constructs a T_TIMESTAMP Atom. * * @param timeStamp the value of the Atom * @exception IllegalArgumentException if argument null */ public Atom (Timestamp timeStamp) { if (timeStamp == null) throw new IllegalArgumentException(); type_ = Types.T_TIMESTAMP; value_ = TimeStampUtil.timestamp2Internal(timeStamp); } /** * Constructs a T_BOOLEAN Atom with the provided value. * * @param value the boolean value to construct this with. */ public Atom (boolean value) { type_ = Types.T_BOOLEAN; value_ = value ? "J" : "N"; } /** * Converts this to a transport encoding string s that has the property * that an Atom created with newTransportInstance(s) is equal to this. * * @return a string in a transport encoding. If the type of this is T_STRING, * the value is delimited with double quotes. * Other types than T_STRING * start with a single character indicating the type and a type specific string * encoding. The returned string (within the quotes) does not contain quotes, * commas or semicolons. */ public String toTransportString () { StringBuffer buf = new StringBuffer(); if (type_ == Types.T_STRING) { // strings are encoded with enclosing double quotation marks; buf.append('"'); buf.append(StringUtil.encode(value_, '%')); buf.append('"'); } else { // other types start with a type character, followed by a string encoding char typeChar = (char)('A' + (type_-Types.FIRST)); buf.append(typeChar); buf.append(value_); } return buf.toString(); } /** * Constructs an Atom from a String that has been produced using toTransportString. * * @param encoded as defined in method toTransportString * @return newly created Atom. * @exception IllegalArgumentException if the argument was not created by toTransportString. */ public static Atom newTransportInstance (String encoded) { if (encoded == null || encoded.length() == 0) throw new IllegalArgumentException(); if (encoded.charAt(0) == '"') { int len = encoded.length(); // string follows if (encoded.charAt(len-1) != '"') throw new IllegalArgumentException(); return newInstance (Types.T_STRING, StringUtil.decode(encoded.substring(1, len-1), '%')); } else { // other types than string byte type = (byte)(encoded.charAt(0)-'A' + Types.FIRST); if (type < Types.FIRST || type > Types.LAST) throw new IllegalArgumentException(); return newInstance (type, encoded.substring(1)); } } /** * Returns an empty Atom having the same type as this. */ public Atom clear() { switch (type_) { case Types.T_STRING: return EMPTY_STRING; case Types.T_BCD: return EMPTY_BCD; case Types.T_DATE: return EMPTY_DATE; case Types.T_TIMESTAMP: return EMPTY_TIMESTAMP; case Types.T_BOOLEAN: return EMPTY_BOOLEAN; case Types.T_DOM: return EMPTY_DOM; } throw new InternalError (); } /** * Returns true if this Atom holds a value. * * @return true if this has a non empty value. */ public boolean hasValue() { return value_.length() > 0; } /** * Returns the type constant. * * @return the type constant. */ public byte getType() { return type_; } /** * @see IAtomic#toString() */ public String toString() { return toStringImpl (type_, value_); } /** * Returns a string representation of an IAtomic given its type * and its internal encoding.

* * This method may not be called from outside the framework. */ public static String toStringImpl (byte type, String internal) { if (type == Types.T_TIMESTAMP) { if (internal == null || internal.length() == 0) return ""; SimpleDateFormat df = new SimpleDateFormat ("yyyyMMdd HH:mm:ss.SSS z"); return df.format(TimeStampUtil.internal2Date(internal)); } else return internal; } /** * Maps this Atom to string representation using a IFmt object. * The provided formatter is only used if it is type compatible * with the type of this Atom. Otherwise, or if formatter is * null, the internal String encoding is returned. * * @param formatter the IFmt formatter. May be null. * @return non null String. */ public String toString (IFmt formatter) { if (formatter == null) return value_; if (formatter.mayBeAppliedTo(type_)) { return formatter.format(value_); } else return value_; } /** * Extracts a double from this. Returns 0.0 if getType() is not equal to T_BCD or !hasValue(). * * @return the double value of this */ public double toDouble () { if (type_ != Types.T_BCD || !hasValue()) return 0.0; return Double.parseDouble(value_); } /** * @see at.spardat.xma.mdl.IAtomic#toFloat() */ public float toFloat() { if (type_ != Types.T_BCD || !hasValue()) return 0.0F; return Float.parseFloat(value_); } /** * Requires that this is either empty or contains an integer T_BCD value. If !hasValue() * or the type of this is not T_BCD, zero is returned. * * @return the contained integer * @exception NumberFormatException if this does not fit into an int */ public int toInt () { if (type_ != Types.T_BCD || !hasValue()) return 0; return Integer.parseInt(value_); } /** * @see at.spardat.xma.mdl.IAtomic#toLong() */ public long toLong() { if (type_ != Types.T_BCD || !hasValue()) return 0; return Long.parseLong (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toByte() */ public byte toByte() { if (type_ != Types.T_BCD || !hasValue()) return 0; return Byte.parseByte (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toShort() */ public short toShort() { if (type_ != Types.T_BCD || !hasValue()) return 0; return Short.parseShort (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toBigDecimal() */ public BigDecimal toBigDecimal() { if (type_ != Types.T_BCD || !hasValue()) return null; return new BigDecimal (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toByte() */ public Byte toBYTE() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Byte (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toSHORT() */ public Short toSHORT() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Short(value_); } /** * @see at.spardat.xma.mdl.IAtomic#toINTEGER() */ public Integer toINTEGER() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Integer(value_); } /** * @see at.spardat.xma.mdl.IAtomic#toLONG() */ public Long toLONG() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Long(value_); } /** * @see at.spardat.xma.mdl.IAtomic#toFLOAT() */ public Float toFLOAT() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Float (value_); } /** * @see at.spardat.xma.mdl.IAtomic#toDOUBLE() */ public Double toDOUBLE() { if (type_ != Types.T_BCD || !hasValue()) return null; return new Double(value_); } /** * Returns a newly constructed java.util.Date object representing the value of this. * * @return null if the type is not equal to T_DATE or T_TIMESTAMP or !hasValue(). */ public Date toDate () { return toDateImpl (type_, value_); } /** * Helper method to convert date- and timestamp-atomics to java.util.Date. * This is a framework-internal method and is not intended to be called from outside. */ public static Date toDateImpl (byte type, String internal) { if (internal == null || internal.length() == 0) return null; if (type == Types.T_DATE) { return DateUtil.internal2Gregorian (internal).getTime(); } else if (type == Types.T_TIMESTAMP) { return TimeStampUtil.internal2Date(internal); } else return null; } /** * Returns true if getType() equals T_BOOLEAN and the stored value equals TRUE. If * there is no value stored or the stored value is not TRUE, false is returned. * * @return boolean indicating the value in this. */ public boolean isTrue() { if (type_ != Types.T_BOOLEAN) return false; return value_.equals("J"); } /** * Returns the estimated length of the byte stream resulting from streaming an Atom. */ public static int streamedSize (Atom a) { if (a == null) return 1; return 3 + a.value_.length(); } /** * Reads an Atom from an input stream and returns it. The returned Atom * may be null. */ public static Atom internalize (XmaInput i) throws IOException { byte type = i.readByte(); if (type == Types.FIRST-1) return null; Atom a = new Atom(); a.type_ = type; a.value_ = i.readString(); return a; } /** * Writes the state to an output stream. a may be null. */ public static void externalize (Atom a, XmaOutput o) throws IOException { if (a == null) o.writeByte("typ", Types.FIRST-1); else { o.writeByte("typ", a.type_); o.writeString("val", a.value_); } } /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo (Object o) { Atom a2 = (Atom)o; // empty atoms are the lowest if (value_.length() == 0) { // this is empty if (a2.value_.length() == 0) return 0; // both are empty return -1; // this is empty, bot not a2 } else { // this is not empty if (a2.value_.length() == 0) return 1; // but a2 is empty } // here, both are non empty switch (type_) { case Types.T_STRING: return value_.compareTo(a2.value_); case Types.T_BCD: double d1 = toDouble(), d2 = a2.toDouble(); if (d1 < d2) return -1; if (d1 > d2) return 1; return 0; case Types.T_DATE: return toDate().compareTo(a2.toDate()); case Types.T_TIMESTAMP: return toDate().compareTo(a2.toDate()); case Types.T_BOOLEAN: boolean b1 = isTrue(), b2 = a2.isTrue(); if (b1 == b2) return 0; if (b1) return 1; else return -1; case Types.T_DOM: return value_.compareTo(a2.value_); } throw new InternalError (); } /** * Returns a describing short string for a type code. */ public static String type2String (byte t) { String type = "?"; switch (t) { case Types.T_STRING: type = "STR"; break; case Types.T_BCD: type = "BCD"; break; case Types.T_DATE: type = "DAT"; break; case Types.T_TIMESTAMP: type = "TST"; break; case Types.T_BOOLEAN: type = "BOO"; break; case Types.T_DOM: type = "DOM"; break; } return type; } /** * @see at.spardat.xma.mdl.util.Descriptive#describe(at.spardat.xma.mdl.util.DNode) */ public void describe (DNode n) { n.sb() .app("type", type2String(type_)).comma() .app("value", value_) .eb(); } /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals (Object obj) { if (obj == null || !(obj instanceof Atom)) return false; Atom a = (Atom)obj; return type_ == a.type_ && value_.equals(a.value_); } /** * Estimates the number of bytes this object consumes in memory. */ public int estimateMemory () { return MemoryEstimator.sizeOfObject(2) + MemoryEstimator.sizeOf(value_); } /** * @see at.spardat.xma.mdl.IAtomic#getEncodedValue() */ public String getEncodedValue () { return value_; } /** * @see java.lang.Object#hashCode() */ public int hashCode() { return value_.hashCode() ^ type_; } // public static void main(String[] args) { // // Collator collator = Collator.getInstance(Locale.getDefault()); // //collator.setStrength(Collator.PRIMARY); // int cmp = collator.compare("abc", "ABC"); // System.out.println("cmpVal: " + cmp); // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy