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.spi; 036 037import java.util.HashSet; 038import java.util.IdentityHashMap; 039import java.util.LinkedList; 040import java.util.List; 041import java.util.Map; 042import java.util.Set; 043 044import org.granite.client.tide.data.Conflicts; 045import org.granite.client.tide.data.EntityManager; 046import org.granite.client.tide.server.ServerSession; 047 048/** 049 * @author William DRAI 050 */ 051public class MergeContext { 052 053 private static ThreadLocal<Map<EntityManager, MergeContext>> mergeContext = new ThreadLocal<Map<EntityManager, MergeContext>>() { 054 @Override 055 protected Map<EntityManager, MergeContext> initialValue() { 056 return new IdentityHashMap<EntityManager, MergeContext>(); 057 } 058 }; 059 060 private final EntityManager entityManager; 061 private final DirtyCheckContext dirtyCheckContext; 062 private IdentityHashMap<Object, Object> entityCache = null; 063 private LinkedList<Object> mergeStack = new LinkedList<Object>(); 064 065 private String externalDataSessionId = null; 066 private EntityManager sourceEntityManager = null; 067 private ServerSession serverSession = null; 068 private boolean mergeUpdate = false; 069 private boolean merging = false; 070 private Set<Object> versionChangeCache = null; 071 private boolean resolvingConflict = false; 072 private boolean skipDirtyCheck = false; 073 private Conflicts mergeConflicts = null; 074 private boolean uninitializing = false; 075 076 077 public static MergeContext get(EntityManager entityManager) { 078 return mergeContext.get().get(entityManager); 079 } 080 081 public static void destroy(EntityManager entityManager) { 082 mergeContext.get().remove(entityManager); 083 } 084 085 086 public MergeContext(EntityManager entityManager, DirtyCheckContext dirtyCheckContext, ServerSession serverSession) { 087 this.entityManager = entityManager; 088 this.dirtyCheckContext = dirtyCheckContext; 089 this.serverSession = serverSession; 090 mergeContext.get().put(entityManager, this); 091 } 092 093 094 public void initMerge() { 095 if (this.entityCache == null) { 096 this.entityCache = new IdentityHashMap<Object, Object>(); 097 this.mergeUpdate = true; 098 } 099 } 100 101 public void clear() { 102 this.entityCache = null; 103 this.mergeConflicts = null; 104 this.versionChangeCache = null; 105 this.resolvingConflict = false; 106 this.uninitializing = false; 107 this.merging = false; 108 this.mergeUpdate = false; 109 } 110 111 public void addConflict(Object localEntity, Object receivedEntity, List<String> properties) { 112 if (this.mergeConflicts == null) 113 this.mergeConflicts = new Conflicts(this.entityManager); 114 115 this.mergeConflicts.addConflict(localEntity, receivedEntity, properties); 116 } 117 118 public void initMergeConflicts() { 119 this.entityCache = null; 120 this.versionChangeCache = null; 121 this.resolvingConflict = false; 122 } 123 124 public void checkConflictsResolved() { 125 if (this.mergeConflicts != null && this.mergeConflicts.isAllResolved()) 126 this.mergeConflicts = null; 127 } 128 129 public boolean isResolvingConflict() { 130 return this.resolvingConflict; 131 } 132 133 public void setResolvingConflict(boolean resolvingConflict) { 134 this.resolvingConflict = resolvingConflict; 135 } 136 137 public Conflicts getMergeConflicts() { 138 return this.mergeConflicts; 139 } 140 141 public Map<?, ?> getEntityCache() { 142 return this.entityCache; 143 } 144 145 public IdentityHashMap<Object, Object> saveEntityCache() { 146 IdentityHashMap<Object, Object> entityCache = this.entityCache; 147 this.entityCache = new IdentityHashMap<Object, Object>(); 148 return entityCache; 149 } 150 public void restoreEntityCache(IdentityHashMap<Object, Object> entityCache) { 151 this.entityCache = entityCache; 152 } 153 154 public String getExternalDataSessionId() { 155 return this.externalDataSessionId; 156 } 157 158 public void setExternalDataSessionId(String externalDataSessionId) { 159 this.externalDataSessionId = externalDataSessionId; 160 } 161 162 public void setServerSession(ServerSession serverSession) { 163 this.serverSession = serverSession; 164 } 165 166 public ServerSession getServerSession() { 167 return serverSession; 168 } 169 170 public void setSourceEntityManager(EntityManager sourceEntityManager) { 171 this.sourceEntityManager = sourceEntityManager; 172 } 173 174 public EntityManager getSourceEntityManager() { 175 return this.sourceEntityManager; 176 } 177 178 public boolean isMergeUpdate() { 179 return this.mergeUpdate; 180 } 181 182 public void setMergeUpdate(boolean mergeUpdate) { 183 this.mergeUpdate = mergeUpdate; 184 } 185 186 public boolean isMerging() { 187 return this.merging; 188 } 189 190 public void setMerging(boolean merging) { 191 this.merging = merging; 192 } 193 194 public boolean isSkipDirtyCheck() { 195 return this.skipDirtyCheck; 196 } 197 198 public void setSkipDirtyCheck(boolean skipDirtyCheck) { 199 this.skipDirtyCheck = skipDirtyCheck; 200 } 201 202 public Object getFromCache(Object obj) { 203 if (this.entityCache == null) 204 return null; 205 return this.entityCache.get(obj); 206 } 207 208 public void pushMerge(Object obj, Object dest) { 209 pushMerge(obj, dest, true); 210 } 211 public void pushMerge(Object obj, Object dest, boolean push) { 212 if (this.entityCache != null) 213 this.entityCache.put(obj, dest); 214 if (push) 215 this.mergeStack.push(dest); 216 } 217 public Object getCachedMerge(Object obj) { 218 return this.entityCache.get(obj); 219 } 220 public Object popMerge() { 221 return this.mergeStack.pop(); 222 } 223 public Object getCurrentMerge() { 224 return this.mergeStack.peek(); 225 } 226 public void setCurrentMerge(Object merge) { 227 this.mergeStack.set(0, merge); 228 } 229 public int getMergeStackSize() { 230 return this.mergeStack.size(); 231 } 232 233 public Object getSavedProperties(Object object) { 234 return dirtyCheckContext.getSavedProperties(object); 235 } 236 237 public Object getCachedObject(Object object) { 238 return entityManager.getCachedObject(object, true); 239 } 240 241 public Object[] getOwnerEntity(Object entity) { 242 return entityManager.getOwnerEntity(entity); 243 } 244 245 public boolean isUnsaved(Object object) { 246 return dirtyCheckContext.isUnsaved(object); 247 } 248 249 public void clearCache() { 250 this.entityCache = null; 251 } 252 253 private Set<Object> getVersionChangeCache() { 254 if (this.versionChangeCache == null) 255 this.versionChangeCache = new HashSet<Object>(); 256 return this.versionChangeCache; 257 } 258 259 public void markVersionChanged(Object obj) { 260 getVersionChangeCache().add(obj); 261 } 262 263 public boolean hasVersionChanged(Object obj) { 264 return this.versionChangeCache != null ? this.versionChangeCache.contains(obj) : false; 265 } 266 267 public void setUninitializing(boolean uninitializing) { 268 this.uninitializing = uninitializing; 269 } 270 271 public boolean isUninitializing() { 272 return this.uninitializing; 273 } 274 275 public boolean isUninitializeAllowed() { 276 return this.entityManager.isUninitializeAllowed(); 277 } 278}