1. Domain model
package is.codion.framework.demos.petstore.domain;
import is.codion.framework.domain.DomainModel;
import is.codion.framework.domain.DomainType;
import is.codion.framework.domain.entity.EntityDefinition;
import is.codion.framework.domain.entity.EntityType;
import is.codion.framework.domain.entity.StringFactory;
import is.codion.framework.domain.entity.attribute.Column;
import is.codion.framework.domain.entity.attribute.ForeignKey;
import java.math.BigDecimal;
import static is.codion.framework.domain.DomainType.domainType;
import static is.codion.framework.domain.entity.KeyGenerator.sequence;
import static is.codion.framework.domain.entity.OrderBy.ascending;
public final class Petstore extends DomainModel {
public static final DomainType DOMAIN = domainType(Petstore.class);
public Petstore() {
super(DOMAIN);
add(address(), category(), product(), sellerContactInfo(), item(), tag(), tagItem());
}
public interface Address {
EntityType TYPE = DOMAIN.entityType("address");
Column<Integer> ID = TYPE.integerColumn("Address id");
Column<String> STREET_1 = TYPE.stringColumn("Street 1");
Column<String> STREET_2 = TYPE.stringColumn("Street 2");
Column<String> CITY = TYPE.stringColumn("City");
Column<String> STATE = TYPE.stringColumn("State");
Column<Integer> ZIP = TYPE.integerColumn("Zip");
Column<Double> LATITUDE = TYPE.doubleColumn("Latitude");
Column<Double> LONGITUDE = TYPE.doubleColumn("Longitude");
}
EntityDefinition address() {
return Address.TYPE.define(
Address.ID.define()
.primaryKey()
.name("addressid"),
Address.STREET_1.define()
.column()
.caption(Address.STREET_1.name())
.name("street1")
.maximumLength(55)
.nullable(false),
Address.STREET_2.define()
.column()
.caption(Address.STREET_2.name())
.name("street2")
.maximumLength(55),
Address.CITY.define()
.column()
.caption(Address.CITY.name())
.name("city")
.maximumLength(55)
.nullable(false),
Address.STATE.define()
.column()
.caption(Address.STATE.name())
.name("state")
.maximumLength(25)
.nullable(false),
Address.ZIP.define()
.column()
.caption(Address.ZIP.name())
.name("zip")
.nullable(false),
Address.LATITUDE.define()
.column()
.caption(Address.LATITUDE.name())
.name("latitude")
.nullable(false)
.maximumFractionDigits(2),
Address.LONGITUDE.define()
.column()
.caption(Address.LONGITUDE.name())
.name("longitude")
.nullable(false)
.maximumFractionDigits(2))
.tableName("petstore.address")
.keyGenerator(sequence("petstore.address_seq"))
.orderBy(ascending(Address.CITY, Address.STREET_1, Address.STREET_2))
.stringFactory(StringFactory.builder()
.value(Address.STREET_1).text(" ")
.value(Address.STREET_2).text(", ")
.value(Address.CITY).text(" ")
.value(Address.ZIP).text(", ")
.value(Address.STATE)
.build())
.caption("Addresses")
.build();
}
public interface Category {
EntityType TYPE = DOMAIN.entityType("category");
Column<Integer> ID = TYPE.integerColumn("Category id");
Column<String> NAME = TYPE.stringColumn("Name");
Column<String> DESCRIPTION = TYPE.stringColumn("Description");
Column<String> IMAGE_URL = TYPE.stringColumn("Image URL");
}
EntityDefinition category() {
return Category.TYPE.define(
Category.ID.define()
.primaryKey()
.name("categoryid"),
Category.NAME.define()
.column()
.caption(Category.NAME.name())
.name("name")
.maximumLength(25)
.nullable(false),
Category.DESCRIPTION.define()
.column()
.caption(Category.DESCRIPTION.name())
.name("description")
.maximumLength(255)
.nullable(false),
Category.IMAGE_URL.define()
.column()
.caption(Category.IMAGE_URL.name())
.name("imageurl")
.hidden(true))
.tableName("petstore.category")
.keyGenerator(sequence("petstore.category_seq"))
.orderBy(ascending(Category.NAME))
.stringFactory(Category.NAME)
.caption("Categories")
.build();
}
public interface Product {
EntityType TYPE = DOMAIN.entityType("product");
Column<Integer> ID = TYPE.integerColumn("Product id");
Column<Integer> CATEGORY_ID = TYPE.integerColumn("Category id");
Column<String> NAME = TYPE.stringColumn("Name");
Column<String> DESCRIPTION = TYPE.stringColumn("Description");
Column<String> IMAGE_URL = TYPE.stringColumn("Image URL");
ForeignKey CATEGORY_FK = TYPE.foreignKey("Category", CATEGORY_ID, Category.ID);
}
EntityDefinition product() {
return Product.TYPE.define(
Product.ID.define()
.primaryKey()
.name("productid"),
Product.CATEGORY_ID.define()
.column()
.name("categoryid")
.nullable(false),
Product.CATEGORY_FK.define()
.foreignKey()
.caption(Product.CATEGORY_FK.name()),
Product.NAME.define()
.column()
.caption(Product.NAME.name())
.name("name")
.maximumLength(25)
.nullable(false),
Product.DESCRIPTION.define()
.column()
.caption(Product.DESCRIPTION.name())
.name("description")
.maximumLength(255)
.nullable(false),
Product.IMAGE_URL.define()
.column()
.caption(Product.IMAGE_URL.name())
.name("imageurl")
.maximumLength(55)
.hidden(true))
.tableName("petstore.product")
.keyGenerator(sequence("petstore.product_seq"))
.orderBy(ascending(Product.NAME))
.stringFactory(StringFactory.builder()
.value(Product.CATEGORY_FK)
.text(" - ")
.value(Product.NAME)
.build())
.caption("Products")
.build();
}
public interface SellerContactInfo {
EntityType TYPE = DOMAIN.entityType("sellercontactinfo");
Column<Integer> ID = TYPE.integerColumn("Contactinfo id");
Column<String> FIRST_NAME = TYPE.stringColumn("First name");
Column<String> LAST_NAME = TYPE.stringColumn("Last name");
Column<String> EMAIL = TYPE.stringColumn("Email");
}
EntityDefinition sellerContactInfo() {
return SellerContactInfo.TYPE.define(
SellerContactInfo.ID.define()
.primaryKey()
.name("contactinfoid"),
SellerContactInfo.FIRST_NAME.define()
.column()
.caption(SellerContactInfo.FIRST_NAME.name())
.searchable(true)
.name("firstname")
.maximumLength(24)
.nullable(false),
SellerContactInfo.LAST_NAME.define()
.column()
.caption(SellerContactInfo.LAST_NAME.name())
.searchable(true)
.name("lastname")
.maximumLength(24)
.nullable(false),
SellerContactInfo.EMAIL.define()
.column()
.caption(SellerContactInfo.EMAIL.name())
.name("email")
.maximumLength(24)
.nullable(false))
.tableName("petstore.sellercontactinfo")
.keyGenerator(sequence("petstore.sellercontactinfo_seq"))
.orderBy(ascending(SellerContactInfo.LAST_NAME, SellerContactInfo.FIRST_NAME))
.stringFactory(StringFactory.builder()
.value(SellerContactInfo.LAST_NAME)
.text(", ")
.value(SellerContactInfo.FIRST_NAME)
.build())
.caption("Seller info")
.build();
}
public interface Item {
EntityType TYPE = DOMAIN.entityType("item");
Column<Integer> ID = TYPE.integerColumn("Item id");
Column<Integer> PRODUCT_ID = TYPE.integerColumn("Product id");
Column<String> NAME = TYPE.stringColumn("Name");
Column<String> DESCRIPTION = TYPE.stringColumn("Description");
Column<String> IMAGE_URL = TYPE.stringColumn("Image URL");
Column<String> IMAGE_THUMB_URL = TYPE.stringColumn("Image thumbnail URL");
Column<BigDecimal> PRICE = TYPE.bigDecimalColumn("Price");
Column<Integer> CONTACT_INFO_ID = TYPE.integerColumn("Contactinfo id");
Column<Integer> ADDRESS_ID = TYPE.integerColumn("Address id");
Column<Boolean> DISABLED = TYPE.booleanColumn("Disabled");
ForeignKey PRODUCT_FK = TYPE.foreignKey("Product", PRODUCT_ID, Product.ID);
ForeignKey CONTACT_INFO_FK = TYPE.foreignKey("Contact info", CONTACT_INFO_ID, SellerContactInfo.ID);
ForeignKey ADDRESS_FK = TYPE.foreignKey("Address", ADDRESS_ID, Address.ID);
}
EntityDefinition item() {
return Item.TYPE.define(
Item.ID.define()
.primaryKey()
.name("itemid"),
Item.PRODUCT_ID.define()
.column()
.name("productid")
.nullable(false),
Item.PRODUCT_FK.define()
.foreignKey(2)
.caption(Item.PRODUCT_FK.name()),
Item.NAME.define()
.column()
.caption(Item.NAME.name())
.name("name")
.maximumLength(30)
.nullable(false),
Item.DESCRIPTION.define()
.column()
.caption(Item.DESCRIPTION.name())
.name("description")
.maximumLength(500)
.nullable(false),
Item.IMAGE_URL.define()
.column()
.caption(Item.IMAGE_URL.name())
.name("imageurl")
.maximumLength(55)
.hidden(true),
Item.IMAGE_THUMB_URL.define()
.column()
.caption(Item.IMAGE_THUMB_URL.name())
.name("imagethumburl")
.maximumLength(55)
.hidden(true),
Item.PRICE.define()
.column()
.caption(Item.PRICE.name())
.name("price")
.nullable(false)
.maximumFractionDigits(2),
Item.CONTACT_INFO_ID.define()
.column()
.name("contactinfo_contactinfoid")
.nullable(false),
Item.CONTACT_INFO_FK.define()
.foreignKey()
.caption(Item.CONTACT_INFO_FK.name()),
Item.ADDRESS_ID.define()
.column()
.name("address_addressid")
.nullable(false),
Item.ADDRESS_FK.define()
.foreignKey()
.caption("Address"),
Item.DISABLED.define()
.booleanColumn(Integer.class, 1, 0)
.caption(Item.DISABLED.name())
.name("disabled")
.defaultValue(false)
.nullable(false))
.tableName("petstore.item")
.keyGenerator(sequence("petstore.item_seq"))
.orderBy(ascending(Item.NAME))
.stringFactory(StringFactory.builder()
.value(Item.PRODUCT_FK)
.text(" - ")
.value(Item.NAME)
.build())
.caption("Items")
.build();
}
public interface Tag {
EntityType TYPE = DOMAIN.entityType("tag");
Column<Integer> ID = TYPE.integerColumn("Tag id");
Column<String> TAG = TYPE.stringColumn("Tag");
Column<Integer> REFCOUNT = TYPE.integerColumn("Reference count");
}
EntityDefinition tag() {
return Tag.TYPE.define(
Tag.ID.define()
.primaryKey()
.name("tagid"),
Tag.TAG.define()
.column()
.caption(Tag.TAG.name())
.name("tag")
.maximumLength(30)
.nullable(false),
Tag.REFCOUNT.define()
.subquery("SELECT COUNT(*) FROM petstore.tag_item WHERE tagid = tag.tagid")
.caption(Tag.REFCOUNT.name())
.name("refcount"))
.tableName("petstore.tag")
.keyGenerator(sequence("petstore.tag_seq"))
.orderBy(ascending(Tag.TAG))
.selectTableName("petstore.tag tag")
.stringFactory(Tag.TAG)
.caption("Tags")
.build();
}
public interface TagItem {
EntityType TYPE = DOMAIN.entityType("tag_item");
Column<Integer> ITEM_ID = TYPE.integerColumn("Item id");
Column<Integer> TAG_ID = TYPE.integerColumn("Tag id");
ForeignKey ITEM_FK = TYPE.foreignKey("Item", ITEM_ID, Item.ID);
ForeignKey TAG_FK = TYPE.foreignKey("Tag", TAG_ID, Tag.ID);
}
EntityDefinition tagItem() {
return TagItem.TYPE.define(
TagItem.ITEM_ID.define()
.primaryKey(0)
.name("itemid"),
TagItem.ITEM_FK.define()
.foreignKey(3)
.caption(TagItem.ITEM_FK.name()),
TagItem.TAG_ID.define()
.primaryKey(1)
.name("tagid"),
TagItem.TAG_FK.define()
.foreignKey()
.caption(TagItem.TAG_FK.name()))
.tableName("petstore.tag_item")
.stringFactory(StringFactory.builder()
.value(TagItem.ITEM_FK)
.text(" - ")
.value(TagItem.TAG_FK)
.build())
.caption("Item tags")
.build();
}
}
1.1. Domain unit test
package is.codion.framework.demos.petstore.domain;
import is.codion.framework.domain.test.DomainTest;
import org.junit.jupiter.api.Test;
import static is.codion.framework.demos.petstore.domain.Petstore.*;
public class PetstoreTest extends DomainTest {
public PetstoreTest() {
super(new Petstore());
}
@Test
void address() throws Exception {
test(Address.TYPE);
}
@Test
void category() throws Exception {
test(Category.TYPE);
}
@Test
void item() throws Exception {
test(Item.TYPE);
}
@Test
void product() throws Exception {
test(Product.TYPE);
}
@Test
void sellerInfo() throws Exception {
test(SellerContactInfo.TYPE);
}
@Test
void tag() throws Exception {
test(Tag.TYPE);
}
@Test
void tagItem() throws Exception {
test(TagItem.TYPE);
}
}
2. Model
2.1. Main application model
package is.codion.framework.demos.petstore.model;
import is.codion.framework.db.EntityConnectionProvider;
import is.codion.swing.framework.model.SwingEntityApplicationModel;
import is.codion.swing.framework.model.SwingEntityModel;
import static is.codion.framework.demos.petstore.domain.Petstore.*;
public final class PetstoreAppModel extends SwingEntityApplicationModel {
public PetstoreAppModel(EntityConnectionProvider connectionProvider) {
super(connectionProvider);
SwingEntityModel categoryModel = new SwingEntityModel(Category.TYPE, connectionProvider);
SwingEntityModel productModel = new SwingEntityModel(Product.TYPE, connectionProvider);
productModel.editModel().initializeComboBoxModels(Product.CATEGORY_FK);
SwingEntityModel itemModel = new SwingEntityModel(Item.TYPE, connectionProvider);
itemModel.editModel().initializeComboBoxModels(Item.PRODUCT_FK, Item.CONTACT_INFO_FK, Item.ADDRESS_FK);
SwingEntityModel tagItemModel = new SwingEntityModel(TagItem.TYPE, connectionProvider);
tagItemModel.editModel().initializeComboBoxModels(TagItem.ITEM_FK, TagItem.TAG_FK);
categoryModel.tableModel().refresh();
itemModel.addDetailModels(tagItemModel);
productModel.addDetailModels(itemModel);
categoryModel.addDetailModels(productModel);
addEntityModel(categoryModel);
}
}
3. UI
package is.codion.framework.demos.petstore.ui;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import javax.swing.JLabel;
import static is.codion.framework.demos.petstore.domain.Petstore.Address;
public class AddressEditPanel extends EntityEditPanel {
public AddressEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(Address.CITY);
createTextField(Address.CITY);
createTextField(Address.STATE);
createTextField(Address.ZIP);
createTextField(Address.STREET_1);
createTextField(Address.STREET_2);
createTextField(Address.LATITUDE);
createTextField(Address.LONGITUDE);
setLayout(Layouts.flexibleGridLayout(4, 2));
addInputPanel(Address.CITY);
addInputPanel(Address.STATE);
add(new JLabel());
addInputPanel(Address.ZIP);
addInputPanel(Address.STREET_1);
addInputPanel(Address.STREET_2);
addInputPanel(Address.LATITUDE);
addInputPanel(Address.LONGITUDE);
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import static is.codion.framework.demos.petstore.domain.Petstore.Category;
public class CategoryEditPanel extends EntityEditPanel {
public CategoryEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(Category.NAME);
createTextField(Category.NAME);
createTextField(Category.DESCRIPTION).columns(18);
createTextField(Category.IMAGE_URL);
setLayout(Layouts.flexibleGridLayout(2, 2));
addInputPanel(Category.NAME);
addInputPanel(Category.DESCRIPTION);
addInputPanel(Category.IMAGE_URL);
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import static is.codion.framework.demos.petstore.domain.Petstore.SellerContactInfo;
public class ContactInfoEditPanel extends EntityEditPanel {
public ContactInfoEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(SellerContactInfo.LAST_NAME);
createTextField(SellerContactInfo.LAST_NAME);
createTextField(SellerContactInfo.FIRST_NAME);
createTextField(SellerContactInfo.EMAIL);
setLayout(Layouts.flexibleGridLayout(3, 1));
addInputPanel(SellerContactInfo.LAST_NAME);
addInputPanel(SellerContactInfo.FIRST_NAME);
addInputPanel(SellerContactInfo.EMAIL);
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import static is.codion.framework.demos.petstore.domain.Petstore.*;
public class ItemEditPanel extends EntityEditPanel {
public ItemEditPanel(SwingEntityEditModel model) {
super(model);
defaults().textFieldColumns().set(14);
defaults().foreignKeyComboBoxPreferredWidth().set(180);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(Item.PRODUCT_FK);
createForeignKeyComboBox(Item.PRODUCT_FK);
createTextField(Item.NAME);
createTextFieldPanel(Item.DESCRIPTION)
.buttonFocusable(false);
createTextField(Item.PRICE);
createForeignKeyComboBoxPanel(Item.CONTACT_INFO_FK, this::createContactInfoEditPanel)
.includeAddButton(true);
createForeignKeyComboBoxPanel(Item.ADDRESS_FK, this::createAddressEditPanel)
.includeAddButton(true);
createTextField(Item.IMAGE_URL);
createTextField(Item.IMAGE_THUMB_URL);
createCheckBox(Item.DISABLED);
setLayout(Layouts.flexibleGridLayout(3, 3));
addInputPanel(Item.PRODUCT_FK);
addInputPanel(Item.NAME);
addInputPanel(Item.DESCRIPTION);
addInputPanel(Item.PRICE);
addInputPanel(Item.CONTACT_INFO_FK);
addInputPanel(Item.ADDRESS_FK);
addInputPanel(Item.IMAGE_URL);
addInputPanel(Item.IMAGE_THUMB_URL);
addInputPanel(Item.DISABLED);
}
private ContactInfoEditPanel createContactInfoEditPanel() {
return new ContactInfoEditPanel(new SwingEntityEditModel(SellerContactInfo.TYPE, editModel().connectionProvider()));
}
private AddressEditPanel createAddressEditPanel() {
return new AddressEditPanel(new SwingEntityEditModel(Address.TYPE, editModel().connectionProvider()));
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
import static is.codion.framework.demos.petstore.domain.Petstore.Product;
public class ProductEditPanel extends EntityEditPanel {
public ProductEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(Product.CATEGORY_FK);
createForeignKeyComboBox(Product.CATEGORY_FK);
createTextField(Product.NAME);
createTextField(Product.DESCRIPTION).columns(16);
setLayout(Layouts.flexibleGridLayout(3, 1));
addInputPanel(Product.CATEGORY_FK);
addInputPanel(Product.NAME);
addInputPanel(Product.DESCRIPTION);
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.framework.demos.petstore.domain.Petstore.Tag;
import is.codion.framework.demos.petstore.domain.Petstore.TagItem;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
public class TagItemEditPanel extends EntityEditPanel {
public TagItemEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(TagItem.ITEM_FK);
createForeignKeyComboBox(TagItem.ITEM_FK)
.preferredWidth(180);
createForeignKeyComboBoxPanel(TagItem.TAG_FK, this::createTagEditPanel)
.includeAddButton(true);
setLayout(Layouts.flexibleGridLayout(2, 1));
addInputPanel(TagItem.ITEM_FK);
addInputPanel(TagItem.TAG_FK);
}
private TagEditPanel createTagEditPanel() {
return new TagEditPanel(new SwingEntityEditModel(Tag.TYPE, editModel().connectionProvider()));
}
}
package is.codion.framework.demos.petstore.ui;
import is.codion.framework.demos.petstore.domain.Petstore.Tag;
import is.codion.swing.common.ui.layout.Layouts;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.ui.EntityEditPanel;
public class TagEditPanel extends EntityEditPanel {
public TagEditPanel(SwingEntityEditModel model) {
super(model);
}
@Override
protected void initializeUI() {
initialFocusAttribute().set(Tag.TAG);
createTextField(Tag.TAG).columns(16);
setLayout(Layouts.flexibleGridLayout(1, 1));
addInputPanel(Tag.TAG);
}
}
4. Main application panel
package is.codion.framework.demos.petstore.ui;
import is.codion.common.user.User;
import is.codion.framework.demos.petstore.model.PetstoreAppModel;
import is.codion.swing.framework.model.SwingEntityModel;
import is.codion.swing.framework.ui.EntityApplicationPanel;
import is.codion.swing.framework.ui.EntityPanel;
import is.codion.swing.framework.ui.TabbedDetailLayout;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import static is.codion.framework.demos.petstore.domain.Petstore.*;
import static is.codion.swing.framework.ui.EntityPanel.PanelState.HIDDEN;
public final class PetstoreAppPanel extends EntityApplicationPanel<PetstoreAppModel> {
public PetstoreAppPanel(PetstoreAppModel applicationModel) {
super(applicationModel);
}
@Override
protected List<EntityPanel> createEntityPanels() {
/* CATEGORY
* PRODUCT
* ITEM
* ITEMTAG
*/
SwingEntityModel categoryModel = applicationModel().entityModel(Category.TYPE);
SwingEntityModel productModel = categoryModel.detailModel(Product.TYPE);
SwingEntityModel itemModel = productModel.detailModel(Item.TYPE);
SwingEntityModel tagItemModel = itemModel.detailModel(TagItem.TYPE);
EntityPanel categoryPanel = new EntityPanel(categoryModel,
new CategoryEditPanel(categoryModel.editModel()),
config -> config.detailLayout(entityPanel -> TabbedDetailLayout.builder(entityPanel)
.splitPaneResizeWeight(0.3)
.build()));
EntityPanel productPanel = new EntityPanel(productModel,
new ProductEditPanel(productModel.editModel()));
EntityPanel itemPanel = new EntityPanel(itemModel,
new ItemEditPanel(itemModel.editModel()),
config -> config.detailLayout(entityPanel -> TabbedDetailLayout.builder(entityPanel)
.initialDetailState(HIDDEN)
.build()));
EntityPanel tagItemPanel = new EntityPanel(tagItemModel,
new TagItemEditPanel(tagItemModel.editModel()));
categoryPanel.addDetailPanel(productPanel);
productPanel.addDetailPanel(itemPanel);
itemPanel.addDetailPanels(tagItemPanel);
return List.of(categoryPanel);
}
@Override
protected List<EntityPanel.Builder> createSupportEntityPanelBuilders() {
SwingEntityModel.Builder tagModelBuilder =
SwingEntityModel.builder(Tag.TYPE)
.detailModel(SwingEntityModel.builder(TagItem.TYPE));
SwingEntityModel.Builder sellerContactInfoModelBuilder =
SwingEntityModel.builder(SellerContactInfo.TYPE)
.detailModel(SwingEntityModel.builder(Item.TYPE)
.detailModel(SwingEntityModel.builder(TagItem.TYPE)));
return Arrays.asList(
EntityPanel.builder(Address.TYPE)
.editPanel(AddressEditPanel.class),
EntityPanel.builder(sellerContactInfoModelBuilder)
.editPanel(ContactInfoEditPanel.class)
.detailPanel(EntityPanel.builder(Item.TYPE)
.editPanel(ItemEditPanel.class)
.detailPanel(EntityPanel.builder(TagItem.TYPE)
.editPanel(TagItemEditPanel.class))
.detailLayout(entityPanel -> TabbedDetailLayout.builder(entityPanel)
.initialDetailState(HIDDEN)
.build())),
EntityPanel.builder(tagModelBuilder)
.editPanel(TagEditPanel.class)
.detailPanel(EntityPanel.builder(TagItem.TYPE)
.editPanel(TagItemEditPanel.class))
.detailLayout(entityPanel -> TabbedDetailLayout.builder(entityPanel)
.initialDetailState(HIDDEN)
.build()));
}
public static void main(String[] args) {
Locale.setDefault(new Locale("en"));
EntityPanel.Config.TOOLBAR_CONTROLS.set(true);
EntityApplicationPanel.builder(PetstoreAppModel.class, PetstoreAppPanel.class)
.applicationName("The Pet Store")
.domainType(DOMAIN)
.defaultLoginUser(User.parse("scott:tiger"))
.start();
}
}
5. Load test
package is.codion.framework.demos.petstore.testing;
import is.codion.common.user.User;
import is.codion.framework.db.EntityConnectionProvider;
import is.codion.framework.demos.petstore.domain.Petstore;
import is.codion.framework.demos.petstore.model.PetstoreAppModel;
import is.codion.framework.model.EntityTableModel;
import is.codion.swing.framework.model.SwingEntityModel;
import is.codion.tools.loadtest.LoadTest;
import is.codion.tools.loadtest.LoadTest.Scenario;
import is.codion.tools.loadtest.LoadTest.Scenario.Performer;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import static is.codion.tools.loadtest.model.LoadTestModel.loadTestModel;
import static is.codion.tools.loadtest.ui.LoadTestPanel.loadTestPanel;
public final class PetstoreLoadTest {
private static final User UNIT_TEST_USER =
User.parse(System.getProperty("codion.test.user", "scott:tiger"));
private static final class PetstoreAppModelFactory
implements Function<User, PetstoreAppModel> {
@Override
public PetstoreAppModel apply(User user) {
PetstoreAppModel applicationModel = new PetstoreAppModel(
EntityConnectionProvider.builder()
.domainType(Petstore.DOMAIN)
.clientTypeId(getClass().getSimpleName())
.user(user)
.build());
SwingEntityModel categoryModel = applicationModel.entityModels().iterator().next();
categoryModel.detailModelLink(categoryModel.detailModels().iterator().next()).active().set(true);
SwingEntityModel productModel = categoryModel.detailModels().iterator().next();
productModel.detailModelLink(productModel.detailModels().iterator().next()).active().set(true);
SwingEntityModel itemModel = productModel.detailModels().iterator().next();
itemModel.detailModelLink(itemModel.detailModels().iterator().next()).active().set(true);
return applicationModel;
}
}
private static final class PetstoreUsageScenario
implements Performer<PetstoreAppModel> {
private static final Random RANDOM = new Random();
@Override
public void perform(PetstoreAppModel application) throws Exception {
SwingEntityModel categoryModel = application.entityModels().iterator().next();
categoryModel.tableModel().selection().clear();
categoryModel.tableModel().refresh();
selectRandomRow(categoryModel.tableModel());
selectRandomRow(categoryModel.detailModels().iterator().next().tableModel());
selectRandomRow(categoryModel.detailModels().iterator().next().detailModels().iterator().next().tableModel());
}
private static void selectRandomRow(EntityTableModel<?> tableModel) {
if (tableModel.items().visible().count() > 0) {
tableModel.selection().index().set(RANDOM.nextInt(tableModel.items().visible().count()));
}
}
}
public static void main(String[] args) {
LoadTest<PetstoreAppModel> loadTest =
LoadTest.builder(new PetstoreAppModelFactory(),
application -> application.connectionProvider().close())
.user(UNIT_TEST_USER)
.scenarios(List.of(Scenario.builder(new PetstoreUsageScenario())
.name("selectRecords")
.build()))
.name("Petstore LoadTest - " + EntityConnectionProvider.CLIENT_CONNECTION_TYPE.get())
.build();
loadTestPanel(loadTestModel(loadTest)).run();
}
}