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}