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
|
/*******************************************************************************
* Copyright (c) 2023 Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*******************************************************************************/
package org.aspectj.weaver.patterns;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Test helper class reflecting nesting structure for AND ('&&'), OR ('||') and NOT ('!') pointcuts, enabling
* comparisons disregarding order of AND/OR pointcuts on the same nesting level. For this class, there is no difference
* between 'A && B && C', 'A && C && B', 'C && B '&& A' etc., i.e. the commutative law is respected.
*
* @author Alexander Kriegisch
*/
public class LogicalPointcutStructure {
private enum PointcutType { NOT, AND, OR, TEXT }
private final PointcutType type;
private final List<LogicalPointcutStructure> children = new ArrayList<>();
private final Set<LogicalPointcutStructure> childrenSet = new HashSet<>();
private final String text;
private LogicalPointcutStructure(PointcutType type, LogicalPointcutStructure... children) {
this(type, null, children);
}
private LogicalPointcutStructure(PointcutType type, String text) {
this(type, text, (LogicalPointcutStructure[]) null);
}
private LogicalPointcutStructure(PointcutType type, String text, LogicalPointcutStructure... children) {
if (type == null)
throw new IllegalArgumentException("pointcutType must be != null");
if (text == null && children == null)
throw new IllegalArgumentException("either text or children must be != null");
if (text != null && children != null)
throw new IllegalArgumentException("cannot have both text and children, one must be null");
if (text != null && type != PointcutType.TEXT)
throw new IllegalArgumentException("if text is given, type must match to be TEXT");
if (children != null && type == PointcutType.TEXT)
throw new IllegalArgumentException("if children are given, type must be != TEXT");
this.type = type;
this.text = text;
if (children != null) {
this.children.addAll(Arrays.asList(children));
this.childrenSet.addAll(this.children);
}
}
public PointcutType getType() {
return type;
}
public List<LogicalPointcutStructure> getChildren() {
return children;
}
public String getText() {
return text;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
LogicalPointcutStructure that = (LogicalPointcutStructure) o;
if (type != that.type)
return false;
if (!childrenSet.equals(that.childrenSet))
return false;
return Objects.equals(text, that.text);
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + childrenSet.hashCode();
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
@Override
public String toString() {
return type == PointcutType.TEXT
? "\"" + text + "\""
: type + "(" + children.toString().replaceFirst("^.(.*).$", "$1") + ")";
}
public static LogicalPointcutStructure NOT(LogicalPointcutStructure child) {
return new LogicalPointcutStructure(PointcutType.NOT, child);
}
public static LogicalPointcutStructure NOT(Object childObject) {
LogicalPointcutStructure child;
if (childObject instanceof LogicalPointcutStructure)
child = (LogicalPointcutStructure) childObject;
else if (childObject instanceof String)
child = TEXT((String) childObject);
else
throw new IllegalArgumentException("each child must be either LogicalPointcutStructure or String");
return new LogicalPointcutStructure(PointcutType.NOT, child);
}
public static LogicalPointcutStructure AND(LogicalPointcutStructure... children) {
return new LogicalPointcutStructure(PointcutType.AND, children);
}
public static LogicalPointcutStructure AND(Object... childObjects) {
LogicalPointcutStructure[] children = new LogicalPointcutStructure[childObjects.length];
LogicalPointcutStructure child;
Object childObject;
for (int i = 0; i < childObjects.length; i++) {
childObject = childObjects[i];
if (childObject instanceof LogicalPointcutStructure)
child = (LogicalPointcutStructure) childObject;
else if (childObject instanceof String)
child = TEXT((String) childObject);
else
throw new IllegalArgumentException("each child must be either LogicalPointcutStructure or String");
children[i] = child;
}
return new LogicalPointcutStructure(PointcutType.AND, children);
}
public static LogicalPointcutStructure OR(LogicalPointcutStructure... children) {
return new LogicalPointcutStructure(PointcutType.OR, children);
}
public static LogicalPointcutStructure OR(Object... childObjects) {
LogicalPointcutStructure[] children = new LogicalPointcutStructure[childObjects.length];
LogicalPointcutStructure child;
Object childObject;
for (int i = 0; i < childObjects.length; i++) {
childObject = childObjects[i];
if (childObject instanceof LogicalPointcutStructure)
child = (LogicalPointcutStructure) childObject;
else if (childObject instanceof String)
child = TEXT((String) childObject);
else
throw new IllegalArgumentException("each child must be either LogicalPointcutStructure or String");
children[i] = child;
}
return new LogicalPointcutStructure(PointcutType.OR, children);
}
public static LogicalPointcutStructure TEXT(String text) {
return new LogicalPointcutStructure(PointcutType.TEXT, text);
}
public static LogicalPointcutStructure fromPointcut(Pointcut pointcut) {
if (pointcut instanceof NotPointcut) {
NotPointcut notPointcut = (NotPointcut) pointcut;
return NOT(fromPointcut(notPointcut.getNegatedPointcut()));
}
else if (pointcut instanceof AndPointcut) {
List<LogicalPointcutStructure> children = new ArrayList<>();
AndPointcut andPointcut = (AndPointcut) pointcut;
children.add(fromPointcut(andPointcut.getRight()));
while (andPointcut.getLeft() instanceof AndPointcut) {
andPointcut = (AndPointcut) andPointcut.getLeft();
children.add(fromPointcut(andPointcut.getRight()));
}
children.add(fromPointcut(andPointcut.getLeft()));
return AND(children.toArray(new LogicalPointcutStructure[0]));
}
else if (pointcut instanceof OrPointcut) {
List<LogicalPointcutStructure> children = new ArrayList<>();
OrPointcut orPointcut = (OrPointcut) pointcut;
children.add(fromPointcut(orPointcut.getRight()));
while (orPointcut.getLeft() instanceof OrPointcut) {
orPointcut = (OrPointcut) orPointcut.getLeft();
children.add(fromPointcut(orPointcut.getRight()));
}
children.add(fromPointcut(orPointcut.getLeft()));
return OR(children.toArray(new LogicalPointcutStructure[0]));
}
else {
return TEXT(pointcut.toString());
}
}
public static void main(String[] args) {
// true
System.out.println(verifyToString(
OR("A", NOT(OR("B", "C"))),
"OR(\"A\", NOT(OR(\"B\", \"C\")))"
));
// true
System.out.println(verifyToString(
OR(AND("A", NOT(OR("B", "C")), "D"), NOT(OR("E", "F"))),
"OR(AND(\"A\", NOT(OR(\"B\", \"C\")), \"D\"), NOT(OR(\"E\", \"F\")))"
));
// true
System.out.println(verifyEquals(
OR("A", NOT(OR("B", "C"))),
OR(NOT(OR("C", "B")), "A")
));
// true
System.out.println(verifyEquals(
OR(AND("A", NOT(OR("B", "C")), "D"), NOT(OR("E", "F"))),
OR(NOT(OR("F", "E")), AND("A", NOT(OR("C", "B")), "D"))
));
// false
System.out.println(verifyEquals(
OR(AND("A", NOT(OR("B", "C")), "D"), NOT(OR("E", "F"))),
OR(NOT(OR("F", "E")), AND(NOT(OR("C", "B", "D")), "A"))
));
}
private static boolean verifyToString(LogicalPointcutStructure structure, String toStringExpected) {
System.out.println();
System.out.println("Expected: " + toStringExpected);
System.out.println("Actual: " + structure);
return toStringExpected.equals(structure.toString());
}
private static boolean verifyEquals(LogicalPointcutStructure structure1, LogicalPointcutStructure structure2) {
System.out.println();
System.out.println("Structure 1: " + structure1);
System.out.println("Structure 2: " + structure2);
return structure1.equals(structure2);
}
}
|