Skip to content

Commit

Permalink
fix: Update current UI instance upon locale change
Browse files Browse the repository at this point in the history
Fixes #11599
  • Loading branch information
mshabarov committed Sep 1, 2021
1 parent ff4dbc5 commit 9033bba
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 1 deletion.
6 changes: 6 additions & 0 deletions flow-server/src/main/java/com/vaadin/flow/component/UI.java
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,12 @@ public ExecutionRegistration beforeClientResponse(Component component,
"The 'execution' parameter may not be null");
}

if (component.getUI().isPresent() && component.getUI().get() != this) {
throw new IllegalArgumentException(
"The given component doesn't belong to the UI the task to be executed on"
);
}

return internals.getStateTree().beforeClientResponse(
component.getElement().getNode(), execution);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,15 @@ public void setLocale(Locale locale) {
checkHasLock();
this.locale = locale;

getUIs().forEach(ui -> ui.setLocale(locale));
getUIs().forEach(ui -> {
Map<Class<?>, CurrentInstance> oldInstances = CurrentInstance
.setCurrent(ui);
try {
ui.setLocale(locale);
} finally {
CurrentInstance.restoreInstances(oldInstances);
}
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright 2000-2021 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.flow.uitest.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HtmlComponent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.NativeButton;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.i18n.LocaleChangeEvent;
import com.vaadin.flow.i18n.LocaleChangeObserver;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.VaadinSession;

@Route("com.vaadin.flow.uitest.ui.LocaleChangeView")
public class LocaleChangeView extends Div {

public static final String SAME_UI_RESULT_ID = "same-ui-result-id";
public static final String CHANGE_LOCALE_BUTTON_ID =
"change-locale-button-id";
public static final String SHOW_RESULTS_BUTTON_ID =
"show-results-button-id";

public LocaleChangeView() {
Locale defaultLocale = UI.getCurrent().getLocale();
NativeButton changeLocaleButton = new NativeButton("Change Locale",
click -> {
if (defaultLocale.equals(Locale.ENGLISH)) {
changeSessionLocale(Locale.FRANCE);
} else {
changeSessionLocale(Locale.ENGLISH);
}
});
changeLocaleButton.setId(CHANGE_LOCALE_BUTTON_ID);

LocaleObserverComponent localeObserverComponent = new LocaleObserverComponent(
defaultLocale);

NativeButton showLocaleUpdates = new NativeButton("Show locale updates",
click -> localeObserverComponent.showLocaleUpdates());
showLocaleUpdates.setId(SHOW_RESULTS_BUTTON_ID);

add(changeLocaleButton, showLocaleUpdates,
new HtmlComponent(Tag.BR), localeObserverComponent);
}

private void changeSessionLocale(Locale france) {
UI.getCurrent().getSession().setLocale(france);
}

@Tag("Div")
private static class LocaleObserverComponent extends Component
implements HasComponents, LocaleChangeObserver {

private final Locale defaultLocale;

public LocaleObserverComponent(Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}

@Override
public void localeChange(LocaleChangeEvent event) {
if (event.getLocale().equals(defaultLocale)) {
return;
}
final boolean sameUI = getUI().isPresent()
&& getUI().get() == UI.getCurrent();

registerLocaleUpdate(sameUI);
}

public void showLocaleUpdates() {
LocaleUpdates localeUpdates = getLocaleUpdates();
renderResults(localeUpdates);
}

private void renderResults(LocaleUpdates localeUpdates) {
for (int i = 0; i < localeUpdates.getUiCheckResults().size(); i++) {
Boolean checkResult = localeUpdates.getUiCheckResults().get(i);
Span sameUIResult = new Span();
sameUIResult.setId(String.format("%s-%d", SAME_UI_RESULT_ID,
i));
sameUIResult.setText(Boolean.toString(checkResult));
Span caption = new Span(String.format(
"Component %d uses current UI instance = ", i));
add(caption, sameUIResult, new HtmlComponent(Tag.BR));
}
}

private void registerLocaleUpdate(boolean sameUIcheckUp) {
VaadinSession session = VaadinSession.getCurrent();
session.lock();
try {
LocaleUpdates localeUpdates = session
.getAttribute(LocaleUpdates.class);
if (localeUpdates == null) {
localeUpdates = new LocaleUpdates();
}
localeUpdates.addUICheckResult(sameUIcheckUp);
session.setAttribute(LocaleUpdates.class, localeUpdates);
} finally {
session.unlock();
}
}

private LocaleUpdates getLocaleUpdates() {
VaadinSession session = VaadinSession.getCurrent();
session.lock();
try {
return session.getAttribute(LocaleUpdates.class);
} finally {
session.unlock();
}
}
}

static class LocaleUpdates {
private final List<Boolean> uiCheckResults = new ArrayList<>(3);

public void addUICheckResult(boolean uiCheckResult) {
uiCheckResults.add(uiCheckResult);
}

public List<Boolean> getUiCheckResults() {
return uiCheckResults;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2021 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.flow.uitest.ui;

import java.util.stream.IntStream;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.vaadin.flow.testutil.ChromeBrowserTest;

import static com.vaadin.flow.uitest.ui.LocaleChangeView.CHANGE_LOCALE_BUTTON_ID;
import static com.vaadin.flow.uitest.ui.LocaleChangeView.SAME_UI_RESULT_ID;
import static com.vaadin.flow.uitest.ui.LocaleChangeView.SHOW_RESULTS_BUTTON_ID;

public class LocaleChangeIT extends ChromeBrowserTest {

@Test
public void setSessionLocale_currentUIInstanceUpdatedUponEachLocaleUpdate() {
final int openedUI = 3;

IntStream.range(0, openedUI).forEach(i -> open());

waitForElementPresent(By.id(CHANGE_LOCALE_BUTTON_ID));
findElement(By.id(CHANGE_LOCALE_BUTTON_ID)).click();

waitForElementPresent(By.id(SHOW_RESULTS_BUTTON_ID));
findElement(By.id(SHOW_RESULTS_BUTTON_ID)).click();

IntStream.range(0, openedUI).forEach(i -> {
String id = String.format("%s-%d", SAME_UI_RESULT_ID, i);
waitForElementPresent(By.id(id));
WebElement result = findElement(By.id(id));
Assert.assertTrue(
"Component's UI and current UI instances are different",
Boolean.parseBoolean(result.getText()));
});
}
}

0 comments on commit 9033bba

Please sign in to comment.