001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * *** 008 * 009 * Community License: GPL 3.0 010 * 011 * This file is free software: you can redistribute it and/or modify 012 * it under the terms of the GNU General Public License as published 013 * by the Free Software Foundation, either version 3 of the License, 014 * or (at your option) any later version. 015 * 016 * This file is distributed in the hope that it will be useful, but 017 * WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 019 * GNU General Public License for more details. 020 * 021 * You should have received a copy of the GNU General Public License 022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 023 * 024 * *** 025 * 026 * Available Commercial License: GraniteDS SLA 1.0 027 * 028 * This is the appropriate option if you are creating proprietary 029 * applications and you are not prepared to distribute and share the 030 * source code of your application under the GPL v3 license. 031 * 032 * Please visit http://www.granitedataservices.com/license for more 033 * details. 034 */ 035package org.granite.client.tide.data.impl; 036 037import java.beans.PropertyChangeEvent; 038import java.beans.PropertyChangeListener; 039import java.beans.PropertyChangeSupport; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Map; 043import java.util.Set; 044 045import org.granite.client.collection.CollectionChangeEvent; 046import org.granite.client.collection.CollectionChangeListener; 047import org.granite.client.collection.ObservableCollection; 048import org.granite.client.collection.CollectionChangeEvent.Kind; 049import org.granite.client.tide.impl.BindingUtil; 050import org.granite.client.util.WeakIdentityHashMap; 051import org.granite.util.Introspector; 052import org.granite.util.PropertyDescriptor; 053 054 055/** 056 * @author William DRAI 057 */ 058public class JavaBeanDataManager extends AbstractDataManager { 059 060 private PropertyChangeSupport pcs = new PropertyChangeSupport(this); 061 062 public void addPropertyChangeListener(PropertyChangeListener listener) { 063 pcs.addPropertyChangeListener(listener); 064 } 065 066 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { 067 pcs.addPropertyChangeListener(propertyName, listener); 068 } 069 070 public void removePropertyChangeListener(PropertyChangeListener listener) { 071 pcs.removePropertyChangeListener(listener); 072 } 073 074 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { 075 pcs.removePropertyChangeListener(propertyName, listener); 076 } 077 078 079 @Override 080 public void setPropertyValue(Object entity, String name, Object value) { 081 if (entity == null) 082 return; 083 try { 084 boolean found = false; 085 PropertyDescriptor[] pds = Introspector.getPropertyDescriptors(entity.getClass()); 086 for (PropertyDescriptor pd : pds) { 087 if (pd.getName().equals(name) && pd.getWriteMethod() != null) { 088 pd.getWriteMethod().invoke(entity, value); 089 found = true; 090 break; 091 } 092 } 093 if (!found) 094 super.setPropertyValue(entity, name, value); 095 } 096 catch (Exception e) { 097 throw new RuntimeException("Could not set property " + name + " on entity " + entity, e); 098 } 099 } 100 101 102 private TrackingHandler trackingHandler; 103 104 public void setTrackingHandler(TrackingHandler trackingHandler) { 105 this.trackingHandler = trackingHandler; 106 } 107 108 109 public class EntityPropertyChangeListener implements PropertyChangeListener { 110 @Override 111 public void propertyChange(PropertyChangeEvent pce) { 112 trackingHandler.entityPropertyChangeHandler(pce.getSource(), pce.getPropertyName(), pce.getOldValue(), pce.getNewValue()); 113 } 114 } 115 116 public class EntityCollectionChangeListener implements CollectionChangeListener { 117 @Override 118 public void collectionChange(CollectionChangeEvent ce) { 119 if (ce.getKind() == Kind.ADD) 120 trackingHandler.entityCollectionChangeHandler(ChangeKind.ADD, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 121 else if (ce.getKind() == Kind.REMOVE) 122 trackingHandler.entityCollectionChangeHandler(ChangeKind.REMOVE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 123 else if (ce.getKind() == Kind.REPLACE) 124 trackingHandler.entityCollectionChangeHandler(ChangeKind.REPLACE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 125 } 126 } 127 128 public class DefaultCollectionChangeListener implements CollectionChangeListener { 129 @Override 130 public void collectionChange(CollectionChangeEvent ce) { 131 if (ce.getKind() == Kind.ADD) 132 trackingHandler.collectionChangeHandler(ChangeKind.ADD, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 133 else if (ce.getKind() == Kind.REMOVE) 134 trackingHandler.collectionChangeHandler(ChangeKind.REMOVE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 135 else if (ce.getKind() == Kind.REPLACE) 136 trackingHandler.collectionChangeHandler(ChangeKind.REPLACE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues()); 137 } 138 } 139 140 public class EntityMapChangeListener implements CollectionChangeListener { 141 @Override 142 public void collectionChange(CollectionChangeEvent ce) { 143 if (ce.getKind() == Kind.ADD) 144 trackingHandler.entityMapChangeHandler(ChangeKind.ADD, ce.getCollection(), null, ce.getValues()); 145 else if (ce.getKind() == Kind.REMOVE) 146 trackingHandler.entityMapChangeHandler(ChangeKind.REMOVE, ce.getCollection(), null, ce.getValues()); 147 else if (ce.getKind() == Kind.REPLACE) 148 trackingHandler.entityMapChangeHandler(ChangeKind.REPLACE, ce.getCollection(), null, ce.getValues()); 149 } 150 } 151 152 public class DefaultMapChangeListener implements CollectionChangeListener { 153 @Override 154 public void collectionChange(CollectionChangeEvent ce) { 155 if (ce.getKind() == Kind.ADD) 156 trackingHandler.mapChangeHandler(ChangeKind.ADD, ce.getCollection(), null, ce.getValues()); 157 else if (ce.getKind() == Kind.REMOVE) 158 trackingHandler.mapChangeHandler(ChangeKind.REMOVE, ce.getCollection(), null, ce.getValues()); 159 else if (ce.getKind() == Kind.REPLACE) 160 trackingHandler.mapChangeHandler(ChangeKind.REPLACE, ce.getCollection(), null, ce.getValues()); 161 } 162 } 163 164 private CollectionChangeListener listChangeListener = new DefaultCollectionChangeListener(); 165 private CollectionChangeListener setChangeListener = new DefaultCollectionChangeListener(); 166 private CollectionChangeListener mapChangeListener = new DefaultMapChangeListener(); 167 private PropertyChangeListener entityPropertyChangeListener = new EntityPropertyChangeListener(); 168 private CollectionChangeListener entityListChangeListener = new EntityCollectionChangeListener(); 169 private CollectionChangeListener entitySetChangeListener = new EntityCollectionChangeListener(); 170 private CollectionChangeListener entityMapChangeListener = new EntityMapChangeListener(); 171 172 private WeakIdentityHashMap<Object, TrackingType> trackingListeners = new WeakIdentityHashMap<Object, TrackingType>(); 173 174 175 @Override 176 public void startTracking(Object previous, Object parent) { 177 if (previous == null || trackingListeners.containsKey(previous)) 178 return; 179 180 if (previous instanceof ObservableCollection && previous instanceof List<?>) { 181 if (parent != null) { 182 ((ObservableCollection)previous).addCollectionChangeListener(entityListChangeListener); 183 trackingListeners.put(previous, TrackingType.ENTITY_LIST); 184 } 185 else { 186 ((ObservableCollection)previous).addCollectionChangeListener(listChangeListener); 187 trackingListeners.put(previous, TrackingType.LIST); 188 } 189 } 190 else if (previous instanceof ObservableCollection && previous instanceof Set<?>) { 191 if (parent != null) { 192 ((ObservableCollection)previous).addCollectionChangeListener(entitySetChangeListener); 193 trackingListeners.put(previous, TrackingType.ENTITY_SET); 194 } 195 else { 196 ((ObservableCollection)previous).addCollectionChangeListener(setChangeListener); 197 trackingListeners.put(previous, TrackingType.SET); 198 } 199 } 200 else if (previous instanceof ObservableCollection && previous instanceof Map<?, ?>) { 201 if (parent != null) { 202 ((ObservableCollection)previous).addCollectionChangeListener(entityMapChangeListener); 203 trackingListeners.put(previous, TrackingType.ENTITY_MAP); 204 } 205 else { 206 ((ObservableCollection)previous).addCollectionChangeListener(mapChangeListener); 207 trackingListeners.put(previous, TrackingType.MAP); 208 } 209 } 210 else if (parent != null || isEntity(previous)) { 211 BindingUtil.addPropertyChangeListener(previous, entityPropertyChangeListener); 212 trackingListeners.put(previous, TrackingType.ENTITY_PROPERTY); 213 } 214 } 215 216 @Override 217 public void stopTracking(Object previous, Object parent) { 218 if (previous == null || !trackingListeners.containsKey(previous)) 219 return; 220 221 if (previous instanceof ObservableCollection && previous instanceof List<?>) { 222 if (parent != null) 223 ((ObservableCollection)previous).removeCollectionChangeListener(entityListChangeListener); 224 else 225 ((ObservableCollection)previous).removeCollectionChangeListener(listChangeListener); 226 } 227 else if (previous instanceof ObservableCollection && previous instanceof Set<?>) { 228 if (parent != null) 229 ((ObservableCollection)previous).removeCollectionChangeListener(entitySetChangeListener); 230 else 231 ((ObservableCollection)previous).removeCollectionChangeListener(setChangeListener); 232 } 233 else if (previous instanceof ObservableCollection && previous instanceof Map<?, ?>) { 234 if (parent != null) 235 ((ObservableCollection)previous).removeCollectionChangeListener(entityMapChangeListener); 236 else 237 ((ObservableCollection)previous).removeCollectionChangeListener(mapChangeListener); 238 } 239 else if (parent != null || isEntity(previous)) { 240 BindingUtil.removePropertyChangeListener(previous, entityPropertyChangeListener); 241 } 242 243 trackingListeners.remove(previous); 244 } 245 246 @Override 247 public void clear() { 248 Iterator<Object> ikey = trackingListeners.keySet().iterator(); 249 while (ikey.hasNext()) { 250 Object obj = ikey.next(); 251 TrackingType type = trackingListeners.get(obj); 252 switch (type) { 253 case LIST: 254 ((ObservableCollection)obj).removeCollectionChangeListener(listChangeListener); 255 break; 256 case SET: 257 ((ObservableCollection)obj).removeCollectionChangeListener(setChangeListener); 258 break; 259 case MAP: 260 ((ObservableCollection)obj).removeCollectionChangeListener(mapChangeListener); 261 break; 262 case ENTITY_PROPERTY: 263 BindingUtil.removePropertyChangeListener(obj, entityPropertyChangeListener); 264 break; 265 case ENTITY_LIST: 266 ((ObservableCollection)obj).removeCollectionChangeListener(entityListChangeListener); 267 break; 268 case ENTITY_SET: 269 ((ObservableCollection)obj).removeCollectionChangeListener(entitySetChangeListener); 270 break; 271 case ENTITY_MAP: 272 ((ObservableCollection)obj).removeCollectionChangeListener(entityMapChangeListener); 273 break; 274 } 275 } 276 } 277 278 private boolean dirty = false; 279 280 public boolean isDirty() { 281 return dirty; 282 } 283 284 @Override 285 public void notifyDirtyChange(boolean oldDirty, boolean dirty) { 286 this.dirty = dirty; 287 pcs.firePropertyChange("dirty", oldDirty, dirty); 288 } 289 290 @Override 291 public void notifyEntityDirtyChange(Object entity, boolean oldDirtyEntity, boolean newDirtyEntity) { 292 pcs.firePropertyChange("dirtyEntity", oldDirtyEntity, newDirtyEntity); 293 pcs.firePropertyChange("deepDirtyEntity", oldDirtyEntity, newDirtyEntity); 294 } 295}