/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* ***
*
* Community License: GPL 3.0
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ***
*
* Available Commercial License: GraniteDS SLA 1.0
*
* This is the appropriate option if you are creating proprietary
* applications and you are not prepared to distribute and share the
* source code of your application under the GPL v3 license.
*
* Please visit http://www.granitedataservices.com/license for more
* details.
*/
package org.granite.client.tide.data.spi;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.granite.client.tide.data.Conflicts;
import org.granite.client.tide.data.EntityManager;
import org.granite.client.tide.data.impl.ObjectUtil;
import org.granite.client.tide.server.ServerSession;
/**
* @author William DRAI
*/
public class MergeContext {
private static ThreadLocal<Map<EntityManager, MergeContext>> mergeContext = new ThreadLocal<Map<EntityManager, MergeContext>>() {
@Override
protected Map<EntityManager, MergeContext> initialValue() {
return new IdentityHashMap<EntityManager, MergeContext>();
}
};
private final EntityManager entityManager;
private final DirtyCheckContext dirtyCheckContext;
private IdentityHashMap<Object, Object> entityCache = null;
private LinkedList<Object> mergeStack = new LinkedList<Object>();
private String externalDataSessionId = null;
private EntityManager sourceEntityManager = null;
private ServerSession serverSession = null;
private boolean mergeUpdate = false;
private boolean merging = false;
private Set<Object> versionChangeCache = null;
private boolean resolvingConflict = false;
private boolean skipDirtyCheck = false;
private Conflicts mergeConflicts = null;
private boolean uninitializing = false;
public static MergeContext get(EntityManager entityManager) {
return mergeContext.get().get(entityManager);
}
public static void destroy(EntityManager entityManager) {
mergeContext.get().remove(entityManager);
}
public MergeContext(EntityManager entityManager, DirtyCheckContext dirtyCheckContext, ServerSession serverSession) {
this.entityManager = entityManager;
this.dirtyCheckContext = dirtyCheckContext;
this.serverSession = serverSession;
mergeContext.get().put(entityManager, this);
}
public void initMerge() {
if (this.entityCache == null) {
this.entityCache = new IdentityHashMap<Object, Object>();
this.mergeUpdate = true;
}
}
public void clear() {
this.entityCache = null;
this.mergeConflicts = null;
this.versionChangeCache = null;
this.resolvingConflict = false;
this.uninitializing = false;
this.merging = false;
this.mergeUpdate = false;
}
public void addConflict(Object localEntity, Object receivedEntity, List<String> properties) {
if (this.mergeConflicts == null)
this.mergeConflicts = new Conflicts(this.entityManager, this.serverSession);
this.mergeConflicts.addConflict(localEntity, receivedEntity, properties);
}
public void initMergeConflicts() {
this.entityCache = null;
this.versionChangeCache = null;
this.resolvingConflict = false;
}
public void checkConflictsResolved() {
if (this.mergeConflicts != null && this.mergeConflicts.isAllResolved())
this.mergeConflicts = null;
}
public boolean isResolvingConflict() {
return this.resolvingConflict;
}
public void setResolvingConflict(boolean resolvingConflict) {
this.resolvingConflict = resolvingConflict;
}
public Conflicts getMergeConflicts() {
return this.mergeConflicts;
}
public Map<?, ?> getEntityCache() {
return this.entityCache;
}
public IdentityHashMap<Object, Object> saveEntityCache() {
IdentityHashMap<Object, Object> entityCache = this.entityCache;
this.entityCache = new IdentityHashMap<Object, Object>();
return entityCache;
}
public void restoreEntityCache(IdentityHashMap<Object, Object> entityCache) {
this.entityCache = entityCache;
}
public String getExternalDataSessionId() {
return this.externalDataSessionId;
}
public void setExternalDataSessionId(String externalDataSessionId) {
this.externalDataSessionId = externalDataSessionId;
}
public ServerSession getServerSession() {
return serverSession;
}
public void setSourceEntityManager(EntityManager sourceEntityManager) {
this.sourceEntityManager = sourceEntityManager;
}
public EntityManager getSourceEntityManager() {
return this.sourceEntityManager;
}
public boolean isMergeUpdate() {
return this.mergeUpdate;
}
public void setMergeUpdate(boolean mergeUpdate) {
this.mergeUpdate = mergeUpdate;
}
public boolean isMerging() {
return this.merging;
}
public void setMerging(boolean merging) {
this.merging = merging;
}
public boolean isSkipDirtyCheck() {
return this.skipDirtyCheck;
}
public void setSkipDirtyCheck(boolean skipDirtyCheck) {
this.skipDirtyCheck = skipDirtyCheck;
}
public Object getFromCache(Object obj) {
if (this.entityCache == null)
return null;
return this.entityCache.get(obj);
}
public void pushMerge(Object obj, Object dest) {
pushMerge(obj, dest, true);
}
public void pushMerge(Object obj, Object dest, boolean push) {
if (this.entityCache != null)
this.entityCache.put(obj, dest);
if (push)
this.mergeStack.push(dest);
}
public Object getCachedMerge(Object obj) {
return this.entityCache.get(obj);
}
public Object popMerge() {
return this.mergeStack.pop();
}
public Object getCurrentMerge() {
return this.mergeStack.peek();
}
public void setCurrentMerge(Object merge) {
this.mergeStack.set(0, merge);
}
public int getMergeStackSize() {
return this.mergeStack.size();
}
public Object mergeExternal(Object object, Object dest, Object parent, String propertyName) {
return entityManager.mergeExternal(this, object, dest, parent, propertyName, false);
}
public Map<String, Object> getSavedProperties(Object object) {
return dirtyCheckContext.getSavedProperties(object);
}
public Object getCachedObject(Object object) {
return entityManager.getCachedObject(object, true);
}
public Object[] getOwnerEntity(Object entity) {
return entityManager.getOwnerEntity(entity);
}
public boolean isUnsaved(Object object) {
return dirtyCheckContext.isUnsaved(object);
}
public void clearCache() {
this.entityCache = null;
}
public DataManager getDataManager() {
return entityManager.getDataManager();
}
public boolean objectEquals(Object o1, Object o2) {
return ObjectUtil.objectEquals(entityManager.getDataManager(), o1, o2);
}
private Set<Object> getVersionChangeCache() {
if (this.versionChangeCache == null)
this.versionChangeCache = new HashSet<Object>();
return this.versionChangeCache;
}
public void markVersionChanged(Object obj) {
getVersionChangeCache().add(obj);
}
public boolean hasVersionChanged(Object obj) {
return this.versionChangeCache != null ? this.versionChangeCache.contains(obj) : false;
}
public void setUninitializing(boolean uninitializing) {
this.uninitializing = uninitializing;
}
public boolean isUninitializing() {
return this.uninitializing;
}
public boolean isUninitializeAllowed() {
return this.entityManager.isUninitializeAllowed();
}
public void setUninitializeAllowed(boolean uninitializeAllowed) {
this.entityManager.setUninitializeAllowed(uninitializeAllowed);
}
}