1
2 package org.galagosearch.core.retrieval.query;
3
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.Map;
7 import org.galagosearch.tupleflow.Parameters.Value;
8 import org.galagosearch.tupleflow.Parameters;
9
10 /***
11 * <p>Node represents a single node in a query parse tree.</p>
12 *
13 * <p>In Galago, queries are parsed into a tree of Nodes. The query tree can then
14 * be modified using StructuredQuery.copy, or analyzed by using StructuredQuery.walk.
15 * Once the query is in the proper form, the query is converted into a tree of iterators
16 * that can be evaluated.</p>
17 *
18 * @author trevor
19 */
20 public class Node {
21
22 private String operator;
23
24
25 private ArrayList<Node> internalNodes;
26
27
28 private int position;
29
30
31 private Parameters parameters;
32
33 public Node() {
34 internalNodes = new ArrayList<Node>();
35 parameters = new Parameters();
36 }
37
38 public Node(String operator, ArrayList<Node> internalNodes) {
39 this(operator, (String) null, internalNodes, 0);
40 }
41
42 public Node(String operator, ArrayList<Node> internalNodes, int position) {
43 this(operator, (String) null, internalNodes, position);
44 }
45
46 public Node(String operator, String argument) {
47 this(operator, argument, 0);
48 }
49
50 public Node(String operator, String argument, int position) {
51 this(operator, argument, new ArrayList<Node>(), position);
52 }
53
54 public Node(String operator, String argument, ArrayList<Node> internalNodes) {
55 this(operator, argument, internalNodes, 0);
56 }
57
58 public Node(String operator, String argument, ArrayList<Node> internalNodes, int position) {
59 Parameters p = new Parameters();
60
61 if (argument != null) {
62 p.add("default", argument);
63 }
64 this.operator = operator;
65 this.internalNodes = internalNodes;
66 this.position = position;
67 this.parameters = p;
68 }
69
70 public Node(String operator, Parameters parameters, ArrayList<Node> internalNodes, int position) {
71 this.operator = operator;
72 this.internalNodes = internalNodes;
73 this.position = position;
74 this.parameters = parameters;
75 }
76
77 public String getOperator() {
78 return operator;
79 }
80
81 public String getDefaultParameter() {
82 return parameters.get("default", (String)null);
83 }
84
85 public String getDefaultParameter(String key) {
86 return parameters.get(key, getDefaultParameter());
87 }
88
89 public ArrayList<Node> getInternalNodes() {
90 return internalNodes;
91 }
92
93 public int getPosition() {
94 return position;
95 }
96
97 public Parameters getParameters() {
98 return parameters;
99 }
100
101 public boolean needsToBeEscaped(String text) {
102 return text.contains("@") || text.contains(",") ||
103 text.contains(".") || text.contains(" ") ||
104 text.contains("\t") || text.contains("\r") ||
105 text.contains("\n");
106 }
107
108 public String escapeAsNecessary(String text) {
109 if (!needsToBeEscaped(text)) {
110 return text;
111 } else {
112 String[] preferredDelimiters = { "/", "|", "#", "!", "%" };
113
114 for (String delimiter : preferredDelimiters) {
115 if (!text.contains(delimiter)) {
116 return "@" + delimiter + text + delimiter;
117 }
118 }
119
120
121 return text;
122 }
123 }
124
125 @Override
126 public String toString() {
127 StringBuilder builder = new StringBuilder();
128
129 builder.append('#');
130 builder.append(operator);
131
132 if (parameters.containsKey("default")) {
133 String value = parameters.get("default");
134 builder.append(':');
135 builder.append(escapeAsNecessary(value));
136 }
137
138 Map<String, List<Value>> parameterMap = parameters.value().map();
139
140 if (parameterMap != null) {
141 for (String key : parameterMap.keySet()) {
142 if (key.equals("default")) {
143 continue;
144 }
145 String value = parameterMap.get(key).get(0).toString();
146
147 builder.append(':');
148 builder.append(escapeAsNecessary(key));
149 builder.append('=');
150 builder.append(escapeAsNecessary(value));
151 }
152 }
153
154 if (internalNodes.size() == 0) {
155 builder.append("()");
156 } else {
157 builder.append("( ");
158 for (Node child : internalNodes) {
159 builder.append(child.toString());
160 builder.append(' ');
161 }
162 builder.append(")");
163 }
164
165 return builder.toString();
166 }
167
168 @Override
169 public boolean equals(Object o) {
170 if (!(o instanceof Node)) {
171 return false;
172 }
173 if (o == this) {
174 return true;
175 }
176 Node other = (Node) o;
177
178 if ((operator == null) != (other.getOperator() == null)) {
179 return false;
180 }
181 if (operator != null && !other.getOperator().equals(operator)) {
182 return false;
183 }
184 if (internalNodes.size() != other.getInternalNodes().size()) {
185 return false;
186 }
187 for (int i = 0; i < internalNodes.size(); i++) {
188 if (!internalNodes.get(i).equals(other.getInternalNodes().get(i))) {
189 return false;
190 }
191 }
192
193 return true;
194 }
195
196 @Override
197 public int hashCode() {
198 int hash = 7;
199 hash = 67 * hash + (this.operator != null ? this.operator.hashCode() : 0);
200 hash = 67 * hash + (this.internalNodes != null ? this.internalNodes.hashCode() : 0);
201 return hash;
202 }
203 }