All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.util.beans.BeanMonitor Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * #%L
 * Nuiton Utils
 * 
 * $Id: BeanMonitor.java 2316 2012-04-03 13:33:26Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/nuiton-utils/tags/nuiton-utils-2.6.10/nuiton-utils/src/main/java/org/nuiton/util/beans/BeanMonitor.java $
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * This program 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.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package org.nuiton.util.beans;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import static org.nuiton.i18n.I18n._;

/**
 * A monitor of beans.
 * 

* You indicates which properties to monitor (via the constructor). *

* Then attach a bean to monitor via the method {@link #setBean(Object)}. *

* The method {@link #clearModified()} reset the states about modified * properties. *

* The method {@link #wasModified()} tells if there was any modification on * monitored properties for the attached bean since the last call to * {@link #clearModified()} (or {@link #setBean(Object)}. *

* the method {@link #getModifiedProperties()} gives you the names of monitored * properties for the attached bean since the last call to * {@link #clearModified()} (or {@link #setBean(Object)}. * * @author tchemit * @since 1.4.1 */ public class BeanMonitor { /** Logger */ private static final Log log = LogFactory.getLog(BeanMonitor.class); /** Names of properties to watch on attached bean. */ protected final List propertyNames; /** Names of monitored and modified properties for the attached bean. */ protected final Map propertyDiffs; /** * The {@link PropertyChangeListener} which listen modification on bean * only on monitored properties. */ protected final PropertyChangeListener listener; /** The bean to monitor. */ protected Object bean; /** * Constructor of monitor with property names to monitor. * * @param propertyNames the names of properties to monitor */ public BeanMonitor(String... propertyNames) { this.propertyNames = Arrays.asList(propertyNames); propertyDiffs = new LinkedHashMap(); listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (!BeanMonitor.this.propertyNames.contains(propertyName)) { return; } // the property is monitored Object newValue = evt.getNewValue(); Object oldValue = evt.getOldValue(); PropertyDiff propertyDiff; if (propertyDiffs.containsKey(propertyName)) { // property was already modified propertyDiff = propertyDiffs.get(propertyName); // change the target value propertyDiff.setTargetValue(newValue); // check if value did not come back to original Object originalValue = propertyDiff.getSourceValue(); if (ObjectUtils.equals(originalValue, newValue)) { // coming back to original value // the property is no more modified propertyDiffs.remove(propertyName); } } else { // check old value and newvalue are real not equals if (ObjectUtils.notEqual(newValue, oldValue)) { propertyDiff = new PropertyDiff( propertyName, oldValue, propertyName, newValue, null ); // add it to modified properties propertyDiffs.put(propertyName, propertyDiff); } } // if (modifiedProperties.contains(propertyName)) { // // // property already modified // // check if value did not come back to original // Object originalValue = originalValues.get(propertyName); // // if (originalValue == null && newValue == null || // originalValue != null && originalValue.equals(newValue)) { // // // coming back to original value // // the property is no more modified // modifiedProperties.remove(propertyName); // originalValues.remove(propertyName); // return; // } // // // can safely return since original is already known // // and property is already known to be modified // return; // } // // // the property was not modified before // // just mark it and keep the original value // modifiedProperties.add(propertyName); // originalValues.put(propertyName, oldValue); } }; } /** * Obtains the monitored {@link #bean}. * * @return the attached bean, or {@code null} if none attached. */ public Object getBean() { return bean; } /** * Tells if any of the monitored properties were modified on the attached * bean since last call to {@link #clearModified()} or * {@link #setBean(Object)}. * * @return {@code true} if there were a modified monitored property on * the attached bean, {@code false} otherwise. */ public boolean wasModified() { return !propertyDiffs.isEmpty(); } /** * Obtains the names of monitored properties which has been touched for the * attached bean since last call to {@link #clearModified()} or * {@link #setBean(Object)}. * * @return the array of property names to monitor. */ public String[] getModifiedProperties() { Set propertyNames = propertyDiffs.keySet(); return propertyNames.toArray(new String[propertyNames.size()]); } /** * Obtains the original values for all modified properties. * * @return the dictionnary of original values for modified properties */ public Map getOriginalValues() { // always expose a copy of map Map map = new TreeMap(); for (PropertyDiff propertyDiff : propertyDiffs.values()) { map.put(propertyDiff.getSourceProperty(), propertyDiff.getSourceValue()); } return map; } /** * Obtains the property diffs since the bean is monitoried. * * @return the property diffs since the bean is monitoried. * @since 2.4 */ public PropertyDiff[] getPropertyDiffs() { Collection values = propertyDiffs.values(); return values.toArray(new PropertyDiff[values.size()]); } /** * Sets the {@code bean} to monitor. *

* As a side effect, it will attach the {@link #listener} to new bean * (if not null) and remove it from the previous bean attached (if not null). *

* As a second side effect, it will always clean the modified states, * using the method {@link #clearModified()}. * * @param bean the new bean to monitor */ public void setBean(Object bean) { Object oldBean = this.bean; this.bean = bean; // while removing a bean must clean modified states clearModified(); if (oldBean != null) { // dettach listener from old bean try { BeanUtil.removePropertyChangeListener(listener, oldBean); } catch (Exception eee) { log.error(_("nuitonutil.error.could.not.removePCL", listener, oldBean, eee.getMessage())); } } if (bean != null) { // attach listener to new bean try { BeanUtil.addPropertyChangeListener(listener, bean); } catch (Exception eee) { log.error(_("nuitonutil.error.could.not.addPCL", listener, bean, eee.getMessage())); } } } /** To clear the modified states. */ public void clearModified() { propertyDiffs.clear(); // modifiedProperties.clear(); // originalValues.clear(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy