diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index 13438ffa4442b10aa213c4e52a49b45a18e3dff4..2528e987455e0a7b0ccc11eb5756e731a8dc8c69 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -1,5 +1,7 @@ package fr.agrometinfo.www.client; +import java.util.Date; + import org.dominokit.domino.api.shared.extension.ContextAggregator; import org.dominokit.rest.DominoRestConfig; import org.dominokit.rest.shared.request.RequestInterceptor; @@ -14,7 +16,11 @@ import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Window; +import elemental2.dom.DomGlobal; +import fr.agrometinfo.www.client.i18n.AppConstants; import fr.agrometinfo.www.client.presenter.LayoutPresenter; +import fr.agrometinfo.www.client.util.ApplicationUtils; +import fr.agrometinfo.www.shared.service.ApplicationServiceFactory; /** * Entry point classes define <code>onModuleLoad()</code>. @@ -38,11 +44,32 @@ public class App implements EntryPoint { } } + /** + * I18N constants. + */ + public static final AppConstants CSTS = GWT.create(AppConstants.class); + /** * Dispatches {@link Event}s to interested parties. */ private static final EventBus EVENT_BUS = new SimpleEventBus(); + private static void checkVersion() { + final Date clientDate = ApplicationUtils.getVersionDate(); + if (clientDate != null) { + ApplicationServiceFactory.INSTANCE// + .getApplicationDate() // + .onSuccess(serverDate -> { + GWT.log("serverDate = " + serverDate); + GWT.log("clientDate = " + clientDate); + if (serverDate != null && clientDate.before(serverDate) + && DomGlobal.window.confirm(CSTS.reloadingApplication())) { + ApplicationUtils.hardReload(); + } + }) // + .send(); + } + } /** * @return {@link Event}s dispatcher. */ @@ -61,6 +88,8 @@ public class App implements EntryPoint { DominoRestConfig.getInstance().addRequestInterceptor(new LocaleInterceptor()); DominoRestConfig.getInstance().setDefaultResourceRootPath(Window.Location.getPath() + "/rs"); + checkVersion(); + // enabling Charba Charba.enable(); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index d4201d6ef6814789b0b0aef16bc9bbf90aa06c65..23eac3597e063969a7c5ba6998b8a05720ff88b1 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -251,6 +251,12 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo @DefaultStringValue("release-notes.html") String releaseNotesPath(); + /** + * @return translation + */ + @DefaultStringValue("Reloading the application for a new version...") + String reloadingApplication(); + /** * @return translation */ diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/util/ApplicationUtils.java b/www-client/src/main/java/fr/agrometinfo/www/client/util/ApplicationUtils.java index 8157450828f583668ea641eab1201dcfceb07161..b2ff87a8d51b2134f79ded1ec784613e28a93cdf 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/util/ApplicationUtils.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/util/ApplicationUtils.java @@ -1,9 +1,11 @@ package fr.agrometinfo.www.client.util; +import java.util.Date; import java.util.HashMap; import java.util.Map; import com.google.gwt.core.client.GWT; +import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.DOM; /** @@ -11,11 +13,11 @@ import com.google.gwt.user.client.DOM; * * @author Olivier Maury */ -public interface ApplicationUtils { +public final class ApplicationUtils { /** * @return root path of application. */ - static String getApplicationUrl() { + public static String getApplicationUrl() { final String url = GWT.getModuleBaseURL(); final String app = "/" + GWT.getModuleName() + "/"; return url.substring(0, url.length() - app.length()); @@ -24,14 +26,14 @@ public interface ApplicationUtils { /** * @return attributions for map and chart. */ - static String getAttributions() { + public static String getAttributions() { return "© INRAE AgroClim − AgroMetInfo (etalab-2.0)"; } /** * @return available locales for the app. */ - static Map<String, String> getAvailableLocales() { + public static Map<String, String> getAvailableLocales() { final Map<String, String> locales = new HashMap<>(); locales.put("en", "English"); locales.put("fr", "Français"); @@ -41,11 +43,37 @@ public interface ApplicationUtils { /** * @return project version */ - static String getVersion() { + public static String getVersion() { final String val = DOM.getElementById("application_version").getAttribute("content"); if ("VERSION".equals(val)) { return "1.0-dev"; } return val; } + + /** + * @return build date + */ + public static Date getVersionDate() { + final String val = DOM.getElementById("application_date").getAttribute("content"); + if ("DATE".equals(val)) { + return new Date(); + } + return DateTimeFormat.getFormat("yyyy-MM-dd HH:mm:ss").parse(val); + } + + /** + * Reloads the current browser window, removing cache. All GWT state will be + * lost. + */ + public static native void hardReload() /*-{ + $wnd.location.reload(true); + }-*/; + + /** + * No Constructor. + */ + private ApplicationUtils() { + } + } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/util/UiUtils.java b/www-client/src/main/java/fr/agrometinfo/www/client/util/UiUtils.java index 1b7d60869fd19c300f34f4f3e6bd4ba222ccacc4..cdb178074e9a3e6929d33c6210cba28361d8ad22 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/util/UiUtils.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/util/UiUtils.java @@ -87,7 +87,6 @@ public final class UiUtils { return getBrowserName().toLowerCase().contains("opr"); } - /** * No Constructor. */ diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index 9dffd12827e4fbdf55160bfc9a38bd074229d156..0f369e843f1d9d34e2bdc8396128404958bf06e9 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -40,6 +40,7 @@ otherAgroclimApps = Autres services et outils d’AgroClim requiredErrorMessage = * Ce champ est obligatoire. releaseNotes = Notes de version releaseNotesPath = release-notes.html +reloadingApplication = Rechargement de l'application pour une nouvelle version\u2026 seePrivacyPolicy = Consultez le paragraphe « Données personnelles » dans les mentions légales. toggleRightPanel = Afficher / masquer le panneau de droite yes = Oui diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java index 1335edfe0ae3d4dd407f227beabfbbe40b94d8a1..6db4e6c6e2ef518cba93cbaccef9cf9e28d40bc0 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java @@ -1,5 +1,6 @@ package fr.agrometinfo.www.server.rs; +import java.util.Date; import java.util.List; import fr.agrometinfo.www.server.AgroMetInfoConfiguration; @@ -7,12 +8,15 @@ import fr.agrometinfo.www.server.AgroMetInfoConfiguration.ConfigurationKey; import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.server.service.MailService.Mail; +import fr.agrometinfo.www.server.util.AppVersion; import fr.agrometinfo.www.server.util.ST; import fr.agrometinfo.www.server.util.ST.Key; import fr.agrometinfo.www.shared.dto.MessageDTO; import fr.agrometinfo.www.shared.service.ApplicationService; +import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; +import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import lombok.extern.log4j.Log4j2; @@ -34,7 +38,7 @@ public class ApplicationResource implements ApplicationService { Voici un message de <NAME> <<EMAIL>> : - <MESSAGE> + <MESSAGE> """; /** @@ -49,6 +53,26 @@ public class ApplicationResource implements ApplicationService { @Inject private MailService mailService; + /** + * Date of application build. + */ + private Date applicationDate; + + @GET + @Path(ApplicationService.PATH_APPLICATION_DATE) + @Override + public Date getApplicationDate() { + return applicationDate; + } + + /** + * Initialize fixed values. + */ + @PostConstruct + public void init() { + applicationDate = AppVersion.getBuildDate(); + } + @POST @Path(ApplicationService.PATH_SEND_EMAIL) @Override diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/JacksonConfig.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/JacksonConfig.java index 21531ddddb2f851651f863c4dd800c0104dfbcb6..a2682d2f2dea951222f1e9bc9606c9b500b4c26f 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/JacksonConfig.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/JacksonConfig.java @@ -31,6 +31,8 @@ public class JacksonConfig implements ContextResolver<ObjectMapper> { final SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null, null, null)); module.addSerializer(LngLatAlt.class, new LngLatAltSerializer()); objectMapper.registerModule(module); + // NB, to format date as ISO 8601, use objectMapper.setDateFormat(new + // StdDateFormat()) } @Override diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java b/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java index c6759f7d7fef7715f97edb569d8da4f89b63e75c..f123a6cbd727f230a2532510f4450e2fa1eb0c66 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/util/AppVersion.java @@ -1,5 +1,8 @@ package fr.agrometinfo.www.server.util; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Locale; import java.util.ResourceBundle; @@ -16,6 +19,18 @@ public final class AppVersion { private static final ResourceBundle RESOURCES = ResourceBundle.getBundle("fr.agrometinfo.www.server.version", Locale.ROOT); + /** + * @return Date of application build + */ + public static Date getBuildDate() { + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + return sdf.parse(getString("build.date")); + } catch (final ParseException e) { + return null; + } + } + /** * @return DOI of SEASON */ diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/ApplicationService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/ApplicationService.java index 0082e1c85ca25870d3d858b7a9e13790e7f0b34b..4d3facdccfbc24fce3ded03b8471b20721ab5bec 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/ApplicationService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/ApplicationService.java @@ -1,5 +1,8 @@ package fr.agrometinfo.www.shared.service; +import java.util.Date; + +import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -21,15 +24,27 @@ public interface ApplicationService { */ String PATH = "application"; + /** + * Path for {@link ApplicationService#getApplicationDate()}. + */ + String PATH_APPLICATION_DATE = "application_date"; + /** * Path for {@link ApplicationService#send()}. */ String PATH_SEND_EMAIL = "send"; + /** + * @return date of application build + */ + @GET + @Path(PATH_APPLICATION_DATE) + Date getApplicationDate(); + /** * Send an e-mail message to AgroMetInfo team. * - * @param message message + * @param message message * @return nothing */ @POST