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

com.quinsoft.zeidon.domains.DateTimeDomain Maven / Gradle / Ivy

The newest version!
/**
    This file is part of the Zeidon Java Object Engine (Zeidon JOE).

    Zeidon JOE is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zeidon JOE is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Zeidon JOE.  If not, see .

    Copyright 2009-2015 QuinSoft
 */

package com.quinsoft.zeidon.domains;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.quinsoft.zeidon.Application;
import com.quinsoft.zeidon.AttributeInstance;
import com.quinsoft.zeidon.EntityInstance;
import com.quinsoft.zeidon.InvalidAttributeValueException;
import com.quinsoft.zeidon.ObjectEngine;
import com.quinsoft.zeidon.Task;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.utils.JoeUtils;

/**
 * This domain handles any differences needed to deal with dates+time.
 */
public class DateTimeDomain extends AbstractDomain
{
    protected DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern( ObjectEngine.INTERNAL_DATE_STRING_FORMAT + "HHmmss");

    public DateTimeDomain(Application application, Map domainProperties, Task task )
    {
        super( application, domainProperties, task );
    }

    @Override
    public Object convertExternalValue(Task task, AttributeInstance attributeInstance, AttributeDef attributeDef, String contextName, Object externalValue)
    {
        // If external value is an AttributeInstance then get *its* internal value.
        if ( externalValue instanceof AttributeInstance )
            externalValue = ((AttributeInstance) externalValue).getValue();

        // KJS - Added 01/27/11 because of line 2836 in lTrnscpt_Object.java
        // OrderEntityForView( lTrnscpt, "StudentMajorDegreeTrack", "wPrimarySortOrder A GraduationDate A" );
        // value = null so we are getting to the exception.  Will try returning null, see what happens.
        if ( externalValue == null )
            return null;

        if ( externalValue instanceof ZonedDateTime )
            return externalValue;

        if ( externalValue instanceof java.sql.Date )
            return ( (java.sql.Date) externalValue).toLocalDate().atStartOfDay( ZoneId.systemDefault() ) ;

        if ( externalValue instanceof java.util.Date )
            return ZonedDateTime.ofInstant( ((java.util.Date) externalValue).toInstant(), ZoneId.systemDefault() );

        // VML operations use "" as synonymous with null.
        if ( externalValue instanceof String && StringUtils.isBlank( (String) externalValue ) )
            return null;

        if ( externalValue instanceof CharSequence )
        {
            // If string is "NOW" then we'll use current datetime.
            if ( externalValue.toString().equals( "NOW" ) )
                return ZonedDateTime.now();

            DomainContext context = getContext( task, contextName );
            return context.convertExternalValue( task, attributeDef, externalValue.toString() );
        }

        throw new InvalidAttributeValueException( attributeDef, externalValue,
                                                  "Invalid object: Domain %s cannot convert value for context %s.",
                                                  this.getClass().getName(), contextName );
    }

    @Override
    public String convertToString(Task task, AttributeDef attributeDef, Object internalValue)
    {
        if ( internalValue == null )
            return StringDomain.checkNullString( attributeDef.getDomain().getApplication(), null );

        if ( internalValue.toString().isEmpty())
            return internalValue.toString();

        return defaultDateTimeFormatter.format( (ZonedDateTime) internalValue );
    }

    /**
     * Attempt to get the context.  This differs from the normal getContext() by attempting to create
     * a SimpleDateFormatter using the contextName as the format if a context is not found by name.
     */
    @Override
    public DomainContext getContext(Task task, String contextName)
    {
        DomainContext context = getContext( contextName );
        if ( context != null )
            return context;  // We found one by name.

        if ( StringUtils.isBlank( contextName ) )
            throw new ZeidonException("Domain '%s' does not have a default context defined.", getName() );

        // Create a temporary new one and set its edit string to the context name.
        DateContext dateContext = new DateContext( this );
        dateContext.setName( contextName );
        dateContext.setEditString( contextName );
        return dateContext;
    }

    @Override
    public void validateInternalValue( Task task, AttributeDef attributeDef, Object internalValue ) throws InvalidAttributeValueException
    {
      if ( internalValue instanceof ZonedDateTime )
            return;

        throw new InvalidAttributeValueException( attributeDef, internalValue, "Internal value must be Joda ZonedDateTime, not %s",
                                                  internalValue.getClass().getName() );
    }

    /**
     * Adds milliseconds to the datetime value.
     */
    @Override
    public Object addToAttribute( Task task, AttributeInstance attributeInstance, AttributeDef attributeDef, Object currentValue, Object addValue )
    {
        ZonedDateTime date1 = (ZonedDateTime) convertExternalValue( task, attributeInstance, attributeDef, null, currentValue );
        if ( date1 == null )
            throw new ZeidonException( "Target attribute for add is NULL" )
                            .prependAttributeDef( attributeDef );

        if ( addValue == null )
            return date1;

        if ( addValue instanceof Number )
        {
            int nanos = ((Number) addValue).intValue() * 1000000;
            return date1.plusNanos( nanos );
        }

        throw new ZeidonException( "Value type of %s not supported for add to DateDomain", addValue.getClass().getName() );
    }

    @Override
    public Object addToAttribute( Task task,
                                  AttributeInstance attributeInstance,
                                  AttributeDef attributeDef,
                                  Object currentValue,
                                  Object operand,
                                  String contextName )
    {
        if ( ! StringUtils.isBlank( contextName ) )
        {
            return addWithContext( task,
                                   attributeInstance,
                                   attributeDef,
                                   currentValue,
                                   operand,
                                   contextName );
        }

        return addToAttribute( task, attributeInstance, attributeDef, currentValue, operand );
    }

    private Object addWithContext( Task task,
                                   AttributeInstance attributeInstance,
                                   AttributeDef attributeDef,
                                   Object currentValue,
                                   Object operand,
                                   String contextName )
    {
        assert ! StringUtils.isBlank( contextName );

        if ( operand instanceof AttributeInstance )
            operand = ((AttributeInstance) operand).getValue();

        if ( ! ( operand instanceof Integer ) && ! ( operand instanceof Long ) )
        {
            throw new ZeidonException( "When adding to ZonedDateTime with a context, operand must be integer or long value.  " +
                                       "Type of operand = %s", operand.getClass().getName() )
                            .prependAttributeDef( attributeDef );
        }

        int value = ((Number) operand).intValue();
        ZonedDateTime dt = (ZonedDateTime) currentValue;

        switch ( contextName.toLowerCase() )
        {
            case "day":
            case "days":
                return dt.plusDays( value );

            case "hour":
            case "hours":
                return dt.plusHours( value );

            case "minute":
            case "minutes":
                return dt.plusMinutes( value );

            case "milli":
            case "millis":
            case "millisecond":
            case "milliseconds":
                long nanos = ((Number) operand).longValue() * 1000000;
                return dt.plusNanos( nanos );

            case "month":
            case "months":
                return dt.plusMonths( value );

            case "second":
            case "seconds":
                return dt.plusSeconds( value );

            case "week":
            case "weeks":
                return dt.plusWeeks( value );

            case "year":
            case "years":
                return dt.plusYears( value );
        }

        // TODO Auto-generated method stub
        throw new ZeidonException( "Unknown context name '%s' for ZonedDateTime domain", contextName )
                        .prependAttributeDef( attributeDef );
    }

    @Override
    public DomainContext newContext(Task task)
    {
        return new DateContext( this );
    }

    /**
     * Generate a random test value for this domain.  This is used by test code to create random
     * test data.
     *
     * @param task current task
     * @param attributeDef def of the attribute.
     * @param entityInstance if not null this is the EntityInstance that will store the test data.
     *
     * @return random test data for this domain.
     */
    @Override
    public Object generateRandomTestValue( Task task, AttributeDef attributeDef, EntityInstance entityInstance )
    {
        DomainContext context = getDefaultContext();
        return context.convertToString( task, attributeDef, ZonedDateTime.now() );
    }

    private class DateContext extends BaseDomainContext
    {
        /**
         * URL for Java SimpleDateFormat help.
         */
        private static final String JAVA_DATE_FORMATTING_URL = "http://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html";

        public DateContext(Domain domain)
        {
            super( domain );
        }

        private DomainDateTimeFormatter formatter;

        @Override
        public String convertToString(Task task, AttributeDef attributeDef, Object internalValue) throws ZeidonException
        {
            if ( internalValue == null )
                return StringDomain.checkNullString(task.getApplication(), null);

            if ( internalValue.toString().isEmpty())
                return internalValue.toString();

            if ( formatter == null )
                throw new ZeidonException( "JavaEditString is not set for context %s", this.toString() );

            return formatter.format( (ZonedDateTime) internalValue );
        }

        /**
         * Assumes a string.
         */
        @Override
        public Object convertExternalValue(Task task, AttributeDef attributeDef, Object value) throws InvalidAttributeValueException
        {
            if ( value == null )
                return null;

            // If external value is an AttributeInstance then get *its* internal value.
            if ( value instanceof AttributeInstance )
                value = ((AttributeInstance) value).getValue();

            String s = (String) value;

            // VML operations use "" as synonymous with null.
            if ( StringUtils.isBlank( s ) )
                return null;

            // A common internal date/time format is the DefaultTimeFormat.  Let's try
            // a quick check to see if 's' is the same length and only digits.
            if ( s.length() >= ObjectEngine.INTERNAL_DATE_STRING_FORMAT.length() && JoeUtils.onlyDigits( s ) )
                return JoeUtils.parseStandardDateString( s );

            if ( formatter == null )
                throw new ZeidonException( "JavaEditString is not set for context %s", this.toString() );

            try
            {
                return formatter.parse( s );
            }
            catch ( Exception e )
            {
                throw new InvalidAttributeValueException( attributeDef, s, e.getMessage() )
                                     .appendMessage( "Format string = %s", getEditString() )
                                     .appendMessage( "See %s for help on Java Date formatting", JAVA_DATE_FORMATTING_URL )
                                     .setCause( e );
            }
        }

        @Override
        protected void setEditString( String editString )
        {
            super.setEditString( editString );
            formatter = new DomainDateTimeFormatter( editString );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy