blob: 7f6f4c2f4f056f30f0a73f1f7e8b0a0370559d13 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.businessobjects.utils;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.mdm.api.base.ServiceNotProvidedException;
import org.eclipse.mdm.api.base.adapter.EntityType;
import org.eclipse.mdm.api.base.adapter.ModelManager;
import org.eclipse.mdm.api.base.model.ContextType;
import org.eclipse.mdm.api.base.model.Entity;
import org.eclipse.mdm.api.base.model.ValueType;
import org.eclipse.mdm.api.base.query.ComparisonOperator;
import org.eclipse.mdm.api.base.query.Condition;
import org.eclipse.mdm.api.base.query.Filter;
import org.eclipse.mdm.api.base.query.FilterItem;
import org.eclipse.mdm.api.dflt.ApplicationContext;
import org.eclipse.mdm.api.dflt.EntityManager;
import org.eclipse.mdm.api.dflt.model.ValueList;
import org.eclipse.mdm.businessobjects.control.FilterParser;
import org.eclipse.mdm.businessobjects.entity.I18NResponse;
import org.eclipse.mdm.businessobjects.entity.MDMEntityResponse;
import org.eclipse.mdm.businessobjects.entity.SearchAttributeResponse;
import org.eclipse.mdm.businessobjects.service.EntityService;
import org.slf4j.LoggerFactory;
import io.vavr.Value;
import io.vavr.collection.Stream;
import io.vavr.control.Try;
public final class ServiceUtils {
private ServiceUtils() {
}
/**
* returns true if the given filter String is a parent filter of the given
* parent type
*
* @param em
* {@link EntityManager} of the data source
* @param filter
* parent filter string to check
* @param parentType
* class of the parent entity
* @return true if the give filter String is a parent filter
*/
public static boolean isParentFilter(ApplicationContext context, String filter,
Class<? extends Entity> parentType) {
ModelManager mm = context.getModelManager()
.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
EntityType et = mm.getEntityType(parentType);
Filter f = FilterParser.parseFilterString(mm.listEntityTypes(), filter);
List<FilterItem> filterItems = f.stream().collect(Collectors.toList());
if (filterItems.size() == 1 && filterItems.get(0).isCondition()) {
Condition c = filterItems.get(0).getCondition();
return et.getIDAttribute().equals(c.getAttribute()) && ComparisonOperator.EQUAL.equals(c.getComparisonOperator());
} else {
return false;
}
}
/**
* returns the business object ID from a parent filter
*
* @param em
* {@link EntityManager} of the data source
* @param filter
* parent filter string
* @param parentType
* parent type to identify the Id attribute name
* @return the extracted business object Id
* @throws IllegalArgumentException if the given filter is not a parent filter,
* this means the filter does not have exactly one condition on the parent's
* ID attribute with {@link ComparisonOperator#EQUAL}
*/
public static String extactIdFromParentFilter(ApplicationContext context, String filter,
Class<? extends Entity> parentType) {
ModelManager mm = context.getModelManager()
.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
EntityType et = mm.getEntityType(parentType);
Filter f = FilterParser.parseFilterString(mm.listEntityTypes(), filter);
List<FilterItem> filterItems = f.stream().collect(Collectors.toList());
if (filterItems.size() == 1 && filterItems.get(0).isCondition()) {
Condition c = filterItems.get(0).getCondition();
if (et.getIDAttribute().equals(c.getAttribute()) && ComparisonOperator.EQUAL.equals(c.getComparisonOperator()))
{
return c.getValue().extract(ValueType.STRING);
}
}
throw new IllegalArgumentException("Cannot extract parent ID. Filter is not a parent filter: " + filter);
}
/**
* Simple workaround for naming mismatch between Adapter and Business object
* names.
*
* @param entityType
* entity type
* @return MDM business object name
*/
public static String workaroundForTypeMapping(EntityType entityType) {
switch (entityType.getName()) {
case "StructureLevel":
return "Pool";
case "MeaResult":
return "Measurement";
case "SubMatrix":
return "ChannelGroup";
case "MeaQuantity":
return "Channel";
default:
return entityType.getName();
}
}
/**
* Builds {@Link Response} from given {@link Entity}
*
* @param entity
* {@link Entity} to build {@link Response} from
* @return the build {@link Response}
*/
public static <T extends Entity> Response buildEntityResponse(T entity, Status status) {
if (entity != null) {
MDMEntityResponse response = new MDMEntityResponse(entity.getClass(), entity);
// TODO anehmer on 2018-02-08: relations should be included in the output
GenericEntity<Object> genEntity = new GenericEntity<Object>(response, response.getClass());
return Response.status(status)
.entity(genEntity)
.type(MediaType.APPLICATION_JSON)
.build();
} else {
return Response.status(Status.NO_CONTENT)
.type(MediaType.APPLICATION_JSON)
.build();
}
}
/**
* Builds {@Link Response} from given {@link Entity}
*
* @param entity
* {@link Entity} to build {@link Response} from
* @return the build {@link Response}
*/
public static <T extends Entity> Response buildEntityResponse(io.vavr.collection.List<T> entities, Status status) {
if (entities.nonEmpty()) {
@SuppressWarnings("unchecked")
Class<T> entityClass = (Class<T>) entities.get()
.getClass();
MDMEntityResponse response = new MDMEntityResponse(entityClass, entities.asJava());
GenericEntity<Object> genEntity = new GenericEntity<Object>(response, response.getClass());
return Response.status(status)
.entity(genEntity)
.type(MediaType.APPLICATION_JSON)
.build();
} else {
return Response.status(Status.NO_CONTENT)
.type(MediaType.APPLICATION_JSON)
.build();
}
}
/**
* Builds {@Link Response} from given {@link Entity}
*
* @param entity
* {@link Entity} to build {@link Response} from
* @return the build {@link Response}
*/
public static <T extends Entity> Response buildErrorResponse(Throwable t, Status status) {
return Response.status(status)
.entity(t)
.type(MediaType.APPLICATION_JSON)
.build();
}
/**
* Converts the given object to a {@link Response} with the given {@link Status}
*
* @param response
* object to convert
* @param status
* {@link Status} of the {@link Response}
* @return the created {@link Response}
*/
public static Response toResponse(Object response, Status status) {
GenericEntity<Object> genEntity = new GenericEntity<Object>(response, response.getClass());
return Response.status(status)
.entity(genEntity)
.type(MediaType.APPLICATION_JSON)
.build();
}
/**
* Return the search attributes for the {@link ValueList} type.
*
* @param sourceNameSupplier
* {@link Value} with the name of the source (MDM {@link Environment}
* name)
* @param entityClass
* {@link Entity} class to get localization data for
* @param entityService
* {@link EntityService} used to get localization data
* @return the result of the delegated request as {@link Response}
*/
public static <T extends Entity> Response buildSearchAttributesResponse(Value<String> sourceNameSupplier,
Class<T> entityClass, EntityService entityService) {
return entityService.getSearchAttributesSupplier(sourceNameSupplier, entityClass)
.map(searchAttributes -> ServiceUtils
.toResponse(new SearchAttributeResponse(searchAttributes.toJavaList()), Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER)
.getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* Return the localized type and attributes for the {@link Entity} type.
*
* @param sourceNameSupplier
* {@link Value} with the name of the source (MDM {@link Environment}
* name)
* @param entityClass
* {@link Entity} class to get localization data for
* @param entityService
* {@link EntityService} used to get localization data
* @return the {@link Response} with the localized data
*/
public static <T extends Entity> Response buildLocalizationResponse(Value<String> sourceNameSupplier,
Class<T> entityClass, EntityService entityService) {
return Try
.of(() -> ServiceUtils.toResponse(new I18NResponse(
entityService.getLocalizeTypeSupplier(sourceNameSupplier, entityClass)
.get()
.toJavaMap(),
entityService.getLocalizeAttributesSupplier(sourceNameSupplier, entityClass)
.get()
.toJavaMap()),
Status.OK))
.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER)
.getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
}
/**
* A Response representing a server error.
*/
public final static Response SERVER_ERROR_RESPONSE = Response.serverError()
.build();
/**
* Builds an error response based on an exception to be sent to the client
*/
public static final Function<? super Throwable, Response> ERROR_RESPONSE_SUPPLIER = (e) -> {
LoggerFactory.getLogger(ServiceUtils.class)
.error(e.getMessage(), e);
// TODO anehmer on 2017-11-22: customize status according to exception
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity(e.getStackTrace()[0].getClassName() + "." + e.getStackTrace()[0].getMethodName() + ": "
+ e.getMessage())
.type(MediaType.APPLICATION_JSON)
.build();
};
/**
* Returns a {@link Try} to get the {@link ContextType} for the provided name
*
* @param contextTypeName
* name of the {@link ContextType}
* @return a {@link Try} of the {@link ContextType} for the given name
*/
public static Try<ContextType> getContextTypeSupplier(String contextTypeName) {
return Stream.of(ContextType.values())
.filter(contextType -> contextType.name()
.equals(contextTypeName.toUpperCase()))
.toTry();
}
}