package com.im.imjutil.validation;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import javax.xml.datatype.XMLGregorianCalendar;
import sun.misc.BASE64Decoder;
import com.im.imjutil.cipher.Base64Coder;
import com.im.imjutil.config.Configurator;
import com.im.imjutil.exception.SystemUncheckedException;
import com.im.imjutil.exception.ValidationException;
import com.im.imjutil.util.Albums;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;
/**
* Classe utilitaria para conversao de valores no formato
* <code>String</code> para o seu objeto correspondente.
* Caso o valor nao puder ser convertido, o valor padrao do objeto
* sera retornado em seu lugar, nunca disparando excecoes.
*
* @author Felipe Zappala
*/
public final class Convert {
//
// Padroes de conversao
//
private static final SimpleDateFormat dateFormatter;
private static final String PATTERN_DATE;
private static final String PATTERN_TIME;
private static final String PATTERN_TIMESTAMP;
static {
dateFormatter = new SimpleDateFormat();
dateFormatter.setTimeZone(getSystemTimeZone());
PATTERN_DATE = "dd/MM/yyyy";
PATTERN_TIME = "HH:mm:ss";
PATTERN_TIMESTAMP = "dd/MM/yyyy HH:mm:ss";
}
/** Inibindo a instanciacao. */
private Convert() {
super();
}
/**
* Obtem o fuso horario da configuracao do sistema
*/
private static TimeZone getSystemTimeZone() {
TimeZone tz = null;
try {
String userTZ = Configurator.getProperty("system.timezone");
tz = TimeZone.getTimeZone(userTZ);
} catch (Exception e) {
tz = TimeZone.getDefault();
}
return tz;
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* um conjunto {@link Set} de {@link Number}
*/
private static <N extends Number> Set<N> toNumberSet(
Collection<String> numbers, Class<N> clazz) {
if (!Validator.isEmpty(numbers)) {
Set<N> set = new LinkedHashSet<N>(numbers.size());
for (String n : numbers) {
N number = toNumber(n, clazz);
set.add(number);
}
return set;
}
return new LinkedHashSet<N>();
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* uma lista {@link List} de {@link Number}
*/
private static <N extends Number> List<N> toNumberList(
Collection<String> numbers, Class<N> clazz) {
if (!Validator.isEmpty(numbers)) {
List<N> list = new ArrayList<N>(numbers.size());
for (String n : numbers) {
N number = toNumber(n, clazz);
list.add(number);
}
return list;
}
return new ArrayList<N>();
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* uma lista {@link List} de {@link Integer}
*/
public static List<Integer> toIntegerList(Collection<String> numbers) {
return toNumberList(numbers, Integer.class);
}
/**
* Converte uma array de {@link String} em
* uma lista {@link List} de {@link Integer}
*/
public static List<Integer> toIntegerList(String... numbers) {
return toIntegerList(Albums.asList(numbers));
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* um conjunto {@link Set} de {@link Integer}
*/
public static Set<Integer> toIntegerSet(Collection<String> numbers) {
return toNumberSet(numbers, Integer.class);
}
/**
* Converte um array de {@link String} em
* um conjunto {@link Set} de {@link Integer}
*/
public static Set<Integer> toIntegerSet(String... numbers) {
return toIntegerSet(Albums.asSet(numbers));
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* uma lista {@link List} de {@link Long}
*/
public static List<Long> toLongList(Collection<String> numbers) {
return toNumberList(numbers, Long.class);
}
/**
* Converte um array de {@link String} em
* uma lista {@link List} de {@link Long}
*/
public static List<Long> toLongList(String... numbers) {
return toLongList(Albums.asList(numbers));
}
/**
* Converte uma colecao {@link Collection} de {@link String} em
* um conjunto {@link Set} de {@link Long}
*/
public static Set<Long> toLongSet(Collection<String> numbers) {
return toNumberSet(numbers, Long.class);
}
/**
* Converte um array de {@link String} em
* um conjunto {@link Set} de {@link Long}
*/
public static Set<Long> toLongSet(String...numbers) {
return toLongSet(Albums.asSet(numbers));
}
/**
* Converte um numero em {@link String} para seu objeto correspondente.
*
* @param <N> O objeto do numero esperado.
* @param num A string com o numero.
* @param clss A classe de conversao do numero.
* @return O objeto com o numero convertido.
*/
private static <N extends Number> N toNumber(String num, Class<N> clss) {
N number = null;
try {
Constructor<N> constructor = clss.getConstructor(String.class);
number = constructor.newInstance(num.trim());
} catch (Exception e) {
number = toDefault(clss);
}
return number;
}
/**
* Retorna o numero com valor padrao para a classe passada.
*
* @param <N> O tipo do numero.
* @param clazz A classe do numero.
* @return O numero com valor padrao.
*/
private static <N extends Number> N toDefault(Class<N> clazz) {
return toNumber("0", clazz);
}
/**
* Converte para {@code int}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static int toInteger(String number) {
return toNumber(number, Integer.class);
}
/**
* Converte para {@code int}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> int toInteger(N number) {
if (!Validator.isValid(number)) {
return toDefault(Integer.class);
}
return number.intValue();
}
/**
* Converte para {@code long}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static long toLong(String number) {
return toNumber(number, Long.class);
}
/**
* Converte para {@code long}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> long toLong(N number) {
if (!Validator.isValid(number)) {
return toDefault(Long.class);
}
return number.longValue();
}
/**
* Converte para {@code short}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static short toShort(String number) {
return toNumber(number, Short.class);
}
/**
* Converte para {@code short}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> short toShort(N number) {
if (!Validator.isValid(number)) {
return toDefault(Short.class);
}
return number.shortValue();
}
/**
* Converte para {@code byte}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static byte toByte(String number) {
return toNumber(number, Byte.class);
}
/**
* Converte para {@code byte}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> byte toByte(N number) {
if (!Validator.isValid(number)) {
return toDefault(Byte.class);
}
return number.byteValue();
}
/**
* Converte para {@code float}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static float toFloat(String number) {
return toNumber(correctFP(number), Float.class);
}
/**
* Converte para {@code float}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> float toFloat(N number) {
if (!Validator.isValid(number)) {
return toDefault(Float.class);
}
return number.floatValue();
}
/**
* Converte para {@code double}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static double toDouble(String number) {
return toNumber(correctFP(number), Double.class);
}
/**
* Converte para {@code double}.
*
* @param number O valor em algum outro tipo.
* @return O valor em numero nesse tipo.
*/
public static <N extends Number> double toDouble(N number) {
if (!Validator.isValid(number)) {
return toDefault(Double.class);
}
return number.doubleValue();
}
/**
* Converte para {@link BigDecimal}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static BigDecimal toBigDecimal(String number) {
return toNumber(correctFP(number), BigDecimal.class);
}
/**
* Converte para {@link BigDecimal}.
*
* @param number O valor em Number.
* @return O valor em numero.
*/
public static <N extends Number> BigDecimal toBigDecimal(N number) {
if (!Validator.isValid(number)) {
return toDefault(BigDecimal.class);
}
return toNumber(number.toString(), BigDecimal.class);
}
/**
* Converte para {@link BigInteger}.
*
* @param number O valor em String.
* @return O valor em numero.
*/
public static BigInteger toBigInteger(String number) {
return toNumber(number, BigInteger.class);
}
/**
* Converte para {@link BigInteger}.
*
* @param number O valor em Number.
* @return O valor em numero.
*/
public static <N extends Number> BigInteger toBigInteger(N number) {
if (!Validator.isValid(number)) {
return toDefault(BigInteger.class);
}
return toNumber(number.toString().split("\\.")[0], BigInteger.class);
}
/**
* Converte um objeto {@link Date} para um objeto
* do tipo {@link XMLGregorianCalendar} .
*
* @param timestamp Objeto do tipo {@link Date}.
* @return Retorna um objeto do tipo {@link XMLGregorianCalendar}.
* @deprecated Usar o metodo {@link #toXMLGregorianCalendar}
*/
@SuppressWarnings("dep-ann")
public static XMLGregorianCalendar toTimestamp(Date timestamp) {
return toXMLGregorianCalendar(timestamp);
}
/**
* Converte um objeto {@link Date} para um objeto
* do tipo {@link XMLGregorianCalendar} .
*
* @param timestamp Objeto do tipo {@link Date}.
* @return Retorna um objeto do tipo {@link XMLGregorianCalendar}.
*/
public static XMLGregorianCalendar toXMLGregorianCalendar(Date timestamp) {
if (timestamp == null) {
return null;
}
Calendar c = Calendar.getInstance();
c.setTime(timestamp);
return XMLGregorianCalendarImpl.createDateTime(
c.get(Calendar.YEAR),
c.get(Calendar.MONTH) + 1,
c.get(Calendar.DAY_OF_MONTH),
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE),
c.get(Calendar.SECOND));
}
/**
* Converte uma data e a hora no formato do padrao passado.
*
* @param timestamp A data/hora em texto.
* @param pattern O formato da data.
* @return O objeto {@link Date} da data/hora.
*/
public static Date toTimestamp(String pattern, String timestamp) {
if (!Validator.isValid(timestamp, pattern)) {
return null;
}
Date d = null;
try {
dateFormatter.applyPattern(pattern);
d = dateFormatter.parse(timestamp);
} catch (ParseException e) {
/* Do nothing...*/
}
return d;
}
/**
* Converte uma data e a hora no formato: <code>dd/MM/yyyy hh:mm:ss</code>
*
* @param timestamp A data/hora em texto.
* @param pattern O formato da data.
* @return O objeto {@link Date} da data/hora.
*/
public static Date toTimestamp(String timestamp) {
return toTimestamp(PATTERN_TIMESTAMP, timestamp);
}
/**
* Converte uma data no formato: <code>dd/MM/yyyy</code>
*
* @param date A data em texto.
* @return O objeto {@link Date} de data.
*/
public static Date toDate(String date) {
return toTimestamp(PATTERN_DATE, date);
}
/**
* Converte um objeto {@link XMLGregorianCalendar} para um objeto
* do tipo {@link Date}.
*
* @param calendar Objeto do tipo {@link XMLGregorianCalendar}.
* @return Retorna um objeto do tipo {@link Date}.
*/
public static Date toDate(XMLGregorianCalendar calendar) {
if (calendar == null) {
return null;
}
Calendar result = Calendar.getInstance();
result.set(Calendar.YEAR, calendar.getYear());
result.set(Calendar.MONTH, calendar.getMonth() - 1);
result.set(Calendar.DAY_OF_MONTH, calendar.getDay());
result.set(Calendar.HOUR_OF_DAY, calendar.getHour());
result.set(Calendar.MINUTE, calendar.getMinute());
result.set(Calendar.SECOND, calendar.getSecond());
return result.getTime();
}
/**
* Converte uma hora no formato: <code>hh:mm:ss</code>
*
* @param time A hora em texto.
* @return O objeto {@link Date} da hora.
*/
public static Date toTime(String time) {
return toTimestamp(PATTERN_TIME, time);
}
/**
* Converte uma data {@link Date} em um {@link Calendar}
*
* @param date O objeto de data {@link Date}.
* @return O objeto {@link Calendar} resultante.
*/
public static Calendar toCalendar(Date date) {
Calendar calendar = null;
if (date != null) {
calendar = Calendar.getInstance();
calendar.setTime(date);
}
return calendar;
}
/**
* Converte uma data e a hora no formato: <code>dd/MM/yyyy hh:mm:ss</code>
*
* @param timestamp A data/hora em texto.
* @param pattern O formato da data.
* @return O objeto {@link Calendar} da data/hora.
*/
public static Calendar toCalendar(String pattern, String timestamp) {
return toCalendar(toTimestamp(pattern, timestamp));
}
/**
* Converte uma data e a hora no formato: <code>dd/MM/yyyy hh:mm:ss</code>
*
* @param timestamp A data/hora em texto.
* @return O objeto {@link Calendar} da data/hora.
*/
public static Calendar toCalendar(String timestamp) {
return toCalendar(toTimestamp(timestamp));
}
/**
* Converte uma hora no formato: <code>hh:mm:ss</code>
*
* @param time A hora em texto.
* @return O objeto {@link Calendar} da hora.
*/
public static Calendar toTimeCalendar(String time) {
return toCalendar(toTime(time));
}
/**
* Converte uma data no formato: <code>dd/MM/yyyy</code>
*
* @param date A data em texto.
* @return O objeto {@link Calendar} de data.
*/
public static Calendar toDateCalendar(String date) {
return toCalendar(toDate(date));
}
/** Corrige o ponto flutuante, convertendo as virgulas para pontos. */
private static String correctFP(String floatingPoint) {
if (!Validator.isValid(floatingPoint)) {
return null;
}
return floatingPoint.replaceAll("\\,", ".");
}
/**
* Converte para {@code boolean}.
*
* @param bool O valor em {@link String} ou {@link Boolean}.
* @return O valor em boolean.
*/
public static boolean toBoolean(Object bool) {
try {
if (bool instanceof String) {
return Boolean.valueOf((String) bool);
} else if (bool instanceof Boolean) {
return ((Boolean) bool).booleanValue();
} else if (bool instanceof Number) {
return ((Number) bool).doubleValue() != 0;
}
} catch (Exception e) {
//Nada faz...
}
return false;
}
/**
* Converte para {@code char}.
*
* @param character O valor em {@link String}.
* @return O valor em caracter.
*/
public static char toCharacter(String character) {
try {
return character.charAt(0);
} catch (Exception e) {
return '\u0000';
}
}
/**
* Converte para {@code char}.
*
* @param character O valor em {@link String}.
* @return O valor em caracter.
*/
public static char toCharacter(Character character) {
if (character != null) {
return character.charValue();
}
return '\u0000';
}
/**
* Converte uma {@link String} codificada em base64 para {@link byte[]}.
*
* @param base64 A string de bytes codificados em base64.
* @return O byte array resultante.
*/
public static byte[] toBytes(String base64) {
if (!Validator.isValid(base64)) {
throw new ValidationException("String base64 nulo ou vazio");
}
return Base64Coder.decrypt(base64);
}
/**
* Converte uma {@link String} hexadecimal para {@link byte[]}.
*
* @param hexadecimal A string de bytes representados em hexadecimal.
* @return O byte array resultante.
*/
public static byte[] toHexabytes(String hexadecimal) {
if (!Validator.isValid(hexadecimal)) {
throw new ValidationException("String hexadecimal nulo ou vazio");
}
byte[] bytes = new byte[hexadecimal.length() / 2];
for (int i = 0; i < bytes.length; ++i) {
bytes[i] = (byte) Integer.parseInt(
hexadecimal.substring(2*i, 2*i+2), 16);
}
return bytes;
}
/**
* Converte um {@link byte[]} para uma {@link String} codificada em base64.
*
* @param base64 A string de bytes codificados em base64.
* @return O byte array resultante.
*/
public static String toBase64(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
throw new ValidationException("Byte array nulo ou vazio");
}
return Base64Coder.encrypt(bytes);
}
/**
* Converte um {@link byte[]} para uma {@link String} hexadecimal.
*
* @param bytes O array de bytes a ser formatado
* @return A string resultante.
*/
public static String toHexadecimal(byte[] bytes) {
StringBuffer strbuf = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; ++i) {
if ((bytes[i] & 0xff) < 0x10) {
strbuf.append('0');
}
strbuf.append(Long.toString(bytes[i] & 0xff, 16));
}
return strbuf.toString();
}
/**
* Converte um {@link InputStream} em um {@link byte[]}.
*
* @param in O stream a ser convertido.
* @return O array de bytes resultante.
*/
public static byte[] toBytes(InputStream in) {
if (in == null) {
throw new ValidationException("O stream passado e nulo");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
InputStream is = new BufferedInputStream(in);
byte[] buffer = new byte[4096];
int read = 0;
while ( (read = is.read(buffer)) != -1 ) {
baos.write(buffer, 0, read);
}
is.close();
} catch (Exception e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
return baos.toByteArray();
}
/**
* Converte um {@link byte[]} em um {@link InputStream}.
*
* @param in O array de bytes a ser convertido.
* @return O stream resultante.
*/
public static InputStream toInputStream(byte[] bytes) {
try {
return new ByteArrayInputStream(bytes);
} catch (Exception e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
}
/**
* Converte um {@link byte[]} em um {@link InputStream}.
*
* @param in O array de bytes a ser convertido.
* @return O stream resultante.
*/
public static Reader toReader(String str) {
try {
return new InputStreamReader(toInputStream(str.getBytes()));
} catch (Exception e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
}
/**
* Converte um {@link File} em um {@link byte[]}.
*
* @param file O arquivo a ser convertido.
* @return O array de bytes resultante.
*/
public static byte[] toBytes(File file) {
if (file == null) {
throw new ValidationException("O arquivo passado e nulo");
}
if (!file.exists()) {
throw new ValidationException("O arquivo passado nao existe");
}
byte[] bytes;
try {
bytes = toBytes(new FileInputStream(file));
} catch (Exception e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
return bytes;
}
/**
* Converte um {@link byte[]} para um {@link File} em num path temporario
*
* @param bytes O byte array a ser escrito no arquivo
* @param filename Nome do arquivo
* @return O arquivo resultante
*/
public static File toFile(byte[] bytes, String filename) {
if (bytes == null || bytes.length == 0) {
throw new ValidationException("Byte array nulo ou vazio");
}
try {
File f = new File(filename);
OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
os.write(bytes);
os.flush();
os.close();
return f;
} catch (IOException e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
}
/**
* Converte um {@link byte[]} para um {@link File} em num path temporario.
*
* @param bytes O byte array a ser escrito no arquivo.
* @return O arquivo resultante.
*/
public static File toFile(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
throw new ValidationException("Byte array nulo ou vazio");
}
try {
File f = File.createTempFile("TempFile-", ".bin");
OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
os.write(bytes);
os.flush();
os.close();
return f;
} catch (IOException e) {
throw new SystemUncheckedException(e.getMessage(), e);
}
}
/**
* Converte uma string base 64 em um arquivo do tipo {@link File}.
*
* @param base64 Arquivo no formato base64.
* @param filename Nome do arquivo a ser gerado.
* @param Exetensao do arquivo a ser gerado.
* @return Retorna um objeto do tipo {@link File}
*
* @throws Exception Lanca uma excecao para o escopo de chamada do metodo
*/
public static File toFile(String base64, String filename,
String fileExtension) throws Exception {
byte[] imageStream = new BASE64Decoder().decodeBuffer(base64);
File file = File.createTempFile(filename, fileExtension);
FileOutputStream fos = new FileOutputStream(file);
fos.write(imageStream);
fos.close();
return file;
}
/**
* Converte um {@link Object} para {@link String}.
* Caso o objeto for nulo ele retorna uma string vazia.
*
* @param objects Objetos a serem convertidos para {@link String}.
* @return String resultante da conversao.
*/
public static String toString(Object... objects) {
StringBuilder converted = new StringBuilder();
if (objects != null) {
for (Object object : objects) {
converted.append(object);
}
}
return converted.toString();
}
/**
* Converte um {@link InputStream} para {@link String}.
* Caso o objeto for nulo ele retorna uma string vazia.
*
* @param in O stream a ser convertido.
* @return A string resultante
*/
public static String toString(InputStream in) {
try {
return toString(new InputStreamReader(in));
} catch (Exception e) {
return "";
}
}
/**
* Converte um {@link Reader} para {@link String}.
* Caso o objeto for nulo ele retorna uma string vazia.
*
* @param reader O stream a ser convertido.
* @return A string resultante
*/
public static String toString(Reader reader) {
StringBuilder converted = new StringBuilder();
try {
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) {
converted.append(line).append('\n');
}
} catch (Exception e) {
// Nada faz
}
return converted.toString();
}
}