PROBLEM:

Der PAManager der CIAgent-Software wirft bei Verwendung von
Java 1.4 eine StringIndexOutOfBoundsException, sobald Agenten
instantiiert werden sollen. Mit Java 1.3 funktioniert es jedoch.



LÖSUNG:

- die Methode addAgent in der Datei ciagent/CIAgent.java muss
  wie folgt bearbeitet werden (Änderungen an zwei Stellen):

    VORHER:

    public void addAgent(CIAgent child) {
      children.addElement(child) ;
      child.setParent(this) ;
    }

    NACHHER:

    public int addAgent(CIAgent child) {
      children.addElement(child) ;
      child.setParent(this) ;
      return 0;
    }


- neu compilieren von ciagent/CIAgent.java:

    jay-jay@powerslave:~/stud/wbs/ciagent2e> javac ciagent/CIAgent.java

- PAManagerApp starten -- jetzt müssten die Agenten korrekt geladen
  werden, die in ./pamanager.properties aufgelistet sind.

    jay-jay@powerslave:~/stud/wbs/ciagent2e> java pamanager/PAManagerApp

  (unter UNIX sind Dateinamen case sensitive, hier muss man diese
  .properties Datei auf jeden Fall mit Kleinbuchstaben benennen,
  MS-Windows ist es egal)



URSACHE:

Für die Interessierten, hier die Erklärung:

In der Methode pamanager.PAManagerFrame.readPropertiesFile lässt
sich mit einem weiteren catch-Block die Exception abfangen und
verfolgen:

DEBUG: Exception caught. java.lang.StringIndexOutOfBoundsException: String index out of range: -3
java.lang.StringIndexOutOfBoundsException: String index out of range: -3
        at java.lang.String.substring(String.java:1480)
        at java.beans.Introspector.getTargetEventInfo(Introspector.java:861)
        at java.beans.Introspector.getBeanInfo(Introspector.java:371)
        at java.beans.Introspector.getBeanInfo(Introspector.java:144)
        at java.beans.Introspector.getBeanInfo(Introspector.java:205)
        at java.beans.Introspector.<init>(Introspector.java:351)
        at java.beans.Introspector.getBeanInfo(Introspector.java:144)
        at ciagent.CIAgent.getDisplayName(CIAgent.java:302)
        at pamanager.PAManagerFrame.readPropertiesFile(PAManagerFrame.java:560)
        at pamanager.PAManagerFrame.<init>(PAManagerFrame.java:75)
        at pamanager.PAManagerApp.<init>(PAManagerApp.java:27)
        at pamanager.PAManagerApp.main(PAManagerApp.java:63)

Nach längerem Studieren der Methode
java.beans.Introspector.getTargetEventInfo() fällt einem folgende
Stelle auf (siehe Java 1.4 source), an der die Methoden des
JavaBeans dahingehend geprüft werden, ob sie eine
`addFooListener'-Methode sind:

if (name.startsWith(ADD_PREFIX) && argTypes.length == 1 &&
    resultType == Void.TYPE &&
    Introspector.isSubclass(argTypes[0], eventListenerType)) {
    String listenerName = name.substring(3);
    if (listenerName.length() > 0 &&
        argTypes[0].getName().endsWith(listenerName)) {
        adds.put(listenerName, method);
    }
}

Und ein Stück weiter unten wird über diese `adds' Collection
iteriert und dabei dies gerufen:

  String eventName = decapitalize(
      listenerName.substring(0, listenerName.length()-8));


Und genau bei dieser -8 liegt die Ursache:

Die ursprüngliche addAgent-Methode erfüllt alle Bedingungen des
if-Statements, d.h. sie beginnt mit `add' und hat genau einen
Parameter und gibt `void' zurück; last but not least erwartet
addAgent einen Parameter vom Typ CIAgent und CIAgent implementiert
das Interface CIAgentEventListener, das wiederum
java.util.EventListener erweitert, so dass auch die letzte
Bedingung erfüllt ist. Damit aber nicht genug, auch die innere
if-Bedingung ist true, da der erwartete Parameter-Typ CIAgent auf
`Agent' endet.

Es wird aber NICHT geprüft, ob der Methodenname auf `Listener'
endet und weil dies nicht der Fall ist, können auch keine 8
Zeichen abgezogen werden und so entsteht eine
StringIndexOutOfBoundsException.


Fazit:

Mit Java 1.4 schlägt die Introspection eines JavaBean unter ganz
bestimmten Umständen fehl, da in der Methode getTargetEventInfo()
der Klasse java.beans.Introspector eine Annahme getroffen wird,
die zwar oft ausreichen wird, aber nicht in 100% aller Fälle
korrekt ist.

Die `Lösung', die ich oben beschrieben habe, ist also allenfalls
ein Hack oder sagen wir Workaround, der verhindert, dass der
Introspector die addAgent-Methode als EventListener betrachtet.


[2003-10-10  Joachim Jautz]