Skip to content

Commit ca2d94f

Browse files
authored
#33: Added PackageStructure (#34)
1 parent 305da7d commit ca2d94f

File tree

1 file changed

+346
-0
lines changed

1 file changed

+346
-0
lines changed
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
package com.devonfw.sample.archunit;
2+
3+
import java.util.regex.Matcher;
4+
import java.util.regex.Pattern;
5+
6+
import com.tngtech.archunit.core.domain.JavaClass;
7+
8+
/**
9+
* A structured representation of a {@link Package#getName() package name} according to the architecture definition of
10+
* this project.
11+
*/
12+
public class PackageStructure {
13+
14+
/** The {@link #getLayer() layer} {@value} */
15+
public static final String LAYER_COMMON = "common";
16+
17+
/** The {@link #getLayer() layer} {@value} */
18+
public static final String LAYER_DATA_ACCESS = "dataaccess";
19+
20+
/** The {@link #getLayer() layer} {@value} */
21+
public static final String LAYER_LOGIC = "logic";
22+
23+
/** The {@link #getLayer() layer} {@value} */
24+
public static final String LAYER_SERVICE = "service";
25+
26+
/** The {@link #getLayer() layer} {@value} */
27+
public static final String LAYER_CLIENT = "client";
28+
29+
/** The {@link #getLayer() layer} {@value} */
30+
public static final String LAYER_BATCH = "batch";
31+
32+
/** The {@link #getScope() scope} {@value} */
33+
public static final String SCOPE_API = "api";
34+
35+
/** The {@link #getScope() scope} {@value} */
36+
public static final String SCOPE_BASE = "base";
37+
38+
/** The {@link #getScope() scope} {@value} */
39+
public static final String SCOPE_IMPLEMENTATION = "impl";
40+
41+
private final String packageName;
42+
43+
private final boolean valid;
44+
45+
private final String root;
46+
47+
private final String component;
48+
49+
private final String layer;
50+
51+
private final String scope;
52+
53+
private final String detail;
54+
55+
private static final String PATTERN_LAYERS = LAYER_COMMON + "|" + LAYER_DATA_ACCESS + "|" + LAYER_SERVICE + "|"
56+
+ LAYER_BATCH + "|" + LAYER_LOGIC + "|" + LAYER_CLIENT + "|gui";
57+
58+
private static final String REGEX_SEGMENT = "[a-z][a-zA-Z0-9_]+";
59+
60+
private static final String PATTERN_SCOPES = SCOPE_API + "|" + SCOPE_BASE + "|" + SCOPE_IMPLEMENTATION;
61+
62+
private static final String REGEX_PACKAGE =
63+
// 1..root.....................................2..
64+
"(" + REGEX_SEGMENT + "\\." + REGEX_SEGMENT + "(" + "\\." + REGEX_SEGMENT + ")*" + ")" //
65+
// .......3....component............4....layer..............5...6....scope
66+
+ "\\.(" + REGEX_SEGMENT + ")\\.(" + PATTERN_LAYERS + ")(\\.(" + PATTERN_SCOPES + "))?"//
67+
// ....7....detail...........8..
68+
+ "\\.?(" + REGEX_SEGMENT + "(\\." + REGEX_SEGMENT + ")*)?";
69+
70+
private static final Pattern PATTERN = Pattern.compile(REGEX_PACKAGE);
71+
72+
/**
73+
* The constructor.
74+
*
75+
* @param packageName the {@link #getPackage() package name}.
76+
* @param valid the {@link #isValid() valid flag}.
77+
* @param root the {@link #getRoot() root package}.
78+
* @param component the {@link #getComponent() component}.
79+
* @param layer the {@link #getLayer() layer}.
80+
* @param scope the {@link #getScope() scope}.
81+
* @param detail the {@link #getDetail() detail}.
82+
*/
83+
public PackageStructure(String packageName, boolean valid, String root, String component, String layer, String scope,
84+
String detail) {
85+
86+
super();
87+
this.packageName = packageName;
88+
this.valid = valid;
89+
this.root = root;
90+
this.component = component;
91+
this.layer = layer;
92+
this.scope = scope;
93+
this.detail = detail;
94+
}
95+
96+
/**
97+
* @return the {@link Class#getPackage() package} as plain {@link String}.
98+
*/
99+
public String getPackage() {
100+
101+
return this.packageName;
102+
}
103+
104+
/**
105+
* Valid architecture package pattern: (root).(component).(layer)[.(scope).(detail)] (scope and detail are optional),
106+
* Valid package example: 'com.devonfw.sample.archunit.task.service.api'. Where root = com.devonfw.sample; component =
107+
* task; layer = service; scope = "api"; detail = "";
108+
*
109+
* @return {@code true} if this {@link #getPackage() package} is valid according to architecture pattern,
110+
* {@code false} otherwise.
111+
*
112+
*/
113+
public boolean isValid() {
114+
115+
return this.valid;
116+
}
117+
118+
/**
119+
* @return the name of the root-package before the pattern matched. Will be the empty {@link String} if not
120+
* {@link #isValid() valid}.
121+
*/
122+
public String getRoot() {
123+
124+
return this.root;
125+
}
126+
127+
/**
128+
* @param otherPkg the other {@link PackageStructure} to compare.
129+
* @return {@code true} if both this and the given {@link PackageStructure}s have the same {@link #getRoot() root},
130+
* {@code false} otherwise.
131+
*/
132+
public boolean hasSameRoot(PackageStructure otherPkg) {
133+
134+
return getRoot().equals(otherPkg.getRoot());
135+
}
136+
137+
/**
138+
* @return the name of the component. Will be the empty {@link String} if not {@link #isValid() valid}.
139+
*/
140+
public String getComponent() {
141+
142+
return this.component;
143+
}
144+
145+
/**
146+
* @param otherPkg the other {@link PackageStructure} to compare.
147+
* @return {@code true} if both this and the given {@link PackageStructure}s have the same {@link #getComponent()
148+
* component}, {@code false} otherwise.
149+
*/
150+
public boolean hasSameComponent(PackageStructure otherPkg) {
151+
152+
return getComponent().equals(otherPkg.getComponent());
153+
}
154+
155+
/**
156+
* @return the name of the layer. Will be the empty {@link String} if not {@link #isValid() valid}.
157+
*/
158+
public String getLayer() {
159+
160+
return this.layer;
161+
}
162+
163+
/**
164+
* @param otherPkg the other {@link PackageStructure} to compare.
165+
* @return {@code true} if both this and the given {@link PackageStructure}s have the same {@link #getLayer() layer},
166+
* {@code false} otherwise.
167+
*/
168+
public boolean hasSameLayer(PackageStructure otherPkg) {
169+
170+
return getLayer().equals(otherPkg.getLayer());
171+
}
172+
173+
/**
174+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_BATCH batch}, {@code false} otherwise.
175+
*/
176+
public boolean isLayerBatch() {
177+
178+
return LAYER_BATCH.equals(getLayer());
179+
}
180+
181+
/**
182+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_CLIENT client}, {@code false} otherwise.
183+
*/
184+
public boolean isLayerClient() {
185+
186+
return LAYER_CLIENT.equals(getLayer());
187+
}
188+
189+
/**
190+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_COMMON common}, {@code false} otherwise.
191+
*/
192+
public boolean isLayerCommon() {
193+
194+
return LAYER_COMMON.equals(getLayer());
195+
}
196+
197+
/**
198+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_DATA_ACCESS dataaccess}, {@code false}
199+
* otherwise.
200+
*/
201+
public boolean isLayerDataAccess() {
202+
203+
return LAYER_DATA_ACCESS.equals(getLayer());
204+
}
205+
206+
/**
207+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_LOGIC logic}, {@code false} otherwise.
208+
*/
209+
public boolean isLayerLogic() {
210+
211+
return LAYER_LOGIC.equals(getLayer());
212+
}
213+
214+
/**
215+
* @return {@code true} if the {@link #getLayer() layer} is {@link #LAYER_SERVICE service}, {@code false} otherwise.
216+
*/
217+
public boolean isLayerService() {
218+
219+
return LAYER_SERVICE.equals(getLayer());
220+
}
221+
222+
/**
223+
* @return the name of the scope. Will be the empty {@link String} if not {@link #isValid() valid}.
224+
*/
225+
public String getScope() {
226+
227+
return this.scope;
228+
}
229+
230+
/**
231+
* @return {@code true} if {@link #getScope() scope} is present (not empty).
232+
*/
233+
public boolean hasScope() {
234+
235+
return !this.scope.isEmpty();
236+
}
237+
238+
/**
239+
* @return {@code true} if the {@link #getScope() scope} is {@link #SCOPE_API api}, {@code false} otherwise.
240+
*/
241+
public boolean isScopeApi() {
242+
243+
return SCOPE_API.equals(this.scope);
244+
}
245+
246+
/**
247+
* @return {@code true} if the {@link #getScope() scope} is {@link #SCOPE_BASE base}, {@code false} otherwise.
248+
*/
249+
public boolean isScopeBase() {
250+
251+
return SCOPE_BASE.equals(this.scope);
252+
}
253+
254+
/**
255+
* @return {@code true} if the {@link #getScope() scope} is {@link #SCOPE_IMPLEMENTATION impl}, {@code false}
256+
* otherwise.
257+
*/
258+
public boolean isScopeImpl() {
259+
260+
return SCOPE_IMPLEMENTATION.equals(this.scope);
261+
}
262+
263+
/**
264+
* @return the detail (suffix) of the package after the official segments specified by the architecture. Will be the
265+
* empty {@link String} if not present.
266+
*/
267+
public String getDetail() {
268+
269+
return this.detail;
270+
}
271+
272+
/**
273+
* @return {@code true} if {@link #getDetail() detail} is present (not empty).
274+
*/
275+
public boolean hasDetail() {
276+
277+
return !this.detail.isEmpty();
278+
}
279+
280+
@Override
281+
public String toString() {
282+
283+
return this.packageName;
284+
}
285+
286+
/**
287+
* @param pkgName the {@link Package#getName() package name} (excluding the type/class).
288+
* @return a new {@link PackageStructure} instance parsed from the given {@code pkgName}.
289+
*/
290+
public static PackageStructure of(String pkgName) {
291+
292+
String root = "";
293+
String component = "";
294+
String layer = "";
295+
String scope = "";
296+
String detail = "";
297+
Matcher matcher = PATTERN.matcher(pkgName);
298+
boolean valid = matcher.matches();
299+
if (valid) {
300+
root = matcher.group(1);
301+
component = matcher.group(3);
302+
layer = matcher.group(4);
303+
scope = nonNull(matcher.group(6));
304+
detail = nonNull(matcher.group(7));
305+
}
306+
return new PackageStructure(pkgName, valid, root, component, layer, scope, detail);
307+
}
308+
309+
/**
310+
* @param type the arch-unit {@link JavaClass}.
311+
* @return a new {@link PackageStructure} instance parsed from the {@code JavaClass#getPackageName() package name} of
312+
* the given {@link JavaClass}.
313+
*/
314+
public static PackageStructure of(JavaClass type) {
315+
316+
return of(type.getPackageName());
317+
}
318+
319+
/**
320+
* @param type the java {@link Class}.
321+
* @return a new {@link PackageStructure} instance parsed from the {@code Class#getPackageName() package name} of the
322+
* given {@link Class}.
323+
*/
324+
public static PackageStructure of(Class<?> type) {
325+
326+
return of(type.getPackageName());
327+
}
328+
329+
/**
330+
* @param pkg the java {@link Package}.
331+
* @return a new {@link PackageStructure} instance parsed from the {@code Package#getName() package name} of the given
332+
* {@link Package}.
333+
*/
334+
public static PackageStructure of(Package pkg) {
335+
336+
return of(pkg.getName());
337+
}
338+
339+
private static String nonNull(String s) {
340+
341+
if (s == null) {
342+
return "";
343+
}
344+
return s;
345+
}
346+
}

0 commit comments

Comments
 (0)