/*******************************************************************************
* Copyright 2013 Thomas Letsch (contact@thomas-letsch.de)
*
* 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 org.vaadin.addons.javaee.container;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.EJB;
import org.vaadin.addons.javaee.container.jpa.JPAEntityProvider;
import com.googlecode.javaeeutils.jpa.PersistentEntity;
import com.googlecode.javaeeutils.reflection.ReflectionUtils;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.filter.And;
import com.vaadin.data.util.filter.UnsupportedFilterException;
public abstract class AbstractEntityContainer<ENTITY extends PersistentEntity> implements EntityContainer<ENTITY> {
private static final long serialVersionUID = 1L;
@EJB
protected JPAEntityProvider jpaEntityProvider;
protected List<Container.ItemSetChangeListener> itemSetChangeListeners = new ArrayList<>();
protected List<Container.PropertySetChangeListener> propertySetChangeListeners = new ArrayList<>();
protected List<Filter> filters = new ArrayList<>();
protected List<SortDefinition> sortDefinitions = new ArrayList<>();
protected Map<String, Class<?>> properties = new HashMap<>();
protected Class<ENTITY> entityClass;
protected boolean needsFiltering = false;
protected boolean filterSet = false;
public AbstractEntityContainer(Class<ENTITY> entityClass) {
this.entityClass = entityClass;
initProperties(entityClass);
}
@Override
public abstract List<ENTITY> findAllEntities();
@Override
public Class<ENTITY> getEntityClass() {
return entityClass;
}
protected void initProperties(Class<ENTITY> entityClass) {
for (Field field : ReflectionUtils.getAllInstanceFields(entityClass)) {
if (!Modifier.isStatic(field.getModifiers())) {
properties.put(field.getName(), field.getType());
}
}
}
@Override
public void clear() {
filterSet = false;
notifyItemSetChanged();
}
@Override
public void loadItemWithRelations(EntityItem<ENTITY> item) {
refreshItem(item);
}
@Override
public Item getItem(Object itemId) {
return getItem((Long) itemId);
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Object addItemAfter(Object previousItemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Item addItemAfter(Object previousItemId, Object newItemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Collection<?> getContainerPropertyIds() {
return properties.keySet();
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
properties.put((String) propertyId, type);
notifyPropertySetChanged();
return true;
}
@Override
public Property<?> getContainerProperty(Object itemId, Object propertyId) {
Item item = getItem(itemId);
return item == null ? null : item.getItemProperty(propertyId);
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
boolean result = properties.remove(propertyId.toString()) != null;
notifyPropertySetChanged();
return result;
}
@Override
public Class<?> getCollectionType(String propertyId) {
return jpaEntityProvider.getType(entityClass, propertyId);
}
@Override
public Class<?> getType(Object propertyId) {
Class<?> type = properties.get(propertyId);
if (type == null) {
type = ReflectionUtils.getType(entityClass, (String) propertyId);
if (type != null) {
properties.put((String) propertyId, type);
}
}
return type;
}
private void notifyPropertySetChanged() {
PropertySetChangeEvent event = new EntityPropertySetChangeEvent<ENTITY>(this);
for (Container.PropertySetChangeListener listener : this.propertySetChangeListeners) {
listener.containerPropertySetChange(event);
}
}
protected void notifyItemSetChanged() {
ItemSetChangeEvent event = new EntityItemSetChangeEvent<ENTITY>(this);
for (Container.ItemSetChangeListener listener : this.itemSetChangeListeners) {
listener.containerItemSetChange(event);
}
}
@Override
public void addListener(PropertySetChangeListener listener) {
propertySetChangeListeners.add(listener);
}
@Override
public void addPropertySetChangeListener(PropertySetChangeListener listener) {
propertySetChangeListeners.add(listener);
}
@Override
public void removePropertySetChangeListener(PropertySetChangeListener listener) {
propertySetChangeListeners.remove(listener);
}
@Override
public void removeListener(PropertySetChangeListener listener) {
propertySetChangeListeners.remove(listener);
}
@Override
public void addItemSetChangeListener(ItemSetChangeListener listener) {
itemSetChangeListeners.add(listener);
}
@Override
public void addListener(ItemSetChangeListener listener) {
itemSetChangeListeners.add(listener);
}
@Override
public void removeItemSetChangeListener(ItemSetChangeListener listener) {
itemSetChangeListeners.remove(listener);
}
@Override
public void removeListener(ItemSetChangeListener listener) {
itemSetChangeListeners.remove(listener);
}
@Override
public Collection<Filter> getContainerFilters() {
return filters;
}
protected Filter getContainerFilter() {
if (filters.isEmpty()) {
return null;
}
if (filters.size() == 1) {
return filters.get(0);
}
Filter filter = new And(filters.toArray(new Filter[] {}));
return filter;
}
@Override
public <T extends Annotation> T getAnnotation(String fieldName, Class<T> annotationClass) {
return ReflectionUtils.getAnnotation(entityClass, fieldName, annotationClass);
}
protected boolean needProcess() {
return !needsFiltering || filterSet;
}
@Override
public void needsFiltering() {
needsFiltering = true;
}
@Override
public Object firstItemId() {
if (!needProcess()) {
return null;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return null;
}
return entities.get(0).getId();
}
@Override
public Object lastItemId() {
if (!needProcess()) {
return null;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return null;
}
return entities.get(entities.size() - 1).getId();
}
@Override
public Object nextItemId(Object itemId) {
if (!needProcess()) {
return null;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return null;
}
int index = entities.indexOf(getItem((Long) itemId).getEntity());
if (index == -1 || index >= entities.size() - 1) {
return null;
}
return entities.get(index + 1).getId();
}
@Override
public Object prevItemId(Object itemId) {
if (!needProcess()) {
return null;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return null;
}
int index = entities.indexOf(getItem((Long) itemId).getEntity());
if (index <= 0) {
return null;
}
return entities.get(index - 1).getId();
}
@Override
public boolean isFirstId(Object itemId) {
if (itemId == null) {
return false;
}
if (!needProcess()) {
return false;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return false;
}
int index = entities.indexOf(getItem((Long) itemId).getEntity());
return index == 0;
}
@Override
public boolean isLastId(Object itemId) {
if (itemId == null) {
return false;
}
if (!needProcess()) {
return false;
}
List<ENTITY> entities = findAllEntities();
if (entities.isEmpty()) {
return false;
}
int index = entities.indexOf(getItem((Long) itemId).getEntity());
return index == entities.size() - 1;
}
@Override
public List<String> getPropertyNames() {
return new ArrayList<String>(properties.keySet());
}
@Override
public void addContainerFilter(Filter filter) throws UnsupportedFilterException {
filterSet = true;
this.filters.add(filter);
notifyItemSetChanged();
}
@Override
public void removeContainerFilter(Filter filter) {
this.filters.remove(filter);
notifyItemSetChanged();
}
@Override
public void removeAllContainerFilters() {
this.filters.clear();
filterSet = false;
notifyItemSetChanged();
}
@Override
public void sort(Object[] propertyId, boolean[] ascending) {
sortDefinitions.clear();
for (int i = 0; i < propertyId.length; i++) {
sortDefinitions.add(new SortDefinition(propertyId[i].toString(), (ascending.length > i) ? ascending[i] : true));
}
notifyItemSetChanged();
}
@Override
public Collection<?> getSortableContainerPropertyIds() {
return getPropertyNames();
}
@Override
public Collection<?> getItemIds() {
if (!needProcess()) {
return Collections.EMPTY_LIST;
}
List<ENTITY> entitys = findAllEntities();
List<Long> ids = new ArrayList<Long>(entitys.size());
for (ENTITY entity : entitys) {
ids.add(entity.getId());
}
return ids;
}
@Override
public boolean containsId(Object itemId) {
if (!needProcess()) {
return false;
}
for (ENTITY item : findAllEntities()) {
if (item.getId().equals(itemId)) {
return true;
}
}
return false;
}
@Override
public int size() {
if (!needProcess()) {
return 0;
}
return findAllEntities().size();
}
@Override
public void refreshCache() {
}
@Override
public void refreshEntity(Long id) {
}
}