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

org.eclipse.birt.core.data.DataTypeUtil Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2004, 2009 Actuate Corporation.
 * 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:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.core.data;

import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;

import java.text.ParseException;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.TimeZone;

import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.regex.Pattern;

import javax.sql.rowset.serial.SerialBlob;

import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.exception.CoreException;
import org.eclipse.birt.core.format.DateFormatter;
import org.eclipse.birt.core.i18n.ResourceConstants;
import org.eclipse.birt.core.i18n.ResourceHandle;
import org.eclipse.birt.core.script.JavascriptEvalUtil;

import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.util.ULocale;

/**
 * A utility function The convert method converts the source object, which can
 * be any supported data type, into an object given specified type. If no
 * reasonable conversion can be made, throw a BirtException.
 */
public final class DataTypeUtil
{

	// Defalult Locale, if we have any problem parse string to date for Locale.getDefault()
	// we will try to parse it for Locale.US
	private static ULocale DEFAULT_LOCALE = ULocale.US;
	private static ULocale JRE_DEFAULT_LOCALE = ULocale.getDefault( );
	private static SimpleDateFormat MysqlUSDateFormatter = new SimpleDateFormat( "M/d/yyyy HH:mm" );
	
	private static Pattern p1 = Pattern.compile( ".*[0-9]+:[0-9]+:[0-9]+.*" );
	private static Pattern p2 = Pattern.compile( ".*[0-9]+:[0-9]+.*" );
	
	// cache DateFormatter of ICU
	private static Map dfMap = new HashMap( );
	private static Map nfMap = new HashMap( );
	// Default Date/Time Style
	private static int DEFAULT_DATE_STYLE = DateFormat.FULL;

	// resource bundle for exception messages 
	public static ResourceBundle resourceBundle = ( new ResourceHandle( JRE_DEFAULT_LOCALE ) ).getUResourceBundle( );

	public static long count = 0;
	
	/**
	 * convert an object to given type
	 * Types supported:
	 * 	 	DataType.INTEGER_TYPE
	 * 		DataType.DECIMAL_TYPE
	 * 		DataType.BOOLEAN_TYPE
	 * 		DataType.DATE_TYPE
	 * 		DataType.DOUBLE_TYPE
	 * 		DataType.STRING_TYPE
	 * 		DataType.BLOB_TYPE
	 *		DataType.SQL_DATE_TYPE
	 *		DataType.SQL_TIME_TYPE
	 * @param source
	 * @param toType
	 * @return
	 * @throws BirtException
	 */
	public static Object convert( Object source, int toType )
			throws BirtException
	{
		source = JavascriptEvalUtil.convertJavascriptValue( source );
		
		// here we assume the efficiency of if else is higher than switch case
		if ( toType == DataType.UNKNOWN_TYPE || toType == DataType.ANY_TYPE )
			return source;

		switch ( toType )
		{
			case DataType.INTEGER_TYPE :
				return toInteger( source );
			case DataType.DECIMAL_TYPE :
				return toBigDecimal( source );
			case DataType.BOOLEAN_TYPE :
				return toBoolean( source );
			case DataType.DATE_TYPE :
				return toDate( source );
			case DataType.DOUBLE_TYPE :
				return toDouble( source );
			case DataType.STRING_TYPE :
				return toString( source );
			case DataType.BLOB_TYPE :
				return toBytes( source );
			case DataType.BINARY_TYPE :
				return toBytes( source );
			case DataType.SQL_DATE_TYPE:
				return toSqlDate( source );
			case DataType.SQL_TIME_TYPE:
				return toSqlTime( source );
			case DataType.JAVA_OBJECT_TYPE:
				return source;
			default :
				throw new CoreException( ResourceConstants.INVALID_TYPE,
						resourceBundle );
		}
	}

	/**
	 * convert a object to given class
	 * Classes supported:
	 * 		Integer.class
	 * 		BigDecimal.class
	 * 		Boolean.class
     *      Time.class
	 * 		Date.class
	 * 		Double.class
	 * 		String.class
	 * 		Blob.class
	 * @param source
	 * @param toTypeClass
	 * @return
	 * @throws BirtException
	 */
	public static Object convert( Object source, Class toTypeClass )
			throws BirtException
	{
		if ( source!= null && source.getClass( ) == toTypeClass )
		{
			return source;
		}
		
		if ( toTypeClass == DataType.getClass( DataType.ANY_TYPE ) )
			return source;
		if ( toTypeClass == Integer.class )
			return toInteger( source );
		if ( toTypeClass == BigDecimal.class )
			return toBigDecimal( source );
		if ( toTypeClass == Boolean.class )
			return toBoolean( source );
        if ( toTypeClass == Time.class )
            return toSqlTime( source );
        if ( toTypeClass == java.sql.Date.class)
           	return toSqlDate( source );
        if ( toTypeClass == java.sql.Timestamp.class ) 
			return toTimestamp( source );
		if ( toTypeClass == Date.class ) 
			return toDate( source );
		if ( toTypeClass == Double.class )
			return toDouble( source );
		if ( toTypeClass == String.class )
			return toString( source );
		if ( toTypeClass == Blob.class )
		{
			if ( source instanceof byte[] )
				return source;
			else
				return toBlob( source );				
		}
		if ( toTypeClass == byte[].class )
			return source;
		if ( toTypeClass == Object.class )
		{
			return source;
		}

		throw new CoreException( ResourceConstants.INVALID_TYPE,
				resourceBundle );
	}

	/**
	 * Boolean -> Integer
	 * 		true 	-> 1
	 * 		others 	-> 0 
	 * Date -> Integer
	 * 		Date.getTime();
	 * String -> Integer
	 * 		Integer.valueOf();
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Integer toInteger( Object source ) throws BirtException
	{
		if ( source == null )
			return null;

		if ( source instanceof Integer )
		{
			return (Integer) source;
		}
		else if ( source instanceof Number )
		{
			// This takes care of BigDecimal, BigInteger, Byte, Double, 
			// Float, Long, Short
			if ( !isConvertableToInteger( (Number) source ) )
			{
				throw new CoreException( ResourceConstants.CONVERT_FAILS,
						new Object[]{
								source.toString( ), "Integer"
						} );
			}
			int intValue = ( (Number) source ).intValue( );
			return Integer.valueOf( intValue );
		}
		else if ( source instanceof Boolean )
		{
			if ( true == ( (Boolean) source ).booleanValue( ) )
				return Integer.valueOf( 1 );
			return Integer.valueOf( 0 );
		}
		else if ( source instanceof Date )
		{
			long longValue = ( (Date) source ).getTime( );
			if ( !isConvertableToInteger( Long.valueOf( longValue ) ))
			{
				throw new CoreException( ResourceConstants.CONVERT_FAILS,
						new Object[]{
								source.toString( ), "Integer"
						} );
			}
			return Integer.valueOf( (int) longValue );
		}
		else if ( source instanceof CharSequence )
		{
			source = source.toString( );
			try
			{
				return Integer.valueOf( (String) source );
			}
			catch ( NumberFormatException e )
			{
				try
				{
					Number number = NumberFormat.getInstance( JRE_DEFAULT_LOCALE ).parse( (String)source );
					if( number != null )
					{
						if ( !isConvertableToInteger( number ))
						{
							throw new CoreException( ResourceConstants.CONVERT_FAILS,
									new Object[]{
											source.toString( ), "Integer"
									} );
						}
						return Integer.valueOf( number.intValue( ));
					}
					
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "Integer"
							} );
				}
				catch ( ParseException e1 )
				{
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "Integer"
							} );
				}
			}
		}
		else
		{
			throw new CoreException( ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Integer"
					} );
		}
	}

	/**
	 * Boolean -> BigDecimal
	 * 		true 	-> 1
	 * 		others 	-> 0 
	 * Date -> BigDecimal
	 * 		Date.getTime();
	 * String -> BigDecimal
	 * 		new BigDecimal(String);
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static BigDecimal toBigDecimal( Object source ) throws BirtException
	{
		if ( source == null )
			return null;

		if ( source instanceof BigDecimal )
		{
			return (BigDecimal) source;
		}
		else if ( source instanceof Number )
		{
			// This takes care of BigDecimal, BigInteger, Byte, Double, 
			// Float, Long, Short, Integer
			// An intermediate conversion using String is preferrable per JavaDoc
			// comment in BigDecimal(String) constructor
			if ( source instanceof Double
					&& ( ( (Double) source ).isInfinite( ) || ( (Double) source ).isNaN( ) ) )
				return null;
			else if ( source instanceof Float
					&& ( ( (Float) source ).isInfinite( ) || ( (Float) source ).isNaN( ) ) )
				return null;
			
			String str = ( (Number) source ).toString( );
			try
			{
				return new BigDecimal( str );
			}
			catch ( NumberFormatException e )
			{
				throw new CoreException( 
						ResourceConstants.CONVERT_FAILS,
						new Object[]{
								str, "BigDecimal"
						} );
			}
		}
		else if ( source instanceof Boolean )
		{
			if ( true == ( (Boolean) source ).booleanValue( ) )
				return BigDecimal.ONE;
			return BigDecimal.ZERO;
		}
		else if ( source instanceof Date )
		{
			long longValue = ( (Date) source ).getTime( );
			return new BigDecimal( longValue );
		}
		else if ( source instanceof CharSequence )
		{
			//if empty string, return null
			source = source.toString( );
			if( ( (String) source ).length( )==0 )
			{
				return null;
			}
			try
			{
				return new BigDecimal( (String) source );
			}
			catch ( NumberFormatException e )
			{
				try
				{
					Number number = NumberFormat.getInstance( JRE_DEFAULT_LOCALE )
							.parse( (String) source );
					if( number != null )
						return new BigDecimal( number.toString( ) );
					
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "BigDecimal"
							} );
				}
				catch ( ParseException e1 )
				{
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "BigDecimal"
							} );
				}
			}
		}
		else
		{
			throw new CoreException(
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "BigDecimal"
					} );
		}
	}

	/**
	 * Number -> Boolean
	 * 		0 		-> false
	 * 		others 	-> true
	 * String -> Boolean
	 * 		"true" 	-> true (ignore case)
	 * 		"false" -> false (ignore case)
	 * 		other string will throw an exception
	 * Date -> Boolean
	 * 		throw exception
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Boolean toBoolean( Object source ) throws BirtException
	{
		if ( source == null )
			return null;

		if ( source instanceof Boolean )
		{
			return (Boolean) source;
		}
		else if ( source instanceof Number )
		{
			// Takes care of all numeric types
			if ( ( (Number) source ).doubleValue( ) == 0 )
				return Boolean.FALSE;
			return Boolean.TRUE;
		}
		else if ( source instanceof CharSequence )
		{
			source = source.toString( );
			if ( ( (String) source ).equalsIgnoreCase( "true" ) )
				return Boolean.TRUE;
			else if ( ( (String) source ).equalsIgnoreCase( "false" ) )
				return Boolean.FALSE;
			else
			{
				try
				{
					if ( Double.parseDouble( (String) source ) == 0 )
						return Boolean.FALSE;
					else
						return Boolean.TRUE;
				}
				catch ( NumberFormatException e )
				{
					throw new CoreException(
							ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "Boolean"
							} );
				}
			}
		}
		else
		{
			throw new CoreException( 
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Boolean"
					});
		}
	}

	/**
	 * Number -> Date
	 * 		new Date((long)Number)
	 * String -> Date
	 * 		toDate(String)  
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Date toDate( Object source ) throws BirtException
	{
		if ( source == null )
			return null;

		if ( source instanceof Date )
		{
			return new Date( ( (Date) source ).getTime( ) );
		}
		else if ( source instanceof CharSequence )
		{
			return toDate( source.toString( ) );
		}
		else if ( source instanceof Double )
		{
			// Rounding Double to the nearest Long.
			// This should be a relatively safe operation since this type
			// of conversion is usually done for representing aggregate
			// function results as Date.
			return new Date( Math.round( (Double) source ) );
		}
		else
		{
			throw new CoreException(
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					});
		}
	}
    
	/**
	 * 
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Timestamp toTimestamp( Object source ) throws BirtException
	{
		Date date = toDate( source );
		if( date == null )
			return null;
		return new Timestamp( date.getTime( ));
	}
	
    /**
     * Date -> Time
     * String -> Time
     * @param source
     * @return
     * @throws BirtException
     */
    public static Time toSqlTime( Object source ) throws BirtException
    {
        if ( source == null )
            return null;

        if ( source instanceof Date )
        {
       		return toSqlTime( (Date)source);
        }
        else if ( source instanceof CharSequence )
		{
			source = source.toString( );
            try
            {
                return toSqlTime( toDate((String ) source) );
            }
            catch( Exception e )
            {
                try
                {
                	return toSqlTime( (String)source );
                }
                catch ( Exception e1 )
                {
                	
                }
            }
        }
        else if ( source instanceof Double )
		{
        	// Rounding to the nearest Long is safe here since the Long value
        	// represents milliseconds
        	return toSqlTime( new Date( Math.round( (Double) source ) ) );
		}

        throw new CoreException(
                    ResourceConstants.CONVERT_FAILS,
                    new Object[]{
                            source.toString( ), "Time"
                    } );
    }

    /**
     * 
     * @param value
     * @return
     */
    private static Time toSqlTime( String s )
    {
		int hour;
		int addHour;
		int minute;
		int second;
		int firstColon;
		int secondColon;
		int marker;
		
		if ( s == null )
			throw new java.lang.IllegalArgumentException( );

		firstColon = s.indexOf( ':' );
		secondColon = s.indexOf( ':', firstColon + 1 );
		for ( marker = secondColon + 1; marker < s.length( ); marker++ )
		{
			if ( !isDigitTen( s.charAt( marker ) ) )
				break;
		}
		addHour = 0;
		String markerValue = null;
		String aMarker = null;
		if ( marker < s.length( ) )
		{
			markerValue = s.substring( marker ).trim( );
			if ( "am".compareToIgnoreCase( markerValue ) == 0 )
			{
				addHour = 0;
				aMarker = "am";
			}
			else if ( "pm".compareToIgnoreCase( markerValue ) == 0 )
			{
				addHour = 12;
				aMarker = "pm";
			}
			else
			{
				throw new java.lang.IllegalArgumentException( );
			}
		}
		if ( firstColon <= 0  ||
				secondColon <= 0 || secondColon >= s.length( ) - 1 )
		{
			throw new java.lang.IllegalArgumentException( );
		}
		hour = Integer.parseInt( s.substring( 0, firstColon ) );
		minute = Integer.parseInt( s.substring( firstColon + 1, secondColon ) );
		if( minute < 0 || minute > 60 )
			throw new java.lang.IllegalArgumentException( );
		if ( marker < s.length( ) )
			second = Integer.parseInt( s.substring( secondColon + 1, marker ) );
		else
			second = Integer.parseInt( s.substring( secondColon + 1 ) );
		if( second < 0 || second > 60 )
			throw new java.lang.IllegalArgumentException( );
		if( hour == 12 && minute == 0 && second == 0 && aMarker != null )
		{
			if ( "am".equals( aMarker ) )
			{
				hour = 24;
			}
			else
			{
				hour = 12;
			}
		}
		else
		{
			if ( hour < 0 ||
				( hour > 12 && markerValue != null && markerValue.length( ) > 0 ) )
				throw new java.lang.IllegalArgumentException( );
			hour += addHour;
			if( hour > 24 )
				throw new java.lang.IllegalArgumentException( );
		}
		
		return toSqlTime( hour, minute, second );
	}
    
    /**
     * 
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    private static Time toSqlTime( int hour, int minute, int second )
    {
    	Calendar calendar = Calendar.getInstance( );
		calendar.clear( );
		calendar.set( Calendar.HOUR_OF_DAY, hour );
		calendar.set( Calendar.MINUTE, minute );
		calendar.set( Calendar.SECOND, second );
		return new java.sql.Time( calendar.getTimeInMillis( ) );
    }
    
    /**
     * 
     * @param c
     * @return
     */
    private static boolean isDigitTen( char c )
	{
		if ( c <= '9' && c >= '0' )
			return true;
		return false;
	}
    
    /**
	 * 
	 * @param date
	 * @return
	 */
    private static java.sql.Time toSqlTime( Date date )
    {
    	Calendar calendar = Calendar.getInstance( );
		calendar.clear( );
		calendar.setTimeInMillis( date.getTime( ) );
		calendar.set( Calendar.YEAR, 1970 );
		calendar.set( Calendar.MONTH, 0 );
		calendar.set( Calendar.DAY_OF_MONTH, 1 );
		return new java.sql.Time( calendar.getTimeInMillis( ) );
    }
    
    /**
     * Date -> Time
     * String -> Time
     * @param source
     * @return
     * @throws BirtException
     */
    public static java.sql.Date toSqlDate( Object source ) throws BirtException
    {
        if ( source == null )
            return null;

        if ( source instanceof java.sql.Date )
        {
        	return maskSQLDate( ( java.sql.Date )source );
        }
        else if ( source instanceof Date )
        {
    		return toSqlDate( (Date)source );
        }
        else if ( source instanceof CharSequence )
		{
			source = source.toString( );
            try
            {
                return toSqlDate( toDate((String ) source) );
            }
            catch( Exception e )
            {
                try
                {
                	return java.sql.Date.valueOf( (String)source );
                }
                catch ( Exception e1 )
                {
                	
                }
            }
        }
        else if ( source instanceof Double )
		{
        	// Rounding to the nearest Long is safe here since the Long value
        	// represents milliseconds
        	return toSqlDate( new Date( Math.round( (Double) source ) ) );
		}

        throw new CoreException(
                    ResourceConstants.CONVERT_FAILS,
                    new Object[]{
                            source.toString( ), "java.sql.Date"
                    } );
    }
    
    /**
     * 
     * @param date
     * @return
     */
    private static java.sql.Date toSqlDate( Date date )
    {
    	Calendar calendar = Calendar.getInstance( );
		calendar.clear( );
		calendar.setTimeInMillis( date.getTime( ) );
		calendar.set( Calendar.HOUR_OF_DAY, 0 );
		calendar.set( Calendar.MINUTE, 0 );
		calendar.set( Calendar.SECOND, 0 );
		calendar.set( Calendar.MILLISECOND, 0 );		
		return new java.sql.Date( calendar.getTimeInMillis( ) );
    }
    
    /**
     * mask out time info for sql Date
     * @param date
     * @return
     */
    private static java.sql.Date maskSQLDate( java.sql.Date date )
    {
    	Calendar calendar = Calendar.getInstance( );
		calendar.clear( );
		calendar.setTimeInMillis( date.getTime( ) );
		calendar.set( Calendar.HOUR_OF_DAY, 0 );
		calendar.set( Calendar.MINUTE, 0 );
		calendar.set( Calendar.SECOND, 0 );
		calendar.set( Calendar.MILLISECOND, 0 );		
		return new java.sql.Date( calendar.getTimeInMillis( ) );
    }
    
    
    /**
	 * A temp solution to the adoption of ICU4J to BIRT. Simply delegate
	 * toDate( String, Locale) method.
	 * 
	 * @param source
	 *            the String to be convert
	 * @param locate
	 * 			  the locate of the string
	 * @return result Date
	 */
	public static Date toDate( String source, Locale locale )
			throws BirtException
	{
		return toDate( source, ULocale.forLocale( locale ) );
	}

	/**
	 * convert String with the specified locale to java.util.Date
	 * 
	 * @param source
	 *            the String to be convert
	 * @param locate
	 * 			  the locate of the string
	 * @return result Date
	 */
	public static Date toDate( String source, ULocale locale )
			throws BirtException
	{
		return toDate( source, locale, null );
	}
	
	/**
	 * Parses a date/time string
	 *
	 * @param source
	 * @param locale
	 * @param timeZone
	 * @return
	 * @throws BirtException
	 */
	public static Date toDate( String source, ULocale locale, TimeZone timeZone )
			throws BirtException
	{
		DateFormat dateFormat = getDateFormatObject( source, locale, timeZone );
		Date resultDate = null;
		try
		{
			resultDate = dateFormat.parse( source );
			return resultDate;
		}
		catch ( ParseException e )
		{
			throw new CoreException(
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					} );
		}
	}

	/**
	 * @deprecated use getDateFormatObject instead
	 */
	public static DateFormat getDateFormat( String source, ULocale locale, TimeZone timeZone )
			throws BirtException
	{
		return getDateFormatObject( source, locale, timeZone );
	}

	/**
	 * Retrieve date format object that matches the given date/time string
	 * @since 4.8
	 *
	 * @param source
	 * @param locale
	 * @param timeZone
	 * @return
	 * @throws BirtException
	 */
	public static DateFormat getDateFormatObject( String source, ULocale locale, TimeZone timeZone )
			throws BirtException
	{
		if ( source == null )
			return null;

		DateFormat dateFormat = null;
		Date resultDate = null;
		
		boolean existTime = p1.matcher( source ).matches( )
				|| p2.matcher( source ).matches( );

		for ( int i = DEFAULT_DATE_STYLE; i <= DateFormat.SHORT; i++ )
		{
			for ( int j = DEFAULT_DATE_STYLE; j <= DateFormat.SHORT; j++ )
			{
				dateFormat = DateFormatFactory.getDateTimeInstance( i, j, locale );
				TimeZone savedTimeZone = null; 
				if( timeZone != null )
				{
					savedTimeZone = dateFormat.getTimeZone( );
					dateFormat.setTimeZone( timeZone );
				}
				try
				{
					resultDate = dateFormat.parse( source );
					return dateFormat;
				}
				catch ( ParseException e1 )
				{
				}
				finally 
				{
					if( savedTimeZone != null )
						dateFormat.setTimeZone( savedTimeZone );
				}
			}

			// only Date, no Time 
			if ( !existTime )
			{
				dateFormat = DateFormatFactory.getDateInstance( i, locale );
				TimeZone savedTimeZone = null; 
				if( timeZone != null )
				{
					savedTimeZone = dateFormat.getTimeZone( );
					dateFormat.setTimeZone( timeZone );
				}
				try
				{
					resultDate = dateFormat.parse( source );
					return dateFormat;
				}
				catch ( ParseException e1 )
				{
				}
				finally 
				{
					if( savedTimeZone != null )
						dateFormat.setTimeZone( savedTimeZone );
				}
			}
		}

		// for the String can not be parsed, throws a BirtException
		if ( resultDate == null )
		{
			throw new CoreException( 
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					} );
		}

		// never access here
		return dateFormat;
	}

	/**
	 * Convert a string to a Date instance according to the TimeZone value
	 * 
	 * @param source
	 * @param timeZone
	 * @return
	 * @throws BirtException
	 */
	public static Date toDate( String source, TimeZone timeZone ) throws BirtException
	{
		assert timeZone != null;
		try
		{
			return toDateISO8601( source, timeZone );
		}
		catch ( BirtException e )
		{
			try
			{
				// format the String for JRE default locale
				return toDate( source, JRE_DEFAULT_LOCALE, timeZone );
			}
			catch ( BirtException use )
			{
				// format the String for Locale.US
				return toDate( source, DEFAULT_LOCALE, timeZone );
			}
		}
	}
	
	/**
	 * A temp solution to the adoption of ICU4J in BIRT. It is a simple
	 * delegation to toDateWithCheck( String, Locale ).
	 * 
	 * @param source
	 * @param locale
	 * @return Date
	 * @throws BirtException
	 */
	public static Date toDateWithCheck( String source, Locale locale )
			throws BirtException
	{
		return toDateWithCheck( source, ULocale.forLocale( locale ) );
	}

	/**
	 * Convert string to date with check.
	 * JDK may do incorrect converse, for example:
	 * 		2005/1/1 Local.US, format pattern is MM/dd/YY.
	 * Above conversion can be done without error, but obviously
	 * the result is not right. This method will do such a simple check,
	 * in DateFormat.SHORT case instead of all cases.
	 * 		Year is not lower than 0.
	 * 		Month is from 1 to 12.
	 * 		Day is from 1 to 31.  
	 * @param source
	 * @param locale
	 * @return Date
	 * @throws BirtException
	 */
	public static Date toDateWithCheck( String source, ULocale locale )
			throws BirtException
	{
		DateFormat dateFormat = DateFormatFactory.getDateInstance( DateFormat.SHORT,
				locale );
		Date resultDate = null;
		try
		{
			resultDate = dateFormat.parse( source );
		}
		catch ( ParseException e )
		{
			return toDate( source, locale );
		}

		// check whether conversion is correct
		if ( DateUtil.checkValid( dateFormat, source ) == false )
		{
			throw new CoreException( 
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					});
		}

		return resultDate;
	}

	public static Double toDouble( Object source, Locale locale ) throws CoreException
	{
		return toDouble( source, ULocale.forLocale( locale ));
	}
	
	public static Double toDouble( Object source, ULocale locale ) throws CoreException
	{
		if ( source == null )
			return null;

		if ( source instanceof Double )
		{
			return (Double) source;
		}
		else if ( source instanceof Number )
		{
			if ( !isConvertableToDouble( (Number) source ) )
			{
				throw new CoreException( ResourceConstants.CONVERT_FAILS,
						new Object[]{
								source.toString( ), "Double"
						} );
			}
			double doubleValue = ( (Number) source ).doubleValue( );
			return new Double( doubleValue );
		}
		else if ( source instanceof Boolean )
		{
			if ( true == ( (Boolean) source ).booleanValue( ) )
				return new Double( 1d );
			return new Double( 0d );
		}
		else if ( source instanceof Date )
		{
			double doubleValue = ( (Date) source ).getTime( );
			return new Double( doubleValue );
		}
		else if ( source instanceof CharSequence )
		{
			source = source.toString( );
			try
			{
				return Double.valueOf( (String) source );
			}
			catch ( NumberFormatException e )
			{
				try
				{
					Number number = NumberFormat.getInstance( locale == null
							? JRE_DEFAULT_LOCALE : locale )
							.parse( (String) source );
					if( number != null )
					{
						if ( !isConvertableToDouble( number ) )
						{
							throw new CoreException( ResourceConstants.CONVERT_FAILS,
									new Object[]{
											source.toString( ), "Double"
									} );
						}
						return new Double( number.doubleValue( ));
					}
					
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "Double"
							} );
				}
				catch ( ParseException e1 )
				{
					throw new CoreException( ResourceConstants.CONVERT_FAILS,
							new Object[]{
									source.toString( ), "Double"
							} );
				}
			}
		}
		else
		{
			throw new CoreException(
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Double"
					});
		}
	}
	/**
	 * Boolean -> Double
	 * 		true 	-> 1
	 * 		others 	-> 0 
	 * Date -> Double
	 * 		Date.getTime();
	 * String -> Double
	 * 		Double.valueOf(String);
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Double toDouble( Object source ) throws BirtException
	{
		return toDouble( source, JRE_DEFAULT_LOCALE );
	}

	
	/**
	 * Number -> String
	 * 		Number.toString()
	 * Boolean -> String
	 * 		Boolean.toString()
	 * Date	-> String
	 * 		toString(Date)
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static String toString( Object source ) throws BirtException
	{
		return toString( source, JRE_DEFAULT_LOCALE );
	}

	/**
	 * A temp solution to the adoption of ICU4J. It is a simple delegation
	 * to toString( Object, Locale ).
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static String toString( Object source, Locale locale )
			throws BirtException
	{
		return toString( source, ULocale.forLocale( locale ) );
	}
	
	/**
	 * Convert an object to an locale neutral String value. For Date values we will convert to ISO8601 format.
	 * User can specify the time zone to output.
	 * 
	 * @param source
	 * @param zone
	 * @return
	 * @throws BirtException
	 */
	public static String toLocaleNeutralString( Object source, TimeZone zone ) throws BirtException
	{
		if ( source == null )
			return null;
		if ( source instanceof Time )
		{
			return toLocaleNeutralString( source );
		}
		else if ( source instanceof java.sql.Date )
		{
			return toLocaleNeutralString( source );
		}
		else if ( source instanceof Timestamp )
		{
			return toLocaleNeutralString( source );
		}
		else if ( source instanceof Date )
		{
			return DateFormatISO8601.format( (Date) source, zone );
		}
		else
		{
			return toLocaleNeutralString( source );
		}
	}

	/**
	 * Convert an object to an locale neutral String value. For Date values we will convert to ISO8601 format.
	 * This will always output default(current) time zone.
	 * 
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static String toLocaleNeutralString( Object source ) throws BirtException
	{
		if ( source == null )
			return null;
		if ( source instanceof Time )
		{
			return ((Time) source).toString( );
		}
		else if ( source instanceof java.sql.Date )
		{
			return ((java.sql.Date) source).toString( );
		}
		else if ( source instanceof Timestamp )
		{
			return ((java.sql.Timestamp) source).toString( );
		}
		else if ( source instanceof Date )
		{
			return DateFormatISO8601.format( (Date) source );
		}
		else if ( source instanceof Number )
		{
			return ((Number) source).toString( );
		}
		else 
		{
			return toLimitedSizeString( source );
		}
	}
	
	/**
	 * Number -> String
	 * 		Number.toString()
	 * Boolean -> String
	 * 		Boolean.toString()
	 * Date	-> String
	 * 		toString(Date,locale)
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static String toString( Object source, ULocale locale )
			throws BirtException
	{
		if ( source == null )
			return null;
		if ( source instanceof Time )
		{
			return toString( (Date) source, locale );
		}
		else if ( source instanceof java.sql.Date )
		{
			return ((java.sql.Date) source).toString( );
		}
		else if ( source instanceof Timestamp )
		{
			return ((java.sql.Timestamp) source).toString( );
		}
		else if ( source instanceof Date )
		{
			return toString( (Date) source, locale );
		}
		else if ( source instanceof Number )
		{
			return toString( (Number) source, locale );
		}
		else 
		{
			return toLimitedSizeString( source );
		}
	}

	/**
	 * 
	 * @param source
	 * @return
	 */
	private static String toLimitedSizeString( Object source )
	{
		if ( source instanceof byte[] )
		{
			StringBuffer buf = new StringBuffer( );
			final int strLength = 8;

			byte[] sourceValue = (byte[]) source;
			int length = Math.min( sourceValue.length, strLength );
			for ( int i = 0; i < length; i++ )
			{
				buf.append( Integer.toHexString( sourceValue[i] ).toUpperCase( ) );
				buf.append( " " );
			}
			if ( sourceValue.length > strLength )
			{
				buf.append( "..." );
			}
			return buf.toString( );
		}
		else
		{
			return source.toString( );
		}
	}

	/**
	 * 
	 * @param source
	 * @param locale
	 * @return
	 */
	private static String toString( Number source, ULocale locale )
	{
		NumberFormat nf = (NumberFormat)nfMap.get( locale );
		if( nf == null )
		{
			synchronized( nfMap )
			{
				nf = (NumberFormat)nfMap.get( locale );
				if( nf == null )
				{
					nf = NumberFormat.getInstance( locale );
					nfMap.put( locale, nf );
				}
			}
		}
		return nf.format( source );
	}
	
	/**
	 * Converting Blob to/from other types is not currently supported
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static Blob toBlob( Object source ) throws BirtException
	{
		// Converting Blob to/from other types is not currently supported
		if ( source == null )
			return null;

		if ( source instanceof Blob )
			return (Blob) source;
		else if ( source instanceof byte[] )
		{
			try
			{
				return new SerialBlob( (byte[]) source );
			}
			catch ( Exception e )
			{
				throw new CoreException( ResourceConstants.CONVERT_FAILS,
						new Object[]{
								source.toString( ), "Blob"
						} );
			}
		}
		else
			throw new CoreException( ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Blob"
					} );
	}

	/**
	 * @param source
	 * @return byte array
	 * @throws BirtException
	 */
	public static byte[] toBytes( Object source ) throws BirtException
	{
		// Converting Blob to/from other types is not currently supported
		if ( source == null )
			return null;

		if ( source instanceof byte[] )
			return (byte[]) source;
		else if ( source instanceof Blob )
		{
			try
			{
				return ( (Blob) source ).getBytes( (long) 1,
						(int) ( (Blob) source ).length( ) );
			}
			catch ( SQLException e )
			{
				throw new CoreException( ResourceConstants.CONVERT_FAILS,
						new Object[]{
								source.toString( ), "Binary"
						} );

			}
		}
		else
			throw new CoreException( ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Binary"
					} );
	}

	/**
	 * Converts a Java class to its corresponding data type constant
	 * defined in DataType 
	 */
	public static int toApiDataType( Class clazz )
	{
		if ( clazz == null )
			return DataType.UNKNOWN_TYPE;

		if ( clazz == DataType.AnyType.class )
			return DataType.ANY_TYPE;
		else if ( Integer.class.isAssignableFrom( clazz ) )
			return DataType.INTEGER_TYPE;
		else if ( Double.class.isAssignableFrom( clazz ) )
			return DataType.DOUBLE_TYPE;
		else if ( String.class.isAssignableFrom( clazz ) )
			return DataType.STRING_TYPE;
		else if ( BigDecimal.class.isAssignableFrom( clazz ) )
			return DataType.DECIMAL_TYPE;
		else if ( clazz == java.sql.Date.class )
			return DataType.SQL_DATE_TYPE;
		else if ( clazz == java.sql.Time.class )
			return DataType.SQL_TIME_TYPE;
		else if ( Date.class.isAssignableFrom( clazz ) )
			return DataType.DATE_TYPE;
		else if ( byte[].class.isAssignableFrom( clazz ) )
			return DataType.BINARY_TYPE;
		else if ( Clob.class.isAssignableFrom( clazz )
				|| clazz.getName( )
						.equals( "org.eclipse.datatools.connectivity.oda.IClob" ) )
			return DataType.STRING_TYPE;
		else if ( Blob.class.isAssignableFrom( clazz )
				|| clazz.getName( )
						.equals( "org.eclipse.datatools.connectivity.oda.IBlob" ) )
			return DataType.BLOB_TYPE;
		else if ( clazz == Boolean.class )
			return DataType.BOOLEAN_TYPE;
        else if ( clazz == Object.class )
            return DataType.JAVA_OBJECT_TYPE;

		// any other types are not recognized nor supported;
		return DataType.UNKNOWN_TYPE;
	}
	
	public static Class fromApiDataTypeToJavaClass( int apiDataType )
	{
		switch ( apiDataType )
		{
			case DataType.ANY_TYPE:
				return DataType.AnyType.class;
			case DataType.INTEGER_TYPE:
				return Integer.class;
			case DataType.DOUBLE_TYPE:
				return Double.class;
			case DataType.STRING_TYPE:
				return String.class;
			case DataType.DECIMAL_TYPE:
				return BigDecimal.class;
			case DataType.SQL_DATE_TYPE:
				return java.sql.Date.class;
			case DataType.SQL_TIME_TYPE:
				return java.sql.Time.class;
			case DataType.DATE_TYPE:
				return java.util.Date.class;
			case DataType.BINARY_TYPE:
				return byte[].class;
			case DataType.BOOLEAN_TYPE:
				return Boolean.class;
			case DataType.JAVA_OBJECT_TYPE:
				return Object.class;
			case DataType.BLOB_TYPE:
				try
				{
					Class c = Class.forName("org.eclipse.datatools.connectivity.oda.IBlob");
					return c;
				}catch(Exception exp)
				{
					
				}
			default:
				return DataType.AnyType.class;
		}

	}

	/**
	 * Converts an ODA data type code to its 
	 * corresponding Data Engine API data type constant
	 * defined in DataType.
	 * @param odaDataTypeCode   an ODA data type code
	 * @throws BirtException if the specified ODA data type code
	 *                      is not a supported type
	 */
	public static int toApiDataType( int odaDataTypeCode ) throws BirtException
	{
		Class odiTypeClass = toOdiTypeClass( odaDataTypeCode );
		return toApiDataType( odiTypeClass );
	}

	/**
	 * Convert object to a suitable type from its value 
	 * Object -> Integer -> Double -> BigDecimal -> Date -> String
	 */
	public static Object toAutoValue( Object evaValue )
	{
		if ( evaValue == null )
			return null;

		Object value = null;
		if ( evaValue instanceof CharSequence )
		{
			// 1: to Integer
			String stringValue = evaValue.toString( );
			value = toIntegerValue( evaValue );
			if ( value == null )
			{
				try
				{
					// 2: to Double
					value = Double.valueOf( stringValue );
				}
				catch ( NumberFormatException e1 )
				{
					try
					{
						// 3: to BigDecimal
						value = new BigDecimal( stringValue );
					}
					catch ( NumberFormatException e2 )
					{
						try
						{
							// 4: to Date
							value = toDate( stringValue );
						}
						catch ( BirtException e3 )
						{
							value = evaValue;
						}
					}
				}
			}
		}
		return value;
	}

	/**
	 * convert object to Integer. If fails, return null. 
	 * Object -> Integer
	 */
	public static Integer toIntegerValue( Object evaValue )
	{
		// to Integer
		Integer value = null;
		if ( evaValue instanceof CharSequence )
		{
			String stringValue = evaValue.toString( );
			try
			{
				// 1: to Integer
				value = Integer.valueOf( stringValue );
			}
			catch ( NumberFormatException e1 )
			{
				try
				{
					Double ddValue = Double.valueOf( stringValue );
					int intValue = ddValue.intValue( );
					double doubleValue = ddValue.doubleValue( );
					// TODO: improve this implementation
					// here examine whether the two values are equal.1.0e-5
					if ( Math.abs( intValue - doubleValue ) < 0.0000001 )
					{
						value = Integer.valueOf( String.valueOf( intValue ) );
					}
					else
					{
						value = null;
					}
				}
				catch ( NumberFormatException e2 )
				{
					value = null;
				}
			}
		}
		return value;
	}

	/**
	 * Convert String without specified locale to java.util.Date
	 * Try to format the given String for JRE default Locale,
	 * if it fails, try to format the String for Locale.US 
	 * @param source
	 *            the String to be convert
	 * @param locate
	 * 			  the locate of the string
	 * @return result Date
	 */
	private static Date toDate( String source ) throws BirtException
	{
		source = source.trim( );
		try
		{
			return toDateISO8601( source, null );
		}
		catch ( BirtException e )
		{
			try
			{
				// format the String for JRE default locale
				return toDate( source, JRE_DEFAULT_LOCALE );
			}
			catch ( BirtException use )
			{
				try
				{
					// format the String for Locale.US
					return toDate( source, DEFAULT_LOCALE );
				}
				catch ( BirtException de )
				{
					return toDateForSpecialFormat( source );
				}
			}
		}
	}

	/**
	 * convert String with ISO8601 date format to java.util.Date
	 * 
	 * @param source
	 *            the String to be convert
	 * @param locate
	 * 			  the locate of the string
	 * @return result Date
	 */
	private static Date toDateISO8601( String source, TimeZone timeZone ) throws BirtException
	{
		Date resultDate = null;

		try
		{
			resultDate = DateFormatISO8601.parse( source, timeZone );
			return resultDate;
		}
		catch ( ParseException e1 )
		{
			throw new CoreException( 
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					} );
		}
	}

	private static Date toDateForSpecialFormat( String source ) throws BirtException
	{
		try
		{
			return MysqlUSDateFormatter.parse( source );
		}
		catch ( ParseException e1 )
		{
			throw new CoreException( 
					ResourceConstants.CONVERT_FAILS,
					new Object[]{
							source.toString( ), "Date"
					} );
		}
	}

	/**
	 * Find the date format pattern string for a given datetime string without specified locale.
	 * If a suitable date format cannot be found or the pattern string cannot be retrieved, returns null
	 * @since 4.8
	 *
	 * @param source
	 * @return
	 * @throws BirtException
	 */
	public static String getDateFormat( String source ) throws BirtException
	{
		source = source.trim( );
		SimpleDateFormat sdf = null;
		try
		{
			sdf = DateFormatISO8601.getSimpleDateFormat( source, null );
		}
		catch ( BirtException e )
		{
			try
			{
				DateFormat dateformat = getDateFormatObject( source, JRE_DEFAULT_LOCALE, null );
				sdf = (SimpleDateFormat) dateformat;
			}
			catch ( BirtException use )
			{
				try
				{
					DateFormat dateformat = getDateFormatObject( source, DEFAULT_LOCALE, null );
					sdf = (SimpleDateFormat) dateformat;
				}
				catch ( BirtException de )
				{
					try {
						MysqlUSDateFormatter.parse( source );
						return "M/d/yyyy HH:mm";
					}
					catch ( ParseException e1 )
					{
					}
				}
			}
			catch ( ClassCastException ce )
			{
				// If a DateFormat cannot be cast to SimpleDateFormat, then
				// it will not be able to return its format pattern string
			}
		}

		if ( sdf != null )
			return sdf.toPattern();
		return null;
	}
	
	/**
	 * Call org.eclipse.birt.core.format.DateFormatter
	 * 
	 * @param source
	 * @return
	 */
	private static String toString( Date source, ULocale locale )
	{
		DateFormatter df = null;

		// avoid any multi-thread issue
		df = (DateFormatter) ( dfMap.get( locale ) );
		if ( df == null )
		{
			synchronized ( dfMap )
			{
				df = (DateFormatter) ( dfMap.get( locale ) );
				if ( df == null )
				{
					df = new DateFormatter( locale );
					dfMap.put( locale, df );
				}
			}
		}

		return df.format( (Date) source );
	}

	/**
	 * Converts an ODA data type code to the Java class
	 * of its corresponding Data Engine ODI data type. 

* ODA Data Type -> ODI Type Class
* Integer -> java.lang.Integer
* Double -> java.lang.Double
* Character -> java.lang.String
* Decimal -> java.math.BigDecimal
* Date -> java.sql.Date
* Time -> java.sql.Time
* Timestamp -> java.sql.Timestamp
* Blob -> java.sql.Blob
* Clob -> java.sql.Clob
* Boolean -> java.lang.Boolean
* JavaObject -> java.lang.Object
*
* @param odaDataTypeCode an ODA data type code * @return the ODI type class that corresponds with * the specified ODA data type * @throws BirtException if the specified ODA data type is not a supported type */ public static Class toOdiTypeClass( int odaDataTypeCode ) throws BirtException { if ( odaDataTypeCode != Types.CHAR && odaDataTypeCode != Types.INTEGER && odaDataTypeCode != Types.DOUBLE && odaDataTypeCode != Types.DECIMAL && odaDataTypeCode != Types.DATE && odaDataTypeCode != Types.TIME && odaDataTypeCode != Types.TIMESTAMP && odaDataTypeCode != Types.BLOB && odaDataTypeCode != Types.CLOB && odaDataTypeCode != Types.BOOLEAN && odaDataTypeCode != Types.JAVA_OBJECT && odaDataTypeCode != Types.NULL ) { throw new CoreException( ResourceConstants.INVALID_TYPE); } Class fieldClass = null; switch ( odaDataTypeCode ) { case Types.CHAR : fieldClass = String.class; break; case Types.INTEGER : fieldClass = Integer.class; break; case Types.DOUBLE : fieldClass = Double.class; break; case Types.DECIMAL : fieldClass = BigDecimal.class; break; case Types.DATE : fieldClass = java.sql.Date.class; break; case Types.TIME : fieldClass = Time.class; break; case Types.TIMESTAMP : fieldClass = Timestamp.class; break; case Types.BLOB : fieldClass = Blob.class; break; case Types.CLOB : fieldClass = Clob.class; break; case Types.BOOLEAN : fieldClass = Boolean.class; break; case Types.JAVA_OBJECT : fieldClass = Object.class; break; case Types.NULL : fieldClass = null; break; } return fieldClass; } /** * Converts an ODI type class to its corresponding * ODA data type code.
* ODI Type Class -> ODA Data Type
* java.lang.Integer -> Integer
* java.lang.Double -> Double
* java.lang.String -> Character
* java.math.BigDecimal -> Decimal
* java.util.Date -> Timestamp
* java.sql.Date -> Date
* java.sql.Time -> Time
* java.sql.Timestamp -> Timestamp
* java.sql.Blob -> Blob
* java.sql.Clob -> Clob
* java.lang.Boolean -> Boolean
* java.lang.Object -> JavaObject
*

* All other type classes are mapped to the ODA String data type. * @param odiTypeClass a type class used by the Data Engine ODI component * @return the ODA data type that maps to the ODI type class. */ public static int toOdaDataType( Class odiTypeClass ) { int odaType = Types.CHAR; // default if ( odiTypeClass == null ) odaType = Types.CHAR; else if ( odiTypeClass == String.class ) odaType = Types.CHAR; else if ( odiTypeClass == Integer.class ) odaType = Types.INTEGER; else if ( odiTypeClass == Double.class ) odaType = Types.DOUBLE; else if ( odiTypeClass == BigDecimal.class ) odaType = Types.DECIMAL; else if ( odiTypeClass == Time.class ) odaType = Types.TIME; else if ( odiTypeClass == Timestamp.class ) odaType = Types.TIMESTAMP; else if ( odiTypeClass == java.sql.Date.class ) odaType = Types.DATE; else if ( odiTypeClass == java.util.Date.class ) odaType = Types.TIMESTAMP; else if ( odiTypeClass == Blob.class ) odaType = Types.BLOB; else if ( odiTypeClass == Clob.class ) odaType = Types.CLOB; else if ( odiTypeClass == Boolean.class ) odaType = Types.BOOLEAN; else if ( odiTypeClass == Object.class ) odaType = Types.JAVA_OBJECT; return odaType; } private static boolean isConvertableToInteger( Number n ) { assert n != null; long longValue = n.longValue( ); return longValue >= Integer.MIN_VALUE && longValue <= Integer.MAX_VALUE; } private static boolean isConvertableToDouble( Number n ) { assert n != null; double doubleValue = n.doubleValue( ); return !Double.isInfinite( doubleValue ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy