Skip to content

Commit f44720c

Browse files
Feature/service now uib (#83)
* added service now api integration * Add Service Now functions and Service Now Getting Started * Add Service Now functions and Service Now Getting Started * Add ServiceNow functions and ServiceNow Getting Started * Add ServiceNow functions and ServiceNow Getting Started * Refactoring based on the comments * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * refactoring bellatrix.servicenow update getting-started\bellatrix.servicenow * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features to servicenow module * Add UIB features examples to servicenow module * Add UIB features examples to servicenow module * UIB Data Creation features refactoring aligned with Dependency resolver in the data module * UIB Data Creation features refactoring aligned with Dependency resolver in the data module * UIB fixes --------- Co-authored-by: veselinov.viktor <[email protected]> Co-authored-by: EliNedyalkova <dAtp23M24@>
1 parent 01697fb commit f44720c

File tree

85 files changed

+2133
-214
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2133
-214
lines changed

bellatrix.data/src/main/java/solutions/bellatrix/data/http/infrastructure/DependencyResolver.java

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public class DependencyResolver {
2525
private static final Set<Class<?>> buildingEntities = new HashSet<>();
2626
private static final Set<Class<?>> creatingEntities = new HashSet<>();
2727
private static final Set<Class<?>> deletingEntities = new HashSet<>();
28-
28+
private static final Set<Class<?>> updatingEntities = new HashSet<>();
29+
2930
/**
3031
* Resolves all dependencies for the given entity by creating
3132
* dependent entities where fields are marked with @Dependency
@@ -56,6 +57,13 @@ public static <T> T createDependencies(T entity) {
5657
return createDependenciesRecursive(entity);
5758
}
5859

60+
public static <T> T updateDependencies(T entity) {
61+
if (entity == null) {
62+
return null;
63+
}
64+
return updateDependenciesRecursive(entity);
65+
}
66+
5967
public static <T> void deleteDependencies(T entity) {
6068
if (entity == null) return;
6169
deletingEntities.clear();
@@ -163,14 +171,46 @@ private static <T> T deleteDependenciesRecursive(T entity) {
163171
deletingEntities.remove(entityClass);
164172
}
165173
}
174+
175+
private static <T> T updateDependenciesRecursive(T entity) {
176+
if (entity == null) {
177+
return null;
178+
}
179+
180+
Class<?> entityClass = entity.getClass();
181+
182+
// Check for circular dependency
183+
if (updatingEntities.contains(entityClass)) {
184+
throw new RuntimeException("Circular dependency detected for entity: " + entityClass.getSimpleName());
185+
}
186+
187+
// Add to resolving set
188+
updatingEntities.add(entityClass);
189+
190+
try {
191+
// Get all fields with @Dependency annotations
192+
List<Field> dependencyFields = getDependencyFields(entityClass);
193+
194+
// Resolve each dependency field
195+
for (Field field : dependencyFields) {
196+
updateFieldDependencyRecursive(entity, field);
197+
}
198+
199+
return entity;
200+
} finally {
201+
// Remove from resolving set
202+
updatingEntities.remove(entityClass);
203+
}
204+
}
205+
166206

167207
/**
168208
* Gets all fields with @Dependency annotations from the given class.
169209
*
170210
* @param entityClass The entity class to scan
171211
* @return List of fields with @Dependency annotations
172212
*/
173-
private static List<Field> getDependencyFields(Class<?> entityClass) {
213+
protected static List<Field> getDependencyFields(Class<?> entityClass) {
174214
List<Field> dependencyFields = new ArrayList<>();
175215
Field[] fields = entityClass.getDeclaredFields();
176216

@@ -333,7 +373,7 @@ private static Object buildDependencyEntity(Dependency dependencyAnnotation) {
333373
* @param entityType The entity class to find a factory for
334374
* @return The factory instance or null if not found
335375
*/
336-
private static EntityFactory<?> findFactoryForEntity(Class<?> entityType) {
376+
public static EntityFactory<?> findFactoryForEntity(Class<?> entityType) {
337377
String entityName = entityType.getSimpleName();
338378
String factoryClassName = entityName + "RepositoryFactory";
339379

@@ -406,4 +446,34 @@ private static boolean trySetViaSetter(Object target, Field field, Object value)
406446
}
407447
return false;
408448
}
449+
450+
private static void updateFieldDependencyRecursive(Object entity, Field field) {
451+
try {
452+
field.setAccessible(true);
453+
Dependency dependencyAnnotation = field.getAnnotation(Dependency.class);
454+
Entity currentValue = (Entity)field.get(entity);
455+
456+
// Skip if field already has a value and forceCreate is false
457+
if (currentValue == null || currentValue.getIdentifier() == null) {
458+
return;
459+
}
460+
461+
// Create the dependency entity using the repository
462+
Object builtDependencyEntity = currentValue == null ? buildDependencyEntity(dependencyAnnotation) : currentValue;
463+
464+
// Get the repository directly using the entity type from the annotation
465+
@SuppressWarnings("unchecked")
466+
Repository<Entity> repository = (Repository<Entity>) RepositoryProvider.INSTANCE.get((Class<? extends Entity>) dependencyAnnotation.entityType());
467+
468+
Log.info("Updating dependency entity for field '" + field.getName() + "' of type '" + dependencyAnnotation.entityType().getSimpleName() + "'.");
469+
repository.update((Entity) builtDependencyEntity);
470+
471+
// Recursively resolve dependencies for the dependency entity
472+
// This ensures that all dependencies are resolved bottom-up
473+
updateDependenciesRecursive(builtDependencyEntity);
474+
475+
} catch (Exception e) {
476+
throw new RuntimeException("Failed to update dependency for field: " + field.getName(), e);
477+
}
478+
}
409479
}

bellatrix.data/src/main/java/solutions/bellatrix/data/http/infrastructure/Entity.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
package solutions.bellatrix.data.http.infrastructure;
22

3+
import lombok.NoArgsConstructor;
34
import lombok.experimental.SuperBuilder;
5+
import solutions.bellatrix.data.annotations.Dependency;
46
import solutions.bellatrix.data.configuration.RepositoryProvider;
57
import solutions.bellatrix.data.contracts.Repository;
8+
import solutions.bellatrix.data.http.contracts.EntityFactory;
9+
10+
import java.lang.reflect.Field;
11+
import java.lang.reflect.InvocationTargetException;
12+
import java.util.List;
13+
14+
import static solutions.bellatrix.data.http.infrastructure.DependencyResolver.getDependencyFields;
615

716
@SuperBuilder
17+
@NoArgsConstructor
818
@SuppressWarnings("unchecked")
919
public abstract class Entity<TIdentifier, TEntity> {
1020
public TEntity get() {
@@ -40,6 +50,48 @@ public void deleteDependenciesAndSelf() {
4050
DependencyResolver.deleteDependencies(this);
4151
}
4252

53+
public TEntity getWithDependencies() throws IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException {
54+
var repository = (Repository<Entity>)RepositoryProvider.INSTANCE.get(this.getClass());
55+
var record = repository.getById(this);
56+
List<Field> dependencyFields = getDependencyFields(record.getClass());
57+
58+
for (Field field : dependencyFields) {
59+
field.setAccessible(true);
60+
Dependency dependencyAnnotation = field.getAnnotation(Dependency.class);
61+
62+
Entity currentValue = (Entity)field.get(this);
63+
// Skip if field already has a value and forceCreate is false
64+
if (currentValue != null && !dependencyAnnotation.forceCreate()) {
65+
break;
66+
}
67+
68+
Field f = record.getClass().getDeclaredField(String.format("id%s", Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1)));
69+
f.setAccessible(true);
70+
var dependencyId = f.get(record).toString();
71+
72+
Class<?> fieldType = field.getType();
73+
EntityFactory<?> factory = DependencyResolver.findFactoryForEntity(fieldType);
74+
if (factory == null) {
75+
throw new IllegalStateException("No factory found for entity type: " + dependencyAnnotation.entityType().getSimpleName());
76+
}
77+
78+
Entity newEntity = factory.buildDefault();
79+
80+
newEntity.setIdentifier(dependencyId);
81+
82+
field.set(record, newEntity.getWithDependencies());
83+
}
84+
85+
return (TEntity) record;
86+
}
87+
88+
public TEntity updateWithDependencies() {
89+
DependencyResolver.updateDependencies(this);
90+
var repository = (Repository<Entity>)RepositoryProvider.INSTANCE.get(this.getClass());
91+
this.setIdentifier((String)repository.update(this).getIdentifier());
92+
return (TEntity)this;
93+
}
94+
4395
public abstract TIdentifier getIdentifier();
4496
public abstract void setIdentifier(String id);
4597
}

bellatrix.data/src/main/java/solutions/bellatrix/data/http/infrastructure/HttpEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import lombok.Data;
44
import lombok.EqualsAndHashCode;
5+
import lombok.NoArgsConstructor;
56
import lombok.experimental.SuperBuilder;
67
import solutions.bellatrix.data.http.contracts.Queryable;
78

89
import java.util.Objects;
910

1011
@Data
1112
@SuperBuilder
13+
@NoArgsConstructor
1214
@EqualsAndHashCode(callSuper = true)
1315
public abstract class HttpEntity<TIdentifier, TEntity> extends Entity<TIdentifier, TEntity> implements Queryable {
1416
private transient HttpResponse response;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package solutions.bellatrix.servicenow.components.enums;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public enum UibToolbarButtonLabel {
7+
HOME("Home"),
8+
LIST("List"),
9+
TEAMS("Teams"),
10+
SCHEDULES("Schedules"),
11+
DASHBOARD("Dashboard");
12+
13+
private final String value;
14+
15+
UibToolbarButtonLabel(String label) {
16+
this.value = label;
17+
}
18+
19+
@Override
20+
public String toString() {
21+
return value;
22+
}
23+
}

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordCheckbox.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package solutions.bellatrix.servicenow.components.uiBuilder;
2+
import solutions.bellatrix.servicenow.components.enums.UibComponentType;
23
import solutions.bellatrix.web.components.*;
34
import solutions.bellatrix.web.components.contracts.ComponentDisabled;
45

5-
public class RecordCheckbox extends WebComponent implements ComponentDisabled {
6-
6+
public class RecordCheckbox extends UIBDefaultComponent implements ComponentDisabled {
77
protected CheckBox checkbox() {
88
return this.createByCss(CheckBox.class, "input[type='checkbox']");
99
}
@@ -12,11 +12,20 @@ public boolean isChecked() {
1212
return checkbox().isChecked();
1313
}
1414

15+
@Override
16+
public void setText(String text) {
17+
}
18+
1519
@Override
1620
public boolean isDisabled() {
1721
return getAttribute("readonly") != null || checkbox().isDisabled() || getAttribute("disabled") != null;
1822
}
1923

24+
@Override
25+
public UibComponentType componentType() {
26+
return null;
27+
}
28+
2029
public void check() {
2130
if (!isChecked() && !isDisabled()) {
2231
checkbox().check();
@@ -40,4 +49,9 @@ public void assertIsChecked() {
4049
public void assertIsUnchecked() {
4150
checkbox().validateIsUnchecked();
4251
}
52+
53+
@Override
54+
public String getText() {
55+
return "";
56+
}
4357
}

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordChoice.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@
1010

1111
public class RecordChoice extends UIBDefaultComponent implements ComponentDisabled, ComponentText {
1212

13-
protected WebComponent dropdown() {
13+
public WebComponent dropdown() {
1414
return this.createByXPath(WebComponent.class, ".//now-select");
1515
}
1616

17-
protected Button dropdownButton() {
17+
public Button dropdownButton() {
1818
return dropdown().createByCss(Button.class, "button");
1919
}
2020

21-
protected List<Button> getDropdownOptions() {
21+
public List<Button> getDropdownOptions() {
2222
return getDropDownWrapper().createAllByCss(Button.class, "div[role='option']");
2323
}
2424

25-
protected Button getOptionByIndex(int index) {
25+
public Button getOptionByIndex(int index) {
2626
return getDropdownOptions().get(index);
2727
}
2828

29-
protected Button getOptionByText(String text) {
29+
public Button getOptionByText(String text) {
3030
var optionFound = getDropdownOptions().stream().filter(x -> x.getText().equals(text)).findFirst();
3131
if (optionFound.isEmpty()) {
3232
throw new RuntimeException("Option with text %s not found.".formatted(text));

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordDateInput.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ protected Button customUiNowDateInputCalendarButton() {
2929

3030
//calendar pop up
3131
protected ShadowRoot customUiDropDownSeismicHoist() {
32-
return create().byCss(ShadowRoot.class, "seismic-hoist").toShadowRootToBeAttached();
32+
return create().byCss(ShadowRoot.class, "seismic-hoist").getShadowRoot();
3333
}
3434

3535
protected Button calendarPopUpOkayButton() {

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordDateTimeInput.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
public class RecordDateTimeInput extends UIBDefaultComponent implements ComponentDisabled, ComponentText {
1717

1818
protected ShadowRoot customUiDropDownSeismicHoist() {
19-
return create().byCss(ShadowRoot.class, "seismic-hoist").toShadowRootToBeAttached();
19+
return create().byCss(ShadowRoot.class, "seismic-hoist").getShadowRoot();
2020
}
2121

2222
protected ShadowRoot customUiNowDateTimeInputByLabel() {

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordInput.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
import org.openqa.selenium.ElementNotInteractableException;
44
import solutions.bellatrix.servicenow.components.enums.UibComponentType;
5-
import solutions.bellatrix.web.components.TextInput;
65
import solutions.bellatrix.web.components.contracts.ComponentDisabled;
76
import solutions.bellatrix.web.components.contracts.ComponentText;
87

98
public class RecordInput extends UIBDefaultComponent implements ComponentDisabled, ComponentText {
10-
11-
protected TextInput textInput() {
12-
return create().byCss(TextInput.class, "input");
9+
public UIBDefaultComponent textInput() {
10+
return create().byCss(UIBDefaultComponent.class, "input");
1311
}
1412

1513
@Override

bellatrix.servicenow/src/main/java/solutions/bellatrix/servicenow/components/uiBuilder/RecordReference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
public class RecordReference extends UIBDefaultComponent implements ComponentDisabled, ComponentText {
1111

1212
protected WebComponent recordTypehead() {
13-
return this.create().byCss(WebComponent.class, "now-record-typeahead").toShadowRootToBeAttached();
13+
return this.create().byCss(WebComponent.class, "now-record-typeahead").getShadowRoot();
1414
}
1515

1616
protected Button referenceButton() {

0 commit comments

Comments
 (0)