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 */ 102 public Serializable normalize(Object value) { 103 if (value == null) { 104 return null; 105 } 106 switch (this) { 107 case STRING: 108 if (value instanceof String) { 109 return (String) value; 110 } 111 throw new IllegalArgumentException("value is not a String: " + value); 112 case BOOLEAN: 113 if (value instanceof Boolean) { 114 return (Boolean) value; 115 } 116 throw new IllegalArgumentException("value is not a Boolean: " + value); 117 case LONG: 118 if (value instanceof Long) { 119 return (Long) value; 120 } 121 if (value instanceof DeltaLong) { 122 return (DeltaLong) value; 123 } 124 throw new IllegalArgumentException("value is not a Long: " + value); 125 case DOUBLE: 126 if (value instanceof Double) { 127 return (Double) value; 128 } 129 throw new IllegalArgumentException("value is not a Double: " + value); 130 case DATETIME: 131 if (value instanceof Calendar) { 132 return (Calendar) value; 133 } 134 if (value instanceof Date) { 135 Calendar cal = new GregorianCalendar(); // XXX timezone 136 cal.setTime((Date) value); 137 return cal; 138 } 139 throw new IllegalArgumentException("value is not a Calendar: " + value); 140 case BINARY: 141 if (value instanceof String) { 142 return (String) value; 143 } 144 throw new IllegalArgumentException("value is not a binary String: " + value); 145 case ACL: 146 if (value instanceof ACLRow) { 147 return (ACLRow) value; 148 } 149 throw new IllegalArgumentException("value is not a ACLRow: " + value); 150 default: 151 throw new RuntimeException(this.toString()); 152 } 153 } 154 155 /** 156 * Normalizes an array value of this type. 157 * <p> 158 * A {@code null} value will be normalized to an empty array. 159 * 160 * @param value the array to normalize 161 * @return the normalized array 162 */ 163 public Serializable[] normalize(Object[] value) { 164 if (value == null) { 165 return emptyArray; 166 } 167 Serializable[] newValue; 168 if (value instanceof Serializable[]) { 169 // update in place 170 newValue = (Serializable[]) value; 171 } else { 172 newValue = new Serializable[value.length]; 173 } 174 for (int i = 0; i < value.length; i++) { 175 newValue[i] = arrayBaseType.normalize(value[i]); 176 } 177 return newValue; 178 } 179 180 /** 181 * Converts a Nuxeo core schema field type into a property type. 182 * 183 * @param fieldType the field type to convert 184 * @param array {@code true} if an array type is required 185 */ 186 public static PropertyType fromFieldType(Type fieldType, boolean array) { 187 if (fieldType instanceof StringType) { 188 return array ? ARRAY_STRING : STRING; 189 } else if (fieldType instanceof BooleanType) { 190 return array ? ARRAY_BOOLEAN : BOOLEAN; 191 } else if (fieldType instanceof LongType) { 192 return array ? ARRAY_LONG : LONG; 193 } else if (fieldType instanceof DoubleType) { 194 return array ? ARRAY_DOUBLE : DOUBLE; 195 } else if (fieldType instanceof DateType) { 196 return array ? ARRAY_DATETIME : DATETIME; 197 } else if (fieldType instanceof BinaryType) { 198 return array ? ARRAY_BINARY : BINARY; 199 } else if (fieldType instanceof IntegerType) { 200 throw new RuntimeException("Unimplemented primitive type: " + fieldType.getClass().getName()); 201 } else if (fieldType instanceof SimpleTypeImpl) { 202 // simple type with constraints -- ignore constraints XXX 203 return fromFieldType(fieldType.getSuperType(), array); 204 } else { 205 throw new RuntimeException("Invalid primitive type: " + fieldType.getClass().getName()); 206 } 207 } 208 209}