 /* Copyright (c) 2007 Pentaho Corporation.  All rights reserved. 
 * This software was developed by Pentaho Corporation and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Pentaho 
 * Data Integration.  The Initial Developer is Pentaho Corporation.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.*/

 

package org.pentaho.di.compatibility;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.pentaho.di.core.Const;

/**
 * This class contains a Value of type String and the length by which it is described.
 * 
 * @author Matt
 * @since 15-10-2004
 *
 */
public class ValueString implements ValueInterface, Cloneable
{
	private String string;
	private int length;
	private static SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS", Locale.US);

	public ValueString()
	{
		string = null;
		length = -1;
	}
	public ValueString(String string)
	{
		this.string = string;
		length = -1;
	}

	public int getType()
	{
		return Value.VALUE_TYPE_STRING;
	}

	public String getTypeDesc()
	{
		return "String";
	}

	public String getString()
	{
		return this.string;
	}

	public double getNumber()
	{
		return Const.toDouble( string, 0.0);
	}

	public Date getDate()
	{
	    if (string!=null)
	    {
//	    	Tom modified this for performance
//			SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
			try
			{
				return df.parse(string);
			}
			catch(ParseException e)
			{
			}
	    }
	    return null;
	}

	public boolean getBoolean()
	{
		return "Y".equalsIgnoreCase(string) || "TRUE".equalsIgnoreCase(string) || "YES".equalsIgnoreCase(string) || "1".equalsIgnoreCase(string);
	}

	public long getInteger()
	{
		return Const.toLong(Const.ltrim(string), 0L); // Remove the leading space to make "int to string to int" conversion possible.
	}
	
	public void    setString(String string)
	{
		this.string = string;
	}
	
	public void    setNumber(double number)
	{
		this.string = ""+number;
	}
	
	public void    setDate(Date date)
	{
		//Tom modified this for performance
//		SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
		this.string = df.format(date);
	}
	
	public void    setBoolean(boolean bool)
	{
		this.string = bool?"Y":"N";
	}
	
	public void    setInteger(long number)
	{
		this.string = ""+number;
	}
	
	public int getLength()
	{
		return length;
	}
	
	public int getPrecision()
	{
		return -1;
	}
	
	public void setLength(int length, int precision)
	{
		this.length = length;
	}
	
	public void setLength(int length)
	{
		this.length = length;
	}
	
	public void setPrecision(int precision)
	{
	}

	public Object clone()
	{
		try
		{
			ValueString retval   = (ValueString)super.clone();
			return retval;
		}
		catch(CloneNotSupportedException e)
		{
			return null;
		}
	}
    
    public BigDecimal getBigNumber()
    {
        if (Const.isEmpty(string)) return null;
        
        // Localise , to .
        if (Const.DEFAULT_DECIMAL_SEPARATOR!='.')
        {
            string = string.replace(Const.DEFAULT_DECIMAL_SEPARATOR, '.');
        }
        
        return new BigDecimal(string);
    }
    
    public void setBigNumber(BigDecimal number)
    {
        string = number.toString();
    }
    
    public Serializable getSerializable() {
        return string;
    }

    public void setSerializable(Serializable ser) {
        ser.toString();
    }

	public byte[] getBytes() {
        if (string==null) return null;
        
        char arr[] = string.toCharArray();
        byte retByte[] = new byte[arr.length];
        
        for (int i = 0; i < arr.length; i++)
        {
        	// only take low byte of char.
        	retByte[i] = (byte)(arr[i] & 0xFF);
        }
        return retByte;
	}

	public void setBytes(byte[] b) {
		try
		{
            string = new String(b, "US-ASCII");
		}
		catch (UnsupportedEncodingException e)
		{
			// we should not get here, ASCII is a mandatory encoding
		    string = null;
		}
	}    
}

@@ -975,33 +975,8 @@
 ate;
-%0Aimport java.util.Locale;
 %0A%0Aim
@@ -1255,16 +1255,20 @@
  length;
+%0D%0A%09%0D
 %0A%09privat
@@ -1276,37 +1276,129 @@
  static 
-SimpleDateFormat df =
+final ThreadLocal  LOCAL_SIMPLE_DATE_PARSER = new ThreadLocal() %7B%0D%0A%09%09protected Object initialValue() %7B%0D%0A%09%09%09return
  new Sim
@@ -1440,20 +1440,26 @@
 SSS%22
-, Locale.US)
+);%0D%0A     %09%7D%0D%0A    %7D
 ;%0A%0A%09
@@ -1905,151 +1905,82 @@
   %7B%0A
-//%09    %09Tom modified this for performance%0A//%09%09%09SimpleDateFormat df = new SimpleDateFormat(%22yyyy/MM/dd HH:mm:ss.SSS%22);%0A%09%09%09try%0A%09%09%09%7B%0A%09%09%09%09return df
+%09%09%09try%0A%09%09%09%7B%0D%0A%09%09%09%09return ((SimpleDateFormat)LOCAL_SIMPLE_DATE_PARSER.get())
 .par
@@ -2593,137 +2593,72 @@
 %7B%0A%09%09
-//Tom modified this for performance%0A//%09%09SimpleDateFormat df = new SimpleDateFormat(%22yyyy/MM/dd HH:mm:ss.SSS%22);%0A%09%09this.string = df
+this.string = ((SimpleDateFormat)LOCAL_SIMPLE_DATE_PARSER.get())
 .for
@@ -4479,9 +4479,8 @@
 %09%7D    %0A%7D
-%0A

Make SimpleDateFormat threadsafe in ValueString