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