ChangeCalendar/backend/src/main/java/com/nttdata/calender/states/State.java

352 lines
13 KiB
Java

package com.nttdata.calender.states;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.bmc.arsys.api.ARException;
import com.bmc.arsys.api.Entry;
import com.nttdata.calender.api.Query;
import com.nttdata.calender.api.RemedyJavaAPI;
import com.nttdata.calender.errorhandling.ErrorTypes.NotFoundError;
/**
* The State class is a singleton class responsible for managing and querying
* state-related information. It handles the retrieval and storage of state
* names in english and german and possible state transitions.
* The states get fetched once at the start of the server.
*/
public class State {
private HashMap<Integer, StateInfo> state;
private static final State INSTANCE = new State();
/**
* Initializes the state with an empty HashMap.
*/
private State() {
this.state = new HashMap<>();
}
/**
* Returns the Singleton instance of the State.
*
* @return the Singleton instance of State
*/
public static State getInstance() {
return INSTANCE;
}
/**
* Returns the state.
*
* @return the state
*/
public HashMap<Integer, StateInfo> getState() {
return state;
}
/**
* Sets the state.
*
* @param state the state to set
*/
public void setState(HashMap<Integer, StateInfo> state) {
this.state = state;
}
/**
* Query for all the information about the state. First, the possible state
* transitions are queried by {@code queryPossibleStates()}. The query consists
* of
* the actual state, the possible state, and the English state name. Then, the
* state names in English and German are queried by {@code queryStateNames()}.
* These pieces of information are then merged and saved into the {@link #state}
* HashMap.
*
* @param api Remedy API object
* @throws ARException
*/
public void queryState(RemedyJavaAPI api) throws ARException, NotFoundError {
// queryStateNames(api);
queryPossibleStates(api);
if (state.isEmpty()) {
throw new NotFoundError("No States found in this context");
}
}
/**
* Query the specified form for the possible states. A state is encoded with an
* integer and has one or multiple states that it could transition to. The state
* and possible states are encoded as integers and saved as {@link StateInfo}.
* Additionally, the English state name is queried and saved into the
* {@link StateInfo}.
*
* @param api Remedy API object
* @throws ARException if an error occurs during the query
*/
public void queryPossibleStates(RemedyJavaAPI api) throws ARException {
var configurationQuery = new Query.QueryBuilder("ITSM:Configuration")
.addFieldId("engName", 700003002)
.addFieldId("gerName", 700003003)
.addFieldId("cancelFlag", 700003004)
.addFieldId("actualState", 700003005)
.addFieldId("restartFlag", 700003010)
.addFieldId("implementerFlag", 700003012)
.addFieldId("possibleState", 700003006) // Include possibleState here
.build();
var configurationStatusQuery = new Query.QueryBuilder("ITSM:Configuration")
.addFieldId("actualState", 700003005)
.addFieldId("possibleState", 700003006)
.build();
var stateFields = api.queryFieldsById("\'Menu\' = \"CHANGE_CALENDER_STATUS\"",
configurationQuery.getFieldIds(),
configurationQuery.getFormName(), null, 0, 0);
var stateStatusFields = api.queryFieldsById("\'Menu\' = \"CHANGE_CALENDER_STATUS_TRANSITIONS\"",
configurationStatusQuery.getFieldIds(),
configurationStatusQuery.getFormName(), null, 0, 0);
populateStateInfo(stateFields, stateStatusFields, configurationQuery, configurationStatusQuery);
// Print state information
// printStateInfo();
}
private void populateStateInfo(List<Entry> stateFields, List<Entry> stateStatusFields,
Query configurationQuery, Query configurationStatusQuery) throws ARException {
for (var stateField : stateFields) {
int actualState = stateField.get(configurationQuery.getFieldId("actualState")).getIntValue();
boolean cancelFlag = false;
boolean restartFlag = false;
boolean implementerFlag = false;
try {
// Extract additional fields
cancelFlag = stateField.get(configurationQuery.getFieldId("cancelFlag")).toString()
.equals("CANCEL_YES");
restartFlag = stateField.get(configurationQuery.getFieldId("restartFlag")).toString()
.equals("RESTARTALLOWED_YES");
implementerFlag = stateField.get(configurationQuery.getFieldId("implementerFlag")).toString()
.equals("SETIMPLEMENTER_YES");
} catch (Exception e) {
// e.printStackTrace();
}
String engName = stateField.get(configurationQuery.getFieldId("engName")).toString();
String gerName = stateField.get(configurationQuery.getFieldId("gerName")).toString();
// Initialize StateInfo with additional fields
StateInfo stateInfo = new StateInfo(engName, gerName, cancelFlag, restartFlag, implementerFlag);
for (var statusField : stateStatusFields) {
int statusActualState = statusField.get(configurationStatusQuery.getFieldId("actualState"))
.getIntValue();
if (actualState == statusActualState) {
int possibleState = statusField.get(configurationStatusQuery.getFieldId("possibleState"))
.getIntValue();
stateInfo.addPossibleState(possibleState);
}
}
// Add StateInfo to the state HashMap
getState().put(actualState, stateInfo);
}
}
private void printStateInfo() {
for (var state : get()) {
// Join possible states into a single string
String possibleStatesString = String.join(", ",
state.possibleStates.stream().map(Object::toString).collect(Collectors.toList()));
// Print the state information
System.out.printf("\n\n[%s]\n[%s]\n[%s]\n[%s]\n[%b]\n[%b]\n[%b]\n\n",
state.actualState, state.stateNameDE, state.stateNameEN,
possibleStatesString, state.cancelFlag, state.restartFlag, state.implementerFlag);
// Print the number of possible states
System.out.println("Possible States: " + state.possibleStates.size());
}
}
/**
* Takes the relevant data about possible states out of the {@code List<Entry>}
* and processes them to be saved into the State.
*
* @param stateFields List of Entry to be processed
* @param configurationQuery Query object of stateFields
*/
// public void updatePossibleStates(List<Entry> stateFields, Query
// configurationQuery) {
// stateFields.stream().forEach(entry -> {
// var actualState =
// entry.get(configurationQuery.getFieldId("actualState")).getIntValue();
// var possibleState =
// entry.get(configurationQuery.getFieldId("possibleState")).getIntValue();
// this.getState().get(actualState).addPossibleState(possibleState);
// });
// }
/**
* Query the German state name from the specified form. The German name in the
* form is associated with the English one. For merging the names into the
* {@link StateInfo}, we return a HashMap that is composed of the English state
* name as the key and the German state name as the value.
*
* @param api Remedy API object
* @throws ARException if an error occurs during the query
*/
// private void queryStateNames(RemedyJavaAPI api) throws ARException {
// var nameQuery = new Query.QueryBuilder("SYS:Menu Items Locale LkUp")
// .addFieldId("englishName", 1000004339)
// .addFieldId("germanName", 1000004338)
// .addFieldId("Locale", 1000004342)
// .addFieldId("SelectionCode", 1000004336)
// .build();
// var stateNames = api.queryFieldsById("\'Menu Type\' = \"Change Status
// Values\"",
// nameQuery.getFieldIds(),
// nameQuery.getFormName(), null, 0, 0);
// updateStateNames(stateNames, nameQuery);
// }
/**
* Takes the relevant data about state names out of the {@code List<Entry>} and
* processes them to be saved into the State.
*
* @param stateFields List of Entry to be processed
* @param nameQuery Query object of stateFields
*/
// public void updateStateNames(List<Entry> stateFields, Query nameQuery) {
// stateFields.stream()
// .filter(entry ->
// Optional.ofNullable(entry.get(nameQuery.getFieldId("Locale")))
// .map(Object::toString)
// .orElse("")
// .equals("de"))
// .forEach(
// entry -> {
// var selectionCode = nameQuery.getFieldId("SelectionCode");
// var englishName = nameQuery.getFieldId("englishName");
// var germanName = nameQuery.getFieldId("germanName");
// this.getState().put(entry.get(selectionCode).getIntValue(),
// new StateInfo(entry.get(englishName).toString(),
// entry.get(germanName).toString()));
// });
// }
/**
* Generate an Array of JSON objects that consists of all the state information.
* These are the integer representation of the actual state, an Array of integer
* representations of possible states, the English name of the actual state, and
* the German name of the actual state.
*
* @return Array of JSON objects with integer representation of state and
* {@link StateInfo}
*/
public ArrayList<StateResponse> get() {
var response = new ArrayList<StateResponse>();
this.state.forEach((key, value) -> {
response.add(new StateResponse(key, value.possibleState, value.stateNameEN, value.stateNameDE,
value.cancelFlag, value.restartFlag, value.implementerFlag));
});
return response;
}
/**
* Represents the state info of a state.
*/
public class StateInfo {
String stateNameEN;
String stateNameDE;
ArrayList<Integer> possibleState;
boolean cancelFlag;
boolean restartFlag;
boolean implementerFlag;
/**
* Initializes an instance of the {@link StateInfo} class.
*
* @param possibleState possible state encoded as an integer
* @param stateNameEN state name in English
* @param stateNameDE state name in German
*/
public StateInfo(int possibleState, String stateNameEN, String stateNameDE) {
this.possibleState = new ArrayList<>();
this.possibleState.add(possibleState);
this.stateNameDE = stateNameDE;
this.stateNameEN = stateNameEN;
}
/**
* Initializes an instance of the {@link StateInfo} class.
*
* @param stateNameEN state name in English
* @param stateNameDE state name in German
*/
public StateInfo(String stateNameEN, String stateNameDE, boolean cancelFlag, boolean restartFlag,
boolean implementerFlag) {
this.stateNameEN = stateNameEN;
this.stateNameDE = stateNameDE;
this.cancelFlag = cancelFlag;
this.restartFlag = restartFlag;
this.implementerFlag = implementerFlag;
this.possibleState = new ArrayList<>();
}
/**
* Adds a possible state to transition to, encoded as an integer, to the
* {@link StateInfo}.
*
* @param possibleState possible state
*/
public void addPossibleState(int possibleState) {
if (!this.possibleState.contains(possibleState)) {
this.possibleState.add(possibleState);
}
}
/**
* Get the state name in English.
*
* @return the state name in English
*/
public String getStateNameEN() {
return stateNameEN;
}
/**
* Get the state name in German.
*
* @return the state name in German
*/
public String getStateNameDE() {
return stateNameDE;
}
/**
* Set the state name in German.
*
* @param stateNameDE the state name in German
*/
public void setStateNameDE(String stateNameDE) {
this.stateNameDE = stateNameDE;
}
/**
* Set the state name in English.
*
* @param stateNameEN the state name in English
*/
public void setStateNameEN(String stateNameEN) {
this.stateNameEN = stateNameEN;
}
}
}