1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.convert;
21
22 import org.apache.myfaces.tobago.component.Attributes;
23 import org.apache.myfaces.tobago.util.ComponentUtils;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import javax.faces.component.UIComponent;
28 import javax.faces.context.FacesContext;
29 import javax.faces.convert.Converter;
30 import javax.faces.convert.ConverterException;
31 import java.lang.invoke.MethodHandles;
32 import java.text.DecimalFormat;
33 import java.text.NumberFormat;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.StringTokenizer;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 @org.apache.myfaces.tobago.apt.annotation.Converter(id = DurationConverter.CONVERTER_ID)
57 public class DurationConverter implements Converter {
58
59 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
60
61 public static final String CONVERTER_ID = "org.apache.myfaces.tobago.Duration";
62
63 private enum Unit {
64 nano, milli, second, minute, hour, day, year
65 }
66
67 @Override
68 public String getAsString(
69 final FacesContext facesContext, final UIComponent component, final Object object)
70 throws ConverterException {
71 if (object == null || object instanceof String) {
72 return (String) object;
73 }
74 double aDouble = ((Number) object).doubleValue();
75 boolean negative = false;
76 if (aDouble < 0) {
77 negative = true;
78 aDouble = -aDouble;
79 }
80 final double factor = getUnitFactor(component);
81 aDouble = aDouble * factor;
82
83 final NumberFormat format = new DecimalFormat("00");
84 long value = Double.valueOf(aDouble).longValue();
85 final int seconds = (int) (value % 60);
86 value = value / 60;
87 final int minutes = (int) (value % 60);
88 value = value / 60;
89 final String string;
90 if (value > 0) {
91 string = (negative ? "-" : "") + value + ":"
92 + format.format(minutes) + ":"
93 + format.format(seconds);
94 } else {
95 string = (negative ? "-" : "") + minutes + ":"
96 + format.format(seconds);
97 }
98 LOG.debug("string = '{}'", string);
99 return string;
100 }
101
102 @Override
103 public Object getAsObject(
104 final FacesContext facesContext, final UIComponent component, final String string)
105 throws ConverterException {
106 final boolean negative = string.indexOf('-') > -1;
107 final StringTokenizer tokenizer = new StringTokenizer(string, " :-");
108 final List<String> elements = new ArrayList<>();
109 while (tokenizer.hasMoreTokens()) {
110 elements.add(tokenizer.nextToken());
111 }
112 final int hours;
113 final int minutes;
114 final int seconds;
115 switch (elements.size()) {
116 case 3:
117 hours = Integer.parseInt(elements.get(0));
118 minutes = Integer.parseInt(elements.get(1));
119 seconds = Integer.parseInt(elements.get(2));
120 break;
121 case 2:
122 hours = 0;
123 minutes = Integer.parseInt(elements.get(0));
124 seconds = Integer.parseInt(elements.get(1));
125 break;
126 case 1:
127 hours = 0;
128 minutes = 0;
129 seconds = Integer.parseInt(elements.get(0));
130 break;
131 default:
132 throw new ConverterException("Cannot parse string='" + string + "'");
133 }
134 final double factor = getUnitFactor(component);
135 final long value = (long) (((hours * 60L + minutes) * 60L + seconds) / factor);
136 if (negative) {
137 return -value;
138 } else {
139 return value;
140 }
141 }
142
143 private static double getUnitFactor(final UIComponent component) {
144 final String unitString = ComponentUtils.getStringAttribute(component, Attributes.unit);
145 Unit unit;
146 if (unitString != null) {
147 try {
148 unit = Unit.valueOf(unitString);
149 } catch (final Exception e) {
150 LOG.warn("Unsupported unit: '{}'", unitString);
151 unit = Unit.milli;
152 }
153 } else {
154 unit = Unit.milli;
155 }
156 switch (unit) {
157 case nano:
158 return 0.000_000_001;
159 default:
160 case milli:
161 return 0.001;
162 case second:
163 return 1.0;
164 case minute:
165 return 60.0;
166 case hour:
167 return 3_600.0;
168 case day:
169 return 86_400.0;
170 case year:
171 return 31_556_736.0;
172 }
173 }
174
175 }