diff options
author | Artur Signell <artur@vaadin.com> | 2013-05-28 12:00:15 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-05-29 12:33:17 +0000 |
commit | a9afca67ba942afa287be3507eb225e0a7b954e6 (patch) | |
tree | d2ddd12b3acc2f83c3361c018717bd557454cec6 /server | |
parent | a3ad62d947c86d3f53f333ca9bc36e4544cd5d46 (diff) | |
download | vaadin-framework-a9afca67ba942afa287be3507eb225e0a7b954e6.tar.gz vaadin-framework-a9afca67ba942afa287be3507eb225e0a7b954e6.zip |
Moved Locale data handling to LocaleService (#11378)
The locale data is now tracked per UI instance and no longer sent in every request.
Change-Id: I4bebd00327da6f8d812181fd76a85eb6196d0010
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/server/JsonPaintTarget.java | 4 | ||||
-rw-r--r-- | server/src/com/vaadin/server/LegacyCommunicationManager.java | 61 | ||||
-rw-r--r-- | server/src/com/vaadin/server/LocaleService.java | 211 | ||||
-rw-r--r-- | server/src/com/vaadin/server/communication/LocaleWriter.java | 204 | ||||
-rw-r--r-- | server/src/com/vaadin/server/communication/UidlWriter.java | 4 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractComponent.java | 9 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 17 |
7 files changed, 236 insertions, 274 deletions
diff --git a/server/src/com/vaadin/server/JsonPaintTarget.java b/server/src/com/vaadin/server/JsonPaintTarget.java index ca70391f64..cd09b2a44b 100644 --- a/server/src/com/vaadin/server/JsonPaintTarget.java +++ b/server/src/com/vaadin/server/JsonPaintTarget.java @@ -388,10 +388,6 @@ public class JsonPaintTarget implements PaintTarget { getUsedResources().add("layouts/" + value + ".html"); } - if (name.equals("locale")) { - manager.requireLocale(value); - } - } @Override diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java index c0194db243..ad662cf6df 100644 --- a/server/src/com/vaadin/server/LegacyCommunicationManager.java +++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java @@ -16,18 +16,12 @@ package com.vaadin.server; -import java.io.IOException; -import java.io.PrintWriter; import java.io.Serializable; -import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -37,7 +31,6 @@ import org.json.JSONException; import org.json.JSONObject; import com.vaadin.server.ClientConnector.ConnectorErrorEvent; -import com.vaadin.server.communication.LocaleWriter; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JavaScriptConnectorState; import com.vaadin.shared.communication.SharedState; @@ -69,9 +62,6 @@ public class LegacyCommunicationManager implements Serializable { */ private final VaadinSession session; - // TODO Refactor to UI shared state (#11378) - private List<String> locales; - // TODO Move to VaadinSession (#11409) private DragAndDropService dragAndDropService; @@ -88,7 +78,6 @@ public class LegacyCommunicationManager implements Serializable { */ public LegacyCommunicationManager(VaadinSession session) { this.session = session; - requireLocale(session.getLocale().toString()); } protected VaadinSession getSession() { @@ -313,52 +302,6 @@ public class LegacyCommunicationManager implements Serializable { } /** - * Prints the queued (pending) locale definitions to a {@link PrintWriter} - * in a (UIDL) format that can be sent to the client and used there in - * formatting dates, times etc. - * - * @deprecated As of 7.1. See #11378. - * - * @param outWriter - */ - @Deprecated - public void printLocaleDeclarations(Writer writer) throws IOException { - new LocaleWriter().write(locales, writer); - } - - /** - * Queues a locale to be sent to the client (browser) for date and time - * entry etc. All locale specific information is derived from server-side - * {@link Locale} instances and sent to the client when needed, eliminating - * the need to use the {@link Locale} class and all the framework behind it - * on the client. - * - * @deprecated As of 7.1. See #11378. - * - * @see Locale#toString() - * - * @param value - */ - @Deprecated - public void requireLocale(String value) { - if (locales == null) { - locales = new ArrayList<String>(); - locales.add(session.getLocale().toString()); - } - if (!locales.contains(value)) { - locales.add(value); - } - } - - /** - * @deprecated As of 7.1. See #11378. - */ - @Deprecated - public void resetLocales() { - locales = null; - } - - /** * @deprecated As of 7.1. Will be removed in the future. */ @Deprecated @@ -486,10 +429,6 @@ public class LegacyCommunicationManager implements Serializable { getClientCache(ui).clear(); ui.getConnectorTracker().markAllConnectorsDirty(); ui.getConnectorTracker().markAllClientSidesUninitialized(); - - // Reset sent locales - resetLocales(); - requireLocale(session.getLocale().toString()); } private static final Logger getLogger() { diff --git a/server/src/com/vaadin/server/LocaleService.java b/server/src/com/vaadin/server/LocaleService.java new file mode 100644 index 0000000000..347c4da5c6 --- /dev/null +++ b/server/src/com/vaadin/server/LocaleService.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.server; + +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.logging.Logger; + +import com.vaadin.shared.ui.ui.UIState.LocaleData; +import com.vaadin.shared.ui.ui.UIState.LocaleServiceState; +import com.vaadin.ui.UI; + +/** + * Server side service which handles locale and the transmission of locale date + * to the client side LocaleService. + * + * @since 7.1 + * @author Vaadin Ltd + */ +public class LocaleService { + + private UI ui; + + private LocaleServiceState state; + + /** + * Creates a LocaleService bound to the given UI + * + * @since 7.1 + * @param ui + * The UI which owns the LocaleService + */ + public LocaleService(UI ui, LocaleServiceState state) { + this.ui = ui; + this.state = state; + } + + /** + * Retrieves the UI this service is bound to + * + * @since 7.1 + * @return the UI for this service + */ + public UI getUI() { + return ui; + } + + /** + * Adds a locale to be sent to the client (browser) for date and time entry + * etc. All locale specific information is derived from server-side + * {@link Locale} instances and sent to the client when needed, eliminating + * the need to use the {@link Locale} class and all the framework behind it + * on the client. + * + * @param locale + * The locale which is required on the client side + */ + public void addLocale(Locale locale) { + for (LocaleData data : getState(false).localeData) { + if (data.name.equals(locale.toString())) { + // Already there + return; + } + } + + getState(true).localeData.add(createLocaleData(locale)); + } + + /** + * Returns the state for this service + * <p> + * The state is transmitted inside the UI state rather than as an individual + * entity. + * </p> + * + * @since 7.1 + * @param markAsDirty + * true to mark the state as dirty + * @return a LocaleServiceState object that can be read in any case and + * modified if markAsDirty is true + */ + private LocaleServiceState getState(boolean markAsDirty) { + if (markAsDirty) { + getUI().markAsDirty(); + } + + return state; + } + + /** + * Creates a LocaleData instance for transportation to the client + * + * @since 7.1 + * @param locale + * The locale for which to create a LocaleData object + * @return A LocaleData object with information about the given locale + */ + protected LocaleData createLocaleData(Locale locale) { + LocaleData localeData = new LocaleData(); + localeData.name = locale.toString(); + + final DateFormatSymbols dfs = new DateFormatSymbols(locale); + localeData.shortMonthNames = dfs.getShortMonths(); + localeData.monthNames = dfs.getMonths(); + // Client expects 0 based indexing, DateFormatSymbols use 1 based + localeData.shortDayNames = new String[7]; + localeData.dayNames = new String[7]; + String[] sDayNames = dfs.getShortWeekdays(); + String[] lDayNames = dfs.getWeekdays(); + for (int i = 0; i < 7; i++) { + localeData.shortDayNames[i] = sDayNames[i + 1]; + localeData.dayNames[i] = lDayNames[i + 1]; + } + + /* + * First day of week (0 = sunday, 1 = monday) + */ + final java.util.Calendar cal = new GregorianCalendar(locale); + localeData.firstDayOfWeek = cal.getFirstDayOfWeek() - 1; + + /* + * Date formatting (MM/DD/YYYY etc.) + */ + + DateFormat dateFormat = DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT, locale); + if (!(dateFormat instanceof SimpleDateFormat)) { + getLogger().warning( + "Unable to get default date pattern for locale " + + locale.toString()); + dateFormat = new SimpleDateFormat(); + } + final String df = ((SimpleDateFormat) dateFormat).toPattern(); + + int timeStart = df.indexOf("H"); + if (timeStart < 0) { + timeStart = df.indexOf("h"); + } + final int ampm_first = df.indexOf("a"); + // E.g. in Korean locale AM/PM is before h:mm + // TODO should take that into consideration on client-side as well, + // now always h:mm a + if (ampm_first > 0 && ampm_first < timeStart) { + timeStart = ampm_first; + } + // Hebrew locale has time before the date + final boolean timeFirst = timeStart == 0; + String dateformat; + if (timeFirst) { + int dateStart = df.indexOf(' '); + if (ampm_first > dateStart) { + dateStart = df.indexOf(' ', ampm_first); + } + dateformat = df.substring(dateStart + 1); + } else { + dateformat = df.substring(0, timeStart - 1); + } + + localeData.dateFormat = dateformat.trim(); + + /* + * Time formatting (24 or 12 hour clock and AM/PM suffixes) + */ + final String timeformat = df.substring(timeStart, df.length()); + /* + * Doesn't return second or milliseconds. + * + * We use timeformat to determine 12/24-hour clock + */ + final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; + // TODO there are other possibilities as well, like 'h' in french + // (ignore them, too complicated) + final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." + : ":"; + // outWriter.print("\"tf\":\"" + timeformat + "\","); + localeData.twelveHourClock = twelve_hour_clock; + localeData.hourMinuteDelimiter = hour_min_delimiter; + if (twelve_hour_clock) { + final String[] ampm = dfs.getAmPmStrings(); + localeData.am = ampm[0]; + localeData.pm = ampm[1]; + } + + return localeData; + } + + private static Logger getLogger() { + return Logger.getLogger(LocaleService.class.getName()); + } + +} diff --git a/server/src/com/vaadin/server/communication/LocaleWriter.java b/server/src/com/vaadin/server/communication/LocaleWriter.java deleted file mode 100644 index c05649da19..0000000000 --- a/server/src/com/vaadin/server/communication/LocaleWriter.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2000-2013 Vaadin Ltd. - * - * 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 com.vaadin.server.communication; - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.logging.Logger; - -/** - * Serializes locale information to JSON. - * - * @author Vaadin Ltd - * @since 7.1 - * @deprecated See <a href="http://dev.vaadin.com/ticket/11378">ticket - * #11378</a>. - */ -@Deprecated -public class LocaleWriter implements Serializable { - - /** - * Writes a JSON object containing localized strings of the given locales. - * - * @param locales - * The list of {@link Locale}s to write. - * @param writer - * The {@link Writer} used to write the JSON. - * @throws IOException - * If the serialization fails. - * - */ - public void write(List<String> locales, Writer writer) throws IOException { - - // Send locale informations to client - writer.write("["); - // TODO locales are currently sent on each request; this will be fixed - // by implementing #11378. - for (int pendingLocalesIndex = 0; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) { - - final Locale l = generateLocale(locales.get(pendingLocalesIndex)); - // Locale name - writer.write("{\"name\":\"" + l.toString() + "\","); - - /* - * Month names (both short and full) - */ - final DateFormatSymbols dfs = new DateFormatSymbols(l); - final String[] short_months = dfs.getShortMonths(); - final String[] months = dfs.getMonths(); - writer.write("\"smn\":[\"" - + // ShortMonthNames - short_months[0] + "\",\"" + short_months[1] + "\",\"" - + short_months[2] + "\",\"" + short_months[3] + "\",\"" - + short_months[4] + "\",\"" + short_months[5] + "\",\"" - + short_months[6] + "\",\"" + short_months[7] + "\",\"" - + short_months[8] + "\",\"" + short_months[9] + "\",\"" - + short_months[10] + "\",\"" + short_months[11] + "\"" - + "],"); - writer.write("\"mn\":[\"" - + // MonthNames - months[0] + "\",\"" + months[1] + "\",\"" + months[2] - + "\",\"" + months[3] + "\",\"" + months[4] + "\",\"" - + months[5] + "\",\"" + months[6] + "\",\"" + months[7] - + "\",\"" + months[8] + "\",\"" + months[9] + "\",\"" - + months[10] + "\",\"" + months[11] + "\"" + "],"); - - /* - * Weekday names (both short and full) - */ - final String[] short_days = dfs.getShortWeekdays(); - final String[] days = dfs.getWeekdays(); - writer.write("\"sdn\":[\"" - + // ShortDayNames - short_days[1] + "\",\"" + short_days[2] + "\",\"" - + short_days[3] + "\",\"" + short_days[4] + "\",\"" - + short_days[5] + "\",\"" + short_days[6] + "\",\"" - + short_days[7] + "\"" + "],"); - writer.write("\"dn\":[\"" - + // DayNames - days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\"" - + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\"" - + days[7] + "\"" + "],"); - - /* - * First day of week (0 = sunday, 1 = monday) - */ - final Calendar cal = new GregorianCalendar(l); - writer.write("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ","); - - /* - * Date formatting (MM/DD/YYYY etc.) - */ - - DateFormat dateFormat = DateFormat.getDateTimeInstance( - DateFormat.SHORT, DateFormat.SHORT, l); - if (!(dateFormat instanceof SimpleDateFormat)) { - getLogger().warning( - "Unable to get default date pattern for locale " - + l.toString()); - dateFormat = new SimpleDateFormat(); - } - final String df = ((SimpleDateFormat) dateFormat).toPattern(); - - int timeStart = df.indexOf("H"); - if (timeStart < 0) { - timeStart = df.indexOf("h"); - } - final int ampm_first = df.indexOf("a"); - // E.g. in Korean locale AM/PM is before h:mm - // TODO should take that into consideration on client-side as well, - // now always h:mm a - if (ampm_first > 0 && ampm_first < timeStart) { - timeStart = ampm_first; - } - // Hebrew locale has time before the date - final boolean timeFirst = timeStart == 0; - String dateformat; - if (timeFirst) { - int dateStart = df.indexOf(' '); - if (ampm_first > dateStart) { - dateStart = df.indexOf(' ', ampm_first); - } - dateformat = df.substring(dateStart + 1); - } else { - dateformat = df.substring(0, timeStart - 1); - } - - writer.write("\"df\":\"" + dateformat.trim() + "\","); - - /* - * Time formatting (24 or 12 hour clock and AM/PM suffixes) - */ - final String timeformat = df.substring(timeStart, df.length()); - /* - * Doesn't return second or milliseconds. - * - * We use timeformat to determine 12/24-hour clock - */ - final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; - // TODO there are other possibilities as well, like 'h' in french - // (ignore them, too complicated) - final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." - : ":"; - // outWriter.print("\"tf\":\"" + timeformat + "\","); - writer.write("\"thc\":" + twelve_hour_clock + ","); - writer.write("\"hmd\":\"" + hour_min_delimiter + "\""); - if (twelve_hour_clock) { - final String[] ampm = dfs.getAmPmStrings(); - writer.write(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1] - + "\"]"); - } - writer.write("}"); - if (pendingLocalesIndex < locales.size() - 1) { - writer.write(","); - } - } - writer.write("]"); // Close locales - } - - /** - * Constructs a {@link Locale} instance to be sent to the client based on a - * short locale description string. - * - * @see #requireLocale(String) - * - * @param value - * @return - */ - private Locale generateLocale(String value) { - final String[] temp = value.split("_"); - if (temp.length == 1) { - return new Locale(temp[0]); - } else if (temp.length == 2) { - return new Locale(temp[0], temp[1]); - } else { - return new Locale(temp[0], temp[1], temp[2]); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(LocaleWriter.class.getName()); - } -} diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index 60a884a635..f715569424 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -283,10 +283,6 @@ public class UidlWriter implements Serializable { + new JSONArray(styleDependencies).toString()); } - // add any pending locale definitions requested by the client - writer.write(", \"locales\": "); - manager.printLocaleDeclarations(writer); - if (manager.getDragAndDropService() != null) { manager.getDragAndDropService().printJSONResponse(writer); } diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index 06060dbf91..9ff36a42d2 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -291,7 +291,10 @@ public abstract class AbstractComponent extends AbstractClientConnector public void setLocale(Locale locale) { this.locale = locale; - // FIXME: Reload value if there is a converter + if (locale != null && isAttached()) { + getUI().getLocaleService().addLocale(locale); + } + markAsDirty(); } @@ -556,6 +559,10 @@ public abstract class AbstractComponent extends AbstractClientConnector focus(); } setActionManagerViewer(); + if (locale != null) { + getUI().getLocaleService().addLocale(locale); + } + } /* diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 545c2c7365..706f7c436b 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -30,6 +30,7 @@ import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; +import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; import com.vaadin.server.PaintTarget; @@ -494,6 +495,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements private boolean hasPendingPush = false; + private LocaleService localeService = new LocaleService(this, + getState(false).localeServiceState); + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -1052,6 +1056,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements @Override public void attach() { super.attach(); + getLocaleService().addLocale(getLocale()); } /** @@ -1428,4 +1433,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements public void setOverlayContainerLabel(String overlayContainerLabel) { getState().overlayContainerLabel = overlayContainerLabel; } + + /** + * Returns the locale service which handles transmission of Locale data to + * the client. + * + * @since 7.1 + * @return The LocaleService for this UI + */ + public LocaleService getLocaleService() { + return localeService; + } + } |