![JAR search and dependency download from the Maven repository](/logo.png)
it.tidalwave.metadata.viewer.impl.Syncer Maven / Gradle / Ivy
/***********************************************************************************************************************
*
* blueMarine Metadata - open source media workflow
* Copyright (C) 2007-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* 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.
*
***********************************************************************************************************************
*
* WWW: http://bluemarine.tidalwave.it
* SCM: https://kenai.com/hg/bluemarine~metadata-src
*
**********************************************************************************************************************/
package it.tidalwave.metadata.viewer.impl;
import java.lang.reflect.Method;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.List;
import it.tidalwave.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.jdesktop.beansbinding.Property;
import it.tidalwave.beans.FastBeanProperty;
import java.util.Date;
/*******************************************************************************
*
* @author Fabrizio Giudici
* @version $Id$
*
******************************************************************************/
public class Syncer implements PropertyChangeListener
{
private static final String CLASS = Syncer.class.getName();
private static final Logger logger = Logger.getLogger(CLASS);
// FIXME: these should be dynamically taken from JavaBeanAspect
private static final List JAVA_BEAN_ASPECT_PROPERTIES =
Arrays.asList("callback", "callbacks", "class", "propertyChangeListeners", "vetoableChangeListeners");
private final Bean source;
private final Bean target;
private final boolean forceEDT;
/** My name, useful only for logging. */
private final String name;
/***************************************************************************
*
*
**************************************************************************/
public Syncer (final String name, final Bean source, final Bean target, final boolean copy, final boolean forceEDT)
{
this.name = name;
this.target = target;
this.source = source;
this.forceEDT = forceEDT;
if (copy)
{
int count = 0;
final long time = System.currentTimeMillis();
final PropertyDescriptor[] descriptors = findDescriptors(target.getClass());
for (final PropertyDescriptor descriptor : descriptors)
{
count++;
final String propertyName = descriptor.getName();
if (!JAVA_BEAN_ASPECT_PROPERTIES.contains(propertyName) && !propertyName.endsWith("Available"))
{
final Property property = FastBeanProperty.create(propertyName);
final Property availableProperty = FastBeanProperty.create(propertyName + "Available");
if (availableProperty.isReadable(source))
{
final boolean available = availableProperty.getValue(source);
availableProperty.setValue(target, available);
if (available)
{
Object value = property.getValue(source);
if (value instanceof Date)
{
value = new Date(((Date)value).getTime());
}
logger.fine(">>>> %s: setting initial value %s.%s = %s", name,target, propertyName, value);
property.setValue(target, value);
}
}
}
}
logger.info(">>>> %s: synced %d properties in %d msec", name, count, System.currentTimeMillis() - time);
}
}
/***************************************************************************
*
*
**************************************************************************/
public void bind()
{
addPropertyChangeListener(source, this);
}
/***************************************************************************
*
*
**************************************************************************/
public void unbind()
{
removePropertyChangeListener(source, this);
}
/***************************************************************************
*
*
**************************************************************************/
public void propertyChange (final PropertyChangeEvent event)
{
final String propertyName = event.getPropertyName();
try
{
if (!JAVA_BEAN_ASPECT_PROPERTIES.contains(propertyName))
{
final Object value = event.getNewValue();
final Property property = FastBeanProperty.create(propertyName);
if (property.isWriteable(target))
{
// logger.fine(">>>> syncing %s %s->%s: %s", propertyName, source, target, value));
final Object oldValue = property.getValue(target);
if (!equals(oldValue, value))
{
logger.fine(">>>> %s: syncing %s %s->%s: %s", name, propertyName, source, target, value);
// TODO: EDT compliance should be instead implemented as a decorator in the bean,
// as form.getBean() doesn't get any protection!
// TODO: the above could not be a problem if you clarify that getBean() must be used
// for aliasing only - make it protected?
if (!forceEDT || SwingUtilities.isEventDispatchThread())
{
property.setValue(target, value);
}
else
{
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
property.setValue(target, value);
}
});
}
}
}
}
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
logger.throwing(CLASS, name + ": failed syncing " + propertyName, e);
}
}
/***************************************************************************
*
*
**************************************************************************/
private static void addPropertyChangeListener (final Object bean, final PropertyChangeListener listener)
{
try
{
final Method method = bean.getClass().getMethod("addPropertyChangeListener", PropertyChangeListener.class);
method.invoke(bean, listener);
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/***************************************************************************
*
*
**************************************************************************/
private static void removePropertyChangeListener (final Object bean, final PropertyChangeListener listener)
{
try
{
final Method method = bean.getClass().getMethod("removePropertyChangeListener", PropertyChangeListener.class);
method.invoke(bean, listener);
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/***************************************************************************
*
*
**************************************************************************/
private static PropertyDescriptor[] findDescriptors (final Class> clazz)
{
try
{
return Introspector.getBeanInfo(clazz).getPropertyDescriptors();
}
catch (IntrospectionException e)
{
throw new RuntimeException(e);
}
}
/***************************************************************************
*
*
**************************************************************************/
private static boolean equals (final Object o1, final Object o2)
{
if (o1 == null)
{
return o2 == null;
}
//FIXME: handle arrays
return o1.equals(o2);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy