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

io.vertigo.ui.core.ViewContext 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.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import com.google.gson.reflect.TypeToken;

import io.vertigo.core.lang.Assertion;
import io.vertigo.datafactory.collections.definitions.FacetDefinition;
import io.vertigo.datafactory.collections.model.Facet;
import io.vertigo.datafactory.collections.model.FacetValue;
import io.vertigo.datafactory.collections.model.FacetedQuery;
import io.vertigo.datafactory.collections.model.FacetedQueryResult;
import io.vertigo.datafactory.collections.model.SelectedFacetValues;
import io.vertigo.datafactory.search.model.SearchQuery;
import io.vertigo.datamodel.structure.definitions.DtDefinition;
import io.vertigo.datamodel.structure.definitions.DtFieldName;
import io.vertigo.datamodel.structure.model.DtList;
import io.vertigo.datamodel.structure.model.DtListURIForMasterData;
import io.vertigo.datamodel.structure.model.DtObject;
import io.vertigo.datamodel.structure.model.Entity;
import io.vertigo.datamodel.structure.util.DtObjectUtil;
import io.vertigo.datastore.filestore.model.FileInfoURI;
import io.vertigo.vega.engines.webservice.json.JsonEngine;
import io.vertigo.vega.webservice.model.UiList;
import io.vertigo.vega.webservice.model.UiObject;
import io.vertigo.vega.webservice.validation.DefaultDtObjectValidator;
import io.vertigo.vega.webservice.validation.DtObjectValidator;
import io.vertigo.vega.webservice.validation.UiMessageStack;
import io.vertigo.vega.webservice.validation.ValidationUserException;

/**
 * Liste des couples (clé, object) enregistrés.
 * @author npiedeloup
 */
public final class ViewContext implements Serializable {

	private static final long serialVersionUID = -8237448155016161135L;

	/** Clée de l'id de context dans le context. */
	public static final ViewContextKey CTX = ViewContextKey.of("CTX");

	private final Set modifiedKeys = new HashSet<>();

	private final ViewContextMap viewContextMap;

	private final JsonEngine jsonEngine;

	public ViewContext(final ViewContextMap viewContextMap, final JsonEngine jsonEngine) {
		Assertion.check()
				.isNotNull(viewContextMap)
				.isNotNull(jsonEngine);
		//---
		this.viewContextMap = viewContextMap;
		this.jsonEngine = jsonEngine;
	}

	/* ================================== Life cycle =====================================*/

	/**
	 * @return Clé de ce context
	 */
	public String getId() {
		return getString(CTX);
	}

	public void setInputCtxId(final String ctxId) {
		viewContextMap.put(ViewContextMap.INPUT_CTX, ctxId);
	}

	public void setCtxId() {
		viewContextMap.put(CTX.get(), UUID.randomUUID().toString());
	}

	/**
	 * Génère un nouvel Id et passe le context en modifiable.
	 */
	public void makeModifiable() {
		viewContextMap.makeModifiable();
	}

	/**
	 * passe le context en non-modifiable.
	 */
	public void makeUnmodifiable() {
		viewContextMap.makeUnmodifiable();
		modifiedKeys.add(CTX.get());
	}

	/**
	 * Mark this context as Dirty : shouldn't be stored and keep old id.
	 */
	public void markDirty() {
		viewContextMap.markDirty();
	}

	/**
	 * @return if context dirty : shouldn't be stored and keep old id
	 */
	public boolean isDirty() {
		return viewContextMap.isDirty();
	}

	public ViewContextMap asMap() {
		return viewContextMap;
	}

	public ViewContextMap asUpdatesMap() {
		return viewContextMap.getFilteredViewContext(Optional.of(modifiedKeys));
	}

	public String getFilteredViewContextAsJson() {
		return jsonEngine.toJson(viewContextMap.getFilteredViewContext(Optional.empty()));
	}

	public void markModifiedKeys(final ViewContextKey... newModifiedKeys) {
		modifiedKeys.addAll(Arrays.stream(newModifiedKeys)
				.map(ViewContextKey::get)
				.collect(Collectors.toSet()));
	}

	public void markModifiedKeys(final String... newModifiedKeys) {
		modifiedKeys.addAll(Arrays.asList(newModifiedKeys));
	}

	/* ================================== Map =====================================*/

	public Serializable get(final Object key) {
		Object sKey = key;
		if (key instanceof ViewContextKey) {
			sKey = ((ViewContextKey) key).get();
		}
		return viewContextMap.get(sKey);

	}

	/** {@inheritDoc} */
	public boolean containsKey(final Object key) {
		if (key instanceof ViewContextKey) {
			return viewContextMap.containsKey(((ViewContextKey) key).get());
		}
		return viewContextMap.containsKey(key);
	}

	/**
	 * @param uiObject UiObject recherché
	 * @return Clé de context de l'élément (null si non trouvé)
	 */
	public String findKey(final UiObject uiObject) {
		return viewContextMap.findKey(uiObject);
	}

	/**
	 * @param dtObject DtObject recherché
	 * @return Clé de context de l'élément (null si non trouvé)
	 */
	public String findKey(final DtObject dtObject) {
		return viewContextMap.findKey(dtObject);
	}

	private Serializable put(final ViewContextKey key, final Serializable value) {
		modifiedKeys.add(key.get());
		return viewContextMap.put(key.get(), value);
	}

	/* ================================== ContextRef =====================================*/

	/**
	 * @param key Clé de context
	 * @return UiObject du context
	 */
	public  void publishRef(final ViewContextKey key, final O value) {
		put(key, value);
	}

	/**
	 * @param key Clé de context
	 * @return UiObject du context
	 */
	public  void publishTypedRef(final ViewContextKey key, final O value, final Type paramType) {
		viewContextMap.addTypeForKey(key.get(), paramType);
		put(key, value);
	}

	/**
	 * @param key Clé de context
	 * @return UiObject du context
	 */
	public  UiObject getUiObject(final ViewContextKey key) {
		return (UiObject) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return UiList du context
	 */
	public  UiList getUiList(final ViewContextKey key) {
		return (UiList) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return UiListModifiable du context
	 */
	public  BasicUiListModifiable getUiListModifiable(final ViewContextKey key) {
		return (BasicUiListModifiable) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return String du context
	 */
	public String getString(final ViewContextKey key) {
		final Object value = get(key);
		if (value instanceof String[] && ((String[]) value).length > 0) {
			//Struts set des String[] au lieu des String
			//on prend le premier
			return ((String[]) value)[0];
		}
		return (String) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return Long du context
	 */
	public Long getLong(final ViewContextKey key) {
		return (Long) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return Integer du context
	 */
	public Integer getInteger(final ViewContextKey key) {
		return (Integer) get(key);
	}

	/**
	 * @param key Clé de context
	 * @return Boolean du context
	 */
	public Boolean getBoolean(final ViewContextKey key) {
		return (Boolean) get(key);
	}

	/* ================================ ContextForm ==================================*/
	/**
	 * Ajoute un objet de type form au context.
	 * @param dto Objet à publier
	 */
	public  void publishDto(final ViewContextKey contextKey, final O dto) {
		final UiObject strutsUiObject = new MapUiObject<>(dto);
		strutsUiObject.setInputKey(contextKey.get());
		put(contextKey, strutsUiObject);
	}

	/**
	 * Vérifie les erreurs de l'objet. Celles-ci sont ajoutées à l'uiMessageStack si nécessaire.
	 */
	public  void checkDtoErrors(final ViewContextKey contextKey, final UiMessageStack uiMessageStack) {
		getUiObject(contextKey).checkFormat(uiMessageStack);
		if (uiMessageStack.hasErrors()) {
			throw new ValidationUserException();
		}
	}

	/**
	 * @return objet métier valid�. Lance une exception si erreur.
	 */
	public  O readDto(final ViewContextKey contextKey, final UiMessageStack uiMessageStack) {
		return readDto(contextKey, new DefaultDtObjectValidator<>(), uiMessageStack);
	}

	/**
	 * @return objet métier validé. Lance une exception si erreur.
	 */
	public  O readDto(final ViewContextKey contextKey, final DtObjectValidator validator, final UiMessageStack uiMessageStack) {
		checkDtoErrors(contextKey, uiMessageStack);
		// ---
		final O validatedDto = getUiObject(contextKey).mergeAndCheckInput(Collections.singletonList(validator), uiMessageStack);
		if (uiMessageStack.hasErrors()) {
			throw new ValidationUserException();
		}
		return validatedDto;
	}

	/* ================================ ContextList ==================================*/

	/**
	 * Ajoute une liste au context.
	 * @param dtList List à publier
	 */
	private  void publishDtList(final ViewContextKey contextKey, final Optional> keyFieldNameOpt, final DtList dtList, final boolean modifiable) {
		if (modifiable) {
			put(contextKey, new BasicUiListModifiable<>(dtList, contextKey.get()));
		} else {
			put(contextKey, new UiListUnmodifiable<>(dtList, keyFieldNameOpt));
		}
	}

	/**
	 * Ajoute une liste au context.
	 * @param dtList List à publier
	 */
	public  void publishDtList(final ViewContextKey contextKey, final DtFieldName keyFieldName, final DtList dtList) {
		publishDtList(contextKey, Optional.of(keyFieldName), dtList, false);
	}

	/**
	 * Ajoute une liste au context.
	 * @param dtList List à publier
	 */
	public  void publishDtList(final ViewContextKey contextKey, final DtList dtList) {
		publishDtList(contextKey, Optional.empty(), dtList, false);
	}

	/**
	 * @return List des objets métiers validée. Lance une exception si erreur.
	 */
	public  DtList readDtList(final ViewContextKey contextKey, final DtObjectValidator validator, final UiMessageStack uiMessageStack) {
		return ((UiListUnmodifiable) getUiList(contextKey)).mergeAndCheckInput(Collections.singletonList(validator), uiMessageStack);
	}

	/**
	 * @return List des objets métiers validée. Lance une exception si erreur.
	 */
	public  DtList readDtList(final ViewContextKey contextKey, final UiMessageStack uiMessageStack) {
		return readDtList(contextKey, new DefaultDtObjectValidator<>(), uiMessageStack);
	}

	/* ================================ ContextListModifiable ==================================*/

	/**
	 * Ajoute une liste au context.
	 * @param dtList List à publier
	 */
	public  void publishDtListModifiable(final ViewContextKey contextKey, final DtList dtList) {
		publishDtList(contextKey, Optional.empty(), dtList, true);
	}

	/**
	 * Vérifie les erreurs de la liste. Celles-ci sont ajoutées à l'uiMessageStack si nécessaire.
	 */
	public  void checkDtListErrors(final ViewContextKey contextKey, final UiMessageStack uiMessageStack) {
		getUiListModifiable(contextKey).checkFormat(uiMessageStack);
		if (uiMessageStack.hasErrors()) {
			throw new ValidationUserException();
		}
	}

	/**
	 * @return List des objets métiers validée. Lance une exception si erreur.
	 */
	public  DtList readDtListModifiable(final ViewContextKey contextKey, final UiMessageStack uiMessageStack) {
		return readDtListModifiable(contextKey, new DefaultDtObjectValidator<>(), uiMessageStack);
	}

	/**
	 * @return List des objets métiers validée. Lance une exception si erreur.
	 */
	public  DtList readDtListModifiable(final ViewContextKey contextKey, final DtObjectValidator validator, final UiMessageStack uiMessageStack) {
		checkDtListErrors(contextKey, uiMessageStack);
		// ---
		final DtList validatedList = ((BasicUiListModifiable) getUiListModifiable(contextKey)).mergeAndCheckInput(Collections.singletonList(validator), uiMessageStack);
		if (uiMessageStack.hasErrors()) {
			throw new ValidationUserException();
		}
		return validatedList;
	}

	/* ================================ ContextMdList ==================================*/

	/**
	 * Publie une liste de référence.
	 * @param contextKey Context key
	 * @param entityClass Class associée
	 * @param code Code
	 */
	public  void publishMdl(final ViewContextKey contextKey, final Class entityClass, final String code) {
		final DtDefinition dtDefinition = DtObjectUtil.findDtDefinition(entityClass);
		put(contextKey, new UiMdList(new DtListURIForMasterData(dtDefinition, code)));
	}

	/* ================================ FileInfo ==================================*/

	/**
	 * Get UI file uri.
	 * @param contextKey Context key
	 */
	public Optional getFileInfoURI(final ViewContextKey contextKey) {
		final ArrayList list = getFileInfoURIs(contextKey);
		Assertion.check().isTrue(list.size() <= 1, "Can't list a list of {0} elements to Option", list.size());
		return list.isEmpty() ? Optional.empty() : Optional.of(list.iterator().next());
	}

	/**
	 * Get UI file info uri list.
	 * @param contextKey Context key
	 */
	public ArrayList getFileInfoURIs(final ViewContextKey contextKey) {
		return (ArrayList) get(contextKey);
	}

	/**
	 * Publish file's info.
	 * @param contextKey Context key
	 * @param fileInfo file's info
	 */
	public void publishFileInfoURI(final ViewContextKey contextKey, final FileInfoURI fileInfoURI) {
		final ArrayList list = new ArrayList<>();
		if (fileInfoURI != null) {
			list.add(fileInfoURI);
		}
		publishFileInfoURIs(contextKey, list);
	}

	/**
	 * Publish list of file's info.
	 * @param contextKey Context key
	 * @param fileInfos list of file's info.
	 */
	public void publishFileInfoURIs(final ViewContextKey contextKey, final ArrayList fileInfoURIs) {
		viewContextMap.addTypeForKey(contextKey.get(), TypeToken.getParameterized(ArrayList.class, FileInfoURI.class).getType());
		put(contextKey, fileInfoURIs);
	}

	/* ================================ FacetedQueryResult ==================================*/

	/**
	 * Publie une FacetedQueryResult.
	 * @param contextKey Context key
	 * @param keyFieldName Id's fieldName
	 * @param facetedQueryResult Result
	 */
	public  void publishFacetedQueryResult(final ViewContextKey> contextKey,
			final DtFieldName keyFieldName, final FacetedQueryResult facetedQueryResult, final ViewContextKey criteriaContextKey) {
		if (facetedQueryResult.getClusterFacetDefinition().isPresent()) {
			publishDtList(() -> contextKey.get() + "_list", Optional.of(keyFieldName), new DtList(facetedQueryResult.getDtList().getDefinition()), false);
			put(() -> contextKey.get() + "_cluster", translateClusters(facetedQueryResult, Optional.of(keyFieldName)));
			//publishClustersList(contextKey.get() + "_list", facetedQueryResult, Optional.of(keyFieldName));
		} else {
			publishDtList(() -> contextKey.get() + "_list", Optional.of(keyFieldName), facetedQueryResult.getDtList(), false);
			put(() -> contextKey.get() + "_cluster", new HashMap<>());
		}
		put(() -> contextKey.get() + "_facets", translateFacets(facetedQueryResult.getFacets()));

		final FacetedQuery facetedQuery = facetedQueryResult.getSource().getFacetedQuery().get();
		put(() -> contextKey.get() + "_selectedFacets", new UiSelectedFacetValues(
				facetedQuery.getSelectedFacetValues(),
				facetedQuery.getDefinition().getFacetDefinitions()
						.stream()
						.map(FacetDefinition::getName)
						.collect(Collectors.toList())));
		put(() -> contextKey.get() + "_totalcount", facetedQueryResult.getCount());
		put(() -> contextKey.get() + "_criteriaContextKey", criteriaContextKey.get());
	}

	private  ArrayList translateClusters(final FacetedQueryResult facetedQueryResult, final Optional> keyFieldNameOpt) {
		//if it's a cluster add data's cluster
		final Map> clusters = facetedQueryResult.getClusters();
		final ArrayList jsonCluster = new ArrayList<>();
		for (final Entry> cluster : clusters.entrySet()) {
			final DtList dtList = cluster.getValue();
			if (!dtList.isEmpty()) {
				final ClusterUiList clusterElement = new ClusterUiList(
						dtList, keyFieldNameOpt,
						cluster.getKey().getCode(),
						cluster.getKey().getLabel().getDisplay(),
						dtList.getDefinition().getClassSimpleName(),
						getFacetCount(cluster.getKey(), facetedQueryResult));
				jsonCluster.add(clusterElement);
			}
		}
		return jsonCluster;

	}
	/* private  void publishClustersList(final String prefix, final FacetedQueryResult facetedQueryResult, final Optional> keyFieldNameOpt) {
			//if it's a cluster add data's cluster
			final Map> clusters = facetedQueryResult.getClusters();
			for (final Entry> cluster : clusters.entrySet()) {
				final DtList dtList = cluster.getValue();
				if (!dtList.isEmpty()) {
					publishDtList(() -> prefix + "_" + cluster.getKey().getCode(), keyFieldNameOpt, dtList, false);
				}
			}
		}*/

	private static Long getFacetCount(final FacetValue key, final FacetedQueryResult facetedQueryResult) {
		final FacetDefinition clusterFacetDefinition = facetedQueryResult.getClusterFacetDefinition().get();
		return facetedQueryResult.getFacets()
				.stream()
				.filter(facet -> clusterFacetDefinition.equals(facet.getDefinition()))
				.flatMap(facet -> facet.getFacetValues().entrySet().stream())
				.filter(facetEntry -> key.getCode().equals(facetEntry.getKey().getCode()))
				.findFirst()
				.orElseThrow(() -> new IllegalArgumentException("Can't found facet for search cluster"))
				.getValue();
	}

	private static ArrayList translateFacets(final List facets) {
		final ArrayList facetsList = new ArrayList<>();
		for (final Facet facet : facets) {
			final ArrayList> facetValues = new ArrayList<>();
			for (final Entry entry : facet.getFacetValues().entrySet()) {
				if (entry.getValue() > 0) {
					final HashMap facetValue = new HashMap<>();
					facetValue.put("code", entry.getKey().getCode());
					facetValue.put("count", entry.getValue());
					facetValue.put("label", entry.getKey().getLabel().getDisplay());
					facetValues.add(facetValue);
				}
			}
			final HashMap facetAsMap = new HashMap<>();
			facetAsMap.put("code", facet.getDefinition().getName());
			facetAsMap.put("multiple", facet.getDefinition().isMultiSelectable());
			facetAsMap.put("label", facet.getDefinition().getLabel().getDisplay());
			facetAsMap.put("values", facetValues);
			facetsList.add(facetAsMap);
		}
		return facetsList;
	}

	/**
	 * Returns selectedFacetValues of a given facetedQuery.
	 * @param contextKey Context key
	 * @return selectedFacetValues
	 */
	public  SelectedFacetValues getSelectedFacetValues(final ViewContextKey> contextKey) {
		return ((UiSelectedFacetValues) get(contextKey.get() + "_selectedFacets")).toSelectedFacetValues();
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy