javaa.beans.DefaultPersistenceDelegate Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package javaa.beans;
import javaa.beans.BeanInfo;
import javaa.beans.Encoder;
import javaa.beans.Expression;
import javaa.beans.IntrospectionException;
import javaa.beans.Introspector;
import javaa.beans.PersistenceDelegate;
import javaa.beans.PropertyDescriptor;
import javaa.beans.Statement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import jadex.common.SAccess;
/**
* Default PersistenceDelegate for normal classes. The instances of this class
* are used when other customized PersistenceDelegate is not set in the encoders
* for a particular type.
*
* This PersistenceDelegate assumes that the bean to be made persistent has a
* default constructor that takes no parameters or a constructor that takes some
* properties as its parameters. Only the properties that can be got or set
* based on the knowledge gained through an introspection will be made
* persistent. In the case that a bean is constructed with some properties, the
* value of these properties should be available via the conventional getter
* method.
*
*
* @see Encoder
*/
public class DefaultPersistenceDelegate extends PersistenceDelegate {
// shared empty property name array
private static String[] EMPTY_PROPERTIES = new String[0];
// names of the properties accepted by the bean's constructor
private String[] propertyNames = EMPTY_PROPERTIES;
/**
* Constructs a DefaultPersistenceDelegate
instance that
* supports the persistence of a bean which has a default constructor.
*
*/
public DefaultPersistenceDelegate() {
// empty
}
/**
* Constructs a DefaultPersistenceDelegate
instance that
* supports the persistence of a bean which is constructed with some
* properties.
*
* @param propertyNames
* the name of the properties that are taken as parameters by the
* bean's constructor
*/
public DefaultPersistenceDelegate(String[] propertyNames) {
if (null != propertyNames) {
this.propertyNames = propertyNames;
}
}
/**
* Initializes the new instance in the new environment so that it becomes
* equivalent with the old one, meanwhile recording this process in the
* encoder.
*
* This is done by inspecting each property of the bean. The property value
* from the old bean instance and the value from the new bean instance are
* both retrieved and examined to see whether the latter mutates to the
* former, and if not, issue a call to the write method to set the
* equivalent value for the new instance. Exceptions occured during this
* process are reported to the exception listener of the encoder.
*
*
* @param type
* the type of the bean
* @param oldInstance
* the original bean object to be recorded
* @param newInstance
* the simmulating new bean object to be initialized
* @param enc
* the encoder to write the outputs to
*/
@Override
protected void initialize(Class> type, Object oldInstance,
Object newInstance, Encoder enc) {
// Call the initialization of the super type
super.initialize(type, oldInstance, newInstance, enc);
// Continue only if initializing the "current" type
if (type != oldInstance.getClass()) {
return;
}
// Get all bean properties
BeanInfo info = null;
try {
info = Introspector.getBeanInfo(type);
} catch (IntrospectionException ex) {
enc.getExceptionListener().exceptionThrown(ex);
return;
}
PropertyDescriptor[] pds = info.getPropertyDescriptors();
// Initialize each found non-transient property
for (int i = 0; i < pds.length; i++) {
// Skip a property whose transient attribute is true
if (Boolean.TRUE.equals(pds[i].getValue("transient"))) { //$NON-NLS-1$
continue;
}
// Skip a property having no setter or getter
if (null == pds[i].getWriteMethod()
|| null == pds[i].getReadMethod()) {
continue;
}
// Get the value of the property in the old instance
Expression getterExp = new Expression(oldInstance, pds[i]
.getReadMethod().getName(), null);
try {
// Calculate the old value of the property
Object oldVal = getterExp.getValue();
// Write the getter expression to the encoder
enc.writeExpression(getterExp);
// Get the target value that exists in the new environment
Object targetVal = enc.get(oldVal);
// Get the current property value in the new environment
Object newVal = new Expression(newInstance, pds[i]
.getReadMethod().getName(), null).getValue();
/*
* Make the target value and current property value equivalent
* in the new environment
*/
if (null == targetVal) {
if (null != newVal) {
// Set to null
Statement setterStm = new Statement(oldInstance, pds[i]
.getWriteMethod().getName(),
new Object[] { null });
enc.writeStatement(setterStm);
}
} else {
PersistenceDelegate pd = enc
.getPersistenceDelegate(targetVal.getClass());
if (!pd.mutatesTo(targetVal, newVal)) {
Statement setterStm = new Statement(oldInstance, pds[i]
.getWriteMethod().getName(),
new Object[] { oldVal });
enc.writeStatement(setterStm);
}
}
} catch (Exception ex) {
enc.getExceptionListener().exceptionThrown(ex);
}
}
}
/*
* Get the field value of an object using privileged code.
*/
private Object getFieldValue(Object oldInstance, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Class extends Object> c = oldInstance.getClass();
final Field f = c.getDeclaredField(fieldName);
AccessController.doPrivileged(new PrivilegedAction