/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.common.io; import slash.common.type.CompactCalendar; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.*; import java.util.logging.Logger; import java.util.prefs.Preferences; import static java.lang.Double.POSITIVE_INFINITY; import static java.lang.Integer.toHexString; import static java.lang.Math.*; import static java.text.DateFormat.MEDIUM; import static java.text.DateFormat.SHORT; import static java.util.Calendar.*; import static slash.common.type.CompactCalendar.UTC; import static slash.common.type.CompactCalendar.fromMillis; /** * Provides value transfer functionality. * * @author Christian Pesch */ public class Transfer { private Transfer() {} private static final Preferences preferences = Preferences.userNodeForPackage(Transfer.class); private static final Logger log = Logger.getLogger(Transfer.class.getName()); private static final String REDUCE_TIME_TO_SECOND_PRECISION_PREFERENCE = "reduceTimeToSecondPrecision"; public static final String ISO_LATIN1_ENCODING = "ISO-8859-1"; public static final String UTF8_ENCODING = "UTF-8"; public static final String UTF16_ENCODING = "UTF-16"; public static final String UTF16LE_ENCODING = "UTF-16LE"; public static double roundFraction(double number, int fractionCount) { double factor = pow(10, fractionCount); return round(number * factor) / factor; } public static double ceilFraction(double number, int fractionCount) { double factor = pow(10, fractionCount); return ceil(number * factor) / factor; } public static double roundMeterToMillimeterPrecision(double number) { return floor(number * 10000.0) / 10000.0; } public static long roundMillisecondsToSecondPrecision(long number) { return (number / 1000) * 1000; } public static int ceiling(int dividend, int divisor, boolean roundUpToAtLeastOne) { double fraction = (double) dividend / divisor; double result = ceil(fraction); return max((int) result, roundUpToAtLeastOne ? 1 : 0); } public static int widthInDigits(long number) { return 1 + (int) (log(number) / log(10)); } public static String trim(String string) { if (string == null) return null; string = string.trim(); if (string.length() == 0) return null; else return string; } public static String trim(String string, int length) { if (string == null) return null; string = trim(string); return string.substring(0, min(string.length(), length)); } public static String trimLineFeeds(String string) { string = string.replace('\n', ' '); string = string.replace('\r', ' '); return string; } public static String toMixedCase(String string) { if (string != null && string.toUpperCase().equals(string)) { StringBuilder buffer = new StringBuilder(); StringTokenizer tokenizer = new StringTokenizer(string, " -", true); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.length() > 1) buffer.append(token.substring(0, 1).toUpperCase()).append(token.substring(1).toLowerCase()); else buffer.append(token); } return buffer.toString(); } else return string; } public static String escape(String string, char escape, char replacement, String defaultString) { String trimmed = trim(string); if (trimmed != null) trimmed = trimmed.replaceAll("\\" + escape, String.valueOf(replacement)); else trimmed = defaultString; return trimmed; } public static String escape(String string, char escape, char replacement) { return escape(string, escape, replacement, ""); } public static Double formatDouble(BigDecimal aBigDecimal) { return aBigDecimal != null ? aBigDecimal.doubleValue() : null; } public static Integer formatInt(BigInteger aBigInteger) { return aBigInteger != null ? aBigInteger.intValue() : null; } private static final NumberFormat DECIMAL_NUMBER_FORMAT = DecimalFormat.getNumberInstance(Locale.US); static { DECIMAL_NUMBER_FORMAT.setGroupingUsed(false); DECIMAL_NUMBER_FORMAT.setMinimumFractionDigits(1); DECIMAL_NUMBER_FORMAT.setMaximumFractionDigits(20); } public static String formatDoubleAsString(Double aDouble) { if (aDouble == null) return "0.0"; return DECIMAL_NUMBER_FORMAT.format(aDouble); } public static String formatDoubleAsString(Double aDouble, int exactFractionCount) { StringBuilder buffer = new StringBuilder(formatDoubleAsString(aDouble)); int index = buffer.indexOf("."); if (index == -1) { buffer.append("."); } while (buffer.length() - index <= exactFractionCount) buffer.append("0"); while (buffer.length() - index > exactFractionCount + 1) buffer.deleteCharAt(buffer.length() - 1); return buffer.toString(); } public static String formatIntAsString(Integer anInteger) { if (anInteger == null) return "0"; return Integer.toString(anInteger); } public static String formatIntAsString(Integer anInteger, int exactDigitCount) { StringBuilder buffer = new StringBuilder(formatIntAsString(anInteger)); while (buffer.length() < exactDigitCount) buffer.insert(0, "0"); return buffer.toString(); } public static BigInteger formatInt(Integer anInteger) { if (anInteger == null) return null; return BigInteger.valueOf(anInteger); } public static Float formatFloat(Double aDouble) { if (aDouble == null) return null; return aDouble.floatValue(); } public static Double parseDouble(String string) { String trimmed = trim(string); if (trimmed != null) { trimmed = trimmed.replaceAll(",", "."); try { return Double.parseDouble(trimmed); } catch (NumberFormatException e) { if (trimmed.equals("\u221e")) return POSITIVE_INFINITY; throw e; } } else return null; } public static String formatDuration(long milliseconds) { long seconds = milliseconds / 1000; long minutes = seconds / 60; long hours = minutes / 60; return formatIntAsString((int) hours, 2) + ":" + formatIntAsString((int) minutes % 60, 2) + ":" + formatIntAsString((int) seconds % 60, 2); } public static Integer parseInteger(String string) { String trimmed = trim(string); if (trimmed != null) { if (trimmed.startsWith("+")) trimmed = trimmed.substring(1); return Integer.parseInt(trimmed); } else return null; } public static int parseInt(String string) { Integer integer = parseInteger(string); return integer != null ? integer : -1; } public static Long parseLong(String string) { String trimmed = trim(string); if (trimmed != null) { if (trimmed.startsWith("+")) trimmed = trimmed.substring(1); return Long.parseLong(trimmed); } else return null; } public static long parselong(String string) { Long aLong = parseLong(string); return aLong != null ? aLong : -1; } public static boolean isEmpty(String string) { return string == null || string.length() == 0; } public static boolean isEmpty(Integer integer) { return integer == null || integer == 0; } public static boolean isEmpty(Long aLong) { return aLong == null || aLong == 0; } public static boolean isEmpty(Double aDouble) { return aDouble == null || aDouble == 0.0; } public static boolean isEmpty(BigDecimal bigDecimal) { return bigDecimal == null || isEmpty(bigDecimal.doubleValue()); } public static double toDouble(Double aDouble) { return aDouble == null ? 0.0 : aDouble; } public static int[] toArray(List<Integer> integers) { int[] result = new int[integers.size()]; for (int i = 0; i < result.length; i++) { result[i] = integers.get(i); } return result; } public static String encodeUri(String uri) { try { return URLEncoder.encode(uri, UTF8_ENCODING); } catch (UnsupportedEncodingException e) { log.severe("Cannot encode uri " + uri + ": " + e); return uri; } } public static String encodeUriButKeepSlashes(String uri) { return encodeUri(uri).replace("%2F", "/"); // better not .replace("%3A", ":"); } public static String decodeUri(String uri) { try { return URLDecoder.decode(uri, UTF8_ENCODING); } catch (UnsupportedEncodingException e) { log.severe("Cannot decode uri " + uri + ": " + e); return uri; } } private static final char URI_ESCAPE_CHAR = '%'; private static final String FORBIDDEN_CHARACTERS = "\\/:*?\"<>|"; public static String encodeFileName(String name) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if ((c == '.' && i == 0) || c == URI_ESCAPE_CHAR || FORBIDDEN_CHARACTERS.indexOf(c) != -1) { builder.append(URI_ESCAPE_CHAR); if (c < 0x10) builder.append('0'); builder.append(toHexString(c)); } else { builder.append(c); } } return builder.toString(); } private static final DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(SHORT, MEDIUM); private static String currentDateTimeTimeZone = ""; private static final DateFormat dateFormat = DateFormat.getDateInstance(SHORT); private static String currentDateTimeZone = ""; private static final DateFormat timeFormat = DateFormat.getTimeInstance(MEDIUM); private static String currentTimeTimeZone = ""; public synchronized static DateFormat getDateTimeFormat(String timeZonePreference) { if (!currentDateTimeTimeZone.equals(timeZonePreference)) { dateTimeFormat.setTimeZone(TimeZone.getTimeZone(timeZonePreference)); currentDateTimeTimeZone = timeZonePreference; } return dateTimeFormat; } public synchronized static DateFormat getDateFormat(String timeZonePreference) { if (!currentDateTimeZone.equals(timeZonePreference)) { dateFormat.setTimeZone(TimeZone.getTimeZone(timeZonePreference)); currentDateTimeZone = timeZonePreference; } return dateFormat; } public synchronized static DateFormat getTimeFormat(String timeZonePreference) { if (!currentTimeTimeZone.equals(timeZonePreference)) { timeFormat.setTimeZone(TimeZone.getTimeZone(timeZonePreference)); currentTimeTimeZone = timeZonePreference; } return timeFormat; } public static CompactCalendar parseXMLTime(XMLGregorianCalendar calendar) { if (calendar == null) return null; GregorianCalendar gregorianCalendar = calendar.toGregorianCalendar(UTC, null, null); return fromMillis(gregorianCalendar.getTimeInMillis()); } private static DatatypeFactory datatypeFactory = null; private static synchronized DatatypeFactory getDataTypeFactory() throws DatatypeConfigurationException { if (datatypeFactory == null) { datatypeFactory = DatatypeFactory.newInstance(); } return datatypeFactory; } public static XMLGregorianCalendar formatXMLTime(CompactCalendar time) { return formatXMLTime(time, preferences.getBoolean(REDUCE_TIME_TO_SECOND_PRECISION_PREFERENCE, false)); } public static XMLGregorianCalendar formatXMLTime(CompactCalendar time, boolean reduceTimeToSecondPrecision) { if (time == null) return null; try { GregorianCalendar gregorianCalendar = toUTC(time.getCalendar()); XMLGregorianCalendar result = getDataTypeFactory().newXMLGregorianCalendar(gregorianCalendar); if (reduceTimeToSecondPrecision) result.setFractionalSecond(null); return result; } catch (DatatypeConfigurationException e) { return null; } } @SuppressWarnings("MagicConstant") private static GregorianCalendar toUTC(Calendar calendar) { GregorianCalendar gregorianCalendar = new GregorianCalendar(UTC, Locale.getDefault()); gregorianCalendar.clear(); gregorianCalendar.set(calendar.get(YEAR), calendar.get(MONTH), calendar.get(DATE), calendar.get(HOUR_OF_DAY), calendar.get(MINUTE), calendar.get(SECOND)); gregorianCalendar.set(MILLISECOND, calendar.get(MILLISECOND)); return gregorianCalendar; } }