Commit d8968d01 authored by LAVENIER's avatar LAVENIER
Browse files

[enh] Allow to change the Lock mode type, by configuration option

[fix] Fix error message i18n, when pod not ready
parent a029a762
......@@ -43,6 +43,7 @@ import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.env.ConfigurableEnvironment;
import javax.persistence.LockModeType;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
......@@ -897,6 +898,10 @@ public class SumarisConfiguration extends PropertyPlaceholderConfigurer {
return applicationConfig.getOptionAsInt(SumarisConfigurationOption.LOCK_TIMEOUT.getKey());
}
public LockModeType getLockModeType() {
return LockModeType.valueOf(applicationConfig.getOption(SumarisConfigurationOption.LOCK_MODE_TYPE.getKey()));
}
public String getCsvSeparator() {
return applicationConfig.getOption(SumarisConfigurationOption.CSV_SEPARATOR.getKey());
}
......
......@@ -28,6 +28,7 @@ import net.sumaris.core.dao.technical.hibernate.spatial.HSQLSpatialDialect;
import org.nuiton.config.ConfigOptionDef;
import org.nuiton.version.Version;
import javax.persistence.LockModeType;
import java.io.File;
import java.net.URL;
import java.util.Locale;
......@@ -563,6 +564,12 @@ public enum SumarisConfigurationOption implements ConfigOptionDef {
"0",
Integer.class),
LOCK_MODE_TYPE(
"javax.persistence.lock.mode",
n("sumaris.config.option.javax.persistence.lock.mode.description"),
LockModeType.PESSIMISTIC_WRITE.name(),
String.class),
ENABLE_TECHNICAL_TABLES_UPDATE(
"sumaris.persistence.technicalTables.update",
n("sumaris.config.option.persistence.technicalTables.update.description"),
......
......@@ -35,7 +35,10 @@ public class CacheEventLogger implements CacheEventListener<Object, Object> {
@Override
public void onEvent(CacheEvent cacheEvent) {
// TODO: send clear cache event to the ActiveMQ event queue
//log.info("custom Caching event {} {} {} {} ", cacheEvent.getType(),cacheEvent.getKey(),cacheEvent.getOldValue(),cacheEvent.getNewValue());
if (log.isDebugEnabled()) {
log.debug("Caching event {} {}", cacheEvent.getType(), cacheEvent.getKey());
// TODO: send clear cache event to the ActiveMQ event queue
}
}
}
\ No newline at end of file
......@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableMap;
import com.querydsl.jpa.impl.JPAQuery;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.config.SumarisConfiguration;
import net.sumaris.core.config.SumarisConfigurationOption;
import net.sumaris.core.dao.technical.Daos;
import net.sumaris.core.dao.technical.SortDirection;
import net.sumaris.core.dao.technical.model.IEntity;
......@@ -79,8 +80,8 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
private boolean debugEntityLoad = false;
private boolean checkUpdateDate = true;
private boolean lockForUpdate = false;
private LockModeType lockForUpdateMode = LockModeType.PESSIMISTIC_WRITE;
private Map<String, Object> lockForUpdateProperties = null;
private LockModeType lockForUpdateMode;
private Map<String, Object> lockForUpdateProperties;
private EntityManager entityManager;
......@@ -107,8 +108,9 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
@PostConstruct
protected void init() {
// Init lock timeout
lockForUpdateProperties = ImmutableMap.of("javax.persistence.lock.timeout", configuration.getLockTimeout());
// Set lock timeout - see lockForUpdate()
lockForUpdateProperties = ImmutableMap.of(SumarisConfigurationOption.LOCK_TIMEOUT.getKey(), configuration.getLockTimeout());
lockForUpdateMode = configuration.getLockModeType();
}
public boolean isCheckUpdateDate() {
......@@ -474,7 +476,6 @@ public abstract class SumarisJpaRepositoryImpl<E extends IEntity<ID>, ID extends
}
}
protected String getTableName(String entityName) {
return I18n.t("sumaris.persistence.table." + entityName.substring(0, 1).toLowerCase() + entityName.substring(1));
}
......
......@@ -50,6 +50,9 @@ spring.jpa.properties.hibernate.dialect=${spring.jpa.database-platform}
sumaris.extraction.query.timeout=300000
spring.jpa.properties.javax.persistence.query.timeout=30000
spring.jpa.properties.org.hibernate.timeout=30
# JPA / Entity lock
spring.jpa.properties.javax.persistence.lock.mode=PESSIMISTIC_WRITE
spring.jpa.properties.javax.persistence.lock.timeout=0
# Schema management / Liquibase
......
......@@ -26,8 +26,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.*;
import graphql.schema.GraphQLSchema;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.event.config.ConfigurationReadyEvent;
import net.sumaris.core.service.technical.ConfigurationService;
import org.nuiton.i18n.I18n;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
......@@ -36,6 +39,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
@RestController
......@@ -44,6 +48,7 @@ public class GraphQLRestController {
private final GraphQL graphQL;
private final ObjectMapper objectMapper;
private boolean ready = false;
private final ConfigurationService configurationService;
@Autowired
......@@ -53,7 +58,12 @@ public class GraphQLRestController {
this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
this.objectMapper = objectMapper;
this.configurationService = configurationService;
log.info(String.format("Starting GraphQL endpoint {%s}...", GraphQLPaths.BASE_PATH));
log.info("Starting GraphQL endpoint {{}}...", GraphQLPaths.BASE_PATH);
}
@EventListener({ConfigurationReadyEvent.class})
protected void onConfigurationReady(ConfigurationReadyEvent event) {
ready = true;
}
@PostMapping(value = GraphQLPaths.BASE_PATH,
......@@ -68,9 +78,9 @@ public class GraphQLRestController {
@ResponseBody
public Map<String, Object> indexFromAnnotated(@RequestBody Map<String, Object> request, HttpServletRequest rawRequest) {
ExecutionResult result;
if (!this.configurationService.isReady()) {
if (!this.ready) {
result = new ExecutionResultImpl.Builder()
.addError(GraphqlErrorBuilder.newError().message("Pod is starting. Please wait...").build())
.addError(GraphqlErrorBuilder.newError().message(I18n.l(rawRequest.getLocale(), "sumaris.error.starting")).build())
.build();
}
else {
......
......@@ -79,7 +79,7 @@ public class SubscriptionWebSocketHandler extends TextWebSocketHandler {
private Map<String, List<Subscription>> subscriptionsBySessionId = Maps.newConcurrentMap();
private AtomicBoolean ready = new AtomicBoolean(false);
private boolean ready = false;
@Resource(name = "webSocketGraphQL")
private GraphQL graphQL;
......@@ -101,12 +101,12 @@ public class SubscriptionWebSocketHandler extends TextWebSocketHandler {
@Override
public void onReady(ConfigurationReadyEvent event) {
configuration.removeListener(this);
SubscriptionWebSocketHandler.this.ready.set(true);
SubscriptionWebSocketHandler.this.ready = true;
}
});
}
else {
ready.set(true);
ready = true;
}
}
......@@ -159,8 +159,9 @@ public class SubscriptionWebSocketHandler extends TextWebSocketHandler {
protected void handleInitConnection(WebSocketSession session, Map<String, Object> request) {
// When not ready, force to stop the security chain
if (!this.ready.get()) {
throw new AuthenticationServiceException("Cannot authenticate: not ready");
if (!this.ready) {
// TODO: use session locale ?
throw new AuthenticationServiceException(I18n.t("sumaris.error.starting"));
}
Map<String, Object> payload = (Map<String, Object>) request.get("payload");
......
......@@ -22,11 +22,13 @@ package net.sumaris.server.http.security;
* #L%
*/
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.event.config.ConfigurationEvent;
import net.sumaris.core.event.config.ConfigurationReadyEvent;
import net.sumaris.core.event.config.ConfigurationUpdatedEvent;
import net.sumaris.server.config.SumarisServerConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.i18n.I18n;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
......@@ -44,7 +46,6 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.commons.lang3.StringUtils.removeStart;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
......@@ -52,13 +53,14 @@ import static org.springframework.http.HttpHeaders.AUTHORIZATION;
/**
* @author peck7 on 03/12/2018.
*/
@Slf4j
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String TOKEN = "token";
private static final String BASIC = "Basic";
private SumarisServerConfiguration configuration;
private AtomicBoolean ready = new AtomicBoolean(false);
private boolean ready = false;
private boolean enableAuthBasic;
private boolean enableAuthToken;
......@@ -77,9 +79,8 @@ public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter
setEnableAuthBasic(configuration.enableAuthBasic());
setEnableAuthToken(configuration.enableAuthToken());
if (!this.ready.get()) {
this.ready.set(true);
}
log.info("Started authenticated filer, using {authBasic: {}, authToken: {}}...", enableAuthBasic, enableAuthToken);
this.ready = true;
}
public void setEnableAuthToken(boolean enableAuthToken) {
......@@ -94,8 +95,8 @@ public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// When not ready, force to stop the security chain
if (!this.ready.get()) {
throw new AuthenticationServiceException("Cannot authenticate: not ready");
if (!this.ready) {
throw new AuthenticationServiceException(I18n.l(request.getLocale(), "sumaris.error.starting"));
}
String authorization = request.getHeader(AUTHORIZATION);
......
......@@ -60,7 +60,7 @@ sumaris.error.missingConverter=Convert not found for type {%s}
sumaris.error.notFound=Remote resource not found
sumaris.error.person.notFound=User not found on server
sumaris.error.person.register.mail.disable=Email validation has been disables. Please fill property {%s} in the configuration file.
sumaris.error.trash.notfound=
sumaris.error.trash.notfound=Trash resource not found
sumaris.error.trip.notFound=Trip {%s} not found.
sumaris.error.validation.required=Missing mandatory attribute\: %s
sumaris.model.account.settings=settings
......@@ -83,3 +83,4 @@ sumaris.server.mail.subject.prefix=[%s]
sumaris.server.person.register.confirm.success=Confirm registration of user {%s}
sumaris.server.started=Application is running on port\: {%s}
sumaris.server.subscription.getRequest=Received WS subscription request\: %s
sumaris.error.starting=Pod is starting. Please wait...
\ No newline at end of file
......@@ -56,8 +56,8 @@ sumaris.error.email.service=Envoi d'email impossible. Veuillez renseigner les pr
sumaris.error.missingConverter=Convertisseur non trouvé pour le type {%s}
sumaris.error.notFound=Donnée serveur inexistante
sumaris.error.person.notFound=Utilisateur inexistant sur le serveur
sumaris.error.trash.notfound=
sumaris.error.trip.notFound=Marée {%s} introuvable.
sumaris.error.trash.notfound=Donnée en corbeille inexistante
sumaris.error.trip.notFound=Marée {%s} inexistante
sumaris.error.validation.required=Attribut obligatoire manquant \: %s
sumaris.model.account.settings=settings
sumaris.model.settings.latLongFormat=settings.latLongFormat
......@@ -78,4 +78,5 @@ sumaris.server.keypair.pubkey.random=Clé publique (aléatoire) utilisée par le
sumaris.server.mail.subject.prefix=[%s]
sumaris.server.person.register.confirm.success=Confirmation de l'utilisateur {%s}
sumaris.server.started=Application démarrée sur le port {%s}
sumaris.error.starting=Serveur en cours de démarrage. Veuillez patienter...
sumaris.server.subscription.getRequest=Requête abonnement recue \: %s
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment