1 package org.metricshub.winrm;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 import java.util.stream.Collectors;
35 import org.metricshub.winrm.exceptions.WqlQuerySyntaxException;
36
37 public class WqlQuery {
38
39
40
41
42
43
44
45
46
47
48 private static final Pattern WQL_PATTERN = Pattern.compile(
49 "^\\s*(SELECT\\s+(?:\\*|([a-z0-9._]+(?:\\s*,\\s*[a-z0-9._]+)*))\\s+FROM\\s+)?(?:((?:ASSOCIATORS|REFERENCES)\\s+OF\\s+\\{.*\\})|([a-z0-9_]+))(\\s+WHERE\\s*+.+)?\\s*$",
50 Pattern.CASE_INSENSITIVE | Pattern.DOTALL
51 );
52
53 private String wql;
54 private List<String> selectedProperties;
55 private Map<String, Set<String>> subPropertiesMap;
56 private String cleanWql;
57
58 private WqlQuery(
59 String wql,
60 List<String> selectedProperties,
61 Map<String, Set<String>> subPropertiesMap,
62 String cleanWql
63 ) {
64 this.wql = wql;
65 this.selectedProperties = selectedProperties;
66 this.subPropertiesMap = subPropertiesMap;
67 this.cleanWql = cleanWql;
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public static WqlQuery newInstance(CharSequence wql) throws WqlQuerySyntaxException {
89 Utils.checkNonNull(wql, "wql");
90
91 Matcher wqlMatcher = WQL_PATTERN.matcher(wql);
92
93
94 if (!wqlMatcher.find()) {
95 throw new WqlQuerySyntaxException(wql.toString());
96 }
97
98
99 String selectFragment = wqlMatcher.group(1);
100 String propertiesFragment = wqlMatcher.group(2);
101 String associatorsFragment = wqlMatcher.group(3);
102 String classFragment = wqlMatcher.group(4);
103 String restFragment = wqlMatcher.group(5);
104
105
106 if (selectFragment == null && associatorsFragment == null) {
107 throw new WqlQuerySyntaxException(wql.toString());
108 }
109
110 List<String> properties = buildSelectedProperties(propertiesFragment);
111 Map<String, Set<String>> subPropertiesMap = buildSupPropertiesMap(properties);
112 String cleanWql = buildCleanWql(associatorsFragment, subPropertiesMap, classFragment, restFragment);
113
114 return new WqlQuery(wql.toString(), properties, subPropertiesMap, cleanWql);
115 }
116
117
118
119
120
121
122
123 static List<String> buildSelectedProperties(String propertiesFragment) {
124 if (Utils.isNotBlank(propertiesFragment)) {
125 return Arrays.asList(propertiesFragment.trim().toLowerCase().split("\\s*,\\s*"));
126 }
127 return new ArrayList<>();
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 static Map<String, Set<String>> buildSupPropertiesMap(final List<String> properties) {
145
146 if (properties == null || properties.isEmpty()) {
147 return new HashMap<>();
148 }
149
150 Map<String, Set<String>> subPropertiesMap = new LinkedHashMap<>();
151 properties
152 .stream()
153 .filter(Utils::isNotBlank)
154 .forEachOrdered(property -> {
155
156
157
158 String[] propertyFragmentArray = property.toLowerCase().split("\\.", 2);
159 String mainProperty = propertyFragmentArray[0];
160 String subProperty = propertyFragmentArray.length == 2 ? propertyFragmentArray[1] : null;
161
162
163 subPropertiesMap.compute(
164 mainProperty,
165 (key, subPropertiesSet) -> {
166 if (subPropertiesSet == null) {
167 subPropertiesSet = new HashSet<>();
168 }
169 if (subProperty != null) {
170 subPropertiesSet.add(subProperty);
171 }
172 return subPropertiesSet;
173 }
174 );
175 });
176
177 return subPropertiesMap;
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 static String buildCleanWql(
200 String associatorsFragment,
201 Map<String, Set<String>> subPropertiesMap,
202 String classFragment,
203 String restFragment
204 ) {
205 String cleanWql;
206
207 if (associatorsFragment == null) {
208 if (subPropertiesMap.keySet().isEmpty()) {
209 cleanWql = "SELECT * FROM " + classFragment;
210 } else {
211 cleanWql = String.format(
212 "SELECT %s FROM %s",
213 subPropertiesMap.keySet().stream().collect(Collectors.joining(",")),
214 classFragment
215 );
216 }
217 } else {
218 cleanWql = associatorsFragment;
219 }
220 if (restFragment != null) {
221 cleanWql = cleanWql + restFragment;
222 }
223 return cleanWql;
224 }
225
226
227
228
229
230
231 public List<String> getSelectedProperties() {
232 return Collections.unmodifiableList(selectedProperties);
233 }
234
235
236
237
238
239
240
241 public Map<String, Set<String>> getSubPropertiesMap() {
242
243 final Map<String, Set<String>> view = new LinkedHashMap<>();
244 subPropertiesMap
245 .forEach((property, subProperties) -> view.put(property, Collections.unmodifiableSet(subProperties)));
246 return Collections.unmodifiableMap(view);
247 }
248
249 public String getCleanWql() {
250 return cleanWql;
251 }
252
253 @Override
254 public String toString() {
255 return wql;
256 }
257 }