1 package org.simantics.structural.synchronization.base;
\r
3 import gnu.trove.map.hash.THashMap;
\r
4 import gnu.trove.procedure.TObjectObjectProcedure;
\r
5 import gnu.trove.procedure.TObjectProcedure;
\r
6 import gnu.trove.set.hash.THashSet;
\r
8 import java.io.PrintWriter;
\r
11 * The entry point to the mapping structure between Simantics database and a
\r
12 * designated solver. It is used to synchronize changes from Simantics to the
\r
15 * @author Hannu Niemistö
\r
17 abstract public class MappingBase<T extends ComponentBase<T>> {
\r
19 abstract public T getConfiguration();
\r
22 * Set of all components indexed by their UID.
\r
24 transient protected THashMap<String, T> configurationByUid;
\r
27 * Set of components whose removal is delayed because they might
\r
28 * have been moved somewhere else.
\r
30 transient THashSet<T> pendingRemoval = new THashSet<T>();
\r
33 * This is a structure that is used to return the state of the removed modules
\r
34 * when the removal is undone.
\r
36 public transient StateUndoContextBase undoContext;
\r
38 public transient ComponentFactory<T> componentFactory;
\r
41 * The synchronization has processed all change sets before this change set
\r
42 * (excluding this change set).
\r
43 * It means that next synchronization operation should start examining changes
\r
44 * made in this revision and revisions after this.
\r
46 public long currentRevision;
\r
49 * Tells whether the uids in the components can be used
\r
50 * in the synchronization. This is normally true, but
\r
51 * may be set temporarily false when export/import:in
\r
54 private boolean trustUids;
\r
56 public MappingBase() {
\r
57 this(null, -1L, false);
\r
60 public MappingBase(T configuration, boolean trustUids) {
\r
61 this(configuration, -1L, trustUids);
\r
64 public MappingBase(T configuration, long currentRevision, boolean trustUids) {
\r
65 undoContext = createUndoContext();
\r
66 componentFactory = createComponentFactory();
\r
68 createConfigurationById(configuration);
\r
69 this.currentRevision = currentRevision;
\r
70 this.trustUids = trustUids;
\r
73 abstract public StateUndoContextBase createUndoContext();
\r
74 abstract public ComponentFactory<T> createComponentFactory();
\r
76 protected void createConfigurationById(T configuration) {
\r
77 THashMap<String, T> configurationByUid = new THashMap<String, T>();
\r
78 browseConfiguration(configurationByUid, configuration);
\r
79 this.configurationByUid = configurationByUid;
\r
82 private void browseConfiguration(
\r
83 THashMap<String, T> configurationByUid,
\r
85 configurationByUid.put(configuration.uid, configuration);
\r
86 for(T child : configuration.getChildren()) {
\r
87 browseConfiguration(configurationByUid, child);
\r
88 child.parent = configuration;
\r
92 public T detachOrCreateComponent(String uid) {
\r
93 T result = configurationByUid.get(uid);
\r
94 if(result == null) {
\r
95 result = componentFactory.create(uid);
\r
96 configurationByUid.put(uid, result);
\r
99 if(result.getParent() == null)
\r
100 pendingRemoval.remove(result);
\r
102 result.getParent().detachByUid(uid);
\r
108 * Marks that the component should be removed. The actual removal
\r
109 * is delayed until the call of {@link #removePending} so that if the
\r
110 * component is not actually removed but moved or renamed, we don't lose
\r
113 public void addPendingRemoval(T component) {
\r
114 pendingRemoval.add(component);
\r
117 public void printUidMap() {
\r
118 printUidMap(new PrintWriter(System.out));
\r
121 public void printUidMap(final PrintWriter out) {
\r
122 out.println("Component tree");
\r
124 getConfiguration().printConfiguration(out, 1);
\r
125 if(configurationByUid != null) {
\r
126 out.println("UIDs");
\r
127 configurationByUid.forEachEntry(new TObjectObjectProcedure<String, T>() {
\r
129 public boolean execute(String a, T b) {
\r
130 out.println(" " + a + " (" + b.solverComponentName + ", " + b.componentId + ", " + b.uid + ")");
\r
138 * Removes the component recursively.
\r
140 public void remove(final Solver solver, T component) {
\r
141 if(configurationByUid != null)
\r
142 configurationByUid.remove(component.uid);
\r
143 if(component.getChildMap() != null)
\r
144 component.getChildMap().forEachValue(new TObjectProcedure<T>() {
\r
146 public boolean execute(T child) {
\r
147 remove(solver, child);
\r
151 if(component.componentId > 0 && !component.attached)
\r
152 solver.remove(component.componentId);
\r
156 * Saves undo state recursively
\r
158 public void saveUndoState(final Solver solver, T component) {
\r
159 if(component.getChildMap() != null)
\r
160 component.getChildMap().forEachValue(new TObjectProcedure<T>() {
\r
162 public boolean execute(T child) {
\r
163 saveUndoState(solver, child);
\r
167 else if(component.componentId > 0 && !component.attached)
\r
168 undoContext.saveState(solver, component.componentId, component.uid);
\r
172 * Removes components that are marked pending with {@link #addPendingRemoval} method.
\r
174 public void removePending(final Solver solver) {
\r
175 pendingRemoval.forEach(new TObjectProcedure<T>() {
\r
177 public boolean execute(T component) {
\r
178 saveUndoState(solver, component);
\r
182 pendingRemoval.forEach(new TObjectProcedure<T>() {
\r
184 public boolean execute(T component) {
\r
185 remove(solver, component);
\r
189 pendingRemoval.clear();
\r
193 * Changes the {@link #trustUids} flag.
\r
195 public void setTrustUids(boolean trustUids) {
\r
196 if(trustUids != this.trustUids) {
\r
197 this.trustUids = trustUids;
\r
199 T configuration = getConfiguration();
\r
200 if(configuration != null)
\r
201 createConfigurationById(configuration);
\r
205 configurationByUid = null;
\r
208 public boolean getTrustUids() {
\r
212 public void dispose() {
\r
213 if (configurationByUid != null)
\r
214 configurationByUid.clear();
\r
215 pendingRemoval.clear();
\r