/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* ***
*
* Community License: GPL 3.0
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ***
*
* Available Commercial License: GraniteDS SLA 1.0
*
* This is the appropriate option if you are creating proprietary
* applications and you are not prepared to distribute and share the
* source code of your application under the GPL v3 license.
*
* Please visit http://www.granitedataservices.com/license for more
* details.
*/
package org.granite.client.tide.data.impl;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.granite.binding.PropertyChangeHelper;
import org.granite.binding.collection.CollectionChangeEvent;
import org.granite.binding.collection.CollectionChangeListener;
import org.granite.binding.collection.ObservableCollection;
import org.granite.binding.collection.CollectionChangeEvent.Kind;
import org.granite.client.util.WeakIdentityHashMap;
import org.granite.util.Introspector;
import org.granite.util.PropertyDescriptor;
/**
* @author William DRAI
*/
public class JavaBeanDataManager extends AbstractDataManager {
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.removePropertyChangeListener(propertyName, listener);
}
@Override
public void setPropertyValue(Object entity, String name, Object value) {
if (entity == null)
return;
try {
boolean found = false;
PropertyDescriptor[] pds = Introspector.getPropertyDescriptors(entity.getClass());
for (PropertyDescriptor pd : pds) {
if (pd.getName().equals(name) && pd.getWriteMethod() != null) {
Object oldValue = null;
if (pd.getReadMethod() != null)
oldValue = pd.getReadMethod().invoke(entity);
pd.getWriteMethod().invoke(entity, value);
if (pd.getReadMethod() != null)
PropertyChangeHelper.firePropertyChange(entity, name, oldValue, value);
found = true;
break;
}
}
if (!found)
super.setPropertyValue(entity, name, value);
}
catch (Exception e) {
throw new RuntimeException("Could not set property " + name + " on entity " + entity, e);
}
}
private TrackingHandler trackingHandler;
public void setTrackingHandler(TrackingHandler trackingHandler) {
this.trackingHandler = trackingHandler;
}
public class EntityPropertyChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent pce) {
trackingHandler.entityPropertyChangeHandler(pce.getSource(), pce.getPropertyName(), pce.getOldValue(), pce.getNewValue());
}
}
public class EntityCollectionChangeListener implements CollectionChangeListener {
@Override
public void collectionChange(CollectionChangeEvent ce) {
if (ce.getKind() == Kind.ADD)
trackingHandler.entityCollectionChangeHandler(ChangeKind.ADD, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
else if (ce.getKind() == Kind.REMOVE)
trackingHandler.entityCollectionChangeHandler(ChangeKind.REMOVE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
else if (ce.getKind() == Kind.REPLACE)
trackingHandler.entityCollectionChangeHandler(ChangeKind.REPLACE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
}
}
public class DefaultCollectionChangeListener implements CollectionChangeListener {
@Override
public void collectionChange(CollectionChangeEvent ce) {
if (ce.getKind() == Kind.ADD)
trackingHandler.collectionChangeHandler(ChangeKind.ADD, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
else if (ce.getKind() == Kind.REMOVE)
trackingHandler.collectionChangeHandler(ChangeKind.REMOVE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
else if (ce.getKind() == Kind.REPLACE)
trackingHandler.collectionChangeHandler(ChangeKind.REPLACE, ce.getCollection(), (Integer)ce.getKey(), ce.getValues());
}
}
public class EntityMapChangeListener implements CollectionChangeListener {
@Override
public void collectionChange(CollectionChangeEvent ce) {
if (ce.getKind() == Kind.ADD)
trackingHandler.entityMapChangeHandler(ChangeKind.ADD, ce.getCollection(), null, ce.getValues());
else if (ce.getKind() == Kind.REMOVE)
trackingHandler.entityMapChangeHandler(ChangeKind.REMOVE, ce.getCollection(), null, ce.getValues());
else if (ce.getKind() == Kind.REPLACE)
trackingHandler.entityMapChangeHandler(ChangeKind.REPLACE, ce.getCollection(), null, ce.getValues());
}
}
public class DefaultMapChangeListener implements CollectionChangeListener {
@Override
public void collectionChange(CollectionChangeEvent ce) {
if (ce.getKind() == Kind.ADD)
trackingHandler.mapChangeHandler(ChangeKind.ADD, ce.getCollection(), null, ce.getValues());
else if (ce.getKind() == Kind.REMOVE)
trackingHandler.mapChangeHandler(ChangeKind.REMOVE, ce.getCollection(), null, ce.getValues());
else if (ce.getKind() == Kind.REPLACE)
trackingHandler.mapChangeHandler(ChangeKind.REPLACE, ce.getCollection(), null, ce.getValues());
}
}
private CollectionChangeListener listChangeListener = new DefaultCollectionChangeListener();
private CollectionChangeListener setChangeListener = new DefaultCollectionChangeListener();
private CollectionChangeListener mapChangeListener = new DefaultMapChangeListener();
private PropertyChangeListener entityPropertyChangeListener = new EntityPropertyChangeListener();
private CollectionChangeListener entityListChangeListener = new EntityCollectionChangeListener();
private CollectionChangeListener entitySetChangeListener = new EntityCollectionChangeListener();
private CollectionChangeListener entityMapChangeListener = new EntityMapChangeListener();
private WeakIdentityHashMap<Object, TrackingType> trackingListeners = new WeakIdentityHashMap<Object, TrackingType>();
@Override
public void startTracking(Object previous, Object parent) {
if (previous == null || trackingListeners.containsKey(previous))
return;
if (previous instanceof ObservableCollection && previous instanceof List<?>) {
if (parent != null) {
((ObservableCollection)previous).addCollectionChangeListener(entityListChangeListener);
trackingListeners.put(previous, TrackingType.ENTITY_LIST);
}
else {
((ObservableCollection)previous).addCollectionChangeListener(listChangeListener);
trackingListeners.put(previous, TrackingType.LIST);
}
}
else if (previous instanceof ObservableCollection && previous instanceof Set<?>) {
if (parent != null) {
((ObservableCollection)previous).addCollectionChangeListener(entitySetChangeListener);
trackingListeners.put(previous, TrackingType.ENTITY_SET);
}
else {
((ObservableCollection)previous).addCollectionChangeListener(setChangeListener);
trackingListeners.put(previous, TrackingType.SET);
}
}
else if (previous instanceof ObservableCollection && previous instanceof Map<?, ?>) {
if (parent != null) {
((ObservableCollection)previous).addCollectionChangeListener(entityMapChangeListener);
trackingListeners.put(previous, TrackingType.ENTITY_MAP);
}
else {
((ObservableCollection)previous).addCollectionChangeListener(mapChangeListener);
trackingListeners.put(previous, TrackingType.MAP);
}
}
else if (parent != null || isEntity(previous)) {
PropertyChangeHelper.addPropertyChangeListener(previous, entityPropertyChangeListener);
trackingListeners.put(previous, TrackingType.ENTITY_PROPERTY);
}
}
@Override
public void stopTracking(Object previous, Object parent) {
if (previous == null || !trackingListeners.containsKey(previous))
return;
if (previous instanceof ObservableCollection && previous instanceof List<?>) {
if (parent != null)
((ObservableCollection)previous).removeCollectionChangeListener(entityListChangeListener);
else
((ObservableCollection)previous).removeCollectionChangeListener(listChangeListener);
}
else if (previous instanceof ObservableCollection && previous instanceof Set<?>) {
if (parent != null)
((ObservableCollection)previous).removeCollectionChangeListener(entitySetChangeListener);
else
((ObservableCollection)previous).removeCollectionChangeListener(setChangeListener);
}
else if (previous instanceof ObservableCollection && previous instanceof Map<?, ?>) {
if (parent != null)
((ObservableCollection)previous).removeCollectionChangeListener(entityMapChangeListener);
else
((ObservableCollection)previous).removeCollectionChangeListener(mapChangeListener);
}
else if (parent != null || isEntity(previous)) {
PropertyChangeHelper.removePropertyChangeListener(previous, entityPropertyChangeListener);
}
trackingListeners.remove(previous);
}
@Override
public void clear() {
Iterator<Object> ikey = trackingListeners.keySet().iterator();
while (ikey.hasNext()) {
Object obj = ikey.next();
TrackingType type = trackingListeners.get(obj);
switch (type) {
case LIST:
((ObservableCollection)obj).removeCollectionChangeListener(listChangeListener);
break;
case SET:
((ObservableCollection)obj).removeCollectionChangeListener(setChangeListener);
break;
case MAP:
((ObservableCollection)obj).removeCollectionChangeListener(mapChangeListener);
break;
case ENTITY_PROPERTY:
PropertyChangeHelper.removePropertyChangeListener(obj, entityPropertyChangeListener);
break;
case ENTITY_LIST:
((ObservableCollection)obj).removeCollectionChangeListener(entityListChangeListener);
break;
case ENTITY_SET:
((ObservableCollection)obj).removeCollectionChangeListener(entitySetChangeListener);
break;
case ENTITY_MAP:
((ObservableCollection)obj).removeCollectionChangeListener(entityMapChangeListener);
break;
}
}
}
private boolean dirty = false;
public boolean isDirty() {
return dirty;
}
@Override
public void notifyDirtyChange(boolean oldDirty, boolean dirty) {
this.dirty = dirty;
pcs.firePropertyChange("dirty", oldDirty, dirty);
}
@Override
public void notifyEntityDirtyChange(Object entity, boolean oldDirtyEntity, boolean newDirtyEntity) {
pcs.firePropertyChange(new PropertyChangeEvent(entity, "dirtyEntity", oldDirtyEntity, newDirtyEntity));
pcs.firePropertyChange(new PropertyChangeEvent(entity, "deepDirtyEntity", oldDirtyEntity, newDirtyEntity));
}
}