io.vertigo.ui.impl.springmvc.controller.AbstractVSpringMvcController Maven / Gradle / Ivy
/**
* vertigo - simple java starter
*
* Copyright (C) 2013-2019, vertigo-io, KleeGroup, [email protected] (http://www.kleegroup.com)
* KleeGroup, Centre d'affaire la Boursidiere - BP 159 - 92357 Le Plessis Robinson Cedex - France
*
* 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.impl.springmvc.controller;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import io.vertigo.commons.transaction.VTransactionManager;
import io.vertigo.commons.transaction.VTransactionWritable;
import io.vertigo.dynamo.kvstore.KVStoreManager;
import io.vertigo.lang.Assertion;
import io.vertigo.ui.core.ComponentStates;
import io.vertigo.ui.core.FormMode;
import io.vertigo.ui.core.ViewContext;
import io.vertigo.ui.core.ViewContextKey;
import io.vertigo.ui.core.ViewContextMap;
import io.vertigo.ui.exception.ExpiredViewContextException;
import io.vertigo.ui.impl.springmvc.util.UiRequestUtil;
import io.vertigo.ui.impl.springmvc.util.UiUtil;
import io.vertigo.util.StringUtil;
import io.vertigo.vega.webservice.validation.UiMessageStack;
/**
* Super class des Actions SpringMvc.
*
* @author npiedeloup, mlaroche
*/
public abstract class AbstractVSpringMvcController {
public static final String DEFAULT_VIEW_NAME_ATTRIBUTE = "defaultViewName";
/** Clé de la collection des contexts dans le KVStoreManager. */
public static final String CONTEXT_COLLECTION_NAME = "VViewContext";
/** Clé de context du UiUtil. */
public static final ViewContextKey UTIL_CONTEXT_KEY = ViewContextKey.of("util");
/** Clé de context du mode. */
public static final ViewContextKey MODE_CONTEXT_KEY = ViewContextKey.of("mode");
//TODO voir pour déléguer cette gestion des modes
/** Clé de context du mode Edit. */
public static final ViewContextKey MODE_EDIT_CONTEXT_KEY = ViewContextKey.of("modeEdit");
/** Clé de context du mode ReadOnly. */
public static final ViewContextKey MODE_READ_ONLY_CONTEXT_KEY = ViewContextKey.of("modeReadOnly");
/** Clé de context du mode Create. */
public static final ViewContextKey MODE_CREATE_CONTEXT_KEY = ViewContextKey.of("modeCreate");
/** Préfix des clés des paramètres passés par l'url. */
public static final String URL_PARAM_PREFIX = "params.";
private static final String SLASH = "/";
/**
* Indique que l'initialisation du context par un parametre de l'url est autorisé.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface AcceptCtxQueryParam {
//rien
}
@Inject
private KVStoreManager kvStoreManager;
@Inject
private VTransactionManager transactionManager;
public void prepareContext(final HttpServletRequest request) throws ExpiredViewContextException {
final RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
ViewContext viewContext = null;
final String ctxId = request.getParameter(ViewContext.CTX.get());
if ("POST".equals(request.getMethod()) || ctxId != null && acceptCtxQueryParam()) {
if (ctxId == null) {
contextMiss(null);
} else {
ViewContextMap viewContextMap;
try (VTransactionWritable transactionWritable = transactionManager.createCurrentTransaction()) {
viewContextMap = kvStoreManager.find(CONTEXT_COLLECTION_NAME, ctxId, ViewContextMap.class).orElse(null);
UiRequestUtil.setRequestScopedAttribute("createdContext", false);
}
if (viewContextMap == null) {
contextMiss(ctxId);
}
viewContext = new ViewContext(viewContextMap);
viewContext.makeModifiable();
}
viewContext.setInputCtxId(ctxId);
attributes.setAttribute("viewContext", viewContext, RequestAttributes.SCOPE_REQUEST);
} else {
viewContext = new ViewContext(new ViewContextMap());
attributes.setAttribute("viewContext", viewContext, RequestAttributes.SCOPE_REQUEST);
//initContextUrlParameters(request, viewContext);
//TODO vérifier que l'action demandée n'attendait pas de context : il va etre recrée vide ce qui n'est pas bon dans certains cas.
preInitContext(viewContext);
Assertion.checkState(viewContext.containsKey(UTIL_CONTEXT_KEY), "Pour surcharger preInitContext vous devez rappeler les parents super.preInitContext(). Action: {0}",
getClass().getSimpleName());
//initContext();
}
viewContext.setCtxId();
if (useDefaultViewName()) {
request.setAttribute(DEFAULT_VIEW_NAME_ATTRIBUTE, getDefaultViewName(this));
}
}
/**
* Definition if whe should use the vertigo conventions to determine the default viewname
* @return if we should use it
*/
protected boolean useDefaultViewName() {
return true;
}
private static String getDefaultViewName(final AbstractVSpringMvcController controller) {
String path = controller.getClass().getName();
path = path.substring(0, path.lastIndexOf('.'));
//package is
// group.id.project.feature.controllers and we look in feature/...
// or group.id.project.controllers and we look in project/
Assertion.checkState(path.contains(".controllers"), "Default naming only works if your package contains .controllers, it's not the case for the controller {0}", controller.getClass());
path = path.substring(path.lastIndexOf('.', path.indexOf(".controllers") - 1) + 1);
path = path.replaceAll("\\.controllers", "");
path = path.replaceAll("\\.", SLASH);
String simpleName = StringUtil.first2LowerCase(controller.getClass().getSimpleName());
simpleName = simpleName.replaceAll("Controller", "");
return path + SLASH + simpleName;
}
private boolean acceptCtxQueryParam() {
return this.getClass().isAnnotationPresent(AcceptCtxQueryParam.class);
}
/**
* Appeler lorsque que le context est manquant.
* Par défaut lance une ExpiredContextException.
* Mais une action spécifique pourrait reconstruire le context si c'est pertinent.
* @param ctxId Id du context manquant (seule info disponible)
* @throws ExpiredViewContextException Context expiré (comportement standard)
*/
protected void contextMiss(final String ctxId) throws ExpiredViewContextException {
throw new ExpiredViewContextException("Context ctxId:'" + ctxId + "' manquant");
}
/**
* Preinitialisation du context, pour ajouter les composants standard.
* Si surcharger doit rappeler le super.preInitContext();
*/
protected void preInitContext(final ViewContext viewContext) {
viewContext.publishRef(UTIL_CONTEXT_KEY, new UiUtil());
viewContext.asMap().put("componentStates", new ComponentStates());
toModeReadOnly();
}
/**
* Conserve et fige le context.
* Utilisé par le KActionContextStoreInterceptor.
*/
public final void storeContext() {
final ViewContext viewContext = getViewContext();
try (VTransactionWritable transactionWritable = transactionManager.createCurrentTransaction()) {
kvStoreManager.put(CONTEXT_COLLECTION_NAME, viewContext.getId(), viewContext.asMap());// we only store the underlying map
transactionWritable.commit();
}
}
/**
* Conserve et fige le context.
* Utilisé par le KActionContextStoreInterceptor.
*/
public final void makeUnmodifiable() {
final ViewContext viewContext = getViewContext();
viewContext.makeUnmodifiable();
}
/** {@inheritDoc} */
public final void validate() {
//rien
}
/** {@inheritDoc} */
private static final ViewContext getViewContext() {
final RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
final ViewContext viewContext = (ViewContext) attributes.getAttribute("viewContext", RequestAttributes.SCOPE_REQUEST);
Assertion.checkNotNull(viewContext);
//---
return viewContext;
}
/**
* Passe en mode edition.
*/
protected static final void toModeEdit() {
//TODO voir pour déléguer cette gestion des modes
final ViewContext viewContext = getViewContext();
viewContext.publishRef(MODE_CONTEXT_KEY, FormMode.edit);
viewContext.publishRef(MODE_READ_ONLY_CONTEXT_KEY, false);
viewContext.publishRef(MODE_EDIT_CONTEXT_KEY, true);
viewContext.publishRef(MODE_CREATE_CONTEXT_KEY, false);
}
/**
* Passe en mode creation.
*/
protected static final void toModeCreate() {
//TODO voir pour déléguer cette gestion des modes
final ViewContext viewContext = getViewContext();
viewContext.publishRef(MODE_CONTEXT_KEY, FormMode.create);
viewContext.publishRef(MODE_READ_ONLY_CONTEXT_KEY, false);
viewContext.publishRef(MODE_EDIT_CONTEXT_KEY, false);
viewContext.publishRef(MODE_CREATE_CONTEXT_KEY, true);
}
/**
* Passe en mode readonly.
*/
protected static final void toModeReadOnly() {
//TODO voir pour déléguer cette gestion des modes
final ViewContext viewContext = getViewContext();
viewContext.publishRef(MODE_CONTEXT_KEY, FormMode.readOnly);
viewContext.publishRef(MODE_READ_ONLY_CONTEXT_KEY, true);
viewContext.publishRef(MODE_EDIT_CONTEXT_KEY, false);
viewContext.publishRef(MODE_CREATE_CONTEXT_KEY, false);
}
/**
* @return Si on est en mode edition
*/
protected static final boolean isModeEdit() {
final ViewContext viewContext = getViewContext();
return FormMode.edit.equals(viewContext.get(MODE_CONTEXT_KEY));
}
/**
* @return Si on est en mode readOnly
*/
protected static final boolean isModeRead() {
final ViewContext viewContext = getViewContext();
return FormMode.readOnly.equals(viewContext.get(MODE_CONTEXT_KEY));
}
/**
* @return Si on est en mode create
*/
protected static final boolean isModeCreate() {
final ViewContext viewContext = getViewContext();
return FormMode.create.equals(viewContext.get(MODE_CONTEXT_KEY));
}
/**
* @return Pile des messages utilisateur.
*/
public static final UiMessageStack getUiMessageStack() {
return UiRequestUtil.obtainCurrentUiMessageStack();
}
public boolean isViewContextDirty() {
return getViewContext().isDirty();
}
protected boolean isNewContext() {
return UiRequestUtil.getRequestScopedAttribute("createdContext", Boolean.class).orElse(true);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy