/*
* Copyright 2011 Instituto Superior Tecnico
*
* https://fenix-ashes.ist.utl.pt/
*
* This file is part of the vaadin-framework.
*
* The vaadin-framework Infrastructure is free software: you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation, either version
* 3 of the License, or (at your option) any later version.*
*
* vaadin-framework is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with vaadin-framework. If not, see .
*
*/
package pt.ist.vaadinframework.data;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventObject;
import java.util.HashMap;
import java.util.LinkedList;
import org.apache.commons.lang.StringUtils;
import pt.ist.fenixWebFramework.services.ServiceManager;
import pt.ist.fenixWebFramework.services.ServicePredicate;
import pt.ist.vaadinframework.data.util.ServiceUtils;
import com.vaadin.data.Buffered;
import com.vaadin.data.BufferedValidatable;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Validatable;
import com.vaadin.data.Validator.InvalidValueException;
public abstract class AbstractBufferedItem extends BufferedProperty implements Item,
Item.PropertySetChangeNotifier {
private final LinkedList list = new LinkedList();
private final HashMap map = new HashMap();
private ItemConstructor constructor;
private ItemWriter writer;
private LinkedList propertySetChangeListeners = null;
private boolean propertySetChangePropagationEnabled = true;
private Item.PropertySetChangeEvent lastEvent;
public AbstractBufferedItem(Property wrapped, Hint... hints) {
super(wrapped, hints);
}
public AbstractBufferedItem(Class extends Type> type, Hint... hints) {
super(type, hints);
}
public AbstractBufferedItem(Type value, Hint... hints) {
super(value, hints);
}
public AbstractBufferedItem(Type value, Class extends Type> type, Hint... hints) {
super(value, type, hints);
}
@Override
protected void processNewCacheValue() {
for (Id propertyId : getItemPropertyIds()) {
if (getItemProperty(propertyId) instanceof Buffered) {
((Buffered) getItemProperty(propertyId)).discard();
}
}
}
@Override
public boolean addItemProperty(Object propertyId, Property property) {
// Null ids are not accepted
if (propertyId == null) {
throw new NullPointerException("Item property id can not be null");
}
// Cant add a property twice
if (map.containsKey(propertyId)) {
return false;
}
// Put the property to map
map.put((Id) propertyId, property);
list.add((Id) propertyId);
// Send event
fireItemPropertySetChange();
return true;
}
@Override
public boolean removeItemProperty(Object propertyId) {
// Cant remove missing properties
if (map.remove(propertyId) == null) {
return false;
}
list.remove(propertyId);
// propertyValues.remove(propertyId);
// Send change events
fireItemPropertySetChange();
return true;
}
@Override
public Collection getItemPropertyIds() {
return list != null ? Collections.unmodifiableCollection(list) : (Collection) Collections.emptyList();
}
public void setConstructor(ItemConstructor constructor) {
this.constructor = constructor;
}
public void setWriter(ItemWriter writer) {
this.writer = writer;
}
@Override
public Property getItemProperty(Object propertyId) {
Property property = map.get(propertyId);
if (property == null) {
property = makeProperty((Id) propertyId);
}
return property;
}
/**
* Lazy creation of properties, this method is invoked for every propertyId
* that is requested of the Item. The created properties are not
* automatically registered in the item, you have to invoke {@link #addItemProperty(Object, Property)} yourself. You also need
* to
* ensure that the returned properties are of {@link BufferedProperty}s or {@link Item}s or {@link Collection}s over
* {@link BufferedProperty}s.
*
* @param propertyId
* The key of the property.
* @return A {@link Property} instance.
*/
protected abstract Property makeProperty(Id propertyId);
@Override
public void commit() throws SourceException, InvalidValueException {
ServiceManager.execute(new ServicePredicate() {
@Override
public void execute() {
try {
if (!isInvalidCommitted() && !isValid()) {
validate();
}
if (cache == null) {
construct(true);
fireValueChange();
} else {
applyWriter();
}
for (Id propertyId : getItemPropertyIds()) {
if (getItemProperty(propertyId) instanceof Buffered) {
((Buffered) getItemProperty(propertyId)).commit();
}
}
if (isModified()) {
wrapped.setValue(cache);
}
discard();
modified = false;
} catch (Throwable e) {
ServiceUtils.handleException(e);
throw new SourceException(AbstractBufferedItem.this, e);
}
}
});
}
private void construct(boolean taint) {
Object value;
if (constructor != null) {
try {
Method method = findMethod(constructor.getClass(), getArgumentTypes(constructor.getOrderedArguments()));
Object[] argumentValues = readArguments(constructor.getOrderedArguments());
value = method.invoke(constructor, argumentValues);
} catch (Throwable e) {
ServiceUtils.handleException(e);
throw new SourceException(this, e);
}
} else {
try {
value = getType().newInstance();
} catch (Throwable e) {
ServiceUtils.handleException(e);
throw new SourceException(this, e);
}
}
cache = convertValue(value);
modified = taint;
}
private void applyWriter() {
if (writer != null) {
try {
if (fieldDiffer(writer.getOrderedArguments())) {
LinkedList> argumentTypes = new LinkedList>();
argumentTypes.add(getType());
argumentTypes.addAll(Arrays.asList(getArgumentTypes(writer.getOrderedArguments())));
Method method = findMethod(writer.getClass(), argumentTypes.toArray(new Class>[0]));
LinkedList