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.data;
022    
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import org.granite.client.tide.Context;
028    import org.granite.client.tide.data.spi.DataManager;
029    import org.granite.client.tide.data.spi.MergeContext;
030    import org.granite.client.tide.server.ServerSession;
031    import org.granite.tide.Expression;
032    
033    /**
034     *  EntityManager is the interface for entity management (!)
035     *  It is implemented by the Tide context
036     *
037     *  @author William DRAI
038     */
039    public interface EntityManager {
040        
041        /**
042         *  Return the entity manager id
043         * 
044         *  @return the entity manager id
045         */
046        public String getId();
047        
048        /**
049         *  Return the entity manager state
050         * 
051         *  @return the entity manager state
052         */
053        public boolean isActive();
054        
055        /**
056         *  Clear entity cache
057         */ 
058        public void clearCache();
059        
060        /**
061         *  Clear the current context
062         *  Destroys all components/context variables
063         */
064        public void clear();
065        
066        public DataManager getDataManager();
067        
068        /**
069         *  Allow uninitialize of persistent collections
070         *
071         *  @param allowed allow uninitialize of collections
072         */
073        public void setUninitializeAllowed(boolean allowed);
074        
075        /**
076         *  @return allow uninitialize of collections
077         */
078        public boolean isUninitializeAllowed();
079        
080        
081        public static interface Propagation {
082            
083            public void propagate(Identifiable entity, Function func);
084        }
085        
086        public static interface Function {
087            
088            public void execute(EntityManager entityManager, Identifiable entity);
089        }
090        
091        /**
092         *  Setter for the propagation manager
093         * 
094         *  @param propagation propagation function that will visit child entity managers
095         */
096        public void setEntityManagerPropagation(Propagation propagation);
097        
098        /**
099         *  Setter for the remote initializer implementation
100         * 
101         *  @param remoteInitializer instance of IRemoteInitializer
102         */
103        public void setRemoteInitializer(RemoteInitializer remoteInitializer);
104        
105        /**
106         *  Setter for the remote validator implementation
107         * 
108         *  @param remoteValidator instance of IRemoteValidator
109         */
110        public void setRemoteValidator(RemoteValidator remoteValidator);
111        
112        /**
113         *  Create a new temporary entity manager
114         * 
115         *  @return a temporary entity manager
116         */
117        public EntityManager newTemporaryEntityManager();
118        
119        
120        /**
121         *  Intercept a property getter
122         * 
123         *  @param entity intercepted entity
124         *  @param propName intercepted property name
125         *  @param value current value
126         */
127        public Object getEntityProperty(Identifiable entity, String propName, Object value);
128        
129        /**
130         *  Intercept a property setter
131         * 
132         *  @param entity intercepted entity
133         *  @param propName intercepted property name
134         *  @param oldValue old value
135         *  @param newValue new value
136         */
137        public void setEntityProperty(Identifiable entity, String propName, Object oldValue, Object newValue);
138        
139        /**
140         *  Register a reference to the provided object with either a parent or res
141         * 
142         *  @param entity an entity
143         *  @param parent the parent entity
144         *  @param propName name of the parent entity property that references the entity
145         *  @param res the context expression
146         */ 
147        public void addReference(Object entity, Object parent, String propName, Expression expr);
148        
149        /**
150         *  Remove a reference on the provided object
151         *
152         *  @param obj an entity
153         *  @param parent the parent entity to dereference
154         *  @param propName name of the parent entity property that references the entity
155         *  @param res expression to remove
156         */ 
157        public boolean removeReference(Object entity, Object parent, String propName, Expression exp);
158        
159        /**
160         *  Retrieves context expression path for the specified entity (internal implementation)
161         *   
162         *  @param obj an entity
163         *  @param recurse should recurse until 'real' context path, otherwise object reference can be returned
164         *  @param cache graph visitor cache
165         * 
166         *  @return the path from the entity context (or null is no path found)
167         */
168        public Expression getReference(Object entity, boolean recurse, Set<Object> cache);
169        
170        /**
171         *  Entity manager is dirty when any entity/collection/map has been modified
172         *
173         *  @return is dirty
174         */
175        public boolean isDirty();
176        
177        /**
178         *  Entity is deep dirty when any element in its object graph has been modified
179         *  @param entity root of the entity graph
180         *
181         *  @return is dirty
182         */
183        public boolean isDeepDirtyEntity(Object entity);
184        
185        /**
186         *  Indicates if the entity is persisted on the server (id/version not null/NaN)
187         *
188         *  @param entity an entity
189         *  @return true if saved
190         */
191        public boolean isSaved(Object entity);
192        
193        /**
194         *  @private 
195         *  Retrieve an entity in the cache from its uid
196         *   
197         *  @param object an entity
198         *  @param nullIfAbsent return null if entity not cached in context
199         */
200        public Object getCachedObject(Object object, boolean nullIfAbsent);
201        
202        public Object[] getOwnerEntity(Object object);
203        
204        public MergeContext initMerge();
205        
206        public Object mergeExternal(final MergeContext mergeContext, Object obj, Object previous, Expression expr, Object parent, String propertyName, String setter, boolean forceUpdate);
207        
208        /**
209         *  Merge an object coming from a remote location (in general from a service) in the local context
210         *
211         *  @param obj external object
212         *  @param prev existing local object to merge with
213         *  @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
214         *  @param removals array of entities to remove from the entity manager cache
215         *
216         *  @return merged object (should === previous when previous not null)
217         */
218        public Object mergeExternalData(Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
219        
220        /**
221         *  Merge an object coming from a remote location (in general from a service) in the local context
222         *
223         *  @param obj external object
224         *
225         *  @return merged object
226         */
227        public Object mergeExternalData(ServerSession serverSession, Object obj);
228        
229        /**
230         *  Merge an object coming from a remote location (in general from a service) in the local context
231         *
232         *  @param obj external object
233         *  @param prev existing local object to merge with
234         *  @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
235         *  @param removals array of entities to remove from the entity manager cache
236         *
237         *  @return merged object (should === previous when previous not null)
238         */
239        public Object mergeExternalData(ServerSession serverSession, Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
240        
241        /**
242         *  Merge an object coming from a remote location (in general from a service) in the local context
243         *
244         *  @param obj external object
245         *
246         *  @return merged object
247         */
248        public Object mergeExternalData(Object obj);
249        
250        // public Object internalMergeExternalData(MergeContext mergeContext, Object obj, Object prev, List<Object> removals);
251        
252        /**
253         *  @private 
254         *  Merge an object coming from another entity manager (in general in the global context) in the local context
255         *
256         *  @param sourceEntityManager source context of incoming data
257         *  @param obj external object
258         *  @param externalDataSessionId is merge from external data
259         *
260         *  @return merged object (should === previous when previous not null)
261         */
262        public Object mergeFromEntityManager(EntityManager sourceEntityManager, Object obj, String externalDataSessionId, boolean uninitializing);
263        
264        /**
265         *  Merge conversation entity manager context variables in global entity manager 
266         *  Only applicable to conversation contexts 
267         * 
268         *  @param entityManager conversation entity manager
269         */
270        public void mergeInEntityManager(EntityManager entityManager);
271        
272        /**
273         *  Discard changes of entity from last version received from the server
274         *
275         *  @param entity entity to restore
276         *  @param cache reset cache
277         */ 
278        public void resetEntity(Identifiable entity);
279        
280        /**
281         *  Discard changes of all cached entities from last version received from the server
282         * 
283         *  @param cache reset cache
284         */ 
285        public void resetAllEntities();
286        
287        /**
288         *  Current map of saved properties for the specified entity
289         *  @param entity an entity
290         * 
291         *  @return saved properties for this entity
292         */
293        public Map<String, Object> getSavedProperties(Object entity);
294        
295        
296        public static enum UpdateKind {
297            PERSIST,
298            UPDATE,
299            REMOVE,
300            REFRESH,
301            CONFLICT;
302            
303            private static final String DATA_EVENT_PREFIX = "org.granite.client.tide.data.";
304            
305            public static UpdateKind forName(String kind) {
306                if ("PERSIST".equals(kind))
307                    return PERSIST;
308                else if ("UPDATE".equals(kind))
309                    return UPDATE;
310                else if ("REMOVE".equals(kind))
311                    return REMOVE;
312                throw new IllegalArgumentException("Unknown update kind " + kind);
313            }
314            
315            public String eventName() {
316                    return DATA_EVENT_PREFIX + name().toLowerCase();
317            }
318            
319            public <T> String eventName(Class<T> entityClass) {
320                    return DATA_EVENT_PREFIX + name().toLowerCase() + "." + entityClass.getSimpleName();
321            }
322        }
323        
324        public static class Update {
325            
326            private final UpdateKind kind;
327            private Object entity;
328            
329            public Update(UpdateKind kind, Object entity) {
330                this.kind = kind;
331                this.entity = entity;
332            }
333            
334            public UpdateKind getKind() {
335                return kind;
336            }
337            
338            public Object getEntity() {
339                return entity;
340            }
341    
342            public void setEntity(Object entity) {
343                this.entity = entity;
344            }
345            
346            public static Update forUpdate(String kind, Object entity) {
347                return new Update(UpdateKind.forName(kind), entity);
348            }
349        }
350        
351        /**
352         *  @private
353         *  Handle data updates
354         *
355         *  @param sourceSessionId sessionId from which data updates come (null when from current session) 
356         *  @param updates list of data updates
357         */
358        public void handleUpdates(MergeContext mergeContext, String sourceSessionId, List<Update> updates);
359        
360            public void raiseUpdateEvents(Context context, List<EntityManager.Update> updates);
361            
362        
363        public void addListener(DataConflictListener listener);
364        
365        public void removeListener(DataConflictListener listener);
366        
367        /**
368         *  Accept values for conflict
369         * 
370         *  @param conflict conflict
371         *  @param acceptClient true: keep client changes, false: override with server changes
372         */
373        public void acceptConflict(Conflict conflict, boolean acceptClient);
374        
375        /**
376         *  Trigger remote initialization of lazy-loaded objects
377         * 
378         *  @param object a lazy-loaded object
379         * 
380         *  @return true if initialization triggered
381         */
382        public boolean initializeObject(ServerSession serverSession, Object object);
383        
384        /**
385         *  Trigger remote validation of objects
386         * 
387         *  @param object a lazy-loaded object
388         * 
389         *  @return true if validation triggered
390         */
391        public boolean validateObject(Object object, String property, Object value);
392        
393        
394        public static interface PropagationPolicy {
395            
396            public void propagate();
397        }
398    }