/* * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed 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. * * Contributors: * Nuxeo - initial API and implementation * * $Id: FieldAdapterManager.java 28460 2008-01-03 15:34:05Z sfermigier $ */ package org.nuxeo.ecm.platform.el; import java.lang.reflect.Array; import java.math.BigDecimal; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * The FieldAdapterManager fills the gap between the storage and the display structures. * <p> * The Display representation of a DataModel is a set of JSF Beans There are mainly 3 cases: * <p> * 1 - Perfect match: the JSF components generate a bean that can be directly stored ie: String ... * <p> * 2 - Type Mismatch: The JSF component generate a bean that is not of the right type ie: The JSF generate a Date * whereas the Core expect a Calendar type. * <p> * 3 - Structure Mismatch: The JSF bean must be split in several fields ie: The uploaded file is one object, but the * core expect at least 2 separate fields (filename and content) * * @author Thierry Delprat */ public final class FieldAdapterManager { @SuppressWarnings("unused") private static final Log log = LogFactory.getLog(FieldAdapterManager.class); // Utility class. private FieldAdapterManager() { } /** * Sets value adapting it for storage. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Object getValueForStorage(Object value) { if (value instanceof Date) { value = getDateAsCalendar((Date) value); } else if (value instanceof BigDecimal) { value = getBigDecimalAsLong((BigDecimal) value); } else if (value instanceof Object[]) { Object[] array = (Object[]) value; Class<?> oldType = array.getClass().getComponentType(); Class<?> newType = getComponentTypeForStorage(oldType); Object[] newArray = (Object[]) Array.newInstance(newType, array.length); for (int i = 0; i < array.length; i++) { newArray[i] = getValueForStorage(array[i]); } value = newArray; } else if (value instanceof List) { List list = (List) value; for (int i = 0; i < list.size(); i++) { list.set(i, getValueForStorage(list.get(i))); } } else if (value instanceof Map) { Map<Object, Object> map = (Map) value; Map<Object, Object> newMap = new HashMap<Object, Object>(); for (Map.Entry<Object, Object> entry : map.entrySet()) { newMap.put(entry.getKey(), getValueForStorage(entry.getValue())); } value = newMap; } // TODO: maybe handle list diffs (?) return value; } /** * Returns component type that will be used to store objects of given component type. */ public static Class<?> getComponentTypeForStorage(Class<?> componentType) { Class<?> newType = componentType; if (componentType.equals(Date.class)) { newType = Calendar.class; } return newType; } /** * Gets value adapting it for display. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static Object getValueForDisplay(Object value) { if (value instanceof Calendar) { value = getCalendarAsDate((Calendar) value); } else if (value instanceof Object[]) { Object[] array = (Object[]) value; Class<?> oldType = array.getClass().getComponentType(); Class<?> newType = getComponentTypeForDisplay(oldType); Object[] newArray = (Object[]) Array.newInstance(newType, array.length); for (int i = 0; i < array.length; i++) { newArray[i] = getValueForDisplay(array[i]); } value = newArray; } else if (value instanceof List) { List list = (List) value; for (int i = 0; i < list.size(); i++) { list.set(i, getValueForDisplay(list.get(i))); } } else if (value instanceof Map) { Map<Object, Object> map = (Map) value; Map<Object, Object> newMap = new HashMap<Object, Object>(); for (Map.Entry<Object, Object> entry : map.entrySet()) { newMap.put(entry.getKey(), getValueForDisplay(entry.getValue())); } value = newMap; } return value; } /** * Returns component type that will be used to display objects of given component type. */ public static Class<?> getComponentTypeForDisplay(Class<?> componentType) { Class<?> newType = componentType; if (componentType.equals(Calendar.class)) { newType = Date.class; } return newType; } // Fake converters for now // XXX make an extension point to register Adapters // XXX update TypeManager to handle Adapter configuration private static Calendar getDateAsCalendar(Date value) { Calendar calValue = Calendar.getInstance(); calValue.setTime(value); return calValue; } private static Date getCalendarAsDate(Calendar value) { return value.getTime(); } /** * @since 7.1 */ private static Long getBigDecimalAsLong(BigDecimal value) { return value.longValueExact(); } }