001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *                               ***
008 *
009 *   Community License: GPL 3.0
010 *
011 *   This file is free software: you can redistribute it and/or modify
012 *   it under the terms of the GNU General Public License as published
013 *   by the Free Software Foundation, either version 3 of the License,
014 *   or (at your option) any later version.
015 *
016 *   This file is distributed in the hope that it will be useful, but
017 *   WITHOUT ANY WARRANTY; without even the implied warranty of
018 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
019 *   GNU General Public License for more details.
020 *
021 *   You should have received a copy of the GNU General Public License
022 *   along with this program. If not, see <http://www.gnu.org/licenses/>.
023 *
024 *                               ***
025 *
026 *   Available Commercial License: GraniteDS SLA 1.0
027 *
028 *   This is the appropriate option if you are creating proprietary
029 *   applications and you are not prepared to distribute and share the
030 *   source code of your application under the GPL v3 license.
031 *
032 *   Please visit http://www.granitedataservices.com/license for more
033 *   details.
034 */
035package org.granite.client.tide.data;
036
037import java.util.List;
038import java.util.Map;
039
040import org.granite.client.tide.Context;
041import org.granite.client.tide.data.spi.DataManager;
042import org.granite.client.tide.data.spi.MergeContext;
043import org.granite.client.tide.data.spi.DataManager.TrackingHandler;
044import org.granite.client.tide.server.ServerSession;
045
046/**
047 *  EntityManager is the interface for entity management (!)
048 *  It is implemented by the Tide context
049 *
050 *  @author William DRAI
051 */
052public interface EntityManager {
053    
054    /**
055     *  Return the entity manager id
056     * 
057     *  @return the entity manager id
058     */
059    public String getId();
060    
061    /**
062     *  Return the entity manager state
063     * 
064     *  @return the entity manager state
065     */
066    public boolean isActive();
067    
068    /**
069     *  Clear entity cache
070     */ 
071    public void clearCache();
072    
073    /**
074     *  Clear the current context
075     *  Destroys all components/context variables
076     */
077    public void clear();
078
079    /**
080     * Data manager for this entity manager
081     * @return data manager
082     */
083    public DataManager getDataManager();
084
085    /**
086     * Tracking handler for this entity manager
087     * @return tracking handler
088     */
089    public TrackingHandler getTrackingHandler();
090    
091    /**
092     *  Allow uninitialize of persistent collections
093     *  @param allowed allow uninitialize of collections
094     */
095    public void setUninitializeAllowed(boolean allowed);
096    
097    /**
098     * Allow uninitialize of persistent collections ?
099     *  @return allow uninitialize of collections
100     */
101    public boolean isUninitializeAllowed();
102    
103    /**
104     *  Setter for the remote initializer implementation
105     * 
106     *  @param remoteInitializer instance of IRemoteInitializer
107     */
108    public void setRemoteInitializer(RemoteInitializer remoteInitializer);
109    
110    /**
111     *  Setter for the remote validator implementation
112     * 
113     *  @param remoteValidator instance of IRemoteValidator
114     */
115    public void setRemoteValidator(RemoteValidator remoteValidator);
116    
117    /**
118     *  Create a new temporary entity manager
119     * 
120     *  @return a temporary entity manager
121     */
122    public EntityManager newTemporaryEntityManager();
123    
124    
125    /**
126     *  Register a reference to the provided object with either a parent or res
127     * 
128     *  @param entity an entity
129     *  @param parent the parent entity
130     *  @param propName name of the parent entity property that references the entity
131     */
132    public void addReference(Object entity, Object parent, String propName);
133    
134    /**
135     *  Remove a reference on the provided object
136     *
137     *  @param entity an entity
138     *  @param parent the parent entity to dereference
139     *  @param propName name of the parent entity property that references the entity
140     */
141    public boolean removeReference(Object entity, Object parent, String propName);
142
143    /**
144     *  Entity manager is dirty when any entity/collection/map has been modified
145     *
146     *  @return is dirty
147     */
148    public boolean isDirty();
149    
150    /**
151     *  Entity is dirty when any direct property has been modified
152     *  @param entity
153     *
154     *  @return is dirty
155     */
156    public boolean isDirtyEntity(Object entity);
157    
158    /**
159     *  Entity is deep dirty when any element in its object graph has been modified
160     *  @param entity root of the entity graph
161     *
162     *  @return is dirty
163     */
164    public boolean isDeepDirtyEntity(Object entity);
165    
166    /**
167     *  Indicates if the entity is persisted on the server (id/version not null/NaN)
168     *
169     *  @param entity an entity
170     *  @return true if saved
171     */
172    public boolean isPersisted(Object entity);
173    
174    /**
175     *  Retrieve an entity in the cache from its uid
176     *   
177     *  @param object an entity
178     *  @param nullIfAbsent return null if entity not cached in context
179     */
180    public Object getCachedObject(Object object, boolean nullIfAbsent);
181
182    /**
183     * Return the owner entity for the specified object (collection/map, embedded object or associated object)
184     * @param object an object
185     * @return array containing the owner entity and the property name or null if not found
186     */
187    public Object[] getOwnerEntity(Object object);
188
189    /**
190     * Initialize the merge context in the current thread
191     * MergeContext should be released at the end of the process
192     * @return current merge context
193     */
194    public MergeContext initMerge();
195
196    /**
197     * Merge an object in the local context
198     *
199     * @param mergeContext current merge context
200     * @param obj object to merge
201     * @param previous previous instance
202     * @param parent parent/owning entity
203     * @param propertyName property name from the owning entity
204     * @param forceUpdate true to force update of the destination object even if versions do not match
205     * @return merged object
206     */
207    public Object mergeExternal(final MergeContext mergeContext, Object obj, Object previous, Object parent, String propertyName, boolean forceUpdate);
208    
209    /**
210     *  Merge an object coming from a remote location (in general from a service) in the local context
211     *
212     *  @param obj external object
213     *  @param prev existing local object to merge with
214     *  @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
215     *  @param removals list of entities to remove from the entity manager cache
216     *  @param persists list of entities newly persisted to be added in the entity manager cache
217     *
218     *  @return merged object (should === previous when previous not null)
219     */
220    public Object mergeExternalData(Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
221    
222    /**
223     *  Merge an object coming from a remote location (in general from a service) in the local context
224     *
225     *  @param serverSession the current server session
226     *  @param obj external object
227     *
228     *  @return merged object
229     */
230    public Object mergeExternalData(ServerSession serverSession, Object obj);
231    
232    /**
233     *  Merge an object coming from a remote location (in general from a service) in the local context
234     *
235     *  @param serverSession the current server session
236     *  @param obj external object
237     *  @param prev existing local object to merge with
238     *  @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
239     *  @param removals array of entities to remove from the entity manager cache
240     *  @param persists list of entities newly persisted to be added in the entity manager cache
241     *
242     *  @return merged object (should === previous when previous not null)
243     */
244    public Object mergeExternalData(ServerSession serverSession, Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
245    
246    /**
247     *  Merge an object coming from a remote location (in general from a service) in the local context
248     *
249     *  @param obj external object
250     *
251     *  @return merged object
252     */
253    public Object mergeExternalData(Object obj);
254    
255    // public Object internalMergeExternalData(MergeContext mergeContext, Object obj, Object prev, List<Object> removals);
256    
257    /**
258     *  Merge an object coming from another entity manager (in general in the global context) in the local context
259     *
260     *  @param sourceEntityManager source context of incoming data
261     *  @param obj external object
262     *  @param externalDataSessionId is merge from external data
263     *  @param uninitializing the merge should uninitialize all collections/entities when possible
264     *
265     *  @return merged object (should === previous when previous not null)
266     */
267    public Object mergeFromEntityManager(EntityManager sourceEntityManager, Object obj, String externalDataSessionId, boolean uninitializing);
268    
269    /**
270     *  Merge conversation entity manager context variables in global entity manager 
271     *  Only applicable to conversation contexts 
272     * 
273     *  @param entityManager conversation entity manager
274     */
275    public void mergeInEntityManager(EntityManager entityManager);
276    
277    /**
278     *  Discard changes of entity from last version received from the server
279     *
280     *  @param entity entity to restore
281     */ 
282    public void resetEntity(Object entity);
283    
284    /**
285     *  Discard changes of all cached entities from last version received from the server
286     */ 
287    public void resetAllEntities();
288    
289    /**
290     *  Current map of saved properties for the specified entity
291     *  @param entity an entity
292     * 
293     *  @return saved properties for this entity
294     */
295    public Map<String, Object> getSavedProperties(Object entity);
296
297    /**
298     * Kinds of updates than can be received from the server
299     */
300    public static enum UpdateKind {
301        PERSIST,
302        UPDATE,
303        REMOVE,
304        REFRESH,
305        CONFLICT;
306        
307        private static final String DATA_EVENT_PREFIX = "org.granite.client.tide.data.";
308        
309        public static UpdateKind forName(String kind) {
310            if ("PERSIST".equals(kind))
311                return PERSIST;
312            else if ("UPDATE".equals(kind))
313                return UPDATE;
314            else if ("REMOVE".equals(kind))
315                return REMOVE;
316            throw new IllegalArgumentException("Unknown update kind " + kind);
317        }
318        
319        public String eventName() {
320                return DATA_EVENT_PREFIX + name().toLowerCase();
321        }
322        
323        public <T> String eventName(Class<T> entityClass) {
324                return DATA_EVENT_PREFIX + name().toLowerCase() + "." + entityClass.getSimpleName();
325        }
326    }
327
328    /**
329     * Update received from the server
330     */
331    public static class Update {
332        
333        private final UpdateKind kind;
334        private Object entity;
335        
336        public Update(UpdateKind kind, Object entity) {
337            this.kind = kind;
338            this.entity = entity;
339        }
340        
341        public UpdateKind getKind() {
342            return kind;
343        }
344        
345        public Object getEntity() {
346            return entity;
347        }
348
349        public void setEntity(Object entity) {
350            this.entity = entity;
351        }
352        
353        public static Update forUpdate(String kind, Object entity) {
354            return new Update(UpdateKind.forName(kind), entity);
355        }
356    }
357    
358    /**
359     *  Handle data updates
360     *
361     *  @param mergeContext current merge context
362     *  @param sourceSessionId sessionId from which data updates come (null when from current session) 
363     *  @param updates list of data updates
364     */
365    public void handleUpdates(MergeContext mergeContext, String sourceSessionId, List<Update> updates);
366
367    /**
368     * Dispatch update events on the context
369     * @param context tide context
370     * @param updates list of data updates
371     */
372        public void raiseUpdateEvents(Context context, List<EntityManager.Update> updates);
373
374    /**
375     * Register a listener for data conflicts
376     * @param listener listener
377     */
378    public void addListener(DataConflictListener listener);
379
380    /**
381     * Unregister a listener for data conflicts
382     * @param listener listener
383     */
384    public void removeListener(DataConflictListener listener);
385    
386    /**
387     *  Accept values for conflict
388     * 
389     *  @param conflict conflict
390     *  @param acceptClient true: keep client changes, false: override with server changes
391     */
392    public void acceptConflict(Conflict conflict, boolean acceptClient);
393    
394    /**
395     *  Trigger remote initialization of lazy-loaded objects
396     * 
397     *  @param serverSession current server session
398     *  @param entity owner entity
399     *  @param propertyName property name
400     *  @param object a lazily loaded object
401     * 
402     *  @return true if initialization triggered
403     */
404    public boolean initializeObject(ServerSession serverSession, Object entity, String propertyName, Object object);
405    
406    /**
407     *  Trigger remote validation of objects
408     * 
409     *  @param object an object to remotely validate
410     *  @param property a property to validate
411     *  @param value value to check
412     * 
413     *  @return true if validation triggered
414     */
415    public boolean validateObject(Object object, String property, Object value);
416
417
418    public static interface Propagation {
419
420        public void propagate(Object entity, Function func);
421    }
422
423    public static interface Function {
424
425        public void execute(EntityManager entityManager, Object entity);
426    }
427
428    /**
429     *  Set the propagation manager
430     *
431     *  @param propagation propagation function that will visit child entity managers
432     */
433    public void setEntityManagerPropagation(Propagation propagation);
434
435    public static interface PropagationPolicy {
436        
437        public void propagate();
438    }
439}