001    /*
002     *  Copyright 2001-2011 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time.contrib.hibernate;
017    
018    import java.io.Serializable;
019    import java.sql.PreparedStatement;
020    import java.sql.ResultSet;
021    import java.sql.SQLException;
022    import java.sql.Timestamp;
023    
024    import org.hibernate.HibernateException;
025    import org.hibernate.engine.SessionImplementor;
026    import org.hibernate.type.StandardBasicTypes;
027    import org.hibernate.type.Type;
028    import org.hibernate.usertype.CompositeUserType;
029    import org.joda.time.DateTime;
030    import org.joda.time.Interval;
031    
032    /**
033     * Persist {@link org.joda.time.Interval} via hibernate. Internally, this class
034     * collaborates with {@link org.joda.time.contrib.hibernate.PersistentDateTime}
035     * to convert the start and end components of an Interval to and from the
036     * database correspondents. This class allows clients to execute hibernate or
037     * JPA queries using the attribute names "start" and "end." For example,
038     * <br />
039     * <blockquote>
040     * "from Foo where :date is between barInterval.start and barInterval.end"
041     * </blockquote>
042     * 
043     * @author Christopher R. Gardner (chris_gardner76@yahoo.com)
044     */
045    public class PersistentInterval implements CompositeUserType, Serializable {
046    
047        private static final String[] PROPERTY_NAMES = new String[] { "start", "end" };
048    
049        private static final Type[] TYPES = new Type[] { StandardBasicTypes.TIMESTAMP, StandardBasicTypes.TIMESTAMP };
050    
051        public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
052            return cached;
053        }
054    
055        public Object deepCopy(Object value) throws HibernateException {
056            return value;
057        }
058    
059        public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException {
060            return (Serializable) value;
061        }
062    
063        public boolean equals(Object x, Object y) throws HibernateException {
064            if (x == y) {
065                return true;
066            }
067            if (x == null || y == null) {
068                return false;
069            }
070            return x.equals(y);
071        }
072    
073        public String[] getPropertyNames() {
074            return PROPERTY_NAMES;
075        }
076    
077        public Type[] getPropertyTypes() {
078            return TYPES;
079        }
080    
081        public Object getPropertyValue(Object component, int property) throws HibernateException {
082            Interval interval = (Interval) component;
083            return (property == 0) ? interval.getStart().toDate() : interval.getEnd().toDate();
084        }
085    
086        public int hashCode(Object x) throws HibernateException {
087            return x.hashCode();
088        }
089    
090        public boolean isMutable() {
091            return false;
092        }
093    
094        public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
095                throws HibernateException, SQLException {
096            if (resultSet == null) {
097                return null;
098            }
099            PersistentDateTime pst = new PersistentDateTime();
100            DateTime start = (DateTime) pst.nullSafeGet(resultSet, names[0]);
101            DateTime end = (DateTime) pst.nullSafeGet(resultSet, names[1]);
102            if (start == null || end == null) {
103                return null;
104            }
105            return new Interval(start, end);
106        }
107    
108        public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session)
109                throws HibernateException, SQLException {
110            if (value == null) {
111                statement.setNull(index, StandardBasicTypes.TIMESTAMP.sqlType());
112                statement.setNull(index + 1, StandardBasicTypes.TIMESTAMP.sqlType());
113                return;
114            }
115            Interval interval = (Interval) value;
116            statement.setTimestamp(index, asTimeStamp(interval.getStart()));
117            statement.setTimestamp(index + 1, asTimeStamp(interval.getEnd()));
118        }
119    
120        private Timestamp asTimeStamp(DateTime time) {
121            return new Timestamp(time.getMillis());
122        }
123    
124        public Object replace(Object original, Object target, SessionImplementor session, Object owner)
125                throws HibernateException {
126            return original;
127        }
128    
129        public Class returnedClass() {
130            return Interval.class;
131        }
132    
133        public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
134            throw new UnsupportedOperationException("Immutable Interval");
135        }
136    
137    }