001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 */ 012 013package org.nuxeo.ecm.core.storage.sql; 014 015import java.io.Serializable; 016import java.lang.reflect.Array; 017import java.util.Calendar; 018import java.util.Collection; 019import java.util.Date; 020import java.util.GregorianCalendar; 021 022import org.nuxeo.ecm.core.api.model.DeltaLong; 023import org.nuxeo.ecm.core.schema.types.SimpleTypeImpl; 024import org.nuxeo.ecm.core.schema.types.Type; 025import org.nuxeo.ecm.core.schema.types.primitives.BinaryType; 026import org.nuxeo.ecm.core.schema.types.primitives.BooleanType; 027import org.nuxeo.ecm.core.schema.types.primitives.DateType; 028import org.nuxeo.ecm.core.schema.types.primitives.DoubleType; 029import org.nuxeo.ecm.core.schema.types.primitives.IntegerType; 030import org.nuxeo.ecm.core.schema.types.primitives.LongType; 031import org.nuxeo.ecm.core.schema.types.primitives.StringType; 032 033/** 034 * @author Florent Guillaume 035 */ 036public enum PropertyType { 037 STRING(String.class), // 038 BOOLEAN(Boolean.class), // 039 LONG(Long.class), // 040 DOUBLE(Double.class), // 041 DATETIME(Calendar.class), // 042 BINARY(String.class), // 043 ACL(ACLRow.class), // 044 ARRAY_STRING(STRING, new String[0]), // 045 ARRAY_BOOLEAN(BOOLEAN, new Boolean[0]), // 046 ARRAY_LONG(LONG, new Long[0]), // 047 ARRAY_DOUBLE(DOUBLE, new Double[0]), // 048 ARRAY_DATETIME(DATETIME, new Calendar[0]), // 049 ARRAY_BINARY(BINARY, new String[0]), // 050 COLL_ACL(ACL, new ACLRow[0]); 051 052 private final Class<?> klass; 053 054 private final PropertyType arrayBaseType; 055 056 private final Serializable[] emptyArray; 057 058 PropertyType(Class<?> klass) { 059 this.klass = klass; 060 arrayBaseType = null; 061 emptyArray = null; 062 } 063 064 PropertyType(PropertyType arrayBaseType, Serializable[] emptyArray) { 065 klass = null; 066 this.arrayBaseType = arrayBaseType; 067 this.emptyArray = emptyArray; 068 } 069 070 public boolean isArray() { 071 return arrayBaseType != null; 072 } 073 074 public PropertyType getArrayBaseType() { 075 return arrayBaseType; 076 } 077 078 public Serializable[] getEmptyArray() { 079 return emptyArray; 080 } 081 082 public Serializable[] collectionToArray(Collection<Serializable> collection) { 083 // contrary to list.toArray(), this creates an array 084 // of the property type instead of an Object[] 085 Serializable[] array = (Serializable[]) Array.newInstance(klass, collection.size()); 086 return collection.toArray(array); 087 } 088 089 /** 090 * Normalizes a scalar value of this type. 091 * 092 * @param value the value to normalize 093 * @return the normalized value 094 * @throws IllegalArgumentException 095 */ 096 public Serializable normalize(Object value) { 097 if (value == null) { 098 return null; 099 } 100 switch (this) { 101 case STRING: 102 if (value instanceof String) { 103 return (String) value; 104 } 105 throw new IllegalArgumentException("value is not a String: " + value); 106 case BOOLEAN: 107 if (value instanceof Boolean) { 108 return (Boolean) value; 109 } 110 throw new IllegalArgumentException("value is not a Boolean: " + value); 111 case LONG: 112 if (value instanceof Long) { 113 return (Long) value; 114 } 115 if (value instanceof DeltaLong) { 116 return (DeltaLong) value; 117 } 118 throw new IllegalArgumentException("value is not a Long: " + value); 119 case DOUBLE: 120 if (value instanceof Double) { 121 return (Double) value; 122 } 123 throw new IllegalArgumentException("value is not a Double: " + value); 124 case DATETIME: 125 if (value instanceof Calendar) { 126 return (Calendar) value; 127 } 128 if (value instanceof Date) { 129 Calendar cal = new GregorianCalendar(); // XXX timezone 130 cal.setTime((Date) value); 131 return cal; 132 } 133 throw new IllegalArgumentException("value is not a Calendar: " + value); 134 case BINARY: 135 if (value instanceof String) { 136 return (String) value; 137 } 138 throw new IllegalArgumentException("value is not a binary String: " + value); 139 case ACL: 140 if (value instanceof ACLRow) { 141 return (ACLRow) value; 142 } 143 throw new IllegalArgumentException("value is not a ACLRow: " + value); 144 default: 145 throw new RuntimeException(this.toString()); 146 } 147 } 148 149 /** 150 * Normalizes an array value of this type. 151 * <p> 152 * A {@code null} value will be normalized to an empty array. 153 * 154 * @param value the array to normalize 155 * @return the normalized array 156 * @throws IllegalArgumentException 157 */ 158 public Serializable[] normalize(Object[] value) { 159 if (value == null) { 160 return emptyArray; 161 } 162 Serializable[] newValue; 163 if (value instanceof Serializable[]) { 164 // update in place 165 newValue = (Serializable[]) value; 166 } else { 167 newValue = new Serializable[value.length]; 168 } 169 for (int i = 0; i < value.length; i++) { 170 newValue[i] = arrayBaseType.normalize(value[i]); 171 } 172 return newValue; 173 } 174 175 /** 176 * Converts a Nuxeo core schema field type into a property type. 177 * 178 * @param fieldType the field type to convert 179 * @param array {@code true} if an array type is required 180 * @return 181 */ 182 public static PropertyType fromFieldType(Type fieldType, boolean array) { 183 if (fieldType instanceof StringType) { 184 return array ? ARRAY_STRING : STRING; 185 } else if (fieldType instanceof BooleanType) { 186 return array ? ARRAY_BOOLEAN : BOOLEAN; 187 } else if (fieldType instanceof LongType) { 188 return array ? ARRAY_LONG : LONG; 189 } else if (fieldType instanceof DoubleType) { 190 return array ? ARRAY_DOUBLE : DOUBLE; 191 } else if (fieldType instanceof DateType) { 192 return array ? ARRAY_DATETIME : DATETIME; 193 } else if (fieldType instanceof BinaryType) { 194 return array ? ARRAY_BINARY : BINARY; 195 } else if (fieldType instanceof IntegerType) { 196 throw new RuntimeException("Unimplemented primitive type: " + fieldType.getClass().getName()); 197 } else if (fieldType instanceof SimpleTypeImpl) { 198 // simple type with constraints -- ignore constraints XXX 199 return fromFieldType(fieldType.getSuperType(), array); 200 } else { 201 throw new RuntimeException("Invalid primitive type: " + fieldType.getClass().getName()); 202 } 203 } 204 205}