/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * Copyright (c) 2013, MPL CodeInside http://codeinside.ru */ package ru.codeinside.gses.lazyquerycontainer; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.vaadin.data.Item; import com.vaadin.data.util.BeanItem; import com.vaadin.data.util.ObjectProperty; public abstract class AbstractBeanQuery<T extends Object> implements Query { /** QueryDefinition contains definition of the query properties. */ private QueryDefinition queryDefinition; /** Query configuration contains implementation specific configuration. */ private Map<String, Object> queryConfiguration; /** The properties participating in sort. */ private Object[] sortPropertyIds; /** The ascending or descending state of sort properties. */ private boolean[] sortStates; /** * Default constructor for serialization. */ public AbstractBeanQuery() { } /** * The constructor for parameterizing the query. * @param queryDefinition QueryDefinition contains the query properties. * @param queryConfiguration Implementation specific configuration. * @param sortPropertyIds The properties participating in sort. * @param sortStates The ascending or descending state of sort properties. */ public AbstractBeanQuery(final QueryDefinition queryDefinition, final Map<String, Object> queryConfiguration, final Object[] sortPropertyIds, final boolean[] sortStates) { this.queryDefinition = queryDefinition; this.queryConfiguration = queryConfiguration; this.sortPropertyIds = sortPropertyIds; this.sortStates = sortStates; } /** * @return the queryDefinition */ protected final QueryDefinition getQueryDefinition() { return queryDefinition; } /** * @return the queryConfiguration */ protected final Map<String, Object> getQueryConfiguration() { return queryConfiguration; } /** * @return the sortPropertyIds */ protected final Object[] getSortPropertyIds() { return sortPropertyIds; } /** * @return the sortStates */ protected final boolean[] getSortStates() { return sortStates; } /** * Constructs new item based on QueryDefinition. * @return new item. */ public final Item constructItem() { try { T bean = constructBean(); BeanInfo info = Introspector.getBeanInfo(bean.getClass()); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { for (Object propertyId : queryDefinition.getPropertyIds()) { if (pd.getName().equals(propertyId)) { pd.getWriteMethod().invoke(bean, queryDefinition.getPropertyDefaultValue(propertyId)); } } } return toItem(bean); } catch (Exception e) { throw new RuntimeException( "Error in bean construction or property population with default values.", e); } } /** * Constructs new bean. * @return a new bean. */ protected abstract T constructBean(); /** * Number of beans returned by query. * @return number of beans. */ public abstract int size(); /** * Load batch of items. * @param startIndex Starting index of the item list. * @param count Count of the items to be retrieved. * @return List of items. */ public final List<Item> loadItems(final int startIndex, final int count) { List<Item> items = new ArrayList<Item>(); for (T bean : loadBeans(startIndex, count)) { items.add(toItem(bean)); } return items; } /** * Loads a batch of beans. * @param startIndex index of first bean to return in a batch, * @param count maximum number of beans in this batch. * @return List of beans identified by startIndex and count. */ protected abstract List<T> loadBeans(int startIndex, int count); /** * Saves the modifications done by container to the query result. * Query will be discarded after changes have been saved * and new query loaded so that changed items are sorted * appropriately. * @param addedItems Items to be inserted. * @param modifiedItems Items to be updated. * @param removedItems Items to be deleted. */ public final void saveItems(final List<Item> addedItems, final List<Item> modifiedItems, final List<Item> removedItems) { saveBeans(fromItems(addedItems), fromItems(modifiedItems), fromItems(removedItems)); } /** * Saves the modifications done by container to the query result. * Query will be discarded after changes have been saved * and new query loaded so that changed items are sorted * appropriately. * @param addedBeans Beans to be inserted. * @param modifiedBeans Beans to be updated. * @param removedBeans Beans to be deleted. */ protected abstract void saveBeans(List<T> addedBeans, List<T> modifiedBeans, List<T> removedBeans); /** * Removes all items. * Query will be discarded after delete all items has been called. * @return true if the operation succeeded or false in case of a failure. */ public final boolean deleteAllItems() { throw new UnsupportedOperationException(); } /** * Converts bean to Item. Implemented by encapsulating the Bean * first to BeanItem and then to CompositeItem. * @param bean bean to be converted. * @return item converted from bean. */ @SuppressWarnings({ "unchecked", "rawtypes" }) private Item toItem(final T bean) { BeanItem<T> beanItem = new BeanItem<T>(bean); if (queryDefinition.isCompositeItems()) { CompositeItem compositeItem = new CompositeItem(); compositeItem.addItem("bean", beanItem); for (Object propertyId : queryDefinition.getPropertyIds()) { if (compositeItem.getItemProperty(propertyId) == null) { compositeItem.addItemProperty( propertyId, new ObjectProperty(queryDefinition .getPropertyDefaultValue(propertyId), queryDefinition.getPropertyType(propertyId), queryDefinition.isPropertyReadOnly(propertyId))); } } return compositeItem; } else { return beanItem; } } /** * Converts item back to bean. * @param item Item to be converted to bean. * @return Resulting bean. */ @SuppressWarnings("unchecked") private T fromItem(final Item item) { if (queryDefinition.isCompositeItems()) { return ((BeanItem<T>) (((CompositeItem) item).getItem("bean"))) .getBean(); } else { return ((BeanItem<T>) item).getBean(); } } /** * Converts List of Items to List of Beans. * @param items Item List to be converted. * @return List of beans converted from Items. */ private List<T> fromItems(final List<Item> items) { ArrayList<T> beans = new ArrayList<T>(); for (Item item : items) { beans.add(fromItem(item)); } return beans; } }