1 package org.opentrafficsim.editor;
2
3 import java.rmi.RemoteException;
4 import java.util.LinkedHashSet;
5 import java.util.Map.Entry;
6 import java.util.Objects;
7 import java.util.Set;
8 import java.util.function.Supplier;
9
10 import org.djutils.eval.Eval;
11 import org.djutils.event.Event;
12 import org.djutils.event.EventListener;
13 import org.djutils.event.EventType;
14 import org.djutils.event.reference.ReferenceType;
15 import org.djutils.metadata.MetaData;
16 import org.djutils.metadata.ObjectDescriptor;
17 import org.opentrafficsim.base.OtsRuntimeException;
18 import org.opentrafficsim.editor.decoration.validation.KeyValidator;
19 import org.opentrafficsim.editor.decoration.validation.KeyrefValidator;
20 import org.opentrafficsim.editor.decoration.validation.XPathValidator;
21 import org.w3c.dom.Node;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public class XsdTreeNodeRoot extends XsdTreeNode
38 {
39
40
41
42
43
44 public static final EventType NODE_CREATED = new EventType("NODECREATED",
45 new MetaData("Node created", "Created tree node",
46 new ObjectDescriptor("Node created", "Created tree node", XsdTreeNode.class),
47 new ObjectDescriptor("Parent", "Parent node", XsdTreeNode.class),
48 new ObjectDescriptor("Index", "Index where it is in the parent", Integer.class)));
49
50
51
52
53
54 public static final EventType NODE_REMOVED = new EventType("NODEREMOVED",
55 new MetaData("Node removed", "Removed tree node",
56 new ObjectDescriptor("Node removed", "Removed tree node", XsdTreeNode.class),
57 new ObjectDescriptor("Parent", "Parent node", XsdTreeNode.class),
58 new ObjectDescriptor("Index", "Index where it was in the parent", Integer.class)));
59
60
61 private String directory;
62
63
64 private final Supplier<Boolean> ignoreChanges;
65
66
67 private final Supplier<Eval> evalSupplier;
68
69
70
71
72
73
74
75
76 public XsdTreeNodeRoot(final Schema schema, final Supplier<Boolean> ignoreChanges, final Supplier<Eval> evalSupplier)
77 throws RemoteException
78 {
79 super(schema);
80 this.ignoreChanges = ignoreChanges;
81 this.evalSupplier = evalSupplier;
82
83 setupXPathListener(schema);
84 }
85
86
87
88
89
90 public String getDirectory()
91 {
92 return this.directory;
93 }
94
95
96
97
98
99 public void setDirectory(final String directory)
100 {
101 if (Objects.equals(this.directory, directory))
102 {
103 return;
104 }
105 this.directory = directory;
106
107 invalidateAll();
108 }
109
110 @Override
111 public XsdTreeNodeRoot getRoot()
112 {
113 return this;
114 }
115
116
117
118
119
120 public Eval getEval()
121 {
122 return this.evalSupplier.get();
123 }
124
125
126
127
128 @Override
129 public boolean addListener(final EventListener listener, final EventType eventType, final int position,
130 final ReferenceType referenceType)
131 {
132 if (NODE_CREATED.equals(eventType))
133 {
134 try
135 {
136 XsdTreeNodeUtil.fireCreatedEventOnExistingNodes(this, listener);
137 }
138 catch (RemoteException exception)
139 {
140 throw new OtsRuntimeException("Unexpected remote exception in local context.", exception);
141 }
142 }
143 return super.addListener(listener, eventType, position, referenceType);
144 }
145
146
147
148
149
150
151
152 private void setupXPathListener(final Schema schema) throws RemoteException
153 {
154 Set<KeyValidator> keys = new LinkedHashSet<>();
155 for (Entry<String, Node> entry : schema.keys().entrySet())
156 {
157 String path = entry.getKey().substring(0, entry.getKey().lastIndexOf("."));
158 keys.add(new KeyValidator(entry.getValue(), path, this.ignoreChanges));
159 }
160 Set<KeyValidator> uniques = new LinkedHashSet<>();
161 for (Entry<String, Node> entry : schema.uniques().entrySet())
162 {
163 String path = entry.getKey().substring(0, entry.getKey().lastIndexOf("."));
164 uniques.add(new KeyValidator(entry.getValue(), path, this.ignoreChanges));
165 }
166 Set<KeyrefValidator> keyrefs = new LinkedHashSet<>();
167 for (Entry<String, Node> entry : schema.keyrefs().entrySet())
168 {
169 String keyName = DocumentReader.getAttribute(entry.getValue(), "refer").get().replace("ots:", "");
170 for (KeyValidator key : keys)
171 {
172 if (key.getKeyName().equals(keyName))
173 {
174 String path = entry.getKey().substring(0, entry.getKey().lastIndexOf("."));
175 keyrefs.add(new KeyrefValidator(entry.getValue(), path, key, this.ignoreChanges));
176 break;
177 }
178 }
179 for (KeyValidator unique : uniques)
180 {
181 if (unique.getKeyName().equals(keyName))
182 {
183 String path = entry.getKey().substring(0, entry.getKey().lastIndexOf("."));
184 keyrefs.add(new KeyrefValidator(entry.getValue(), path, unique, this.ignoreChanges));
185 break;
186 }
187 }
188 }
189
190 EventListener listener = new EventListener()
191 {
192 @Override
193 public void notify(final Event event)
194 {
195
196 int iteration = 0;
197 Set<? extends XPathValidator> keysIteration = keys;
198 XsdTreeNode node = (XsdTreeNode) ((Object[]) event.getContent())[0];
199 while (iteration < 3)
200 {
201 for (XPathValidator key : keysIteration)
202 {
203 if (event.getType().equals(NODE_CREATED))
204 {
205 key.addNode(node);
206 }
207 else
208 {
209 key.removeNode(node);
210 }
211 }
212 keysIteration = iteration == 0 ? keyrefs : uniques;
213 iteration++;
214 }
215 }
216 };
217
218 addListener(listener, NODE_CREATED);
219 addListener(listener, NODE_REMOVED);
220 }
221
222 }