1 19 20 package org.apache.cayenne.util; 21 22 import java.util.AbstractList ; 23 import java.util.ArrayList ; 24 import java.util.Collections ; 25 import java.util.Comparator ; 26 import java.util.List ; 27 28 import org.apache.cayenne.CayenneRuntimeException; 29 import org.apache.cayenne.ValueHolder; 30 import org.apache.cayenne.reflect.PropertyUtils; 31 32 46 public class IndexPropertyList extends AbstractList implements ValueHolder { 47 48 52 static final int DEFAULT_GAP = 3; 53 54 57 protected List list; 58 protected String indexProperty; 59 60 boolean dirty; 61 Comparator comparator; 62 63 66 public IndexPropertyList(String indexProperty) { 67 this(indexProperty, new ArrayList (), false); 68 } 69 70 75 public IndexPropertyList(String indexProperty, List objects, boolean sortNeeded) { 76 77 if (indexProperty == null) { 78 throw new IllegalArgumentException ("Null sortProperty"); 79 } 80 81 if (objects == null) { 82 throw new IllegalArgumentException ("Null objects list."); 83 } 84 85 this.indexProperty = indexProperty; 86 this.list = objects; 87 88 this.dirty = sortNeeded; 91 } 92 93 ValueHolder getWrappedValueHolder() { 94 return (list instanceof ValueHolder) ? (ValueHolder) list : null; 95 } 96 97 public boolean isFault() { 98 ValueHolder h = getWrappedValueHolder(); 99 return (h != null) ? h.isFault() : false; 100 } 101 102 public Object setValueDirectly(Object value) throws CayenneRuntimeException { 103 ValueHolder h = getWrappedValueHolder(); 104 return h != null ? h.setValueDirectly(value) : null; 105 } 106 107 public Object setValue(Object value) throws CayenneRuntimeException { 108 ValueHolder h = getWrappedValueHolder(); 109 return h != null ? h.setValue(value) : null; 110 } 111 112 public Object getValue() throws CayenneRuntimeException { 113 ValueHolder h = getWrappedValueHolder(); 114 return h != null ? h.getValue() : null; 115 } 116 117 public Object getValueDirectly() throws CayenneRuntimeException { 118 ValueHolder h = getWrappedValueHolder(); 119 return h != null ? h.getValueDirectly() : null; 120 } 121 122 public void invalidate() { 123 ValueHolder h = getWrappedValueHolder(); 124 if (h != null) { 125 h.invalidate(); 126 } 127 } 128 129 132 public void touch() { 133 this.dirty = true; 134 } 135 136 public Object get(int index) { 137 if (dirty) { 138 sort(); 139 } 140 141 return list.get(index); 142 } 143 144 public int size() { 145 if (dirty) { 146 sort(); 147 } 148 149 return list.size(); 150 } 151 152 public Object set(int index, Object element) { 153 if (dirty) { 154 sort(); 155 } 156 157 Object removed = list.set(index, element); 158 159 if (element != null) { 160 int indexValue = (removed != null) 161 ? getIndexValue(removed) 162 : calculateIndexValue(index); 163 164 setIndexValue(element, indexValue); 165 shift(index + 1, indexValue); 166 } 167 168 if (removed != null && removed != element) { 169 setIndexValue(removed, -1); 170 } 171 172 return removed; 173 } 174 175 public void add(int index, Object element) { 176 if (dirty) { 177 sort(); 178 } 179 180 list.add(index, element); 181 182 if (element != null) { 183 int indexValue = calculateIndexValue(index); 184 185 setIndexValue(element, indexValue); 186 shift(index + 1, indexValue); 187 } 188 } 189 190 public Object remove(int index) { 191 if (dirty) { 192 sort(); 193 } 194 195 Object removed = list.remove(index); 196 197 if (removed != null) { 198 setIndexValue(removed, -1); 199 } 200 201 return removed; 202 } 203 204 208 212 protected int calculateIndexValue(int listIndex) { 213 if (list.isEmpty()) { 214 throw new ArrayIndexOutOfBoundsException (listIndex); 215 } 216 217 if (list.size() == 1 && listIndex == 0) { 218 return 0; 219 } 220 221 223 if (listIndex == list.size() - 1) { 225 return getIndexValue(get(listIndex - 1)) + DEFAULT_GAP; 226 } 227 228 int from = (listIndex == 0) ? -1 : getIndexValue(get(listIndex - 1)); 229 int to = getIndexValue(get(listIndex + 1)); 230 return (to - from > 1) ? (to - from) / 2 + from : from + DEFAULT_GAP; 231 } 232 233 protected int getIndexValue(Object object) { 234 Number n = (Number ) PropertyUtils.getProperty(object, indexProperty); 235 if (n == null) { 236 throw new CayenneRuntimeException("Null index property '" 237 + indexProperty 238 + "' for object " 239 + object); 240 } 241 242 return n.intValue(); 243 } 244 245 protected void setIndexValue(Object object, int index) { 246 PropertyUtils.setProperty(object, indexProperty, new Integer (index)); 247 } 248 249 protected void shift(int startIndex, int afterIndexValue) { 250 int size = size(); 251 for (int i = startIndex; i < size; i++) { 252 Object object = get(i); 253 254 int indexValue = getIndexValue(object); 255 if (indexValue > afterIndexValue) { 256 break; 257 } 258 259 int newValue = calculateIndexValue(i); 260 setIndexValue(object, newValue); 261 afterIndexValue = newValue; 262 } 263 } 264 265 268 protected void sort() { 269 if (!dirty) { 270 return; 271 } 272 273 Collections.sort(unwrapList(), getComparator()); 276 dirty = false; 277 } 278 279 List unwrapList() { 280 if (list instanceof PersistentObjectList) { 281 return ((PersistentObjectList) list).resolvedObjectList(); 282 } 283 else { 284 return list; 285 } 286 } 287 288 291 Comparator getComparator() { 292 if (comparator == null) { 293 comparator = new Comparator () { 294 295 public int compare(Object o1, Object o2) { 296 if ((o1 == null && o2 == null) || o1 == o2) { 297 return 0; 298 } 299 else if (o1 == null && o2 != null) { 300 return -1; 301 } 302 else if (o1 != null && o2 == null) { 303 return 1; 304 } 305 306 Comparable p1 = (Comparable ) PropertyUtils.getProperty( 307 o1, 308 indexProperty); 309 Comparable p2 = (Comparable ) PropertyUtils.getProperty( 310 o2, 311 indexProperty); 312 return (p1 == null) ? -1 : p1.compareTo(p2); 313 } 314 }; 315 } 316 return comparator; 317 } 318 } 319 | Popular Tags |