X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.db.common%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fcommon%2FUndoContextEx.java;h=52fc94861cf1919237b2a5fc2f8956cd5d6dcb59;hp=516426dff1f280dd0f2c0076204147649fef839b;hb=25e3207c8a1aad3cbe72202750f67f0483ccb1a2;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.db.common/src/org/simantics/db/common/UndoContextEx.java b/bundles/org.simantics.db.common/src/org/simantics/db/common/UndoContextEx.java index 516426dff..52fc94861 100644 --- a/bundles/org.simantics.db.common/src/org/simantics/db/common/UndoContextEx.java +++ b/bundles/org.simantics.db.common/src/org/simantics/db/common/UndoContextEx.java @@ -1,341 +1,341 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.db.common; - -import gnu.trove.map.TLongObjectMap; -import gnu.trove.map.hash.TLongObjectHashMap; - -import java.lang.ref.WeakReference; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.simantics.db.Operation; -import org.simantics.db.UndoContext; -import org.simantics.db.common.utils.Logger; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.exception.NoHistoryException; -import org.simantics.db.service.ExternalOperation; -import org.simantics.db.service.UndoRedoSupport; -import org.simantics.db.service.UndoRedoSupport.ChangeListener; -import org.simantics.utils.threads.ThreadUtils; - -public class UndoContextEx implements UndoContext { - private static class Weak { - private final WeakReference reference; - Weak(UndoContext context) { - reference = new WeakReference(context); - } - UndoContext get() { - return reference.get(); - } - } - private static class Operations { - private final Deque operationsQue = new ArrayDeque(); - private final TLongObjectMap operationsMap = new TLongObjectHashMap(); - void addLast(Operation op) { - long id = op.getId(); - Operation old = operationsMap.put(id, op); - if (old != null) { - operationsQue.remove(old); - op.combine(old); - } - operationsQue.addLast(op); - fireChangeEvent(); - } - Operation getLast() { - if (operationsQue.size() < 1) - return null; - Operation op = operationsQue.getLast(); - if (DEBUG) - System.out.println("DEBUG: Get last id=" + op.getId() + "."); - return op; - } - Collection getAll() { - return operationsQue; - } - Operation getCombined(long id) { - return operationsMap.get(id); - } - Operation removeLast() { - Operation op = operationsQue.pollLast(); - if (null != op) - operationsMap.remove(op.getId()); - fireChangeEvent(); - return op; - } - Operation remove(long id) { - Operation op = operationsMap.remove(id); - if (null != op) - operationsQue.remove(op); - fireChangeEvent(); - return op; - } - void clear() { - operationsQue.clear(); - operationsMap.clear(); - fireChangeEvent(); - } - private final CopyOnWriteArrayList changeListeners = new CopyOnWriteArrayList(); - private void fireChangeEvent() { - final Iterator it = changeListeners.iterator(); - ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() { - @Override - public void run() { - while (it.hasNext()) { - ChangeListener l = it.next(); - try { - l.onChanged(); - } catch (Throwable t) { - Logger.defaultLogError(t); - } - } - } - }); - } - void addChangeListener(ChangeListener cl) { - changeListeners.add(cl); - } - void removeChangeListener(ChangeListener cl) { - changeListeners.remove(cl); - } - } - private static HashMap contexts = new HashMap(); - protected static final boolean DEBUG = false; - protected final boolean DISABLED = false; - private final Operations operations = new Operations(); - private final Deque redos = new ArrayDeque(); - private final ArrayList pendingExternals = new ArrayList(); - private final String name; - private boolean undoRedoOn = false; - private final String id; - private boolean commitOkDisabled = false; - - public UndoContextEx() { - this.id = getUniqueId(this.toString()); - this.name = id; - init(); - } - public UndoContextEx(String id) { - this.id = getUniqueId(id); - this.name = id; - init(); - } - public UndoContextEx(String id, String name) { - this.id = getUniqueId(id); - this.name = name; - init(); - } - private String getUniqueId(String id) { - String uniqueId = id; - int i=0; - while (contexts.containsKey(uniqueId)) { - uniqueId += "_" + ++i; - } - return uniqueId; - } - private void init() { - synchronized (this) { - Weak old = contexts.get(id); - assert(null == old); - contexts.put(id, new Weak(this)); - } - } - public static synchronized UndoContext getUndoContext(String id) { - Weak w = contexts.get(id); - UndoContext c = null == w ? null : w.get(); - return c; - } - public static synchronized Collection getUndoContexts() { - Collection ucs = new ArrayList(); - List weaks = new ArrayList(); - List stale = new ArrayList(); - for (Map.Entry e : contexts.entrySet()) { - UndoContext c = e.getValue().get(); - if (null != c) { - ucs.add(c); - weaks.add(new Weak(c)); - } else - stale.add(e.getKey()); - } - for (String id : stale) - contexts.remove(id); - return ucs; - } - @Override - public String toString() { - return name + "@" + Integer.toHexString(hashCode()); - } - @Override - public void commitOk(Operation op) throws DatabaseException { - if (DISABLED) - return; - if (commitOkDisabled) { - if (DEBUG) - System.out.println("DEBUG: Commit ok disabled."); - return; - } - if (DEBUG) - System.out.println("DEBUG: Commit ok id=" + op.getId() + " cs=" + op.getCSId() - + " context=" + this + "."); - if (undoRedoOn) { - undoRedoOn = false; - redos.clear(); - } - // Check if operation is new. - if (op.getId() < 1 || op.getId() == op.getCSId()) { - Operation last = getLast(); - if (null != last && last.getCSId() == op.getCSId()) { - Logger.defaultLogError("Duplicate operation for new operation id=" + op.getId() + "."); - if (DEBUG) - System.out.println("DEBUG: New operation already in undo list id=" + op.getId() + "."); - return; - } - if (DEBUG) - System.out.println("DEBUG: New operation added to undo list id=" + op.getId() + "."); - } else { // Operation is old i.e. part of combined operation. - Operation last = operations.getCombined(op.getId()); - if (null == last) { - Logger.defaultLogError("Missing operation for combined operation id=" + op.getId() + " cs=" + op.getCSId() + "."); - if (DEBUG) - System.out.println("DEBUG: Missing old combined operation id=" + op.getId() + "."); - } - } - operations.addLast(op); - pendingExternals.clear(); - } - public void externalCommit(Operation op) { - operations.addLast(op); - pendingExternals.clear(); - } - public void cancelCommit() { - pendingExternals.clear(); - } - - @Override - public Operation getLast() throws DatabaseException { - return operations.getLast(); - } - protected Operation getLastRedo() throws DatabaseException { - if (redos.size() < 1) - return null; - Operation op = redos.getLast(); - if (DEBUG) - System.out.println("DEBUG: Get last redo id=" + op.getId() + "."); - return op; - } - @Override - public Collection getAll() throws DatabaseException { - return operations.getAll(); - } - @Override - public Collection getRedoList() throws DatabaseException { - return redos; - } - @Override - public List undo(UndoRedoSupport support, int count) throws DatabaseException { - List ops = new ArrayList(count); - for (int i=0; i redo(UndoRedoSupport support, int count) throws DatabaseException { - List ops = new ArrayList(count); - for (int i=0; i getPendingExternals() { - if(pendingExternals.isEmpty()) return Collections.emptyList(); - if(!pendingExternals.isEmpty()) - System.err.println("pending externals: " + pendingExternals); - return new ArrayList(pendingExternals); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.db.common; + +import gnu.trove.map.TLongObjectMap; +import gnu.trove.map.hash.TLongObjectHashMap; + +import java.lang.ref.WeakReference; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.simantics.db.Operation; +import org.simantics.db.UndoContext; +import org.simantics.db.common.utils.Logger; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.NoHistoryException; +import org.simantics.db.service.ExternalOperation; +import org.simantics.db.service.UndoRedoSupport; +import org.simantics.db.service.UndoRedoSupport.ChangeListener; +import org.simantics.utils.threads.ThreadUtils; + +public class UndoContextEx implements UndoContext { + private static class Weak { + private final WeakReference reference; + Weak(UndoContext context) { + reference = new WeakReference(context); + } + UndoContext get() { + return reference.get(); + } + } + private static class Operations { + private final Deque operationsQue = new ArrayDeque(); + private final TLongObjectMap operationsMap = new TLongObjectHashMap(); + void addLast(Operation op) { + long id = op.getId(); + Operation old = operationsMap.put(id, op); + if (old != null) { + operationsQue.remove(old); + op.combine(old); + } + operationsQue.addLast(op); + fireChangeEvent(); + } + Operation getLast() { + if (operationsQue.size() < 1) + return null; + Operation op = operationsQue.getLast(); + if (DEBUG) + System.out.println("DEBUG: Get last id=" + op.getId() + "."); + return op; + } + Collection getAll() { + return operationsQue; + } + Operation getCombined(long id) { + return operationsMap.get(id); + } + Operation removeLast() { + Operation op = operationsQue.pollLast(); + if (null != op) + operationsMap.remove(op.getId()); + fireChangeEvent(); + return op; + } + Operation remove(long id) { + Operation op = operationsMap.remove(id); + if (null != op) + operationsQue.remove(op); + fireChangeEvent(); + return op; + } + void clear() { + operationsQue.clear(); + operationsMap.clear(); + fireChangeEvent(); + } + private final CopyOnWriteArrayList changeListeners = new CopyOnWriteArrayList(); + private void fireChangeEvent() { + final Iterator it = changeListeners.iterator(); + ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() { + @Override + public void run() { + while (it.hasNext()) { + ChangeListener l = it.next(); + try { + l.onChanged(); + } catch (Throwable t) { + Logger.defaultLogError(t); + } + } + } + }); + } + void addChangeListener(ChangeListener cl) { + changeListeners.add(cl); + } + void removeChangeListener(ChangeListener cl) { + changeListeners.remove(cl); + } + } + private static HashMap contexts = new HashMap(); + protected static final boolean DEBUG = false; + protected final boolean DISABLED = false; + private final Operations operations = new Operations(); + private final Deque redos = new ArrayDeque(); + private final ArrayList pendingExternals = new ArrayList(); + private final String name; + private boolean undoRedoOn = false; + private final String id; + private boolean commitOkDisabled = false; + + public UndoContextEx() { + this.id = getUniqueId(this.toString()); + this.name = id; + init(); + } + public UndoContextEx(String id) { + this.id = getUniqueId(id); + this.name = id; + init(); + } + public UndoContextEx(String id, String name) { + this.id = getUniqueId(id); + this.name = name; + init(); + } + private String getUniqueId(String id) { + String uniqueId = id; + int i=0; + while (contexts.containsKey(uniqueId)) { + uniqueId += "_" + ++i; + } + return uniqueId; + } + private void init() { + synchronized (this) { + Weak old = contexts.get(id); + assert(null == old); + contexts.put(id, new Weak(this)); + } + } + public static synchronized UndoContext getUndoContext(String id) { + Weak w = contexts.get(id); + UndoContext c = null == w ? null : w.get(); + return c; + } + public static synchronized Collection getUndoContexts() { + Collection ucs = new ArrayList(); + List weaks = new ArrayList(); + List stale = new ArrayList(); + for (Map.Entry e : contexts.entrySet()) { + UndoContext c = e.getValue().get(); + if (null != c) { + ucs.add(c); + weaks.add(new Weak(c)); + } else + stale.add(e.getKey()); + } + for (String id : stale) + contexts.remove(id); + return ucs; + } + @Override + public String toString() { + return name + "@" + Integer.toHexString(hashCode()); + } + @Override + public void commitOk(Operation op) throws DatabaseException { + if (DISABLED) + return; + if (commitOkDisabled) { + if (DEBUG) + System.out.println("DEBUG: Commit ok disabled."); + return; + } + if (DEBUG) + System.out.println("DEBUG: Commit ok id=" + op.getId() + " cs=" + op.getCSId() + + " context=" + this + "."); + if (undoRedoOn) { + undoRedoOn = false; + redos.clear(); + } + // Check if operation is new. + if (op.getId() < 1 || op.getId() == op.getCSId()) { + Operation last = getLast(); + if (null != last && last.getCSId() == op.getCSId()) { + Logger.defaultLogError("Duplicate operation for new operation id=" + op.getId() + "."); + if (DEBUG) + System.out.println("DEBUG: New operation already in undo list id=" + op.getId() + "."); + return; + } + if (DEBUG) + System.out.println("DEBUG: New operation added to undo list id=" + op.getId() + "."); + } else { // Operation is old i.e. part of combined operation. + Operation last = operations.getCombined(op.getId()); + if (null == last) { + Logger.defaultLogError("Missing operation for combined operation id=" + op.getId() + " cs=" + op.getCSId() + "."); + if (DEBUG) + System.out.println("DEBUG: Missing old combined operation id=" + op.getId() + "."); + } + } + operations.addLast(op); + pendingExternals.clear(); + } + public void externalCommit(Operation op) { + operations.addLast(op); + pendingExternals.clear(); + } + public void cancelCommit() { + pendingExternals.clear(); + } + + @Override + public Operation getLast() throws DatabaseException { + return operations.getLast(); + } + protected Operation getLastRedo() throws DatabaseException { + if (redos.size() < 1) + return null; + Operation op = redos.getLast(); + if (DEBUG) + System.out.println("DEBUG: Get last redo id=" + op.getId() + "."); + return op; + } + @Override + public Collection getAll() throws DatabaseException { + return operations.getAll(); + } + @Override + public Collection getRedoList() throws DatabaseException { + return redos; + } + @Override + public List undo(UndoRedoSupport support, int count) throws DatabaseException { + List ops = new ArrayList(count); + for (int i=0; i redo(UndoRedoSupport support, int count) throws DatabaseException { + List ops = new ArrayList(count); + for (int i=0; i getPendingExternals() { + if(pendingExternals.isEmpty()) return Collections.emptyList(); + if(!pendingExternals.isEmpty()) + System.err.println("pending externals: " + pendingExternals); + return new ArrayList(pendingExternals); + } + +}