src.com.ibm.as400.resource.Resource Maven / Gradle / Ivy
Show all versions of jt400-jdk8 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: Resource.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2000 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.resource;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400BidiTransform;
import com.ibm.as400.access.BidiStringType;
import com.ibm.as400.access.ExtendedIllegalStateException;
import com.ibm.as400.access.Trace;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
The Resource class represents a system resource. This is an abstract
class which provides generic access to the resource's attributes.
Every attribute is identified using an attribute ID. Any given subclass
of Resource will normally document the attribute IDs that it supports.
One example of a concrete subclass of Resource is
{@link com.ibm.as400.resource.RUser RUser}
which represents a system user. RUser supports
many attribute IDs,
each of which can be used to get
attribute values. Here is an example which retrieves an attribute
value from an RUser:
// Create an RUser object to refer to a specific user.
AS400 system = new AS400("MYSYSTEM", "MYUSERID", "MYPASSWORD");
RUser user = new RUser(system, "AUSERID");
// Get the text description attribute value.
String textDescription = (String)user.getAttributeValue(RUser.TEXT_DESCRIPTION);
In addition to using concrete subclasses directly, you
can write generic code to work with any Resource subclass.
Such code may improve reusability and maintainability and will
work with future Resource subclasses without modification.
Every attribute has an associated attribute
{@link com.ibm.as400.resource.ResourceMetaData meta data}
object which describes various properties of the attribute.
The attribute meta data can come in handy when writing generic
code. Here is an example of generic code which prints the
value of every attribute supported by a Resource:
void printAllAttributeValues(Resource resource) throws ResourceException
{
// Get the attribute meta data.
ResourceMetaData[] attributeMetaData = resource.getAttributeMetaData();
// Loop through all attributes and print the values.
for(int i = 0; i < attributeMetaData.length; ++i)
{
Object attributeID = attributeMetaData[i].getID();
Object value = resource.getAttributeValue(attributeID);
System.out.println("Attribute " + attributeID + " = " + value);
}
}
Every Resource and attribute meta data object has an associated
{@link com.ibm.as400.resource.Presentation Presentation}
object which provides translated information about the Resource
or attribute. You can use the Presentation information to
present Resources and attributes to end users. This example
prints a Resource and attribute using their Presentations:
void printSingleAttributeValue(Resource resource, Object attributeID) throws ResourceException
{
// Get the presentation for the Resource and print its full name.
Presentation resourcePresentation = resource.getPresentation();
System.out.println(resourcePresentation.getFullName());
// Get the attribute meta data and the associated Presention.
ResourceMetaData attributeMetaData = resource.getAttributeMetaData(attributeID);
Presentation attributePresentation = attributeMetaData.getPresentation();
// Get the attribute value and print it.
Object value = resource.getAttributeValue(attributeID);
System.out.println(attributePresentation.getName() + " = " + value);
}
The Resource abstract class only provides read access to the attribute
values. {@link com.ibm.as400.resource.ChangeableResource ChangeableResource},
which is a subclass of Resource, adds methods which provide write access to
the attribute values.
Subclass notes:
If you are extending this class to override the mechanism for getting
attribute values, consider whether you need to support bidirectional
character conversion. If you do not plan to support bidirectional character
conversion, then you only need to override
{@link #getAttributeValue(java.lang.Object) getAttributeValue(Object)}.
If you do plan to support bidirectional character conversion, then you need
to override {@link #isBidiEnabled() isBidiEnabled()} to return true
and {@link #getAttributeValue(java.lang.Object, int) getAttributeValue(Object, int)}.
In either case, the overriding method should call the superclass's
method of the same name and perform extra processing only when null
is returned:
public Object getAttributeValue(Object attributeID)
throws ResourceException
{
// Call the superclass first.
Object value = super.getAttributeValue(attributeID);
if (value == null) {
// Establish the connection if needed.
if (! isConnectionEstablished())
establishConnection();
// Go get the attribute value.
value = ...;
}
return value;
}
@see ResourceList
@deprecated Use packages com.ibm.as400.access and com.ibm.as400.access.list instead.
**/
public abstract class Resource
implements Serializable
{
private static final String copyright = "Copyright (C) 1997-2000 International Business Machines Corporation and others.";
static final long serialVersionUID = 4L;
// Private data.
private static Object counterLock_ = new Object();
private static long counter_;
private ResourceMetaDataTable attributes_;
private Dictionary attributeValues_;
private boolean connectionEstablished_ = false;
private String currentLevel_ = null;
private int defaultBidiStringType_ = -1; // @A2A
private Presentation presentation_;
private boolean propertiesFrozen_ = false;
private Object resourceKey_;
private AS400 system_ = null;
private transient Vector activeStatusListeners_;
private transient PropertyChangeSupport propertyChangeSupport_;
private transient VetoableChangeSupport vetoableChangeSupport_;
transient Vector resourceListeners_; // @A1a
/**
Constructs a Resource object.
**/
public Resource()
{
presentation_ = new Presentation();
synchronized(counterLock_) {
resourceKey_ = new Long(counter_++);
}
attributes_ = new ResourceMetaDataTable();
attributeValues_ = new Hashtable();
initializeTransient();
}
/**
Constructs a Resource object.
@param presentation The presentation.
@param resourceKey The resource key.
@param attributeMetaData The attribute meta data, or null if not applicable.
**/
public Resource(Presentation presentation,
Object resourceKey,
ResourceMetaData[] attributeMetaData)
{
if(presentation == null)
throw new NullPointerException("presentation");
if(resourceKey == null)
throw new NullPointerException("resourceKey");
presentation_ = presentation;
resourceKey_ = resourceKey;
attributes_ = new ResourceMetaDataTable(attributeMetaData);
attributeValues_ = new Hashtable();
initializeTransient();
}
/**
Constructs a Resource object.
@param presentation The presentation.
@param resourceKey The resource key.
@param attributeMetaData The attribute meta data, or null if not applicable.
@param values The attribute values. The keys are attribute IDs and
the elements are attribute values. The attribute IDs
and values must be consistent according to the attribute
meta data.
**/
public Resource(Presentation presentation,
Object resourceKey,
ResourceMetaData[] attributeMetaData,
Dictionary values)
{
this(presentation, resourceKey, attributeMetaData);
// Validate the attribute values.
synchronized(values) {
Enumeration keys = values.keys();
while(keys.hasMoreElements()) {
Object attributeID = keys.nextElement();
Object value = values.get(attributeID);
if (Trace.isTraceOn())
Trace.log(Trace.DIAGNOSTIC, "Initializing attribute value " + attributeID + " (for "
+ this + ") to " + value + "(" + value.getClass() + ")");
ResourceMetaData singleAttributeMetaData = attributes_.validateID(attributeID);
values.put(attributeID, singleAttributeMetaData.validateValue(value));
}
}
attributeValues_ = values;
initializeTransient();
}
/**
Constructs a Resource object.
@param presentation The presentation.
@param resourceKey The resource key, or null if it is not set.
@param attributes The attribute meta data.
**/
public Resource(Presentation presentation,
Object resourceKey,
ResourceMetaDataTable attributes)
{
if(presentation == null)
throw new NullPointerException("presentation");
if(attributes == null)
throw new NullPointerException("attributes");
presentation_ = presentation;
resourceKey_ = resourceKey;
attributes_ = attributes;
attributeValues_ = new Hashtable();
initializeTransient();
}
/**
Adds an ActiveStatusListener.
@param listener The listener.
**/
public void addActiveStatusListener(ActiveStatusListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
activeStatusListeners_.addElement(listener);
}
/**
Adds a PropertyChangeListener. The specified PropertyChangeListener's
propertyChange() method will be called each time the value of
any bound property is changed.
@param listener The listener.
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
propertyChangeSupport_.addPropertyChangeListener(listener);
}
// @A1a - Formerly in ChangeableResource.
/**
Adds a ResourceListener.
@param listener The listener.
**/
public void addResourceListener(ResourceListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
resourceListeners_.addElement(listener);
}
/**
Adds a VetoableChangeListener. The specified VetoableChangeListener's
vetoableChange() method will be called each time the value of
any constrained property is changed.
@param listener The listener.
*/
public void addVetoableChangeListener(VetoableChangeListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
vetoableChangeSupport_.addVetoableChangeListener(listener);
}
/**
Indicates if properties are frozen. If this is true, property
changes should not be made. Properties are not the same thing
as attributes. Properties are basic pieces of information
which must be set to make the object usable, such as the system
or other properties that identify the resource on the system.
@return true if properties are frozen, false otherwise.
**/
protected boolean arePropertiesFrozen()
{
return propertiesFrozen_;
}
/**
Indicates if this resource is equal to an object.
@param other The object.
@return true if this resource is equal to the object,
false otherwise.
**/
public boolean equals(Object other)
{
if (other instanceof Resource) {
// If the resource keys are set, then use them to compare.
if ((resourceKey_ != null) && (((Resource)other).resourceKey_ != null))
return resourceKey_.equals(((Resource)other).resourceKey_);
// Otherwise, just use the default.
else
return super.equals(other);
}
else
return false;
}
/**
Establishes the connection to the system, if any. Subclasses can override
this method and put all connection initialization code here.
It is assumed that all properties have been set when this
method is called. Any subclass that overrides this method
should include a call to super.establishConnection().
@exception ResourceException If an error occurs.
**/
protected void establishConnection()
throws ResourceException
{
if (system_ == null)
throw new ExtendedIllegalStateException("system", ExtendedIllegalStateException.PROPERTY_NOT_SET);
if (Trace.isTraceOn())
Trace.log(Trace.DIAGNOSTIC, "Establishing a connection for " + this + ".");
if (!propertiesFrozen_)
freezeProperties();
connectionEstablished_ = true;
}
// @A1a - Moved here from ChangeableResource.
/**
Fires an attributeValuesRefreshed() ResourceEvent.
**/
protected void fireAttributeValuesRefreshed()
{
ResourceEvent event = new ResourceEvent(this, ResourceEvent.ATTRIBUTE_VALUES_REFRESHED);
Vector temp = (Vector)resourceListeners_.clone();
Enumeration list = temp.elements();
while(list.hasMoreElements())
((ResourceListener)list.nextElement()).attributeValuesRefreshed(event);
}
/**
Fires a busy active status event. This indicates that a potentially
long-running operation has started.
**/
protected void fireBusy()
{
ActiveStatusEvent event = new ActiveStatusEvent(this, ActiveStatusEvent.BUSY);
Vector temp = (Vector)activeStatusListeners_.clone();
Enumeration list = temp.elements();
while(list.hasMoreElements())
((ActiveStatusListener)list.nextElement()).busy(event);
}
/**
Fires a idle active status event. This indicates that a potentially
long-running operation has ended.
**/
protected void fireIdle()
{
ActiveStatusEvent event = new ActiveStatusEvent(this, ActiveStatusEvent.IDLE);
Vector temp = (Vector)activeStatusListeners_.clone();
Enumeration list = temp.elements();
while(list.hasMoreElements())
((ActiveStatusListener)list.nextElement()).idle(event);
}
/**
Fires a property change event.
@param propertyName The property name.
@param oldValue The old value.
@param newValue The new value.
**/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue)
{
propertyChangeSupport_.firePropertyChange(propertyName, oldValue, newValue);
}
/**
Fires a vetoable change event.
@param propertyName The property name.
@param oldValue The old value.
@param newValue The new value.
@exception PropertyVetoException If the property change is vetoed.
**/
protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue)
throws PropertyVetoException
{
vetoableChangeSupport_.fireVetoableChange(propertyName, oldValue, newValue);
}
/**
Freezes any property changes. After this is called, property
changes should not be made. Properties are not the same thing
as attributes. Properties are basic pieces of information
which must be set to make the object usable, such as the system
or other properties that identify the resource on the system.
Subclasses can override this method and put initialization
code here that is dependent on properties being set.
Any subclass that overrides this method should include a
call to super.freezeProperties().
@exception ResourceException If an error occurs.
**/
//
// Implementation notes:
//
// 1. This will be called when a resource is added to a
// resource pool, to prevent its key from being changed.
//
// 2. This is separate from establishConnection() because
// there are times when we want to freeze the properties
// without incurring the performance hit of setting up
// the connection. For example, getting a list of Users.
// Each User's properties should be frozen, but we don't
// want to establish a connection for each user unless
// the calling program needs to.
//
protected void freezeProperties()
throws ResourceException
{
if (Trace.isTraceOn())
Trace.log(Trace.DIAGNOSTIC, "Freezing properties for " + this + ".");
propertiesFrozen_ = true;
}
/**
Returns the attribute meta data for a specific attribute.
@param attributeID Identifies the attribute.
@return The attribute meta data.
**/
public ResourceMetaData getAttributeMetaData(Object attributeID)
{
return attributes_.getMetaData(attributeID);
}
/**
Returns the attribute meta data. The array will contain an element
for every supported attribute.
@return The attribute meta data. The array has zero elements if
there are no attributes.
**/
public ResourceMetaData[] getAttributeMetaData()
{
return attributes_.getMetaData(getCurrentLevel());
}
// @A2C
/**
Returns the current value of an attribute.
@param attributeID Identifies the attribute.
@return The attribute value, or null if the attribute
value is not available.
@exception ResourceException If an error occurs.
@see Subclass notes
**/
public Object getAttributeValue(Object attributeID)
throws ResourceException
{
// If this resource is bidi enabled, then punt to the bidi flavor
// of getAttributeValue(). This will ensure that the subclass's
// bidi-enabled getAttributeValue() method gets called even though
// no string type was passed - - and therefore the subclass only
// needs to override the bidi-enabled getAttributeValue().
if (isBidiEnabled())
return getAttributeValue(attributeID, getDefaultBidiStringType());
else
return getAttributeValueImplementation(attributeID);
}
// @A2A
/**
Returns the current value of an attribute.
@param attributeID Identifies the attribute.
@param bidiStringType The bidi string type as defined by the CDRA (Character Data
Representation Architecture). See
{@link com.ibm.as400.access.BidiStringType BidiStringType}
for more information and valid values.
@return The attribute value, or null if the attribute
value is not available.
@exception ResourceException If an error occurs.
@see Subclass notes
**/
public Object getAttributeValue(Object attributeID, int bidiStringType)
throws ResourceException
{
// If this resource is not bidi enabled, then punt to the non-bidi flavor
// of getAttributeValue(). This will ensure that the subclass's
// non-bidi-enabled getAttributeValue() method gets called even though
// a string type was passed - - and therefore the subclass only
// needs to override the non-bidi-enabled getAttributeValue().
if (!isBidiEnabled())
return getAttributeValue(attributeID);
else {
// In the default implementation, we don't use the string type,
// since there is no conversion being done.
return getAttributeValueImplementation(attributeID);
}
}
// @A2A
Object getAttributeValueImplementation(Object attributeID)
throws ResourceException
{
synchronized(this) {
attributes_.validateID(attributeID);
return attributeValues_.get(attributeID);
}
}
/**
Returns the current level. This is the system VRM, or
"" if the system has not been set.
@return The current level.
**/
String getCurrentLevel()
{
if (system_ == null)
return "";
if (currentLevel_ != null)
return currentLevel_;
try {
currentLevel_ = ResourceLevel.vrmToLevel(system_.getVRM());
}
catch(Exception e) {
return "";
}
return currentLevel_;
}
// @A2A
int getDefaultBidiStringType()
{
if (system_ == null)
return BidiStringType.DEFAULT;
if (defaultBidiStringType_ == -1)
defaultBidiStringType_ = AS400BidiTransform.getStringType((char)system_.getCcsid());
return defaultBidiStringType_;
}
/**
Returns the presentation information.
@return The presentation information.
**/
public Presentation getPresentation()
{
return presentation_;
}
/**
Returns the resource key. The resource key uniquely identifies the resource.
The resource key may not be set if the resource's properties are not set.
@return The resource key, or null if the resource key has not been set.
**/
//
// Implementation note:
//
// The resource key is used for identifying reusable objects in the resource
// pool. If there is already an object in the pool with a specified resource
// key, then we can reuse it. Subclasses of this class should define resource
// keys so that if any 2 objects can be used interchangeably, then their resource
// keys should be the same.
//
public Object getResourceKey()
{
return resourceKey_;
}
/**
Returns the system.
@return The system.
**/
public AS400 getSystem()
{
return system_;
}
/**
Initializes an attribute value. This is intended for use by the
subclass when it is initializing attribute values.
@param attributeID Identifies the attribute.
@param value The attribute value. This cannot be null.
**/
protected void initializeAttributeValue(Object attributeID, Object value)
{
if (Trace.isTraceOn())
Trace.log(Trace.DIAGNOSTIC, "Initialized attribute value " + attributeID + " (for "
+ this + ") to " + value + "(" + value.getClass() + ")");
// Validation.
ResourceMetaData attributeMetaData = attributes_.validateID(attributeID);
if (value == null)
throw new NullPointerException("value");
value = attributeMetaData.validateValue(value);
// Make the change.
synchronized(this) {
attributeValues_.put(attributeID, value);
}
}
/**
Initializes the transient data.
**/
private void initializeTransient()
{
activeStatusListeners_ = new Vector();
propertyChangeSupport_ = new PropertyChangeSupport(this);
vetoableChangeSupport_ = new VetoableChangeSupport(this);
resourceListeners_ = new Vector(); // @A1a
}
// @A2A
/**
Indicates if this resource is enabled for bidirectional character conversion.
The default implementation always returns false. Subclasses that are enabled
for bidirectional character conversion should override this method to return
true.
@return Always false.
@see Subclass notes
**/
protected boolean isBidiEnabled()
{
return false;
}
/**
Indicates if a connection to the system is established, if any.
@return true if a connection is established, false otherwise.
**/
protected boolean isConnectionEstablished()
{
return connectionEstablished_;
}
/**
Deserializes the resource.
**/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
initializeTransient ();
}
/**
Refreshes the values for all attributes.
@exception ResourceException If an error occurs.
**/
public void refreshAttributeValues()
throws ResourceException
{
fireAttributeValuesRefreshed(); // @A1a
// Do nothing else by default.
}
/**
Removes an ActiveStatusListener.
@param listener The listener.
**/
public void removeActiveStatusListener(ActiveStatusListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
activeStatusListeners_.removeElement(listener);
}
/**
Removes a PropertyChangeListener.
@param listener The listener.
**/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
propertyChangeSupport_.removePropertyChangeListener(listener);
}
// @A1a - Moved here from ChangeableResource.
/**
Removes a ResourceListener.
@param listener The listener.
**/
public void removeResourceListener(ResourceListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
resourceListeners_.removeElement(listener);
}
/**
Removes a VetoableChangeListener.
@param listener The listener.
**/
public void removeVetoableChangeListener(VetoableChangeListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
vetoableChangeSupport_.removeVetoableChangeListener(listener);
}
/**
Sets the presentation.
@param presentation The presentation.
**/
protected void setPresentation(Presentation presentation)
{
if(presentation == null)
throw new NullPointerException("presentation");
presentation_ = presentation;
}
/**
Sets the resource key.
@param resourceKey The resource key.
**/
//
// Implementation note:
//
// Resources should never change their key once they have
// been added to the resource pool.
//
protected void setResourceKey(Object resourceKey)
{
if(resourceKey == null)
throw new NullPointerException("resourceKey");
resourceKey_ = resourceKey;
}
/**
Sets the system. This does not change the job on
the system. Instead, it changes the system to which
this object references. This cannot be changed
if the object has established a connection to the system.
@param system The system.
@exception PropertyVetoException If the property change is vetoed.
**/
public void setSystem(AS400 system)
throws PropertyVetoException
{
if (system == null)
throw new NullPointerException("system");
if (arePropertiesFrozen())
throw new ExtendedIllegalStateException("propertiesFrozen", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
AS400 oldValue = system_;
fireVetoableChange("system", oldValue, system);
system_ = system;
firePropertyChange("system", oldValue, system);
}
/**
Returns the presentation full name, if any.
@return The presentation full name, if any.
**/
public String toString()
{
if (presentation_ == null)
return super.toString();
else {
String fullName = presentation_.getFullName();
if (fullName.length() > 0)
return fullName;
else
return super.toString();
}
}
/**
Validates the attribute ID.
@param attributeID The attribute ID.
@return The attribute meta data.
**/
ResourceMetaData validateAttributeID(Object attributeID)
{
return attributes_.validateID(attributeID);
}
}