All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertigo.ui.core.MapUiObject Maven / Gradle / Ivy

There is a newer version: 4.2.0
Show newest version
/**
 * vertigo - application development platform
 *
 * Copyright (C) 2013-2021, Vertigo.io, [email protected]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.vertigo.ui.core;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import io.vertigo.core.lang.Assertion;
import io.vertigo.core.lang.BasicType;
import io.vertigo.core.node.Node;
import io.vertigo.core.util.StringUtil;
import io.vertigo.datamodel.smarttype.SmartTypeManager;
import io.vertigo.datamodel.smarttype.definitions.SmartTypeDefinition;
import io.vertigo.datamodel.structure.definitions.DtField;
import io.vertigo.datamodel.structure.definitions.FormatterException;
import io.vertigo.datamodel.structure.model.DtObject;
import io.vertigo.datamodel.structure.util.DtObjectUtil;
import io.vertigo.ui.core.encoders.EncoderDate;
import io.vertigo.vega.engines.webservice.json.VegaUiObject;

/**
 * Objet d'IHM, fournit les valeurs formatés des champs de l'objet métier sous-jacent.
 * Implements Map car struts poste des String[] que l'on reconverti en String (on prend le premier).
 *
 * @author pchretien, npiedeloup
 * @param  Type de DtObject représenté par cet Input
 */
public final class MapUiObject extends VegaUiObject implements Map {
	private static final long serialVersionUID = -4639050257543017072L;
	private static final String SMART_TYPE_MULTIPLE_IDS = "STyMultipleIds";
	private static final String[] EMPTY_INPUT = new String[0];

	/**
	 * Constructor.
	 * @param serverSideDto DtObject
	 */
	public MapUiObject(final D serverSideDto) {
		this(serverSideDto, (D) DtObjectUtil.createDtObject(DtObjectUtil.findDtDefinition(serverSideDto)), Collections.emptySet());
	}

	/**
	 * Constructor.
	 * @param serverSideDto  DtObject
	 * @param inputDto Input DtObject
	 * @param modifiedFields List of modified fields
	 */
	public MapUiObject(final D serverSideDto, final D inputDto, final Set modifiedFields) {
		super(inputDto, modifiedFields);
		setServerSideObject(serverSideDto);
	}

	/** {@inheritDoc} */
	@Override
	public Serializable get(final Object key) {
		final String keyFieldName = String.class.cast(key);
		Assertion.check()
				.isNotBlank(keyFieldName)
				.isTrue(Character.isLowerCase(keyFieldName.charAt(0)) && !keyFieldName.contains("_"), "Le nom du champs doit-être en camelCase ({0}).", keyFieldName);
		//-----
		final DtField dtField = getDtField(keyFieldName);
		if (dtField.getCardinality().hasMany()) {
			return getInputValue(keyFieldName);
		}
		if (isMultiple(dtField)) {
			final String strValue = getSingleInputValue(keyFieldName);
			return parseMultipleValue(strValue);
		} else if (isBoolean(dtField)) {
			final Boolean value = getTypedValue(keyFieldName, Boolean.class);
			return value != null ? String.valueOf(value) : null;
		} else {
			return getSingleInputValue(keyFieldName);
		}
	}

	/** {@inheritDoc} */
	@Override
	public String put(final String fieldName, final Serializable value) {
		Assertion.check()
				.isNotBlank(fieldName)
				.isNotNull(value, "La valeur formatée ne doit pas être null mais vide ({0})", fieldName)
				.isTrue(value instanceof String || value instanceof String[], "Les données saisies doivent être de type String ou String[] ({0} : {1})", fieldName, value.getClass());
		//-----
		final DtField dtField = getDtField(fieldName);
		if (dtField.getCardinality().hasMany()) {
			if (value instanceof String[]) {
				setInputValue(fieldName, (String[]) value);
			} else {
				if (StringUtil.isBlank((String) value)) {
					// single empty value means a reset of the field. An array is never null so we put an empty array.
					setInputValue(fieldName, EMPTY_INPUT);
				} else {
					setInputValue(fieldName, (String) value);
				}
			}
		} else {
			String strValue;
			if (isMultiple(dtField)) {
				strValue = formatMultipleValue(value);
			} else if (isAboutDate(dtField)) {
				strValue = requestParameterToString(value);
				try {
					final SmartTypeManager smartTypeManager = Node.getNode().getComponentSpace().resolve(SmartTypeManager.class);
					final Object typedValue = EncoderDate.stringToValue(strValue, dtField.getSmartTypeDefinition().getBasicType());
					strValue = smartTypeManager.valueToString(dtField.getSmartTypeDefinition(), typedValue);// we fall back in the normal case if everything is right -> go to formatter
				} catch (final FormatterException e) {
					// do nothing we keep the input value
				}
			} else {
				strValue = requestParameterToString(value);
			}
			setInputValue(fieldName, strValue);
		}
		return null;
	}

	private static String requestParameterToString(final Serializable value) {
		return value instanceof String[] ? ((String[]) value)[0] : (String) value;
	}

	private static String formatMultipleValue(final Object values) {
		if (values instanceof String) {
			// just one
			return (String) values;
		}
		// we are a String array
		return Arrays
				.stream((String[]) values)
				.collect(Collectors.joining(";"));
	}

	private static String[] parseMultipleValue(final String strValue) {
		return strValue.split(";");
	}

	private static boolean isMultiple(final DtField dtField) {
		return SMART_TYPE_MULTIPLE_IDS.equals(dtField.getSmartTypeDefinition().getName());
	}

	private static boolean isBoolean(final DtField dtField) {
		return dtField.getSmartTypeDefinition().getScope().isPrimitive() && dtField.getSmartTypeDefinition().getBasicType() == BasicType.Boolean;
	}

	private static boolean isAboutDate(final DtField dtField) {
		return dtField.getSmartTypeDefinition().getScope().isPrimitive() && dtField.getSmartTypeDefinition().getBasicType().isAboutDate();
	}

	/** {@inheritDoc} */
	@Override
	public boolean containsKey(final Object arg0) {
		return fieldIndex.contains(arg0);
	}

	/** Non implémenté. */
	@Override
	public void clear() {
		throw new UnsupportedOperationException();
	}

	/** Non implémenté. */
	@Override
	public boolean containsValue(final Object arg0) {
		throw new UnsupportedOperationException();
	}

	/** Implémentation : TODO : see if it's ok */
	@Override
	public Set> entrySet() {
		return fieldIndex
				.stream()
				.map(key -> new AbstractMap.SimpleEntry<>(key, get(key)))
				.collect(Collectors.toSet());
	}

	/** {@inheritDoc} */
	@Override
	public boolean isEmpty() {
		return fieldIndex.isEmpty();
	}

	/** {@inheritDoc} */
	@Override
	public Set keySet() {
		return fieldIndex;
	}

	/** Not supported. */
	@Override
	public void putAll(final Map arg0) {
		throw new UnsupportedOperationException();
	}

	/** Not supported. */
	@Override
	public String remove(final Object arg0) {
		throw new UnsupportedOperationException();
	}

	/** {@inheritDoc} */
	@Override
	public int size() {
		return fieldIndex.size();
	}

	/** Not supported. */
	@Override
	public Collection values() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Return the typed value.
	 * @param fieldName Field
	 * @return Typed value
	 */
	public Serializable getTypedValue(final String fieldName) {
		return getTypedValue(fieldName, Serializable.class);
	}

	/**
	 * Return a Serializable Map for client.
	 * @param fieldsForClient List of fields
	 * @param valueTransformers Map of transformers
	 * @return HashMap (needed for Serializable)
	 */
	public HashMap mapForClient(final Set fieldsForClient, final Map> valueTransformers) {
		final Set filterSet = new HashSet<>();
		filterSet.addAll(fieldsForClient);
		if (fieldsForClient.contains("*")) {
			filterSet.remove("*");
			filterSet.addAll(fieldIndex);
		}
		final HashMap mapForClient = new HashMap<>(filterSet.size());
		filterSet
				.forEach(key -> mapForClient.put(key, getValueForClient(key, valueTransformers.get(key))));
		return mapForClient;

	}

	private Serializable getValueForClient(final String fieldKey, final Function valueTransformer) {
		final boolean hasFormatModifier = fieldKey.endsWith("_fmt");
		final boolean hasDisplayModifier = fieldKey.endsWith("_display");
		final String fieldName;
		if (hasFormatModifier) {
			fieldName = fieldKey.substring(0, fieldKey.length() - "_fmt".length());
		} else {
			fieldName = hasDisplayModifier ? fieldKey.substring(0, fieldKey.length() - "_display".length()) : fieldKey;
		}
		//--- if error
		if (hasFormatError(fieldName)) {
			return getInputValue(fieldName);
		}
		//--- good data
		if (hasFormatModifier) {
			return getFormattedValue(fieldName);
		}
		if (valueTransformer != null) {
			return valueTransformer.apply(getTypedValue(fieldName, Serializable.class));
		}
		return getEncodedValue(fieldName);

	}

	private Serializable getEncodedValue(final String key) {
		final String keyFieldName = String.class.cast(key);
		Assertion.check()
				.isNotBlank(keyFieldName)
				.isTrue(Character.isLowerCase(keyFieldName.charAt(0)) && !keyFieldName.contains("_"), "Le nom du champs doit-être en camelCase ({0}).", keyFieldName);
		//---
		final DtField dtField = getDtField(keyFieldName);
		final SmartTypeDefinition smartType = dtField.getSmartTypeDefinition();
		if (smartType.getScope().isPrimitive()) {
			if (isAboutDate(dtField)) {
				final Serializable value = getTypedValue(keyFieldName, Serializable.class);
				return EncoderDate.valueToString(value, dtField.getSmartTypeDefinition().getBasicType());// encodeValue
			} else if (isMultiple(dtField)) {
				final String value = getTypedValue(keyFieldName, String.class);
				return value != null ? parseMultipleValue(value) : new String[0];
			}
		}
		return getTypedValue(keyFieldName, Serializable.class);
	}

	private String getFormattedValue(final String keyFieldName) {
		final SmartTypeManager smartTypeManager = Node.getNode().getComponentSpace().resolve(SmartTypeManager.class);
		final DtField dtField = getDtField(keyFieldName);
		final Serializable typedValue = getEncodedValue(keyFieldName);
		return typedValue != null ? smartTypeManager.valueToString(dtField.getSmartTypeDefinition(), typedValue) : null;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy