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.collections.javafx;
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    
026    import org.granite.client.messaging.events.ResultEvent;
027    import org.granite.client.persistence.LazyableCollection;
028    import org.granite.client.tide.PropertyHolder;
029    import org.granite.client.tide.collections.ManagedPersistentAssociation;
030    import org.granite.client.tide.data.EntityManager;
031    import org.granite.client.tide.data.Identifiable;
032    import org.granite.client.tide.data.PersistenceManager;
033    import org.granite.client.tide.data.impl.ObjectUtil;
034    import org.granite.client.tide.data.spi.Wrapper;
035    import org.granite.client.tide.server.ServerSession;
036    import org.granite.logging.Logger;
037    
038    
039    /**
040     *  Internal implementation of persistent collection handling automatic lazy loading.<br/>
041     *  Used for wrapping persistent collections received from the server.<br/>
042     *  Should not be used directly.
043     * 
044     *  @author William DRAI
045     */
046    public abstract class AbstractJavaFXManagedPersistentAssociation implements ManagedPersistentAssociation, PropertyHolder, Wrapper {
047        
048        private static Logger log = Logger.getLogger("org.granite.client.tide.javafx.AbstractJavaFXManagedPersistentAssociation");
049        
050        private final Identifiable entity;
051        private final String propertyName;
052        
053        private ServerSession serverSession = null;
054    
055        private boolean localInitializing = false;
056        private boolean initializing = false;
057        private List<InitializationListener> listeners = new ArrayList<InitializationListener>();
058        private InitializationCallback initializationCallback = null;
059        
060        
061        public Identifiable getOwner() {
062            return entity;
063        } 
064        
065        public String getPropertyName() {
066            return propertyName;
067        }
068        
069        protected AbstractJavaFXManagedPersistentAssociation(Identifiable entity, String propertyName) {
070            this.entity = entity;
071            this.propertyName = propertyName;
072        }
073        
074        public void setServerSession(ServerSession serverSession) {
075            this.serverSession = serverSession;
076        }
077        
078        public ServerSession getServerSession() {
079            return serverSession;
080        }
081            
082        public Object getWrappedObject() {
083            return getObject();
084        }
085        
086        public void propertyResultHandler(String propName, ResultEvent event) {
087        }
088        
089        public void setProperty(String propertyName, Object value) {
090        }
091        
092        public boolean isInitialized() {
093            return ((LazyableCollection)getObject()).isInitialized();
094        }
095        
096        public boolean isInitializing() {
097            return initializing;
098        }
099        
100        public void initializing() {
101            ((LazyableCollection)getObject()).initializing();
102            localInitializing = true;
103        }
104        
105        public void addListener(InitializationListener listener) {
106            if (!listeners.contains(listener))
107                listeners.add(listener);
108        }
109        
110        public void removeListener(InitializationListener listener) {
111            listeners.remove(listener);
112        }
113        
114        private void requestInitialization() {
115            if (localInitializing)
116                return;
117            
118            EntityManager entityManager = PersistenceManager.getEntityManager(entity);
119            if (!initializing && entityManager.initializeObject(serverSession, this))                
120                initializing = true;
121        }
122        
123        protected boolean checkForRead() {
124            return checkForRead(true);
125        }
126        protected boolean checkForRead(boolean requestInitialization) {
127            if (!localInitializing && !isInitialized()) {
128                if (requestInitialization)
129                    requestInitialization();
130                return false;
131            }
132            return true;
133        }
134        protected void checkForWrite() {
135            if (!localInitializing && !isInitialized())
136                throw new IllegalStateException("Cannot modify uninitialized association: " + getOwner() + " property " + getPropertyName()); 
137        }
138        
139        public void initialize() {
140            ((LazyableCollection)getObject()).initialize();
141            localInitializing = false;
142            
143            for (InitializationListener listener : listeners)
144                listener.initialized(this);
145            
146            log.debug("initialized");
147        }
148        
149        public void uninitialize() {
150            ((LazyableCollection)getObject()).uninitialize();
151            initializing = false;
152            initializationCallback = null;
153            localInitializing = false;
154            
155            for (InitializationListener listener : listeners)
156                listener.uninitialized(this);
157        }
158        
159        public void withInitialized(InitializationCallback callback) {
160            if (isInitialized())
161                initializationCallback.call(this);
162            else {
163                initializationCallback = callback;
164                requestInitialization();
165            }
166        }
167            
168        @Override
169        public String toString() {
170            return getClass().getSimpleName() + ":" + ObjectUtil.toString(entity) + "." + getPropertyName() + ": " + getObject().toString();
171        }
172        
173        @Override
174        public boolean equals(Object obj) {
175            if (obj == null || !obj.getClass().equals(getClass()))
176                return false;
177            
178            AbstractJavaFXManagedPersistentAssociation mass = (AbstractJavaFXManagedPersistentAssociation)obj;
179            return entity.equals(mass.entity) && propertyName.equals(mass.propertyName);
180        }
181        
182        @Override
183        public int hashCode() {
184            int hashCode = entity.hashCode();
185            hashCode = 37 * hashCode + propertyName.hashCode();
186            return hashCode;
187        }
188    }