Merge branch 'release/5.45.0'
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / hibernate / PartialUserType.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.hibernate;
10
11 import java.sql.PreparedStatement;
12 import java.sql.ResultSet;
13 import java.sql.SQLException;
14 import java.sql.Types;
15
16 import org.apache.logging.log4j.LogManager;
17 import org.apache.logging.log4j.Logger;
18 import org.hibernate.HibernateException;
19 import org.hibernate.engine.spi.SharedSessionContractImplementor;
20 import org.hibernate.type.StandardBasicTypes;
21 import org.hibernate.usertype.UserType;
22 import org.jadira.usertype.spi.shared.AbstractUserType;
23 import org.joda.time.DateTimeFieldType;
24 import org.joda.time.Partial;
25
26 /**
27 * Persist {@link org.joda.time.Partial} via hibernate.
28 * This is a preliminary implementation that fulfills the needs of CDM but does not fully store a Partial.
29 * Only year, month and day is stored. Since 5.0 also hour and minute is supported.
30 *
31 * @author a.mueller
32 * @since 11.11.2008
33 */
34 public class PartialUserType extends AbstractUserType implements UserType /* extends AbstractSingleColumnUserType<Partial, String, ColumnMapper<Partial,String>> implements UserType */ {
35 private static final long serialVersionUID = -5323104403077597869L;
36
37 private static final Logger logger = LogManager.getLogger();
38
39 //not required
40 public final static PartialUserType INSTANCE = new PartialUserType();
41
42 private static final int[] SQL_TYPES = new int[]{
43 Types.VARCHAR,
44 };
45
46
47 @Override
48 public Partial nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
49 throws HibernateException, SQLException {
50 String partial = (String)StandardBasicTypes.STRING.nullSafeGet(rs, names, session, owner);
51 Partial result = new Partial();
52 if (partial == null || "00000000".equals(partial) || "0000000000000".equals(partial)) {
53 return null;
54 }else if (partial.length() != 8 && partial.length() != 13){
55 throw new HibernateException("Format for Partial not supported. Length mus be 8 or 13: " + partial);
56 }
57 Integer year = Integer.valueOf(partial.substring(0,4));
58 Integer month = Integer.valueOf(partial.substring(4,6));
59 Integer day = Integer.valueOf(partial.substring(6,8));
60 Integer hour = null;
61 Integer minute = null;
62 if (partial.length() == 13){
63 hour = Integer.valueOf(partial.substring(9,11));
64 minute = Integer.valueOf(partial.substring(11,13));
65 }
66
67 if (year != 0){
68 result = result.with(DateTimeFieldType.year(), year);
69 }
70 if (month != 0){
71 result = result.with(DateTimeFieldType.monthOfYear(), month);
72 }
73 if (day != 0){
74 result = result.with(DateTimeFieldType.dayOfMonth(), day);
75 }
76 if (hour != null){
77 result = result.with(DateTimeFieldType.hourOfDay(), hour);
78 }
79 if (minute != null){
80 result = result.with(DateTimeFieldType.minuteOfHour(), minute);
81 }
82 return isEmptyOrNull(result)? null:result;
83 }
84
85 private boolean isEmptyOrNull(Partial partial) {
86 return partial == null ? true : partial.getValues().length == 0;
87 }
88
89 @Override
90 public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index,
91 SharedSessionContractImplementor session) throws HibernateException, SQLException {
92 if (isEmptyOrNull((Partial)value)){
93 StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session);
94 }else {
95 Partial p = ((Partial) value);
96 StandardBasicTypes.STRING.nullSafeSet(preparedStatement, partialToString(p), index, session);
97 }
98 }
99
100 /**
101 * @param p
102 * @return an ISO 8601 like time representations of the form yyyyMMdd
103 */
104 public static String partialToString(Partial p) {
105 //FIXME reduce code by use org.joda.time.format.ISODateTimeFormat.basicDate() instead ?
106 // for a date with unknown day this will produce e.g. 195712??
107 //
108 String strYear = getNullFilledString(p, DateTimeFieldType.year(),4);
109 String strMonth = getNullFilledString(p, DateTimeFieldType.monthOfYear(),2);
110 String strDay = getNullFilledString(p, DateTimeFieldType.dayOfMonth(),2);
111 String strHour = getNullFilledString(p, DateTimeFieldType.hourOfDay(),2);
112 String strMinute = getNullFilledString(p, DateTimeFieldType.minuteOfHour(),2);
113 boolean timeExists = timeExists(p);
114 String result = strYear + strMonth + strDay;
115 if (timeExists) {
116 result = result + "_" + strHour + strMinute;
117 }
118 return result;
119 }
120
121 private static boolean timeExists(Partial partial) {
122 return partial.isSupported(DateTimeFieldType.hourOfDay()) ||
123 partial.isSupported(DateTimeFieldType.minuteOfHour());
124 }
125
126 private static String getNullFilledString(Partial partial, DateTimeFieldType type, int count){
127 String nul = "0000000000";
128 if (! partial.isSupported(type)){
129 return nul.substring(0, count);
130 }else{
131 int value = partial.get(type);
132 String result = String.valueOf(value);
133 if (result.length() > count){
134 logger.error("value to long");
135 result = result.substring(0, count);
136 }else if (result.length() < count){
137 result = nul.substring(0, count - result.length()) + result;
138 }
139 return result;
140 }
141 }
142
143 @Override
144 public Object deepCopy(Object value) throws HibernateException {
145 if (value == null) {
146 return null;
147 }
148
149 return value;
150 }
151
152 @Override
153 public int[] sqlTypes() {
154 return SQL_TYPES;
155 }
156
157 @Override
158 public Class<?> returnedClass() {
159 return Partial.class;
160 }
161 }