001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.client.tide.javafx;
022
023 import java.lang.reflect.Method;
024
025 import javafx.beans.property.BooleanProperty;
026 import javafx.beans.property.Property;
027 import javafx.beans.property.SimpleBooleanProperty;
028 import javafx.beans.property.SimpleObjectProperty;
029 import javafx.beans.value.ChangeListener;
030 import javafx.beans.value.ObservableValue;
031
032 import org.granite.client.tide.data.EntityManager;
033 import org.granite.client.tide.data.Identifiable;
034 import org.granite.client.tide.data.PersistenceManager;
035 import org.granite.client.tide.javafx.JavaFXDataManager;
036
037
038 public class ManagedEntityProperty<T extends Identifiable> extends SimpleObjectProperty<T> {
039
040 private EntityManager entityManager;
041 private JavaFXDataManager dataManager;
042
043 private BooleanProperty saved = new SimpleBooleanProperty(this, "saved", true);
044 private BooleanProperty dirty = new SimpleBooleanProperty(this, "dirty", false);
045
046 public ManagedEntityProperty(EntityManager entityManager, JavaFXDataManager dataManager) {
047 super();
048 init(entityManager, dataManager);
049 }
050
051 public ManagedEntityProperty(EntityManager entityManager, JavaFXDataManager dataManager, T value) {
052 super(value);
053 init(entityManager, dataManager);
054 }
055
056 public ManagedEntityProperty(EntityManager entityManager, JavaFXDataManager dataManager, Object bean, String property) {
057 super(bean, property);
058 init(entityManager, dataManager);
059 }
060
061 public ManagedEntityProperty(EntityManager entityManager, JavaFXDataManager dataManager, Object bean, String property, T value) {
062 super(bean, property, value);
063 init(entityManager, dataManager);
064 }
065
066 public BooleanProperty savedProperty() {
067 return saved;
068 }
069 public boolean isSaved() {
070 return saved.get();
071 }
072
073 public BooleanProperty dirtyProperty() {
074 return dirty;
075 }
076 public boolean isDirty() {
077 return dirty.get();
078 }
079
080 private ChangeListener<Identifiable> entityChangeListener = new ChangeListener<Identifiable>() {
081 @Override
082 public void changed(ObservableValue<? extends Identifiable> observable, Identifiable oldValue, Identifiable newValue) {
083 if (oldValue != null) {
084 Property<Object> versionProperty = getVersionProperty(oldValue);
085 versionProperty.removeListener(versionChangeListener);
086 dirty.unbind();
087 }
088
089 if (newValue == null)
090 return;
091
092 Property<Object> versionProperty = getVersionProperty(newValue);
093 versionProperty.addListener(versionChangeListener);
094 saved.set(versionProperty.getValue() != null);
095
096 EntityManager entityManager = PersistenceManager.getEntityManager(newValue);
097 if (entityManager == null)
098 ManagedEntityProperty.this.entityManager.mergeExternalData(newValue);
099 else if (entityManager != ManagedEntityProperty.this.entityManager)
100 throw new RuntimeException("Entity " + newValue + " cannot be attached: already attached to another entity manager");
101
102 dirty.bind(dataManager.deepDirtyEntity(newValue));
103 }
104 };
105
106 private ChangeListener<Object> versionChangeListener = new ChangeListener<Object>() {
107 @Override
108 public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
109 saved.set(newValue != null);
110 }
111 };
112
113 private void init(EntityManager entityManager, JavaFXDataManager dataManager) {
114 this.entityManager = entityManager;
115 this.dataManager = dataManager;
116 this.addListener(entityChangeListener);
117 }
118
119 public void reset() {
120 if (get() == null)
121 return;
122 entityManager.resetEntity(get());
123 }
124
125 @SuppressWarnings("unchecked")
126 private Property<Object> getVersionProperty(Object value) {
127 String versionPropertyName = dataManager.getEntityDescriptor(value).getVersionPropertyName();
128 if (versionPropertyName == null)
129 throw new RuntimeException("No version property found on entity " + value);
130 try {
131 Method m = value.getClass().getMethod(versionPropertyName + "Property");
132 return (Property<Object>)m.invoke(value);
133 }
134 catch (Exception e) {
135 throw new RuntimeException("Could not get version property on entity " + value, e);
136 }
137
138 }
139 }