1   package com.trendmicro.grid.acl.ds;
2   
3   import com.trendmicro.grid.acl.l0.datatypes.Tagged;
4   
5   import java.util.ArrayList;
6   import java.util.Arrays;
7   import java.util.Collections;
8   import java.util.List;
9   
10  /**
11   * Implements a OO layout to hold parsed tag queries.
12   *
13   * @author juergen_kellerer, 2010-05-07
14   * @version 1.0
15   */
16  public abstract class TagQueryExpression {
17  
18  	private static final TagQueryExpression[] EMPTY_ARRAY = new TagQueryExpression[0];
19  
20  	/**
21  	 * Returns true if the tag should be excluded.
22  	 *
23  	 * @return true if the tag should be excluded.
24  	 */
25  	public abstract boolean isNegated();
26  
27  	/**
28  	 * Returns true if the expression is a collection of child expressions.
29  	 *
30  	 * @return true if the expression is a collection of child expressions.
31  	 */
32  	public abstract boolean isExpression();
33  
34  	/**
35  	 * Returns the tag of of this expression, or an empty string if this
36  	 * expression is a collection of child expressions.
37  	 *
38  	 * @return the tag of of this expression, or an empty string if this
39  	 *         expression is a collection of child expressions.
40  	 */
41  	public abstract String getTag();
42  
43  	/**
44  	 * Returns child expressions.
45  	 *
46  	 * @return child expressions.
47  	 */
48  	public abstract TagQueryExpression[] getExpression();
49  
50  	/**
51  	 * Returns true if the given element matches this expression.
52  	 *
53  	 * @param taggedElement the tagged element to check.
54  	 * @return true if the given element matches this expression.
55  	 */
56  	public abstract boolean matches(Tagged taggedElement);
57  
58  
59  	/**
60  	 * Normalizes a given tag query to a list of groups that get combined using OR.
61  	 *
62  	 * @param expression the given expression to convert.
63  	 * @return a list of 1 or more entries.
64  	 */
65  	public static List<TagQueryExpression> splitIntoORList(TagQueryExpression expression) {
66  		List<TagQueryExpression> list = new ArrayList<TagQueryExpression>();
67  		if (expression.isExpression()) {
68  			TagQueryExpression[] expressions = expression.getExpression();
69  			if (expressions.length != 0) {
70  				if (expressions[0].isExpression())
71  					list.addAll(Arrays.asList(expressions));
72  				else
73  					list.add(expression);
74  			}
75  		} else
76  			list.add(TagQueryExpression.create(Collections.singletonList(expression)));
77  
78  		return list;
79  	}
80  
81  	/**
82  	 * Parses the given expression.
83  	 *
84  	 * @param expression		the expression to parse.
85  	 * @param expressionVersion the expression version to use. (may be set to 'null')
86  	 * @return the parsed expression.
87  	 */
88  	public static TagQueryExpression parse(String expression, String expressionVersion) {
89  		return TagQueryExpressionBuilder.getBuilder(expression).parse(expression);
90  	}
91  
92  	/**
93  	 * Parses the given expression and splits it into an OR list.
94  	 *
95  	 * @param expression		the expression to parse.
96  	 * @param expressionVersion the expression version to use. (may be set to 'null')
97  	 * @return the parsed and split expression.
98  	 */
99  	public static List<TagQueryExpression> parseAndSplit(String expression, String expressionVersion) {
100 		return splitIntoORList(parse(expression, expressionVersion));
101 	}
102 
103 	/**
104 	 * Creates a new expression for the given single tag.
105 	 *
106 	 * @param tag the tag to create the expression for, may be prefixed with '-'.
107 	 * @return a new expression for the given single tag.
108 	 */
109 	public static TagQueryExpression create(final String tag) {
110 		return new TagQueryExpression() {
111 
112 			final boolean negated = tag.startsWith("-");
113 			final String tagValue = (negated ? tag.substring(1) : tag).toLowerCase();
114 
115 			@Override
116 			public boolean isNegated() {
117 				return negated;
118 			}
119 
120 			@Override
121 			public boolean isExpression() {
122 				return false;
123 			}
124 
125 			@Override
126 			public String getTag() {
127 				return tagValue;
128 			}
129 
130 			@Override
131 			public boolean matches(Tagged taggedElement) {
132 				return taggedElement.containsTag(tag) || negated;
133 			}
134 
135 			@Override
136 			public TagQueryExpression[] getExpression() {
137 				return EMPTY_ARRAY;
138 			}
139 
140 			@Override
141 			public String toString() {
142 				return (isNegated() ? " -" : " ") + tagValue;
143 			}
144 		};
145 	}
146 
147 	/**
148 	 * Creates a new expression for the given list of child expressions.
149 	 *
150 	 * @param expressions the expressions to wrap.
151 	 * @return a new expression for the given list of child expressions.
152 	 */
153 	public static TagQueryExpression create(final List<TagQueryExpression> expressions) {
154 		return new TagQueryExpression() {
155 
156 			final TagQueryExpression[] tagExpressions =
157 					expressions.toArray(new TagQueryExpression[expressions.size()]);
158 
159 			@Override
160 			public boolean isNegated() {
161 				return false;
162 			}
163 
164 			@Override
165 			public boolean isExpression() {
166 				return true;
167 			}
168 
169 			@Override
170 			public String getTag() {
171 				return "";
172 			}
173 
174 			@Override
175 			public boolean matches(Tagged taggedElement) {
176 				for (TagQueryExpression expression : tagExpressions) {
177 					if (!expression.matches(taggedElement))
178 						return false;
179 				}
180 				return true;
181 			}
182 
183 			@Override
184 			public TagQueryExpression[] getExpression() {
185 				return tagExpressions;
186 			}
187 
188 			@Override
189 			public String toString() {
190 				return "TagQuery{" +
191 						"expression=" + (tagExpressions == null ? null : Arrays.asList(tagExpressions)) +
192 						'}';
193 			}
194 		};
195 	}
196 }