/* * Copyright 2000-2016 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.tests.performance; import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Random; import java.util.stream.Collectors; import java.util.stream.IntStream; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Country; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.HasComponents; import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; /** * @author Vaadin Ltd * */ public abstract class AbstractBeansMemoryTest<T extends AbstractComponent> extends UI { private int dataSize; private boolean isInMemory; private boolean isDataOnly; private Label logLabel; private Label memoryLabel; @Override protected void init(VaadinRequest request) { String items = request.getParameter("items"); int itemsCount = 1; if (items != null) { itemsCount = Integer.parseInt(items); } VerticalLayout layout = new VerticalLayout(); setContent(layout); layout.addComponent(new Label(getClass().getSimpleName())); memoryLabel = new Label(); memoryLabel.setId("memory"); layout.addComponent(memoryLabel); logLabel = new Label(); logLabel.setId("log"); layout.addComponent(logLabel); T component = createComponent(); setData(null, itemsCount, component, true); layout.addComponent(createMenu(component)); layout.addComponent(component); Button close = new Button("Close UI", event -> close()); close.setId("close"); layout.addComponent(close); } protected abstract T createComponent(); private Random random = new Random(); protected List<Person> createBeans(int size) { return IntStream.range(0, size).mapToObj(this::createPerson) .collect(Collectors.toList()); } protected Person createPerson(int index) { random.setSeed(index); Person person = new Person(); person.setFirstName("First Name " + random.nextInt()); person.setLastName("Last Name " + random.nextInt()); person.setAge(random.nextInt()); person.setBirthDate(new Date(random.nextLong())); person.setDeceased(random.nextBoolean()); person.setEmail(random.nextInt() + "user@example.com"); person.setRent(new BigDecimal(random.nextLong())); person.setSalary(random.nextInt()); person.setSalaryDouble(random.nextDouble()); person.setSex(Sex.values()[random.nextInt(Sex.values().length)]); Address address = new Address(); person.setAddress(address); address.setCity("city " + random.nextInt()); address.setPostalCode(random.nextInt()); address.setStreetAddress("street address " + random.nextInt()); address.setCountry( Country.values()[random.nextInt(Country.values().length)]); return person; } protected abstract void setInMemoryContainer(T component, List<Person> data); protected abstract void setBackendContainer(T component, List<Person> data); @Override public VerticalLayout getContent() { return (VerticalLayout) super.getContent(); } @SuppressWarnings("restriction") private void setData(MenuItem item, int size, T component, boolean memoryContainer) { if (item != null) { MenuItem parent = item.getParent(); parent.getChildren().stream().filter(itm -> !itm.equals(item)) .forEach(itm -> itm.setChecked(false)); logLabel.setValue(item.getText()); } dataSize = size; isInMemory = memoryContainer; List<Person> persons = createBeans(size); if (isDataOnly) { component.setData(persons); persons = Collections.emptyList(); } else { component.setData(null); } if (isInMemory) { setInMemoryContainer(component, persons); } else { setBackendContainer(component, persons); } HasComponents container = component.getParent(); setParent(component, null); memoryLabel.setValue( String.valueOf(ObjectSizeCalculator.getObjectSize(component))); setParent(component, container); } private void setParent(Component component, Component parent) { try { Field field = AbstractComponent.class.getDeclaredField("parent"); field.setAccessible(true); field.set(component, parent); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } } private Component createMenu(T component) { MenuBar menu = new MenuBar(); createContainerSizeMenu(menu.addItem("Size", null), component); createContainerMenu(menu.addItem("Data provider", null), component); menu.addItem("Create only data", item -> toggleDataOnly(item, component)).setCheckable(true); return menu; } private void toggleDataOnly(MenuItem item, T component) { isDataOnly = item.isChecked(); setData(null, dataSize, component, isInMemory); } private void createContainerMenu(MenuItem menu, T component) { MenuItem menuItem = menu.addItem("Use in-memory container", item -> setData(item, dataSize, component, true)); menuItem.setCheckable(true); menuItem.setChecked(true); menuItem = menu.addItem("Use backend container", item -> setData(item, dataSize, component, false)); menuItem.setCheckable(true); } private void createContainerSizeMenu(MenuItem menu, T component) { List<MenuItem> items = IntStream.of(1, 10000, 100000, 500000, 1000000) .mapToObj(size -> addContainerSizeMenu(size, menu, component)) .collect(Collectors.toList()); if (dataSize == 1) { items.get(0).setChecked(true); } } private MenuItem addContainerSizeMenu(int size, MenuItem menu, T component) { MenuItem item = menu.addItem("Set data provider size to " + size, itm -> setData(itm, size, component, isInMemory)); item.setCheckable(true); return item; } }