| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.myfaces.tobago.convert; |
| |
| import org.apache.myfaces.tobago.component.Attributes; |
| import org.apache.myfaces.tobago.util.ComponentUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.faces.component.UIComponent; |
| import javax.faces.context.FacesContext; |
| import javax.faces.convert.Converter; |
| import javax.faces.convert.ConverterException; |
| import java.lang.invoke.MethodHandles; |
| import java.text.DecimalFormat; |
| import java.text.NumberFormat; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| |
| /** |
| * Converts durations. The duration value in the model is of type long. |
| * The string format must have one of this patterns: |
| * <ul> |
| * <li>hh:MM:ss</li> |
| * <li>MM:ss</li> |
| * <li>ss</li> |
| * </ul> |
| * There may be an optional attribute "unit" in the component, which allows to set the unit of the model. |
| * The default unit is "millis". |
| * <table> |
| * <caption>Examples</caption> |
| * <tr><th>input string</th><th>unit</th><th>resulting long in model</th><th>Remark</th></tr> |
| * <tr><td>1:15</td><td>milli</td><td>75000</td><td></td></tr> |
| * <tr><td>1:15:00</td><td>hour</td><td>1</td><td>Loosing 15 Minutes!</td></tr> |
| * <tr><td>1:15:00</td><td>null</td><td>4500000</td><td></td></tr> |
| * </table> |
| */ |
| @org.apache.myfaces.tobago.apt.annotation.Converter(id = DurationConverter.CONVERTER_ID) |
| public class DurationConverter implements Converter { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); |
| |
| public static final String CONVERTER_ID = "org.apache.myfaces.tobago.Duration"; |
| |
| private enum Unit { |
| nano, milli, second, minute, hour, day, year |
| } |
| |
| @Override |
| public String getAsString( |
| final FacesContext facesContext, final UIComponent component, final Object object) |
| throws ConverterException { |
| if (object == null || object instanceof String) { |
| return (String) object; |
| } |
| double aDouble = ((Number) object).doubleValue(); |
| boolean negative = false; |
| if (aDouble < 0) { |
| negative = true; |
| aDouble = -aDouble; |
| } |
| final double factor = getUnitFactor(component); |
| aDouble = aDouble * factor; |
| |
| final NumberFormat format = new DecimalFormat("00"); |
| long value = Double.valueOf(aDouble).longValue(); |
| final int seconds = (int) (value % 60); |
| value = value / 60; |
| final int minutes = (int) (value % 60); |
| value = value / 60; |
| final String string; |
| if (value > 0) { |
| string = (negative ? "-" : "") + value + ":" |
| + format.format(minutes) + ":" |
| + format.format(seconds); |
| } else { |
| string = (negative ? "-" : "") + minutes + ":" |
| + format.format(seconds); |
| } |
| LOG.debug("string = '{}'", string); |
| return string; |
| } |
| |
| @Override |
| public Object getAsObject( |
| final FacesContext facesContext, final UIComponent component, final String string) |
| throws ConverterException { |
| final boolean negative = string.indexOf('-') > -1; |
| final StringTokenizer tokenizer = new StringTokenizer(string, " :-"); |
| final List<String> elements = new ArrayList<>(); |
| while (tokenizer.hasMoreTokens()) { |
| elements.add(tokenizer.nextToken()); |
| } |
| final int hours; |
| final int minutes; |
| final int seconds; |
| switch (elements.size()) { |
| case 3: |
| hours = Integer.parseInt(elements.get(0)); |
| minutes = Integer.parseInt(elements.get(1)); |
| seconds = Integer.parseInt(elements.get(2)); |
| break; |
| case 2: |
| hours = 0; |
| minutes = Integer.parseInt(elements.get(0)); |
| seconds = Integer.parseInt(elements.get(1)); |
| break; |
| case 1: |
| hours = 0; |
| minutes = 0; |
| seconds = Integer.parseInt(elements.get(0)); |
| break; |
| default: |
| throw new ConverterException("Cannot parse string='" + string + "'"); |
| } |
| final double factor = getUnitFactor(component); |
| final long value = (long) (((hours * 60L + minutes) * 60L + seconds) / factor); |
| if (negative) { |
| return -value; |
| } else { |
| return value; |
| } |
| } |
| |
| private static double getUnitFactor(final UIComponent component) { |
| final String unitString = ComponentUtils.getStringAttribute(component, Attributes.unit); |
| Unit unit; |
| if (unitString != null) { |
| try { |
| unit = Unit.valueOf(unitString); |
| } catch (final Exception e) { |
| LOG.warn("Unsupported unit: '{}'", unitString); |
| unit = Unit.milli; |
| } |
| } else { |
| unit = Unit.milli; |
| } |
| switch (unit) { |
| case nano: |
| return 0.000_000_001; |
| default: |
| case milli: |
| return 0.001; |
| case second: |
| return 1.0; |
| case minute: |
| return 60.0; |
| case hour: |
| return 3_600.0; |
| case day: |
| return 86_400.0; |
| case year: |
| return 31_556_736.0; |
| } |
| } |
| |
| } |