HostConfigConverter.java
/*
* This file is part of Waarp Project (named also Waarp or GG).
*
* Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
* tags. See the COPYRIGHT.txt in the distribution for a full listing of
* individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.openr66.protocol.http.restv2.converters;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.waarp.common.database.exception.WaarpDatabaseSqlException;
import org.waarp.common.json.JsonHandler;
import org.waarp.common.logging.SysErrLogger;
import org.waarp.common.role.RoleDefault.ROLE;
import org.waarp.common.utility.SingletonUtils;
import org.waarp.openr66.dao.BusinessDAO;
import org.waarp.openr66.dao.DAOFactory;
import org.waarp.openr66.dao.exception.DAOConnectionException;
import org.waarp.openr66.dao.exception.DAONoDataException;
import org.waarp.openr66.pojo.Business;
import org.waarp.openr66.protocol.http.restv2.errors.RestError;
import org.waarp.openr66.protocol.http.restv2.errors.RestErrorException;
import org.waarp.openr66.protocol.http.restv2.utils.XmlSerializable.Aliases;
import org.waarp.openr66.protocol.http.restv2.utils.XmlSerializable.Aliases.AliasEntry;
import org.waarp.openr66.protocol.http.restv2.utils.XmlSerializable.Businesses;
import org.waarp.openr66.protocol.http.restv2.utils.XmlSerializable.Roles;
import org.waarp.openr66.protocol.http.restv2.utils.XmlSerializable.Roles.RoleEntry;
import org.waarp.openr66.protocol.http.restv2.utils.XmlUtils;
import javax.ws.rs.InternalServerErrorException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static org.waarp.openr66.protocol.http.restv2.RestConstants.*;
import static org.waarp.openr66.protocol.http.restv2.RestConstants.HostConfigFields.*;
import static org.waarp.openr66.protocol.http.restv2.errors.RestErrors.*;
/**
* A collection of utility methods to convert {@link Business} objects to their
* corresponding
* {@link ObjectNode} and vice-versa.
*/
public final class HostConfigConverter {
/**
* Makes the default constructor of this utility class inaccessible.
*/
private HostConfigConverter() throws InstantiationException {
throw new InstantiationException(
getClass().getName() + " cannot be instantiated.");
}
// ########################### PUBLIC METHODS ###############################
/**
* Converts the given {@link Business} object into an {@link ObjectNode}.
*
* @param hostConfig the HostConfig object to convert
*
* @return the converted ObjectNode
*/
public static ObjectNode businessToNode(final Business hostConfig) {
final ArrayNode business = getBusinessArray(hostConfig);
final ArrayNode roles = getRolesArray(hostConfig);
final ArrayNode aliasArray = getAliasArray(hostConfig);
final ObjectNode node = JsonHandler.createObjectNode();
node.putArray(BUSINESS).addAll(business);
node.putArray(ROLES).addAll(roles);
node.putArray(ALIASES).addAll(aliasArray);
node.put(OTHERS, hostConfig.getOthers());
return node;
}
/**
* Converts the given {@link ObjectNode} into a {@link Business} object.
*
* @param object the ObjectNode to convert
*
* @return the corresponding HostConfig object
*
* @throws RestErrorException if the given ObjectNode does not
* represent a Business object
*/
public static Business nodeToNewBusiness(final ObjectNode object) {
Business emptyBusiness = null;
try {
emptyBusiness = new Business(serverName(), "", "<roles></roles>",
"<aliases></aliases>",
"<root><version></version></root>");
} catch (final WaarpDatabaseSqlException e) {
SysErrLogger.FAKE_LOGGER.syserr(e);
}
return nodeToUpdatedBusiness(object, emptyBusiness);
}
/**
* Returns the given {@link Business} object updated with the values defined
* in the {@link ObjectNode}
* parameter. All fields missing from the ObjectNode parameter will stay
* unchanged in the returned Business
* object.
*
* @param object the ObjectNode to convert.
* @param oldBusiness the Business object to update.
*
* @return the updated Business object
*
* @throws RestErrorException if the given ObjectNode does not
* represent a Business object
*/
public static Business nodeToUpdatedBusiness(final ObjectNode object,
final Business oldBusiness) {
final List<RestError> errors = new ArrayList<RestError>();
final Iterator<Map.Entry<String, JsonNode>> fields = object.fields();
while (fields.hasNext()) {
final Map.Entry<String, JsonNode> field = fields.next();
final String name = field.getKey();
final JsonNode value = field.getValue();
if (name.equalsIgnoreCase(BUSINESS)) {
if (value.isArray()) {
final Businesses businessList = new Businesses();
final Iterator<JsonNode> business = value.elements();
while (business.hasNext()) {
final JsonNode businessName = business.next();
if (businessName.isTextual()) {
businessList.business.add(businessName.asText());
} else {
errors.add(
ILLEGAL_FIELD_VALUE(BUSINESS, businessName.toString()));
}
}
oldBusiness.setBusiness(XmlUtils.objectToXml(businessList));
} else {
errors.add(ILLEGAL_FIELD_VALUE(BUSINESS, value.toString()));
}
} else if (name.equalsIgnoreCase(ROLES)) {
if (value.isArray()) {
try {
final Roles roles = nodeToRoles((ArrayNode) value);
oldBusiness.setRoles(XmlUtils.objectToXml(roles));
} catch (final RestErrorException e) {
errors.addAll(e.errors);
}
} else {
errors.add(ILLEGAL_FIELD_VALUE(ROLES, value.toString()));
}
} else if (name.equalsIgnoreCase(ALIASES)) {
if (value.isArray()) {
try {
final Aliases aliases = nodeToAliasList((ArrayNode) value);
oldBusiness.setAliases(XmlUtils.objectToXml(aliases));
} catch (final RestErrorException e) {
errors.addAll(e.errors);
}
} else {
errors.add(ILLEGAL_FIELD_VALUE(ALIASES, value.toString()));
}
} else if (name.equalsIgnoreCase(OTHERS)) {
if (value.isTextual() &&
value.asText().matches("<root><version>.+</version></root>")) {
oldBusiness.setOthers(value.asText());
} else {
errors.add(ILLEGAL_FIELD_VALUE(ALIASES, value.toString()));
}
} else {
errors.add(UNKNOWN_FIELD(name));
}
}
if (errors.isEmpty()) {
return oldBusiness;
} else {
throw new RestErrorException(errors);
}
}
/**
* Returns the requested host's list of roles on the server.
*
* @param hostName the desired host's name
*
* @return the host's list of roles
*
* @throws InternalServerErrorException if an unexpected error
* occurred
*/
public static List<ROLE> getRoles(final String hostName) {
ArrayNode array;
BusinessDAO businessDAO = null;
try {
businessDAO = DAO_FACTORY.getBusinessDAO(true);
final Business config = businessDAO.select(serverName());
array = getRolesArray(config);
} catch (final DAOConnectionException e) {
throw new InternalServerErrorException(e);
} catch (final DAONoDataException e) {
throw new InternalServerErrorException(e);
} finally {
DAOFactory.closeDAO(businessDAO);
}
final Roles roles = nodeToRoles(array);
for (final RoleEntry role : roles.roles) {
if (role.hostName.equals(hostName)) {
return role.roleList;
}
}
return SingletonUtils.singletonList();
}
// ########################## PRIVATE METHODS ###############################
/**
* Converts and returns the list of aliases of the given {@link Business}
* object into an {@link ArrayNode}.
*
* @param hostConfig the server's HostConfig object
*
* @return the server's list of known aliases
*/
private static ArrayNode getAliasArray(final Business hostConfig) {
final ArrayNode array = JsonHandler.createArrayNode();
if (hostConfig.getAliases() != null) {
try {
final Aliases aliases =
XmlUtils.xmlToObject(hostConfig.getAliases(), Aliases.class);
for (final AliasEntry alias : aliases.aliases) {
final ObjectNode node = JsonHandler.createObjectNode();
final ArrayNode aliasIds = JsonHandler.createArrayNode();
for (final String aliasId : alias.aliasList) {
aliasIds.add(aliasId);
}
node.put(HOST_NAME, alias.hostName);
node.putArray(ALIAS_LIST).addAll(aliasIds);
array.add(node);
}
} catch (final InternalServerErrorException ignore) { //NOSONAR
SysErrLogger.FAKE_LOGGER.syserr("No Alias definition");
}
}
return array;
}
/**
* Converts and returns the list of roles of the given {@link Business}
* object into an {@link ArrayNode}.
*
* @param hostConfig the server's HostConfig object
*
* @return the server's list of known aliases
*/
private static ArrayNode getRolesArray(final Business hostConfig) {
final ArrayNode array = JsonHandler.createArrayNode();
if (hostConfig.getRoles() != null) {
try {
final Roles roles =
XmlUtils.xmlToObject(hostConfig.getRoles(), Roles.class);
for (final RoleEntry role : roles.roles) {
final ObjectNode node = JsonHandler.createObjectNode();
final ArrayNode roleTypes = JsonHandler.createArrayNode();
for (final ROLE roleType : role.roleList) {
roleTypes.add(roleType.name());
}
node.put(HOST_NAME, role.hostName);
node.putArray(ROLE_LIST).addAll(roleTypes);
array.add(node);
}
} catch (final InternalServerErrorException ignore) {//NOSONAR
SysErrLogger.FAKE_LOGGER.syserr("No Roles definition");
}
}
return array;
}
/**
* Converts and returns the list of business partners of the given {@link
* Business} object into an
* {@link ArrayNode}.
*
* @param hostConfig the server's HostConfig object
*
* @return the server's list of known aliases
*/
private static ArrayNode getBusinessArray(final Business hostConfig) {
final ArrayNode array = JsonHandler.createArrayNode();
if (hostConfig.getBusiness() != null) {
try {
final Businesses business =
XmlUtils.xmlToObject(hostConfig.getBusiness(), Businesses.class);
for (final String businessId : business.business) {
array.add(businessId);
}
} catch (final InternalServerErrorException ignore) {//NOSONAR
SysErrLogger.FAKE_LOGGER.syserr("No Business definition");
}
}
return array;
}
/**
* Converts the given {@link ArrayNode} into an {@link Aliases} object.
*
* @param array the JSON array of aliases
*
* @return the XML serializable list of aliases
*
* @throws RestErrorException if the given ArrayNode does not
* represent a list of aliases
*/
private static Aliases nodeToAliasList(final ArrayNode array) {
final List<AliasEntry> aliases = new ArrayList<AliasEntry>();
final List<RestError> errors = new ArrayList<RestError>();
final Iterator<JsonNode> elements = array.elements();
while (elements.hasNext()) {
final JsonNode element = elements.next();
final AliasEntry alias = new AliasEntry();
if (!element.isObject()) {
errors.add(ILLEGAL_PARAMETER_VALUE(ALIASES, element.toString()));
continue;
}
final Iterator<Map.Entry<String, JsonNode>> fields = element.fields();
while (fields.hasNext()) {
final Map.Entry<String, JsonNode> field = fields.next();
final String name = field.getKey();
final JsonNode value = field.getValue();
if (name.equalsIgnoreCase(HOST_NAME)) {
if (value.isTextual()) {
alias.hostName = value.asText();
} else {
errors.add(ILLEGAL_PARAMETER_VALUE(HOST_NAME, value.toString()));
}
} else if (name.equalsIgnoreCase(ALIAS_LIST)) {
if (value.isArray()) {
final Iterator<JsonNode> aliasList = value.elements();
while (aliasList.hasNext()) {
final JsonNode aliasId = aliasList.next();
if (aliasId.isTextual()) {
alias.aliasList.add(aliasId.asText());
} else {
errors.add(
ILLEGAL_PARAMETER_VALUE(ALIAS_LIST, aliasId.toString()));
}
}
} else {
errors.add(ILLEGAL_PARAMETER_VALUE(ALIAS_LIST, value.toString()));
}
} else {
errors.add(UNKNOWN_FIELD(name));
}
}
if (alias.hostName.isEmpty()) {
errors.add(MISSING_FIELD(HOST_NAME));
}
if (alias.aliasList.isEmpty()) {
errors.add(MISSING_FIELD(ALIAS_LIST));
}
aliases.add(alias);
}
if (errors.isEmpty()) {
return new Aliases(aliases);
} else {
throw new RestErrorException(errors);
}
}
/**
* Converts the given {@link ArrayNode} into an {@link Roles} object.
*
* @param array the JSON list of roles
*
* @return the XML serializable list of roles
*
* @throws RestErrorException if the given ArrayNode does not
* represent a list of roles
*/
private static Roles nodeToRoles(final ArrayNode array) {
final List<RoleEntry> roles = new ArrayList<RoleEntry>();
final List<RestError> errors = new ArrayList<RestError>();
final Iterator<JsonNode> elements = array.elements();
while (elements.hasNext()) {
final JsonNode element = elements.next();
final RoleEntry role = new RoleEntry();
if (!element.isObject()) {
errors.add(ILLEGAL_PARAMETER_VALUE(ROLES, element.toString()));
continue;
}
final Iterator<Map.Entry<String, JsonNode>> fields = element.fields();
while (fields.hasNext()) {
final Map.Entry<String, JsonNode> field = fields.next();
final String name = field.getKey();
final JsonNode value = field.getValue();
if (name.equalsIgnoreCase(HOST_NAME)) {
if (value.isTextual()) {
role.hostName = value.asText();
} else {
errors.add(ILLEGAL_PARAMETER_VALUE(HOST_NAME, value.toString()));
}
} else if (name.equalsIgnoreCase(ROLE_LIST)) {
if (value.isArray()) {
final Iterator<JsonNode> roleTypes = value.elements();
while (roleTypes.hasNext()) {
final JsonNode roleType = roleTypes.next();
if (roleType.isTextual()) {
try {
role.roleList.add(ROLE.valueOf(roleType.asText()));
} catch (final IllegalArgumentException e) {
errors.add(
ILLEGAL_PARAMETER_VALUE(ROLE_LIST, roleType.toString()));
}
} else {
errors.add(
ILLEGAL_PARAMETER_VALUE(ROLE_LIST, roleType.toString()));
}
}
} else {
errors.add(ILLEGAL_PARAMETER_VALUE(ROLE_LIST, value.toString()));
}
} else {
errors.add(UNKNOWN_FIELD(name));
}
}
if (role.hostName.isEmpty()) {
errors.add(MISSING_FIELD(HOST_NAME));
}
if (role.roleList.isEmpty()) {
errors.add(MISSING_FIELD(ROLE_LIST));
}
roles.add(role);
}
if (errors.isEmpty()) {
return new Roles(roles);
} else {
throw new RestErrorException(errors);
}
}
}