-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDocNode.java
296 lines (272 loc) · 8.41 KB
/
DocNode.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
package com.aircom.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
*
* @author Hasanein Khafaji
* @param <T>
*/
public final class DocNode<T>
{
/**
* This is the name of the DocNode, this works as an identification
* of the DocNode.
*/
private String nodeName;
/**
* The text content of the DocNode, if it will have any textual content
* at all contained within it. The data type of the text content is a
* generic type that is defined at the class level.
*/
private T textContent = null;
/**
* Here we define a boolean value that express if this particular
* node can be thought of as a root element for the DocTree that contains
* it. This will default to false.
*/
private boolean isRootElement;
/**
* Any DocNode might contain a list of child DocNodes contained
* within it, here we define the List of child DocNodes. The initial
* value is null, which signifies that there are no elements contained
* within this root element.
*/
private List<DocNode<T>> childNodes = new ArrayList<DocNode<T>>();
/**
* Here we define a List of attributes that might be contained
* within this particular DocNode. The generic data type of the
* attribute can be anything, this is not to be tied by any means to the
* generic data type of the text content of the DocNode. The use of the "?"
* wildcard simplifies the parameterized argument passing to this generic
* attribute.
*/
private HashMap<String, Attribute<T>> attributesHashMap = new HashMap<String, Attribute<T>>();
public DocNode(String elementName)
{
this.nodeName = elementName;
}
/**
* This method returns the text content contained within this
* DocNode, or returns null if this DocNode doesn't have any text content
* included within it.
*/
public T getTextContent()
{
return textContent;
}
public String getElementName()
{
return nodeName;
}
/**
* This method sets the text content of this node to the
* value of the textContent argument passed into this method.
*/
public void setTextContent(T textContent)
{
this.textContent = textContent;
}
/**
* Sets this DocNode root element status as either
* being a root element of the enclosing DocTree or
* a second-level DocNode.
*/
public void setIsRootElement(boolean isRootElement)
{
this.isRootElement = isRootElement;
}
/**
* returns true if this DocNode is a root element of the
* containing DocTree, false otherwise.
*/
public boolean isRootElement()
{
return isRootElement;
}
/**
* This method returns a defensive copy to the mutable list of child nodes
* to the caller. If there are no child nodes, then this method will return
* an empty ArrayList.
*/
public List<DocNode<T>> getChildNodes()
{
/**
* If there are no child nodes, then return an
* empty ArrayList instead.
*/
if (childNodes == null)
{
return new ArrayList<DocNode<T>>();
}
/**
* Otherwise returns a defensive copy of the
* childNodes to prevent the client from altering the internal
* childNodes.
*/
return new ArrayList<DocNode<T>>(childNodes);
}
/**
* This method sets the child nodes of the DocNode into the
* passed childNodes argument. Rather than setting the passed in
* reference to the childNodes, we are setting a defensive copy to
* the passed argument to prevent any malicious change to our internal
* data structure.
*/
public void setChildNodes(List<DocNode<T>> childNodes)
{
if(childNodes == null)
return;
/**
* Make the defensive copy.
*/
ArrayList<DocNode<T>> defensiveCopy = new ArrayList<DocNode<T>>(childNodes);
/**
* Assign the defensive copy into the internal private childNode
* data structure.
*/
this.childNodes = defensiveCopy;
}
/**
* This method will simply returns the number of children
* contained in this particular DocNode
*/
public int getNumberOfChilds()
{
if (childNodes == null)
{
return 0;
}
return childNodes.size();
}
/**
* This method will simply clear all the nodes contained within
* this particular DocNode.
*/
public void clearAllChildNodes()
{
if (childNodes == null)
{
return;
}
childNodes.removeAll(childNodes);
}
/**
* This method adds the passed DocNode argument into the list of DocNodes
* contained within this particular DocNode.
*/
public void addChildDocNode(DocNode<T> docNode) throws Exception
{
/**
* Avoid un-necessary processing if docNode is null.
*/
if(docNode == null)
return;
/**
* If there are no child nodes that are currently present, then
* we need to create an ArrayList and add the DocNode argument as
* the first child in this ArrayList.
*/
if (childNodes == null)
{
childNodes = new ArrayList<DocNode<T>>();
}
childNodes.add(docNode.clone());
}
/**
* This method will remove the passed in DocNode from the childNodes
* ArrayList, if there are no child nodes currently present, then this
* method will return silently.
*/
public void removeChildDocNode(DocNode<T> docNode)
{
if (childNodes == null)
{
return;
}
childNodes.remove(docNode);
}
/**
* This method will return the number of attributes that are contained
* within this DocNode
*/
public int getNumberOfAttributes()
{
if (attributesHashMap == null)
{
return 0;
}
return attributesHashMap.size();
}
/**
* This method will return all of the attributes that are contained within
* this particular DocNode in an ArrayList.
*/
public List<Attribute<T>> getAllAttributes()
{
if (attributesHashMap == null)
{
return new ArrayList<Attribute<T>>();
}
/**
* Here we need to convert the attributeList HashMap into
* an ArrayList.
*/
return new ArrayList<Attribute<T>>(attributesHashMap.values());
}
/**
* This method is to set the attributesList to the value of the
* ArrayList attribute passed into this method.
*/
public void setAttributeList(Set<Attribute<T>> attributesSet)
{
if (attributesHashMap == null)
{
attributesHashMap = new HashMap<String, Attribute<T>>();
}
for (Attribute<T> attribute : attributesSet)
{
attributesHashMap.put(attribute.getName(), attribute);
}
}
/**
* This method clears all the attributes stored inside this
* DocNode.
*/
public void clearAllAttributes()
{
if (attributesHashMap == null)
{
return;
}
attributesHashMap.clear();
}
/**
* This method adds a single attribute to the list of attributes
* contained within this DocNode.
*/
public void addAttribute(Attribute<T> attribute)
{
if (attributesHashMap == null)
{
attributesHashMap = new HashMap<String, Attribute<T>>();
}
attributesHashMap.put(attribute.getName(), attribute);
}
@Override
protected DocNode<T> clone()
{
DocNode<T> clonnedDocNode = new DocNode<T>(this.nodeName);
clonnedDocNode.attributesHashMap = new HashMap<String, Attribute<T>>(attributesHashMap);
clonnedDocNode.childNodes = new ArrayList<DocNode<T>>(childNodes);
clonnedDocNode.isRootElement = isRootElement; // No need for a defensive copy, it is a primitive and primitves passed by value.
clonnedDocNode.textContent = textContent; // No need for a defensive copy, the textContent is of type String and String class is an immutable class in java.
return clonnedDocNode;
}
@Override
public String toString()
{
return nodeName;
}
}