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 * bstefanescu 011 * 012 * $Id$ 013 */ 014 015package org.nuxeo.ecm.core.api.model.impl; 016 017import java.io.Serializable; 018import java.lang.reflect.Array; 019import java.util.Arrays; 020import java.util.Collection; 021 022import org.nuxeo.common.collections.PrimitiveArrays; 023import org.nuxeo.ecm.core.api.PropertyException; 024import org.nuxeo.ecm.core.api.model.Property; 025import org.nuxeo.ecm.core.api.model.PropertyConversionException; 026import org.nuxeo.ecm.core.schema.types.Field; 027import org.nuxeo.ecm.core.schema.types.JavaTypes; 028import org.nuxeo.ecm.core.schema.types.ListType; 029 030/** 031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 032 */ 033public class ArrayProperty extends ScalarProperty { 034 035 private static final long serialVersionUID = 0L; 036 037 public ArrayProperty(Property parent, Field field, int flags) { 038 super(parent, field, flags); 039 } 040 041 @Override 042 public ListType getType() { 043 return (ListType) super.getType(); 044 } 045 046 @Override 047 public boolean isContainer() { 048 return false; 049 } 050 051 @Override 052 public void setValue(Object value) throws PropertyException { 053 // this code manage dirty status for the arrayproperty and its childs values 054 // it checks whether the property changed, or their index changed 055 if (value == null) { 056 childDirty = new boolean[0]; 057 super.setValue(value); 058 } else { 059 Object[] oldValues = (Object[]) internalGetValue(); 060 boolean[] oldChildDirty = getChildDirty(); 061 super.setValue(value); 062 Object[] newValues = (Object[]) internalGetValue(); 063 boolean[] newChildDirty = new boolean[newValues != null ? newValues.length : 0]; 064 for (int i = 0; i < newChildDirty.length; i++) { 065 Object newValue = newValues[i]; 066 if (oldValues == null || i >= oldValues.length) { 067 newChildDirty[i] = true; 068 } else { 069 Object oldValue = oldValues[i]; 070 if (!((newValue == null && oldValue == null) || (newValue != null && newValue.equals(oldValue)))) { 071 newChildDirty[i] = true; 072 } else { 073 newChildDirty[i] = false || oldChildDirty[i]; 074 } 075 } 076 } 077 childDirty = newChildDirty; 078 } 079 } 080 081 @Override 082 protected boolean isSameValue(Serializable value1, Serializable value2) { 083 Object[] castedtValue1 = (Object[]) value1; 084 Object[] castedtValue2 = (Object[]) value2; 085 return castedtValue1 == castedtValue2 || (castedtValue1 == null && castedtValue2.length == 0) 086 || (castedtValue2 == null && castedtValue1.length == 0) || Arrays.equals(castedtValue1, castedtValue2); 087 } 088 089 @Override 090 public boolean isNormalized(Object value) { 091 return value == null || value.getClass().isArray(); 092 } 093 094 @Override 095 public Serializable normalize(Object value) throws PropertyConversionException { 096 if (isNormalized(value)) { 097 return (Serializable) value; 098 } 099 if (value instanceof Collection) { 100 Collection<?> col = (Collection<?>) value; 101 Class<?> klass = JavaTypes.getClass(getType().getFieldType()); 102 return col.toArray((Object[]) Array.newInstance(klass, col.size())); 103 } 104 throw new PropertyConversionException(value.getClass(), Object[].class, getPath()); 105 } 106 107 @SuppressWarnings("unchecked") 108 @Override 109 public <T> T convertTo(Serializable value, Class<T> toType) throws PropertyConversionException { 110 if (toType.isArray()) { 111 return (T) PrimitiveArrays.toObjectArray(value); 112 } else if (Collection.class.isAssignableFrom(toType)) { 113 return (T) Arrays.asList((Object[]) value); 114 } 115 throw new PropertyConversionException(value.getClass(), toType); 116 } 117 118 @Override 119 public Object newInstance() { 120 return new Serializable[0]; 121 } 122 123 // this boolean array managed the dirty flags for arrayproperty childs 124 private boolean[] childDirty = null; 125 126 protected boolean[] getChildDirty() { 127 if (childDirty == null) { 128 Object[] oldValues = (Object[]) internalGetValue(); 129 if (oldValues == null) { 130 childDirty = new boolean[0]; 131 } else { 132 childDirty = new boolean[oldValues.length]; 133 for (int i = 0; i < childDirty.length; i++) { 134 childDirty[i] = false; 135 } 136 } 137 } 138 return childDirty; 139 } 140 141 /** 142 * This method provides a way to know if some arrayproperty values are dirty: value or index changed. since 7.2 143 */ 144 public boolean isDirty(int index) { 145 if (index > getChildDirty().length) { 146 throw new IndexOutOfBoundsException("Index out of bounds: " + index + ". Bounds are: 0 - " 147 + (getChildDirty().length - 1)); 148 } 149 return getChildDirty()[index]; 150 } 151 152 @Override 153 public void clearDirtyFlags() { 154 // even makes child properties not dirty 155 super.clearDirtyFlags(); 156 for (int i = 0; i < getChildDirty().length; i++) { 157 childDirty[i] = false; 158 } 159 } 160 161}