blob: 3d0e7a580432119054cd0f7c6fc361ff972a1437 [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.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.eclipse.mdm.api.base.model.EnumRegistry;
import org.eclipse.mdm.api.base.model.Enumeration;
import org.eclipse.mdm.api.base.model.EnumerationValue;
import org.eclipse.mdm.api.base.model.FileLink;
import org.eclipse.mdm.api.base.model.MimeType;
import org.eclipse.mdm.api.base.model.Value;
import org.eclipse.mdm.api.base.model.ValueType;
import org.eclipse.mdm.businessobjects.control.MDMEntityAccessException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import io.vavr.control.Option;
/**
* Serializer for values.
*/
public final class Serializer {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
private Serializer() {
}
public static Object serializeValue(Value value) {
if (value.getValueType().isDate()) {
return formatter.format(value.extract());
} else if (value.getValueType().isFileLink()) {
return serializeFileLink(value.extract(ValueType.FILE_LINK));
} else if (value.getValueType().isFileLinkSequence()) {
return Stream.of(value.extract(ValueType.FILE_LINK_SEQUENCE)).map(Serializer::serializeFileLink)
.collect(Collectors.toList());
} else {
return value.extract().toString();
}
}
public static Map<String, String> serializeFileLink(FileLink fileLink) {
return ImmutableMap.of("remotePath", fileLink.getRemotePath(), "mimeType", fileLink.getMimeType().toString(),
"description", fileLink.getDescription());
}
public static LocalDateTime parseDate(String value) {
return LocalDateTime.from(formatter.parse(value));
}
/**
* Applies the given newValue, that has to be deserialized, to the given value
* object re-setting the wrapped value
*
* @param value value object to apply newValue to
* @param newValue object that is to be parsed first and then is applied to the
* given value
*/
public static void applyValue(org.eclipse.mdm.api.base.model.Value value, Object newValue) {
value.set(deserializeValue(value, newValue));
}
/**
* Deserialize the given newValue, using the type information and - in case of
* enumerations - the value's to determine the enumeration name
*
* @param value value providing type information, enumeration name etc.
* @param newValue the value to be deserialized
* @return the deserialized value
*/
public static Object deserializeValue(Value value, Object newValue) {
ValueType<?> type = value.getValueType();
if (type.isBoolean()) {
try {
if (newValue instanceof Number) {
return ((Number) newValue).intValue() == 1;
} else if (newValue instanceof String) {
return Integer.parseInt((String) newValue) == 1;
}
} catch (NumberFormatException e) {
if (newValue instanceof String) {
return Boolean.valueOf((String) newValue);
}
}
} else if (type.isByte()) {
if (newValue instanceof Number) {
return (byte) ((Number) newValue).intValue();
} else if (newValue instanceof String) {
return Byte.parseByte((String) newValue);
}
} else if (type.isShort()) {
if (newValue instanceof Number) {
return (short) ((Number) newValue).intValue();
} else if (newValue instanceof String) {
return Short.parseShort((String) newValue);
}
} else if (type.isInteger()) {
if (newValue instanceof Number) {
return ((Number) newValue).intValue();
} else if (newValue instanceof String) {
return Integer.parseInt((String) newValue);
}
} else if (type.isLong()) {
if (newValue instanceof Number) {
return ((Number) newValue).longValue();
} else if (newValue instanceof String) {
return Long.parseLong((String) newValue);
}
} else if (type.isFloat()) {
if (newValue instanceof Number) {
return ((Number) newValue).floatValue();
} else if (newValue instanceof String) {
return Float.parseFloat((String) newValue);
}
} else if (type.isDouble()) {
if (newValue instanceof Number) {
return ((Number) newValue).doubleValue();
} else if (newValue instanceof String) {
return Double.parseDouble((String) newValue);
}
} else if (type.isDate()) {
if (newValue instanceof Number) {
return LocalDateTime.ofEpochSecond((long) newValue, 0, ZoneOffset.UTC);
} else if (newValue instanceof String) {
if (Strings.isNullOrEmpty((String) newValue)) {
return null;
} else {
return Serializer.parseDate((String) newValue);
}
}
} else if (type.isEnumeration()) {
// find enumeration and the enumeration value
// re-map ValidFlag-VersionState
Option<Enumeration<?>> enumOption = Option.of(EnumRegistry.getInstance()
.get(value.getName().equals("ValidFlag") ? "VersionState" : value.getName()));
// if the enumeration name is not the value name -> search all enums for the
// given newValue
if (enumOption.isEmpty()) {
String[] enumNames = { EnumRegistry.INTERPOLATION, EnumRegistry.AXIS_TYPE,
EnumRegistry.SEQUENCE_REPRESENTATION, EnumRegistry.TYPE_SPECIFICATION, EnumRegistry.SCALAR_TYPE,
EnumRegistry.VERSION_STATE };
for (String enumName : enumNames) {
Enumeration<?> e = EnumRegistry.getInstance().get(enumName);
EnumerationValue enumValue = e.valueOf(newValue.toString());
if (enumValue != null) {
enumOption = Option.of(e);
break;
}
}
}
return enumOption
// get enumValue
.map(enumeration -> enumeration.valueOf((String) newValue))
// if enumValue is not found, null is returned
.filter(Objects::nonNull).onEmpty(() -> {
throw new IllegalArgumentException("EnumerationValue [" + newValue
+ "] not found in Enumeration [" + value.getName() + "]");
}).get();
} else if (type.isFileLink()) {
if (newValue instanceof FileLink) {
return newValue;
} else {
return deserializeFileLink(newValue);
}
} else if (type.isFileLinkSequence()) {
if (newValue instanceof FileLink[]) {
return newValue;
} else if (newValue instanceof List && !((List<?>) newValue).isEmpty()) {
List<FileLink> fileLinks = new ArrayList<>();
for (Object o : (List<?>) newValue) {
fileLinks.add(deserializeFileLink(o));
}
return fileLinks.toArray(new FileLink[0]);
}
} else if (type.isIntegerSequence()) {
return ArrayUtils.toPrimitive(((ArrayList<?>) newValue).toArray(new Integer[0]));
}
// TODO mkoller on 2018-12-06: Missing ValueTypes: ByteStream, Blob,
// FloatComplex, DoubleComplex, Enumeration and all sequence
// ValueTypes
// anehmer: added Enumeration
return newValue;
}
private static FileLink deserializeFileLink(Object newValue) {
if (newValue instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) newValue;
String remotePath = Objects.toString(map.get("remotePath"));
MimeType mimeType = new MimeType(Objects.toString(map.get("mimeType")));
String description = Objects.toString(map.get("description"));
return FileLink.newRemote(remotePath, mimeType, description);
}
throw new MDMEntityAccessException("Cannot deserialize FILE_LINK: " + newValue);
}
}