gt:         if (listener == null)
context: ///////////////////////////////////////////////////////////////////////////////
  //                                                                             
  // 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.
  
  <p>One example of a concrete subclass of Resource is 
  {@link com.ibm.as400.resource.RUser RUser}
  which represents a system user.  RUser supports
  many <a href="{@docRoot}/com/ibm/as400/resource/RUser.html#attributeIDs">attribute IDs</a>, 
  each of which can be used to get
  attribute values.  Here is an example which retrieves an attribute
  value from an RUser:
  
  <blockquote><pre>
  // Create an RUser object to refer to a specific user.
  AS400 system = new AS400("MYSYSTEM", "MYUSERID", "MYPASSWORD");
  RUser user = new RUser(system, "AUSERID");
  <br>
  // Get the text description attribute value.
  String textDescription = (String)user.getAttributeValue(RUser.TEXT_DESCRIPTION);
  </pre></blockquote>
  
  <p>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:
  
  <blockquote><pre>
  void printAllAttributeValues(Resource resource) throws ResourceException
  {
      // Get the attribute meta data.
      ResourceMetaData[] attributeMetaData = resource.getAttributeMetaData();
      <br>
      // Loop through all attributes and print the values.
      for(int i = 0; i &lt; attributeMetaData.length; ++i)
      {
          Object attributeID = attributeMetaData[i].getID();
          Object value = resource.getAttributeValue(attributeID);
          System.out.println("Attribute " + attributeID + " = " + value);
      }
  }
  </pre></blockquote>
  
  <p>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:
  
  <blockquote><pre>
  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());
      <br>
      // Get the attribute meta data and the associated Presention.
      ResourceMetaData attributeMetaData = resource.getAttributeMetaData(attributeID);
      Presentation attributePresentation = attributeMetaData.getPresentation();
      <br>
      // Get the attribute value and print it.
      Object value = resource.getAttributeValue(attributeID);
      System.out.println(attributePresentation.getName() + " = " + value);
  }
  </pre></blockquote>
  
  <p>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. 
  
  <a name="subclass"><p><b>Subclass notes:</b></a>
  <p>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)}.
  
  <p>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:
  
  <blockquote><pre>
      public Object getAttributeValue(Object attributeID)
      throws ResourceException
      {
          // Call the superclass first.
          Object value = super.getAttributeValue(attributeID);
          if (value == null) {
  <br>
              // Establish the connection if needed.
              if (! isConnectionEstablished())
                  establishConnection();
  <br>                       
              // Go get the attribute value.
              value = ...; 
          }
          return value;
      }
  </pre></blockquote>
  
  @see ResourceList
  @deprecated Use packages <tt>com.ibm.as400.access</tt> and <tt>com.ibm.as400.access.list</tt> 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 
  <b>propertyChange()</b> method will be called each time the value of 
  any bound property is changed.
  
  @param listener The listener.
  */
      public void addPropertyChangeListener(PropertyChangeListener listener)
      {
  