/* * The MIT License * Copyright (c) 2012 Microsoft Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package microsoft.exchange.webservices.data.misc; import microsoft.exchange.webservices.data.core.EwsUtilities; import microsoft.exchange.webservices.data.core.ILazyMember; import microsoft.exchange.webservices.data.core.LazyMember; import microsoft.exchange.webservices.data.core.enumeration.property.MapiPropertyType; import microsoft.exchange.webservices.data.core.exception.misc.FormatException; import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; /** * Utility class to convert between MAPI Property type values and strings. */ public class MapiTypeConverter { private static final Log LOG = LogFactory.getLog(MapiTypeConverter.class); private static final IFunction<String, Object> DATE_TIME_PARSER = new IFunction<String, Object>() { public Object func(final String s) { return parseDateTime(s); } }; private static final IFunction<String, Object> MAPI_VALUE_PARSER = new IFunction<String, Object>() { public Object func(final String s) { return MapiTypeConverter.parseMapiIntegerValue(s); } }; /** * The mapi type converter map. */ private static final LazyMember<MapiTypeConverterMap> MAPI_TYPE_CONVERTER_MAP = new LazyMember<MapiTypeConverterMap>(new ILazyMember<MapiTypeConverterMap>() { @Override public MapiTypeConverterMap createInstance() { MapiTypeConverterMap map = new MapiTypeConverterMap(); map.put(MapiPropertyType.ApplicationTime, new MapiTypeConverterMapEntry(Double.class)); MapiTypeConverterMapEntry mapitype = new MapiTypeConverterMapEntry(Double.class); mapitype.setIsArray(true); map.put(MapiPropertyType.ApplicationTimeArray, mapitype); mapitype = new MapiTypeConverterMapEntry(Byte[].class); mapitype.setParse(IFunctions.Base64Decoder.INSTANCE); mapitype.setConvertToString(IFunctions.Base64Encoder.INSTANCE); map.put(MapiPropertyType.Binary, mapitype); mapitype = new MapiTypeConverterMapEntry(Byte[].class); mapitype.setParse(IFunctions.Base64Decoder.INSTANCE); mapitype.setConvertToString(IFunctions.Base64Encoder.INSTANCE); mapitype.setIsArray(true); map.put(MapiPropertyType.BinaryArray, mapitype); mapitype = new MapiTypeConverterMapEntry(Boolean.class); mapitype.setParse(IFunctions.ToBoolean.INSTANCE); mapitype.setConvertToString(IFunctions.ToLowerCase.INSTANCE); map.put(MapiPropertyType.Boolean, mapitype); mapitype = new MapiTypeConverterMapEntry(UUID.class); mapitype.setParse(IFunctions.ToUUID.INSTANCE); mapitype.setConvertToString(IFunctions.ToString.INSTANCE); map.put(MapiPropertyType.CLSID, mapitype); mapitype = new MapiTypeConverterMapEntry(UUID.class); mapitype.setParse(IFunctions.ToUUID.INSTANCE); mapitype.setConvertToString(IFunctions.ToString.INSTANCE); mapitype.setIsArray(true); map.put(MapiPropertyType.CLSIDArray, mapitype); map.put(MapiPropertyType.Currency, new MapiTypeConverterMapEntry(Long.class)); mapitype = new MapiTypeConverterMapEntry(Long.class); mapitype.setIsArray(true); map.put(MapiPropertyType.CurrencyArray, mapitype); map.put(MapiPropertyType.Double, new MapiTypeConverterMapEntry(Double.class)); mapitype = new MapiTypeConverterMapEntry(Double.class); mapitype.setIsArray(true); map.put(MapiPropertyType.DoubleArray, mapitype); map.put(MapiPropertyType.Error, new MapiTypeConverterMapEntry(Integer.class)); map.put(MapiPropertyType.Float, new MapiTypeConverterMapEntry(Float.class)); mapitype = new MapiTypeConverterMapEntry(Float.class); mapitype.setIsArray(true); map.put(MapiPropertyType.FloatArray, mapitype); mapitype = new MapiTypeConverterMapEntry(Integer.class); mapitype.setParse(MAPI_VALUE_PARSER); map.put(MapiPropertyType.Integer, mapitype); mapitype = new MapiTypeConverterMapEntry(Integer.class); mapitype.setIsArray(true); map.put(MapiPropertyType.IntegerArray, mapitype); map.put(MapiPropertyType.Long, new MapiTypeConverterMapEntry(Long.class)); mapitype = new MapiTypeConverterMapEntry(Long.class); mapitype.setIsArray(true); map.put(MapiPropertyType.LongArray, mapitype); mapitype = new MapiTypeConverterMapEntry(String.class); mapitype.setParse(IFunctions.StringToObject.INSTANCE); map.put(MapiPropertyType.Object, mapitype); mapitype = new MapiTypeConverterMapEntry(String.class); mapitype.setParse(IFunctions.StringToObject.INSTANCE); mapitype.setIsArray(true); map.put(MapiPropertyType.ObjectArray, mapitype); map.put(MapiPropertyType.Short, new MapiTypeConverterMapEntry(Short.class)); mapitype = new MapiTypeConverterMapEntry(Short.class); mapitype.setIsArray(true); map.put(MapiPropertyType.ShortArray, mapitype); mapitype = new MapiTypeConverterMapEntry(String.class); mapitype.setParse(IFunctions.StringToObject.INSTANCE); map.put(MapiPropertyType.String, mapitype); mapitype = new MapiTypeConverterMapEntry(String.class); mapitype.setParse(IFunctions.StringToObject.INSTANCE); mapitype.setIsArray(true); map.put(MapiPropertyType.StringArray, mapitype); mapitype = new MapiTypeConverterMapEntry(Date.class); mapitype.setParse(DATE_TIME_PARSER); mapitype.setConvertToString(IFunctions.DateTimeToXSDateTime.INSTANCE); map.put(MapiPropertyType.SystemTime, mapitype); mapitype = new MapiTypeConverterMapEntry(Date.class); mapitype.setParse(DATE_TIME_PARSER); mapitype.setConvertToString(IFunctions.DateTimeToXSDateTime.INSTANCE); mapitype.setIsArray(true); map.put(MapiPropertyType.SystemTimeArray, mapitype); return map; } }); /** * Converts the string list to array. * * @param mapiPropType Type of the MAPI property. * @param strings the strings * @return Array of objects. * @throws Exception the exception */ public static List<Object> convertToValue(MapiPropertyType mapiPropType, Iterator<String> strings) throws Exception { EwsUtilities.validateParam(strings, "strings"); MapiTypeConverterMapEntry typeConverter = getMapiTypeConverterMap() .get(mapiPropType); List<Object> array = new ArrayList<Object>(); int index = 0; while (strings.hasNext()) { Object value = typeConverter.convertToValueOrDefault(strings.next()); array.add(index, value); } return array; } /** * Converts a string to value consistent with MAPI type. * * @param mapiPropType the mapi prop type * @param stringValue the string value * @return the object * @throws ServiceXmlDeserializationException the service xml deserialization exception * @throws FormatException the format exception */ public static Object convertToValue(MapiPropertyType mapiPropType, String stringValue) throws ServiceXmlDeserializationException, FormatException { return getMapiTypeConverterMap().get(mapiPropType).convertToValue( stringValue); } /** * Converts a value to a string. * * @param mapiPropType the mapi prop type * @param value the value * @return String value. */ public static String convertToString(MapiPropertyType mapiPropType, Object value) { /* * if(! (value instanceof FuncInterface<?,?>)){ return null; } */ return (value == null) ? "" : getMapiTypeConverterMap().get( mapiPropType).getConvertToString().func(value); } /** * Change value to a value of compatible type. * * @param mapiType the mapi type * @param value the value * @return the object * @throws Exception the exception */ public static Object changeType(MapiPropertyType mapiType, Object value) throws Exception { EwsUtilities.validateParam(value, "value"); return getMapiTypeConverterMap().get(mapiType).changeType(value); } /** * Converts a MAPI Integer value. * Usually the value is an integer but there are cases where the value has been "schematized" to an * Enumeration value (e.g. NoData) which we have no choice but to fallback and represent as a string. * * @param s The string value. * @return Integer value or the original string if the value could not be parsed as such. */ protected static Object parseMapiIntegerValue(String s) { int intValue; try { intValue = Integer.parseInt(s.trim()); return Integer.valueOf(intValue); } catch (NumberFormatException e) { return s; } } /** * Determines whether MapiPropertyType is an array type. * * @param mapiType the mapi type * @return true, if is array type */ public static boolean isArrayType(MapiPropertyType mapiType) { return getMapiTypeConverterMap().get(mapiType).getIsArray(); } /** * Gets the MAPI type converter map. * * @return the mapi type converter map */ public static Map<MapiPropertyType, MapiTypeConverterMapEntry> getMapiTypeConverterMap() { return MAPI_TYPE_CONVERTER_MAP.getMember(); } private static Object parseDateTime(String s) { String utcPattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; String errMsg = String.format("Date String %s not in " + "valid UTC/local format", s); DateFormat utcFormatter = new SimpleDateFormat(utcPattern); Date dt; if (s.endsWith("Z")) { try { dt = utcFormatter.parse(s); } catch (ParseException e) { s = s.substring(0, 10) + "T12:00:00Z"; try { dt = utcFormatter.parse(s); } catch (ParseException e1) { LOG.error(e); throw new IllegalArgumentException( errMsg, e); } } } else if (s.endsWith("z")) { // String in UTC format yyyy-MM-ddTHH:mm:ssZ utcFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'z'"); try { dt = utcFormatter.parse(s); } catch (ParseException e) { throw new IllegalArgumentException(e); } } else { utcFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); try { dt = utcFormatter.parse(s); } catch (ParseException e) { throw new IllegalArgumentException(e); } } return dt; } }