io.vertigo.ui.core.ViewContext Maven / Gradle / Ivy
/**
* 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