![JAR search and dependency download from the Maven repository](/logo.png)
it.tidalwave.metadata.spi.impl.MetadataItemAspect Maven / Gradle / Ivy
The newest version!
/***********************************************************************************************************************
*
* 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.spi.impl;
import java.lang.reflect.Method;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import it.tidalwave.util.logging.Logger;
import net.sf.cglib.proxy.MethodProxy;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Property;
import it.tidalwave.beans.AbstractEnhancer;
import it.tidalwave.beans.FastBeanProperty;
import it.tidalwave.beans.JavaBean;
import it.tidalwave.beans.JavaBeanAspect;
import java.io.Serializable;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/*******************************************************************************
*
* This special Interceptor enhances beans providing the implementation of the
* MetadataItem interface and the special behavior for isXXXAvailable()
* properties.
*
* @author Fabrizio Giudici
* @version $Id$
*
******************************************************************************/
public class MetadataItemAspect extends JavaBeanAspect
{
private final static String CLASS = MetadataItemAspect.class.getName();
private final static Logger logger = Logger.getLogger(CLASS);
private final static long serialVersionUID = 6408780450730439759L;
private final static String AVAILABLE_SUFFIX = "Available";
// private final static Property AVAILABLE_PROPERTY = BeanProperty.create("available");
// private final static String PROP_LATEST_MODIFICATION_TIME = "latestModificationTime";
private final static List METADATAITEM_METHODS = Arrays.asList(JavaBean.class.getMethods());
// private Date latestModificationTime;
// private boolean available;
// private boolean oldAvailable;
interface SerializablePropertyChangeListener extends PropertyChangeListener, Serializable
{
}
/***************************************************************************
*
* Provides support for updating properties latestModificationTime
* and available
when the inner beans are updated.
*
**************************************************************************/
// private final PropertyChangeListener innerBeanListener = new SerializablePropertyChangeListener()
// {
// public void propertyChange (final PropertyChangeEvent event)
// {
// if (event.getPropertyName().equals(PROP_LATEST_MODIFICATION_TIME))
// {
// updateLatestModificationTime((Date)event.getNewValue());
// }
//
// else
// {
// updateAvailability(oldAvailable, (Boolean)AVAILABLE_PROPERTY.getValue(bean));
// }
// }
// };
/***************************************************************************
*
*
**************************************************************************/
public MetadataItemAspect (@Nonnull final Object bean,
@Nonnull final AbstractEnhancer> enhancer,
@Nonnull final Object ... arguments)
{
super(fixInitialStatus(bean), enhancer, arguments);
// for (final JavaBean enhancedObject : getEnhancedObjects())
// {
// enhancedObject.addPropertyChangeListener(innerBeanListener);
// }
for (final Object argument : arguments)
{
if (argument instanceof Date)
{
// TODO: fail assertion to spot points where you call this
// this.latestModificationTime = (Date)argument;
break;
}
}
// oldAvailable = (Boolean)AVAILABLE_PROPERTY.getValue(bean);
}
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
// public boolean isAvailable()
// {
// return available;
// }
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
// public Date getLatestModificationTime()
// {
// return latestModificationTime;
// }
/***************************************************************************
*
* {@inheritDoc}
*
**************************************************************************/
@Override
@CheckForNull
public Object intercept (@Nonnull final Object object,
@Nonnull final Method method,
@Nonnull final Object[] methodParameters,
@Nonnull final MethodProxy proxy)
throws Throwable
{
Object result;
final String methodName = method.getName();
if (method.getName().startsWith("get") && (methodParameters.length == 0))
{
result = interceptGet(object, method, methodParameters, proxy);
}
else if (methodName.startsWith("set") && (methodParameters.length == 1))
{
result = interceptSet(object, method, methodParameters, proxy);
}
else
{
result = super.intercept(object, method, methodParameters, proxy);
}
return result;
}
/***************************************************************************
*
*
**************************************************************************/
@CheckForNull
private Object interceptGet (@Nonnull final Object object,
@Nonnull final Method method,
@Nonnull final Object[] methodParameters,
@Nonnull final MethodProxy proxy)
throws Throwable
{
Object result;
if (METADATAITEM_METHODS.contains(method))
{
result = method.invoke(this, methodParameters);
}
else
{
result = super.intercept(object, method, methodParameters, proxy);
}
return result;
}
/***************************************************************************
*
*
**************************************************************************/
@CheckForNull
private Object interceptSet (@Nonnull final Object object,
@Nonnull final Method method,
@Nonnull final Object[] methodParameters,
@Nonnull final MethodProxy proxy)
throws Throwable
{
// final boolean oldAvailable = (Boolean)AVAILABLE_PROPERTY.getValue(bean);
Object result = super.intercept(object, method, methodParameters, proxy);
final String changedPropertyName = getPropertyName(method);
final boolean isAvailabilityProperty = changedPropertyName.endsWith(AVAILABLE_SUFFIX);
// if property is set to non null, setPropertyAvailability(true)
if (!isAvailabilityProperty && (methodParameters[0] != null))
{
final String propertyAvailabilityName = changedPropertyName + AVAILABLE_SUFFIX;
final Property propertyAvailability = BeanProperty.create(propertyAvailabilityName);
final boolean oldValue = (Boolean)propertyAvailability.getValue(bean);
if (!oldValue)
{
logger.finest(">>>> %s - %s set to not null, setting %sAvailable=true",
object, changedPropertyName, changedPropertyName);
propertyAvailability.setValue(bean, true);
propertyChangeSupport.firePropertyChange(propertyAvailabilityName, oldValue, true);
}
}
// if the availability is set to false, setProperty(null)
else if (isAvailabilityProperty && Boolean.FALSE.equals(methodParameters[0]))
{
final String propertyName = changedPropertyName.replaceAll(AVAILABLE_SUFFIX + "$", "");
final Property property = BeanProperty.create(propertyName);
final Object oldValue = property.getValue(bean);
if (oldValue != null)
{
logger.finest(">>>> %s - %sAvailable set to false, setting %s=null",
object, propertyName, propertyName);
property.setValue(bean, null);
propertyChangeSupport.firePropertyChange(propertyName, oldValue, null);
}
}
// updateAvailability(oldAvailable, (Boolean)AVAILABLE_PROPERTY.getValue(bean));
// updateLatestModificationTime(new Date());
return result;
}
/***************************************************************************
*
* Fixes the initial status of the bean setting xxxAvailable
* properties when the related xxx
property is not null.
*
* @param bean the bean
* @return the bean
*
**************************************************************************/
@Nonnull
private static Object fixInitialStatus (@Nonnull final Object bean)
{
logger.fine("fixInitialStatus(%s)", bean);
validateBean(bean);
final Class> beanClass = bean.getClass();
final PropertyDescriptor[] propertyDescriptors;
try
{
propertyDescriptors = Introspector.getBeanInfo(beanClass).getPropertyDescriptors();
}
catch (IntrospectionException e)
{
throw new RuntimeException(e);
}
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors)
{
final String propertyName = propertyDescriptor.getName();
if (!propertyName.endsWith(AVAILABLE_SUFFIX))
{
final Property property = FastBeanProperty.create(propertyName);
final Property availabilityProperty = FastBeanProperty.create(propertyName + AVAILABLE_SUFFIX);
// BeanProperty triggers ConcurrentModificationException:
// see https://beansbinding.dev.java.net/issues/show_bug.cgi?id=57
// final Property property = BeanProperty.create(propertyName);
// final Property availabilityProperty = BeanProperty.create(propertyName + AVAILABLE_SUFFIX);
if (availabilityProperty.isReadable(bean) && availabilityProperty.isWriteable(bean))
{
// logger.finer(">>>> checking property %s", propertyName));
if (property.getValue(bean) != null)
{
if (!(Boolean)availabilityProperty.getValue(bean))
{
logger.finest(">>>> %s is not null, setting %s%s=true",
propertyName, propertyName, AVAILABLE_SUFFIX);
availabilityProperty.setValue(bean, true);
}
}
}
}
}
return bean;
}
/***************************************************************************
*
* Updates the availability property and eventually fire an event.
*
* @param oldAvailable the old value
* @param newAvailable the new value
*
**************************************************************************/
// private void updateAvailability (final boolean oldAvailable, final boolean available)
// {
// this.available = available;
//
// if (available != oldAvailable)
// {
// propertyChangeSupport.firePropertyChange("available", oldAvailable, available);
// }
// }
/***************************************************************************
*
* Updates the latestModificationTime
property and eventually
* fires an event.
*
* @param timestamp the new timestamp
*
**************************************************************************/
// private void updateLatestModificationTime (final Date timestamp)
// {
// if ((this.latestModificationTime == null) || this.latestModificationTime.before(timestamp))
// {
// final Date oldValue = this.latestModificationTime;
// this.latestModificationTime = timestamp;
// propertyChangeSupport.firePropertyChange(PROP_LATEST_MODIFICATION_TIME, oldValue,timestamp);
// }
// }
/***************************************************************************
*
* Validates the bean, checking if mandatory properties are defined.
*
* @param bean the bean to validate
* @throws IllegalArgumentException if the bean is not valid
*
**************************************************************************/
private static void validateBean (@Nonnull final Object bean)
throws IllegalArgumentException
{
// if (!AVAILABLE_PROPERTY.isReadable(bean))
// {
// throw new IllegalArgumentException(String.format("Unreadable property %s on %s", AVAILABLE_PROPERTY, bean.getClass()));
// }
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy