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    }