1 package org.simantics.structural.synchronization.base;
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.procedure.TObjectObjectProcedure;
5 import gnu.trove.procedure.TObjectProcedure;
6 import gnu.trove.set.hash.THashSet;
8 import java.io.PrintWriter;
12 * The entry point to the mapping structure between Simantics database and a
13 * designated solver. It is used to synchronize changes from Simantics to the
16 * @author Hannu Niemistö
18 abstract public class MappingBase<T extends ComponentBase<T>> {
20 abstract public T getConfiguration();
23 * Set of all components indexed by their UID.
25 transient protected THashMap<String, T> configurationByUid;
28 * Set of all components indexed by their solver name.
30 transient protected Map<String, T> configurationBySolverName;
33 * Set of components whose removal is delayed because they might
34 * have been moved somewhere else.
36 transient THashSet<T> pendingRemoval = new THashSet<T>();
39 * This is a structure that is used to return the state of the removed modules
40 * when the removal is undone.
42 public transient StateUndoContextBase undoContext;
44 public transient ComponentFactory<T> componentFactory;
47 * The synchronization has processed all change sets before this change set
48 * (excluding this change set).
49 * It means that next synchronization operation should start examining changes
50 * made in this revision and revisions after this.
52 public long currentRevision;
55 * Tells whether the uids in the components can be used
56 * in the synchronization. This is normally true, but
57 * may be set temporarily false when export/import:in
60 private boolean trustUids;
62 public MappingBase() {
63 this(null, -1L, false);
66 public MappingBase(T configuration, boolean trustUids) {
67 this(configuration, -1L, trustUids);
70 public MappingBase(T configuration, long currentRevision, boolean trustUids) {
71 undoContext = createUndoContext();
72 componentFactory = createComponentFactory();
74 createConfigurationById(configuration);
75 this.currentRevision = currentRevision;
76 this.trustUids = trustUids;
79 abstract public StateUndoContextBase createUndoContext();
80 abstract public ComponentFactory<T> createComponentFactory();
82 protected void createConfigurationById(T configuration) {
83 THashMap<String, T> configurationByUid = new THashMap<String, T>();
84 browseConfiguration(configurationByUid, configuration);
85 this.configurationByUid = configurationByUid;
88 private void browseConfiguration(
89 THashMap<String, T> configurationByUid,
91 configurationByUid.put(configuration.uid, configuration);
92 for(T child : configuration.getChildren()) {
93 browseConfiguration(configurationByUid, child);
94 child.parent = configuration;
98 public Map<String, T> getConfigurationBySolverName() {
99 Map<String, T> result = configurationBySolverName;
101 result = configurationBySolverName = createConfigurationBySolverName(getConfiguration());
105 protected Map<String, T> createConfigurationBySolverName(T configuration) {
106 THashMap<String, T> configurationBySolverName = new THashMap<>();
107 browseConfigurationBySolverName(configurationBySolverName, configuration);
108 return configurationBySolverName;
111 private void browseConfigurationBySolverName(
112 THashMap<String, T> configurationBySolverName,
114 configurationBySolverName.put(configuration.solverComponentName, configuration);
115 for(T child : configuration.getChildren()) {
116 browseConfigurationBySolverName(configurationBySolverName, child);
117 child.parent = configuration;
121 public T detachOrCreateComponent(String uid) {
122 T result = configurationByUid.get(uid);
124 result = componentFactory.create(uid);
125 configurationByUid.put(uid, result);
128 if(result.getParent() == null)
129 pendingRemoval.remove(result);
131 result.getParent().detachByUid(uid);
137 * Marks that the component should be removed. The actual removal
138 * is delayed until the call of {@link #removePending} so that if the
139 * component is not actually removed but moved or renamed, we don't lose
142 public void addPendingRemoval(T component) {
143 pendingRemoval.add(component);
146 public void printUidMap() {
147 printUidMap(new PrintWriter(System.out));
150 public void printUidMap(final PrintWriter out) {
151 out.println("Component tree");
153 getConfiguration().printConfiguration(out, 1);
154 if(configurationByUid != null) {
156 configurationByUid.forEachEntry(new TObjectObjectProcedure<String, T>() {
158 public boolean execute(String a, T b) {
159 out.println(" " + a + " (" + b.solverComponentName + ", " + b.componentId + ", " + b.uid + ")");
167 * Removes the component recursively.
169 public void remove(final Solver solver, T component) {
170 if(configurationByUid != null)
171 configurationByUid.remove(component.uid);
172 if (configurationBySolverName != null)
173 configurationBySolverName.remove(component.solverComponentName);
174 if(component.getChildMap() != null)
175 component.getChildMap().forEachValue(new TObjectProcedure<T>() {
177 public boolean execute(T child) {
178 remove(solver, child);
182 if(component.componentId > 0 && !component.attached)
183 solver.remove(component.componentId);
187 * Saves undo state recursively
189 public void saveUndoState(final Solver solver, T component) {
190 if(component.getChildMap() != null)
191 component.getChildMap().forEachValue(new TObjectProcedure<T>() {
193 public boolean execute(T child) {
194 saveUndoState(solver, child);
198 else if(component.componentId > 0 && !component.attached)
199 undoContext.saveState(solver, component.componentId, component.uid);
203 * Removes components that are marked pending with {@link #addPendingRemoval} method.
205 public void removePending(final Solver solver) {
206 pendingRemoval.forEach(new TObjectProcedure<T>() {
208 public boolean execute(T component) {
209 saveUndoState(solver, component);
213 pendingRemoval.forEach(new TObjectProcedure<T>() {
215 public boolean execute(T component) {
216 remove(solver, component);
220 pendingRemoval.clear();
224 * Changes the {@link #trustUids} flag.
226 public void setTrustUids(boolean trustUids) {
227 if(trustUids != this.trustUids) {
228 this.trustUids = trustUids;
230 T configuration = getConfiguration();
231 if(configuration != null)
232 createConfigurationById(configuration);
236 configurationByUid = null;
239 public boolean getTrustUids() {
243 public void dispose() {
244 if (configurationByUid != null)
245 configurationByUid.clear();
246 if (configurationBySolverName != null) {
247 configurationBySolverName.clear();
248 configurationBySolverName = null;
250 pendingRemoval.clear();
253 public boolean hasPendingRemovals() {
254 return !pendingRemoval.isEmpty();