1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.admin.datamodel.attributetype;
22  
23  import java.sql.SQLException;
24  import java.sql.Timestamp;
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.List;
28  
29  import org.efaps.admin.EFapsSystemConfiguration;
30  import org.efaps.admin.KernelSettings;
31  import org.efaps.admin.datamodel.Attribute;
32  import org.efaps.db.Context;
33  import org.efaps.db.wrapper.AbstractSQLInsertUpdate;
34  import org.efaps.util.DateTimeUtil;
35  import org.efaps.util.EFapsException;
36  import org.joda.time.DateTime;
37  import org.joda.time.DateTimeZone;
38  import org.joda.time.ReadableDateTime;
39  import org.joda.time.chrono.ISOChronology;
40  
41  /**
42   * @author The eFaps Team
43   * @version $Id$
44   */
45  public class DateTimeType
46      extends AbstractType
47  {
48      /**
49       * Needed for serialization.
50       */
51      private static final long serialVersionUID = 1L;
52  
53      /**
54       * {@inheritDoc}
55       * @throws EFapsException
56       */
57      @Override
58      public Object readValue(final Attribute _attribute,
59                              final List<Object> _objectList)
60          throws EFapsException
61      {
62          // reads the Value from "Admin_Common_DataBaseTimeZone"
63          final String timezoneID = EFapsSystemConfiguration.get().getAttributeValue(KernelSettings.DBTIMEZONE);
64          final ISOChronology chron;
65          if (timezoneID != null) {
66              final DateTimeZone timezone = DateTimeZone.forID(timezoneID);
67              chron = ISOChronology.getInstance(timezone);
68          } else {
69              chron = ISOChronology.getInstanceUTC();
70          }
71  
72          final List<DateTime> ret = new ArrayList<DateTime>();
73          for (final Object object : _objectList) {
74              if (object instanceof Timestamp || object instanceof Date) {
75                  // to avoid the automatic "correction" of the timezone first a local date must be made
76                  // and than a new Date with the correct timezone must be created
77                  final DateTime dateTime = new DateTime(object);
78                  final DateTime unlocalized = new DateTime(dateTime.getYear(),
79                                  dateTime.getMonthOfYear(),
80                                  dateTime.getDayOfMonth(),
81                                  dateTime.getHourOfDay(),
82                                  dateTime.getMinuteOfHour(),
83                                  dateTime.getSecondOfMinute(),
84                                  dateTime.getMillisOfSecond(),
85                                  chron);
86                  ret.add(unlocalized);
87              } else if (object != null) {
88                  ret.add(new DateTime());
89              } else {
90                  ret.add(null);
91              }
92          }
93          return _objectList.size() > 0 ? (ret.size() > 1 ? ret : ret.get(0)) : null;
94      }
95  
96      /**
97       * {@inheritDoc}
98       */
99      @Override
100     protected void prepare(final AbstractSQLInsertUpdate<?> _insertUpdate,
101                            final Attribute _attribute,
102                            final Object... _values)
103         throws SQLException
104     {
105         checkSQLColumnSize(_attribute, 1);
106         try {
107             _insertUpdate.column(_attribute.getSqlColNames().get(0), eval(_values));
108         } catch (final EFapsException e) {
109             throw new SQLException(e);
110         }
111     }
112 
113 
114     /**
115      * The value that can be set is a Date, a DateTime or a String
116      * yyyy-MM-dd'T'HH:mm:ss.SSSZZ. It will be normalized to ISO Calender with
117      * TimeZone from SystemAttribute Admin_Common_DataBaseTimeZone. In case that
118      * the SystemAttribute is missing UTC will be used.
119      *
120      * @param _value value to evaluate
121      * @return evaluated value
122      * @throws EFapsException on error
123      */
124     protected Timestamp eval(final Object[] _value)
125         throws EFapsException
126     {
127         final Timestamp ret;
128         if ((_value == null) || (_value.length == 0) || (_value[0] == null)) {
129             ret = null;
130         } else  {
131             final DateTime dateTime = DateTimeUtil.translateFromUI(_value[0]);
132             // until now we have a time that depends on the timezone of the application server
133             // to convert it in a timestamp for the efaps database the timezone information (mainly the offset)
134             // must be removed. This is done by creating a local date with the same, date and time.
135             // this guarantees that the datetime inserted into the database depends on the setting
136             // in the configuration and not on the timezone for the application server.
137             final DateTime localized = new DateTime(dateTime.getYear(),
138                                                     dateTime.getMonthOfYear(),
139                                                     dateTime.getDayOfMonth(),
140                                                     dateTime.getHourOfDay(),
141                                                     dateTime.getMinuteOfHour(),
142                                                     dateTime.getSecondOfMinute(),
143                                                     dateTime.getMillisOfSecond());
144             ret = (localized != null) ? new Timestamp(localized.getMillis()) : null;
145         }
146         return ret;
147     }
148 
149     /**
150      * {@inheritDoc}
151      */
152     @Override
153     public String toString4Where(final Object _value)
154         throws EFapsException
155     {
156         String ret = "";
157         if (_value instanceof ReadableDateTime) {
158             ret = Context.getDbType().getStr4DateTime((ReadableDateTime) _value);
159         } else if (_value instanceof String) {
160             ret = (String) _value;
161         }
162         return ret;
163     }
164 }