/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.common;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ObjectUtils;
import org.projectforge.core.ShortDisplayNameCapable;
import de.micromata.hibernate.history.delta.PropertyDelta;
import de.micromata.hibernate.history.delta.SimplePropertyDelta;
/**
* Stores one imported object (e. g. MS Excel row as bean object). It also contains information about the status: New object or modified
* object.
*
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class ImportedElement<T> implements Serializable
{
private static final long serialVersionUID = -3405918702811291053L;
private T value;
private T oldValue;
private int index;
private Class<T> clazz;
private String[] diffProperties;
private List<PropertyDelta> propertyDeltas;
private boolean reconciled;
private boolean selected;
private Map<String, Object> errorProperties;
/**
* Later the diff properties should be replaced by HibernateHistory and AbstractBaseDO mechanism.
* @param clazz Needed for reflection.
* @param diffProperties List of property names which will be used for display property changes.
*/
public ImportedElement(int index, Class<T> clazz, String[] diffProperties)
{
this.index = index;
this.clazz = clazz;
this.diffProperties = diffProperties;
}
public void setValue(T value)
{
this.value = value;
this.propertyDeltas = null;
}
public T getValue()
{
return value;
}
public void setOldValue(T oldValue)
{
this.oldValue = oldValue;
this.propertyDeltas = null;
}
public T getOldValue()
{
return oldValue;
}
public List<PropertyDelta> getPropertyChanges()
{
if (oldValue == null) {
return null;
}
if (propertyDeltas != null) {
return propertyDeltas;
}
for (String fieldname : diffProperties) {
Method method = BeanHelper.determineGetter(clazz, fieldname);
if (method == null) {
throw new UnsupportedOperationException("Oups, no getter for property '"
+ fieldname
+ "' found for (maybe typo in fieldname?): "
+ value);
}
Object newValue = BeanHelper.invoke(value, method);
Object origValue = BeanHelper.invoke(oldValue, method);
boolean modified = false;
if (method.getReturnType() == BigDecimal.class) {
if (NumberHelper.isEqual((BigDecimal) newValue, (BigDecimal) origValue) == false) {
modified = true;
}
} else if (ObjectUtils.equals(newValue, origValue) == false) {
modified = true;
}
if (modified == true) {
if (propertyDeltas == null) {
propertyDeltas = new ArrayList<PropertyDelta>();
}
Object ov;
Object nv;
if (origValue instanceof ShortDisplayNameCapable) {
ov = ((ShortDisplayNameCapable) origValue).getShortDisplayName();
} else {
ov = origValue;
}
if (newValue instanceof ShortDisplayNameCapable) {
nv = ((ShortDisplayNameCapable) newValue).getShortDisplayName();
} else {
nv = newValue;
}
PropertyDelta delta = new MySimplePropertyDelta(fieldname, method.getReturnType(), ov, nv);
propertyDeltas.add(delta);
}
}
return propertyDeltas;
}
private class MySimplePropertyDelta extends SimplePropertyDelta implements Serializable
{
private static final long serialVersionUID = -6828269529571580866L;
private MySimplePropertyDelta(final String propertyName, final Class< ? > propertyType, final Object oldValue, final Object newValue)
{
super(propertyName, propertyType, oldValue, newValue);
}
}
/**
* Noch nicht verprobte Datensätze (isReconciled == false) gelten nicht als modifiziert.
*/
public boolean isModified()
{
return reconciled == true && oldValue != null && CollectionUtils.isEmpty(getPropertyChanges()) == false;
}
/**
* Noch nicht verprobte Datensätze (isReconciled == false) gelten weder als modifiziert noch als nicht modifiziert.
*/
public boolean isUnmodified()
{
return reconciled == true && oldValue != null && oldValue.equals(value) == true;
}
/**
* Noch nicht verprobte Datensätze (isReconciled == false) gelten nicht als neu.
*/
public boolean isNew()
{
return reconciled == true && oldValue == null;
}
/**
* Wurde dieser Eintrag schon verprobt? Erst, wenn er verprobt wurde, ergeben die anderen Abfragen isModified etc. Sinn.
*/
public boolean isReconciled()
{
return reconciled;
}
/**
* @return true, if errorProperties is not empty, otherwise false.
*/
public boolean isFaulty()
{
return MapUtils.isNotEmpty(errorProperties);
}
public void setReconciled(boolean reconciled)
{
this.reconciled = reconciled;
}
/**
* Only selected values will be imported. If hasErrors = true, always false will be returned.
*/
public boolean isSelected()
{
return isFaulty() == false && selected;
}
/**
* If hasErrors == true then this item will be deselected.
* @param selected
*/
public void setSelected(boolean selected)
{
if (isFaulty() == false) {
this.selected = selected;
} else {
this.selected = false;
}
}
/**
* Should be unique in the ImportedSheet and is use-able for indexed properties (e. g. check boxes).
* @return
*/
public int getIndex()
{
return index;
}
/**
* For properties which can't be mapped due to errors (e. g. referenced element not found).
* @param key
* @param value
*/
public void putErrorProperty(String key, Object value)
{
if (errorProperties == null) {
errorProperties = new HashMap<String, Object>();
}
errorProperties.put(key, value);
}
public void removeErrorProperty(String key)
{
if (errorProperties != null) {
errorProperties.remove(key);
}
}
public Map<String, Object> getErrorProperties()
{
return errorProperties;
}
/**
* @param key
* @return The error property if found, otherwise null.
*/
public Object getErrorProperty(String key)
{
Object obj = null;
if (errorProperties != null) {
obj = errorProperties.get(key);
}
if (obj == null) {
return null;
}
return obj;
}
}