/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos 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.
Cyclos 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 Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.utils;
import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import nl.strohalm.cyclos.entities.Entity;
import nl.strohalm.cyclos.entities.EntityReference;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.hibernate.Hibernate;
/**
* Helper class used to format general objects
* @author luis
*/
public class FormatObject {
public static final String[] DEFAULT_EXCLUDES = { "password", "transactionPassword", "pin", "credential", "securityCode" };
public static final String MASKED_VALUE = "***";
private static final NumberFormat INTEGER_FORMAT;
private static final NumberFormat FLOAT_FORMAT;
private static final DateFormat DATE_FORMAT;
private static final DateFormat DATE_TIME_FORMAT;
static {
INTEGER_FORMAT = new DecimalFormat("#,##0", new DecimalFormatSymbols(Locale.US));
FLOAT_FORMAT = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(Locale.US));
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
/**
* Formats a method argument
*/
public static String formatArgument(final Object argument) {
final boolean quote = (argument instanceof String) || (argument instanceof Entity);
final String str = StringUtils.replace(formatObject(argument), "\n", "\\n");
return quote ? '"' + str + '"' : str;
}
/**
* Format an object
*/
public static String formatObject(final Object object) {
return formatObject(object, "<null>");
}
/**
* Format an object
*/
public static String formatObject(final Object object, final String defaultValue) {
return formatObject(object, defaultValue, "<empty>");
}
/**
* Format an object
*/
public static String formatObject(final Object object, final String defaultValue, final String emptyValue) {
if (object == null) {
return defaultValue;
}
try {
if (object instanceof Number) {
if ((object instanceof Float) || (object instanceof Double) || (object instanceof BigDecimal)) {
return FLOAT_FORMAT.format(((Number) object).doubleValue());
}
return INTEGER_FORMAT.format(((Number) object).longValue());
} else if ((object instanceof Calendar) || (object instanceof Date)) {
final Date date = (object instanceof Calendar) ? ((Calendar) object).getTime() : (Date) object;
final Date truncated = DateUtils.truncate(date, Calendar.DATE);
if (date.equals(truncated)) {
return DATE_FORMAT.format(date);
} else {
return DATE_TIME_FORMAT.format(date);
}
} else if (object instanceof Collection<?> || object instanceof Map<?, ?> || object.getClass().isArray()) {
if (object instanceof Iterator<?>) {
return "<iterator>";
} else if (Hibernate.isInitialized(object)) {
Iterator<?> iterator;
if (object instanceof Map<?, ?>) {
iterator = ((Map<?, ?>) object).entrySet().iterator();
} else {
iterator = IteratorUtils.getIterator(object);
}
final StringBuilder sb = new StringBuilder();
sb.append('[');
while (iterator.hasNext()) {
sb.append(formatArgument(iterator.next()));
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append(']');
return sb.toString();
} else {
return "<uninitialized collection>";
}
} else if (object instanceof String) {
return "".equals("object") ? emptyValue : (String) object;
} else if (object instanceof Boolean) {
return object.toString();
} else if ((object instanceof Entity) && (object instanceof EntityReference) || !Hibernate.isInitialized(object)) {
return ClassHelper.getClassName(EntityHelper.getRealClass((Entity) object)) + '#' + ((Entity) object).getId();
} else {
return object.toString();
}
} catch (final Exception e) {
return defaultValue;
}
}
/**
* Format a generic view object
*/
public static String formatVO(final Object vo) {
return formatVO(vo, DEFAULT_EXCLUDES);
}
/**
* Format a generic view object
*/
public static String formatVO(final Object vo, final String... excludedProperties) {
if (vo == null) {
return "<null>";
}
try {
final List<String> exclude = new ArrayList<String>();
exclude.add("class");
if (excludedProperties != null && excludedProperties.length > 0) {
exclude.addAll(Arrays.asList(excludedProperties));
}
final StringBuilder sb = new StringBuilder();
sb.append(ClassHelper.getClassName(vo.getClass())).append(" (");
final PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(vo);
for (final PropertyDescriptor descriptor : propertyDescriptors) {
final String name = descriptor.getName();
if (exclude(exclude, name)) {
continue;
}
String value;
try {
value = formatArgument(PropertyHelper.get(vo, name));
} catch (final Exception e) {
value = "<error retrieving - is uninitialized?>";
}
sb.append(name).append('=').append(value).append(';');
}
sb.setLength(sb.length() - 1);
sb.append(')');
return sb.toString();
} catch (final Exception e) {
return vo.toString();
}
}
/**
* Returns a masked value if the parameter name is in the {@link #DEFAULT_EXCLUDES} array
*/
public static String maskIfNeeded(final String name, final Object value) {
return shouldMask(name) ? MASKED_VALUE : formatObject(value);
}
/**
* Returns whether the given name is in the {@link #DEFAULT_EXCLUDES} array
*/
public static boolean shouldMask(final String name) {
for (final String exclude : FormatObject.DEFAULT_EXCLUDES) {
if (StringUtils.containsIgnoreCase(name, exclude)) {
return true;
}
}
return false;
}
private static boolean exclude(final List<String> list, final String string) {
if (CollectionUtils.isEmpty(list)) {
return false;
}
for (final String exclude : list) {
if (StringUtils.containsIgnoreCase(string, exclude)) {
return true;
}
}
return false;
}
}