/*
GRANITE DATA SERVICES
Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
This file is part of Granite Data Services.
Granite Data Services is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
Granite Data Services is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
package org.granite.client.tide.data;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.granite.client.tide.Context;
import org.granite.client.tide.data.spi.DataManager;
import org.granite.client.tide.data.spi.MergeContext;
import org.granite.client.tide.data.spi.DataManager.TrackingHandler;
import org.granite.client.tide.server.ServerSession;
import org.granite.tide.Expression;
/**
* EntityManager is the interface for entity management (!)
* It is implemented by the Tide context
*
* @author William DRAI
*/
public interface EntityManager {
/**
* Return the entity manager id
*
* @return the entity manager id
*/
public String getId();
/**
* Return the entity manager state
*
* @return the entity manager state
*/
public boolean isActive();
/**
* Clear entity cache
*/
public void clearCache();
/**
* Clear the current context
* Destroys all components/context variables
*/
public void clear();
public DataManager getDataManager();
public TrackingHandler getTrackingHandler();
/**
* Allow uninitialize of persistent collections
*
* @param allowed allow uninitialize of collections
*/
public void setUninitializeAllowed(boolean allowed);
/**
* @return allow uninitialize of collections
*/
public boolean isUninitializeAllowed();
public static interface Propagation {
public void propagate(Object entity, Function func);
}
public static interface Function {
public void execute(EntityManager entityManager, Object entity);
}
/**
* Setter for the propagation manager
*
* @param propagation propagation function that will visit child entity managers
*/
public void setEntityManagerPropagation(Propagation propagation);
/**
* Setter for the remote initializer implementation
*
* @param remoteInitializer instance of IRemoteInitializer
*/
public void setRemoteInitializer(RemoteInitializer remoteInitializer);
/**
* Setter for the remote validator implementation
*
* @param remoteValidator instance of IRemoteValidator
*/
public void setRemoteValidator(RemoteValidator remoteValidator);
/**
* Create a new temporary entity manager
*
* @return a temporary entity manager
*/
public EntityManager newTemporaryEntityManager();
/**
* Register a reference to the provided object with either a parent or res
*
* @param entity an entity
* @param parent the parent entity
* @param propName name of the parent entity property that references the entity
* @param expr the context expression
*/
public void addReference(Object entity, Object parent, String propName, Expression expr);
/**
* Remove a reference on the provided object
*
* @param entity an entity
* @param parent the parent entity to dereference
* @param propName name of the parent entity property that references the entity
* @param expr expression to remove
*/
public boolean removeReference(Object entity, Object parent, String propName, Expression expr);
/**
* Retrieves context expression path for the specified entity (internal implementation)
*
* @param entity an entity
* @param recurse should recurse until 'real' context path, otherwise object reference can be returned
* @param cache graph visitor cache
*
* @return the path from the entity context (or null is no path found)
*/
public Expression getReference(Object entity, boolean recurse, Set<Object> cache);
/**
* Entity manager is dirty when any entity/collection/map has been modified
*
* @return is dirty
*/
public boolean isDirty();
/**
* Entity is dirty when any direct property has been modified
* @param entity
*
* @return is dirty
*/
public boolean isDirtyEntity(Object entity);
/**
* Entity is deep dirty when any element in its object graph has been modified
* @param entity root of the entity graph
*
* @return is dirty
*/
public boolean isDeepDirtyEntity(Object entity);
/**
* Indicates if the entity is persisted on the server (id/version not null/NaN)
*
* @param entity an entity
* @return true if saved
*/
public boolean isPersisted(Object entity);
/**
* Retrieve an entity in the cache from its uid
*
* @param object an entity
* @param nullIfAbsent return null if entity not cached in context
*/
public Object getCachedObject(Object object, boolean nullIfAbsent);
public Object[] getOwnerEntity(Object object);
public MergeContext initMerge();
public Object mergeExternal(final MergeContext mergeContext, Object obj, Object previous, Expression expr, Object parent, String propertyName, boolean forceUpdate);
/**
* Merge an object coming from a remote location (in general from a service) in the local context
*
* @param obj external object
* @param prev existing local object to merge with
* @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
* @param removals list of entities to remove from the entity manager cache
* @param persists list of entities newly persisted to be added in the entity manager cache
*
* @return merged object (should === previous when previous not null)
*/
public Object mergeExternalData(Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
/**
* Merge an object coming from a remote location (in general from a service) in the local context
*
* @param serverSession the current server session
* @param obj external object
*
* @return merged object
*/
public Object mergeExternalData(ServerSession serverSession, Object obj);
/**
* Merge an object coming from a remote location (in general from a service) in the local context
*
* @param serverSession the current server session
* @param obj external object
* @param prev existing local object to merge with
* @param externalDataSessionId sessionId from which the data is coming (other user/server), null if local or current user session
* @param removals array of entities to remove from the entity manager cache
* @param persists list of entities newly persisted to be added in the entity manager cache
*
* @return merged object (should === previous when previous not null)
*/
public Object mergeExternalData(ServerSession serverSession, Object obj, Object prev, String externalDataSessionId, List<Object> removals, List<Object> persists);
/**
* Merge an object coming from a remote location (in general from a service) in the local context
*
* @param obj external object
*
* @return merged object
*/
public Object mergeExternalData(Object obj);
// public Object internalMergeExternalData(MergeContext mergeContext, Object obj, Object prev, List<Object> removals);
/**
* Merge an object coming from another entity manager (in general in the global context) in the local context
*
* @param sourceEntityManager source context of incoming data
* @param obj external object
* @param externalDataSessionId is merge from external data
* @param uninitializing the merge should uninitialize all collections/entities when possible
*
* @return merged object (should === previous when previous not null)
*/
public Object mergeFromEntityManager(EntityManager sourceEntityManager, Object obj, String externalDataSessionId, boolean uninitializing);
/**
* Merge conversation entity manager context variables in global entity manager
* Only applicable to conversation contexts
*
* @param entityManager conversation entity manager
*/
public void mergeInEntityManager(EntityManager entityManager);
/**
* Discard changes of entity from last version received from the server
*
* @param entity entity to restore
*/
public void resetEntity(Object entity);
/**
* Discard changes of all cached entities from last version received from the server
*/
public void resetAllEntities();
/**
* Current map of saved properties for the specified entity
* @param entity an entity
*
* @return saved properties for this entity
*/
public Map<String, Object> getSavedProperties(Object entity);
public static enum UpdateKind {
PERSIST,
UPDATE,
REMOVE,
REFRESH,
CONFLICT;
private static final String DATA_EVENT_PREFIX = "org.granite.client.tide.data.";
public static UpdateKind forName(String kind) {
if ("PERSIST".equals(kind))
return PERSIST;
else if ("UPDATE".equals(kind))
return UPDATE;
else if ("REMOVE".equals(kind))
return REMOVE;
throw new IllegalArgumentException("Unknown update kind " + kind);
}
public String eventName() {
return DATA_EVENT_PREFIX + name().toLowerCase();
}
public <T> String eventName(Class<T> entityClass) {
return DATA_EVENT_PREFIX + name().toLowerCase() + "." + entityClass.getSimpleName();
}
}
public static class Update {
private final UpdateKind kind;
private Object entity;
public Update(UpdateKind kind, Object entity) {
this.kind = kind;
this.entity = entity;
}
public UpdateKind getKind() {
return kind;
}
public Object getEntity() {
return entity;
}
public void setEntity(Object entity) {
this.entity = entity;
}
public static Update forUpdate(String kind, Object entity) {
return new Update(UpdateKind.forName(kind), entity);
}
}
/**
* Handle data updates
*
* @param mergeContext current merge context
* @param sourceSessionId sessionId from which data updates come (null when from current session)
* @param updates list of data updates
*/
public void handleUpdates(MergeContext mergeContext, String sourceSessionId, List<Update> updates);
public void raiseUpdateEvents(Context context, List<EntityManager.Update> updates);
public void addListener(DataConflictListener listener);
public void removeListener(DataConflictListener listener);
/**
* Accept values for conflict
*
* @param conflict conflict
* @param acceptClient true: keep client changes, false: override with server changes
*/
public void acceptConflict(Conflict conflict, boolean acceptClient);
/**
* Trigger remote initialization of lazy-loaded objects
*
* @param serverSession current server session
* @param entity owner entity
* @param propertyName property name
* @param object a lazily loaded object
*
* @return true if initialization triggered
*/
public boolean initializeObject(ServerSession serverSession, Object entity, String propertyName, Object object);
/**
* Trigger remote validation of objects
*
* @param object an object to remotely validate
* @param property a property to validate
* @param value value to check
*
* @return true if validation triggered
*/
public boolean validateObject(Object object, String property, Object value);
public static interface PropagationPolicy {
public void propagate();
}
}