Hi,
I’ve just noticed that it seems that data loaded by a user into a view, appears in the same view of another user.
In other words, here is what happens:
User 1 & User 2 visit the same MyView at approximatively the same time. MyView extends VerticalLayout, implements AfterNavigationObserver and contains a Grid that is instanciated and added by a method tagged @PostConstruct. The grid is filled by data retrieved by a service that is called in the overriden afterNavigation method of the same class. Once the view is loaded, User 1 has only his data in the grid, whereas User 2 has both his data and User 1’s.
I’ve verified and the instances are different (different object hashes) and access by a different user.
Is this the expected behaviour???
Here is an excerpt of the MyView class:
package com.ixm.sna.view;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ixm.sna.entity.ProcedureTest;
import com.ixm.sna.entity.RefFirewallRuleType;
import com.ixm.sna.entity.repository.SysparamRepository;
import com.ixm.sna.restconsumer.ProcedureTestsRestConsumer;
import com.ixm.sna.service.UserService;
import com.ixm.sna.thread.ProcedureTestThread;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.H5;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.AfterNavigationEvent;
import com.vaadin.flow.router.AfterNavigationObserver;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.UIScope;
import org.apache.commons.lang3.ObjectUtils;
@CssImport(value = "frontend://css/grid-cell.css", themeFor = "vaadin-grid")
@Route(value = "MyView", layout = LayoutWithMenuBar.class)
@UIScope
@Component
public class MyView extends VerticalLayout implements AfterNavigationObserver {
private final Logger logger = LoggerFactory.getLogger(MyView.class);
@Autowired
private ProcedureTestsRestConsumer restConsumer;
@Autowired
private SysparamRepository sysparamRepository;
@Autowired
private UserService userService;
private Grid<ProcedureTest> myGrid;
@PostConstruct
public void init() {
setUpView();
}
private void setUpView() {
H5 header = new H5("My View");
add(header);
myGrid = new Grid<>(ProcedureTest.class);
myGrid.setHeightByRows(true);
myGrid.setColumns(
"name", "description", "status"
);
myGrid.addColumn(new ComponentRenderer<>(ct -> {
if (!(ct instanceof ProcedureTest)) {
return new Paragraph();
}
ProcedureTest procedureTest = (ProcedureTest)ct;
if (procedureTest.getProcedureTestResult() == ProcedureTest.ProcedureTestResult.NOT_REACHABLE) {
return new Icon(VaadinIcon.CLOSE_CIRCLE);
} else if (procedureTest.getProcedureTestResult() == ProcedureTest.ProcedureTestResult.REACHABLE) {
return new Icon(VaadinIcon.CHECK);
} else {
// no icon if not tested
return new Paragraph();
}
})).setHeader("Test status").setWidth("50px");
myGrid.setClassNameGenerator(ct -> {
if (!(ct instanceof ProcedureTest)) {
return "error";
}
ProcedureTest procedureTest = (ProcedureTest)ct;
if (procedureTest.getProcedureTestResult()
.equals(ProcedureTest.ProcedureTestResult.REACHABLE)) {
return "success";
} else if (procedureTest.getProcedureTestResult()
.equals(ProcedureTest.ProcedureTestResult.NOT_TESTED)) {
return "not_tested";
} else {
return "error";
}
});
final Button buttonStartTests = new Button("Start tests");
HorizontalLayout firewallButtonStartTest = new HorizontalLayout(buttonStartTests);
add(myGrid, firewallButtonStartTest);
buttonStartTests.addClickListener((event) -> {
buttonStartTests.setEnabled(false);
List<ProcedureTest> procedureTests = myGrid.getDataProvider().fetch(new Query<>()).collect(Collectors.toList());
procedureTests.stream().forEach(ct -> ct.setProcedureTestResult(ProcedureTest.ProcedureTestResult.NOT_TESTED));
new ProcedureTestThread(sysparamRepository.getProcedureTestTimeout(), procedureTests, UI.getCurrent(), (ct, lastFinished) -> {
if (lastFinished) {
buttonStartTests.setEnabled(true);
myGrid.getDataProvider().refreshAll();
} else {
myGrid.getDataProvider().refreshItem(ct);
}
});
});
}
@Override
public void afterNavigation(AfterNavigationEvent ane) {
logger.info("Object accessed: "+ ObjectUtils.identityToString(this) +"; by: "+ userService.getCurrentUser().getUsername());
try {
logger.info("Getting procedureTests.");
List<ProcedureTest> procedureTests = restConsumer.getProcedureTests();
myGrid.setItems(procedureTests);
} catch (Exception e) {
logger.error("Error getting procedureTests.", e);
myGrid.setItems(new ArrayList<>());
}
}
}
Thanks for your help!
ixM