Recently I upgraded my Java SDK from 1.5.0_08 to 1.5.0_11 to resolve a long path name issue for compiled classes. After doing this I updated the following ATG configuration files to reflect this change.
- home/installconfig/config.xml
- home/installconfig/configXMLproperties.txt
- home/localconfig/dasEnv.bat
- uninstall/.ASE2006.3_uninstall/installvariables.properties
ATG allows one to use your own Java class data types for the properties of repository items. This is called User-Defined Property Types.
While working with these user-defined property types I learned a few things that are not explicitly documented.
- The source for
atg.repository.FilePropertyDescriptor is supplied in the installation and it’s a good example for creating your own user-defined property type.
- To set values of properties in your Java class data type do two things.
- Configure the values of these properties using the attribute tag. For example:
<property name="contentFile" property-type="atg.repository.FilePropertyDescriptor">
<attribute name="pathNameProperty" value="contentFileName"/>
</property>
- Access these attributes and set the corresponding properties in the
setValue() method. Continuing with the above example:
public void setValue(String pAttributeName, Object pValue) {
super.setValue(pAttributeName, pValue);
if (pValue == null || pAttributeName == null) return;
if (pAttributeName.equalsIgnoreCase(PATH_NAME_PROPERTY))
mPathNameProperty = pValue.toString();
if (pAttributeName.equalsIgnoreCase(PATH_PREFIX))
mPathPrefix = pValue.toString();
}
- ATG’s documentation suggests it is not necessary to define the data-type attribute if you specify the type with the property-type attribute. However I found that sometimes ATG gets confused and that it is best practice to always set the data-type. So using the above example one would do this.
<property name="contentFile" data-type="string" property-type="atg.repository.FilePropertyDescriptor">
<attribute name="pathNameProperty" value="contentFileName"/>
</property>
- Only one instance of your user-defined property type is ever instantiated. Even if your user-defined property type is used for multiple properties it will still only be instantiated once.
- The JavaDoc for ATG’s RepositoryPropertyDescriptor class, which one typically extends to create ones own user-defined property type, documents the getPropertyValue method like this:
public java.lang.Object getPropertyValue(RepositoryItemImpl pItem, java.lang.Object pValue)
The first argument is the instance of the repository item whose property you are defining.
The second argument would be better named pCachedPropertyValue because it is the cached property value. If it is null then that means there is no cached value. If it is not null that means that in a previous call setPropertyValueInCache(this, yourvalue) was called. Unfortunately this cached value is not that useful because since only one instance of your user-defined property type is ever created, the cached value will be a global value.
This cached value is cleared when invalidateCaches is called on the repository item.
Here is what ATG support said about caching with User-Defined Property Types.
I think user defined properties will not be cached so that will cause your code to be
called several times. If you require some caching you would properly have to
implement it in the code of the user-defined property.
As a user defined property could return data from any external source that might get
updated independently of the ATG application we can not really make a decision on
what should be cached and what should be retrieved anew every single time.
Kind regards,
Olaf Doemer
- The property descriptor implements the Serializable interface so the developer must ensure that it is indeed serializable, i.e. all its members are serializable.
A JavaBeans is simply a Java class with a set of properties, each property which has a getter and/or a setter. For example if the Java class has a name property it could be defined like this.
public class Foo {
private String mName;
public String getName() { return mName; }
public void setName(String pName) { mName = pName; }
}
Typically one accesses the property by directly calling its getter and/or setter. But sometimes you may not know the name of the property in advance but still might want to access the getter and/or setter. To do this one can use Java’s beans and reflection packages.
Here is an example of how one would read the value of a property of a JavaBean. Note that the property name should not be capitalized.
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public Object getProperty(MyBean myBean, String propertyName) {
// get descriptor of property
PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, myBean.getClass());
// invoke read method on property of myBean
Method readMethod = descriptor.getReadMethod();
return readMethod.invoke(memberSavingsProfile, (Object []) null);
}
Note that if your property only has a getter then you would create the PropertyDescriptor like this.
// get descriptor of property that only has a getter
String readMethodName = "get" + org.apache.commons.lang.StringUtils.capitalize(propertyName);
String writeMethodName = null;
PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, myBean.getClass(), readMethodName, writeMethodName);
Accessing the class from a static method which the class owns is a bit tricky. From a non-static method accessing the class is as simple as doing this.
Class thisClass = this.getClass();
In a static method there are two different ways to access the class. One way, which I learned from this forum discussion, is to create a stack trace and use the fact that the top of the stack trace will have the class we want.
// get stack trace
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
// get the class name at the top level of the stack trace
StackTraceElement stackTraceTopLevelElem = stackTrace[0];
String thisClassName = stackTraceTopLevelElem.getClassName();
// get the class using the class loader
Class thisClass;
try {
thisClass = Class.forName(thisClassName);
} catch (ClassNotFoundException exc) {
// this should never happen
}
The other way is to use Java’s SecurityManager class as described in this article. This way seems preferable because it is not as costly as creating an exception as done in the other way.
Here is some sample code using the SecurityManager. Note that we need to use an inner class because the getClassContext() method is protected.
public static void main(String[] args) {
Class clazz = new ClassGetter().getClazz();
}
// inner class is necessary since getClassContext is protected
private static class ClassGetter extends SecurityManager {
protected ClassGetter() {
// do nothing
}
protected Class getClazz() {
Class [] classes = getClassContext();
Class clazz = classes[1];
return clazz;
}
}