Hello again:

I download the sources for Castor 0.9.4.2 and built a jar file with
debugging symbols turned on.  I then let my application idle again
to get some more info.

Here is the exception I got this time:

Exception: java.lang.ArrayIndexOutOfBoundsException: 3
java.lang.ArrayIndexOutOfBoundsException: 3
        at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:715)
        at org.exolab.castor.persist.LockEngine.load(LockEngine.java:359)
        at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:64
9)
        at org.exolab.castor.persist.QueryResults.fetch(QueryResults.java:229)
        at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImp
l.java:640)
        at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImp
l.java:623)
        at admin.LoginCallback.checkLogin(LoginCallback.java:54)
        at
com.jammconsulting.servlet.admin.AdminServlet.process(AdminServlet.java:89)
        at
com.jammconsulting.servlet.admin.AdminServlet.doPost(AdminServlet.java:55)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Application
FilterChain.java:247)
        at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterCh
ain.java:193)
        at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.ja
va:260)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:643)
        at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.ja
va:191)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:643)
        at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at
org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2415)
        at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180
)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:643)
        at
org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.
java:170)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:641)
        at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172
)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:641)
        at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java
:174)
        at
org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invok
eNext(StandardPipeline.java:643)
        at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.connector.warp.WarpRequestHandler.handle(Unknown
Source)
        at org.apache.catalina.connector.warp.WarpConnection.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:536)

Looking at line 715 in ClassMolder, it contains this code:
                temp = fields[i];

This is in this loop:
        for ( int i = 0; i < _fhs.length; i++ ) {

So, obviously, the fields array contains less objects than the _fhs array.

On line 687, I see this statement where the fields array is being filled in:
        fields = (Object[]) locker.getObject( tx );

According to the comments, this is attempting to load the object from the
cache.

I dont know what to do next to try to figure this out.

Any guidance?

Thanks,
        Neil.

--
Neil Aggarwal
JAMM Consulting, Inc.    (972) 612-6056, http://www.JAMMConsulting.com
Custom Internet Development    Websites, Ecommerce, Java, databases


> -----Original Message-----
> From: Neil Aggarwal [mailto:[EMAIL PROTECTED]]
> Sent: Tuesday, February 11, 2003 11:10 AM
> To: [EMAIL PROTECTED]
> Subject: [castor-dev] ArrayIndexOutOfBoundsException after application
> is idle for hours
>
>
> Hello:
>
> I get an ArrayIndexOutOfBoundsException when I leave my application
> alone for a couple of hours.  It does not occur when the application first
> runs.  Also, if I re-start the application, everything is OK again.
>
> Here is the exception:
> Exception: java.lang.ArrayIndexOutOfBoundsException: 3
> java.lang.ArrayIndexOutOfBoundsException: 3
>       at org.exolab.castor.persist.ClassMolder.load(Unknown Source)
>       at org.exolab.castor.persist.LockEngine.load(Unknown Source)
>       at org.exolab.castor.persist.TransactionContext.load(Unknown Source)
>       at org.exolab.castor.persist.QueryResults.fetch(Unknown Source)
>       at
> org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(Unknown
> Source)
>       at
> org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(Unknown
> Source)
>       at admin.LoginCallback.checkLogin(LoginCallback.java:54)
>       at
> com.jammconsulting.servlet.admin.AdminServlet.process(AdminServlet
> .java:89)
>       at
> com.jammconsulting.servlet.admin.AdminServlet.doPost(AdminServlet.java:55)
>       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
>       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
>       at
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(A
> pplication
> FilterChain.java:247)
>       at
> org.apache.catalina.core.ApplicationFilterChain.doFilter(Applicati
> onFilterCh
> ain.java:193)
>       at
> org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapp
> erValve.ja
> va:260)
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:643)
>       at
> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.
> java:480)
>       at
> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
>       at
> org.apache.catalina.core.StandardContextValve.invoke(StandardConte
> xtValve.ja
> va:191)
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:643)
>       at
> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.
> java:480)
>       at
> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
>       at
> org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2415)
>       at
> org.apache.catalina.core.StandardHostValve.invoke(StandardHostValv
> e.java:180
> )
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:643)
>       at
> org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispat
> cherValve.
> java:170)
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:641)
>       at
> org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValv
> e.java:172
> )
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:641)
>       at
> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.
> java:480)
>       at
> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
>       at
> org.apache.catalina.core.StandardEngineValve.invoke(StandardEngine
> Valve.java
> :174)
>       at
> org.apache.catalina.core.StandardPipeline$StandardPipelineValveCon
> text.invok
> eNext(StandardPipeline.java:643)
>       at
> org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.
> java:480)
>       at
> org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
>       at
> org.apache.catalina.connector.warp.WarpRequestHandler.handle(Unknown
> Source)
>       at
> org.apache.catalina.connector.warp.WarpConnection.run(Unknown Source)
>       at java.lang.Thread.run(Thread.java:536)
>
> This happens all the time with my application, but I have not been able to
> repeat it in
> a test case I tried to come up with.  The code is essentially
> identical but
> the same error
> does not occur.
>
> Here is the relevant code in the LoginCallback class which throws the
> exception:
>
>     Database db = null;
>     try {
>       // Get the database
>       db = DbUtil.getDatabase();
>
>       // See if there is an administrator object with the given login and
> password
>       OQLQuery query = db.getOQLQuery("select a from
> "+Administrator.class.getName()+" a where a.emailAddress LIKE $1 and
> a.encryptedPassword = $2" );
>       query.bind(login);
>       query.bind(StringUtils.encrypt(password));
>       QueryResults results = query.execute();
>       if( results.hasMore() ) {
>         Administrator administrator = (Administrator) results.next();
>         req.getSession().setAttribute(ParameterNames.LOGIN,administrator);
>         return LOGIN_OK;
>       }
>
>       // If we are still here, it means the login was not found
>       return LOGIN_FAILED;
>
>     } catch( Exception e ) {
>       // Notify the admin
>       ServletUtil.notifyInternalError(req,e,Constants.ADMIN_EMAIL);
>       return LOGIN_ERROR;
>     } finally {
>       if( db != null ) {
>         try {
>           db.rollback();
>           db.close();
>         } catch( Exception e ) {
>           // Notify the admin
>           ServletUtil.notifyInternalError(req,e,Constants.ADMIN_EMAIL);
>         }
>       }
>     }
>
> Line 54 in the code above is:
>       if( results.hasMore() ) {
>
> Why should hasMore() throw an ArrayIndexOutOfBoundsException?
>
> My theory is that there are multiple Administrator and Subscriber
> objects in
> the database.  Administrator extends Subscriber and somewhere in the code,
> Castor thinks it has more Administrator objects than it really
> does because
> of the subclass relationship.
>
> I am using Castor 0.9.4.2 on Redhat Linux 8.0 with Apache 2.0.43, Tomcat
> 4.1.18,
> and MySQL 3.32.55.
>
> Here is my database.xml file:
> <?xml version="1.0" encoding="UTF-8"?>
>
> <!DOCTYPE databases PUBLIC "-//EXOLAB/Castor JDO Configuration DTD Version
> 1.0//EN" "http://castor.exolab.org/jdo-conf.dtd";>
>
> <database name="newsletter" engine="mysql">
>   <driver class-name="com.mysql.jdbc.Driver"
>             url="jdbc:mysql://localhost:3306/newsletter">
>     <param name="user" value="newsletter" />
>     <param name="password" value="[removed]" />
>   </driver>
>   <mapping href="mapping.xml"/>
> </database>
>
> Here is the mapping.xml file:
> <?xml version="1.0"?>
>
> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
>                          "http://castor.exolab.org/mapping.dtd";>
>
> <mapping>
>
>   <!--
> =================================================================== -->
>   <!--   Mapping for class persistent.Subscriber  -->
>   <!--
> =================================================================== -->
>
>   <class name="persistent.Subscriber"
>          identity="id"
>          access="shared"
>          key-generator="MAX"
>          auto-complete="false">
>     <map-to table="Subscriber" />
>     <cache-type type="count-limited" />
>
>     <field name="emailAddress"
>            type="java.lang.String"
>            required="true"
>            get-method="getEmailAddress"
>            set-method="setEmailAddress">
>       <sql name="emailAddress"
>            type="char" />
>     </field>
>
>     <field name="id"
>            type="integer"
>            get-method="getId"
>            set-method="setId">
>       <sql name="id"
>            type="integer" />
>     </field>
>
>     <field name="subscriptionDate"
>            type="java.util.Date"
>            required="true"
>            get-method="getSubscriptionDate"
>            set-method="setSubscriptionDate">
>       <sql name="subscriptionDate"
>            type="date" />
>     </field>
>
>     <field name="subscriptionSource"
>            type="java.lang.String"
>            required="true"
>            get-method="getSubscriptionSource"
>            set-method="setSubscriptionSource">
>       <sql name="subscriptionSource"
>            type="char" />
>     </field>
>
>   </class>
>
>   <!--
> =================================================================== -->
>   <!--   Mapping for class persistent.Administrator  -->
>   <!--
> =================================================================== -->
>
>   <class name="persistent.Administrator"
>          identity="id"
>          access="shared"
>          extends="persistent.Subscriber"
>          key-generator="MAX"
>          auto-complete="false">
>     <map-to table="Administrator" />
>     <cache-type type="count-limited" />
>
>     <field name="encryptedPassword"
>            type="java.lang.String"
>            required="true"
>            get-method="getEncryptedPassword"
>            set-method="setEncryptedPassword">
>       <sql name="encryptedPassword"
>            type="char" />
>     </field>
>
>     <field name="id"
>            type="integer"
>            get-method="getId"
>            set-method="setId">
>       <sql name="id"
>            type="integer" />
>     </field>
>
>   </class>
>
>   <!--
> =================================================================== -->
>   <!--   Mapping for class persistent.NewsletterContent  -->
>   <!--
> =================================================================== -->
>
>   <class name="persistent.NewsletterContent"
>          identity="id"
>          access="shared"
>          key-generator="MAX"
>          auto-complete="false">
>     <map-to table="NewsletterContent" />
>     <cache-type type="count-limited" />
>
>     <field name="active"
>            type="boolean"
>            get-method="getActive"
>            set-method="setActive">
>       <sql name="active"
>            type="bit" />
>     </field>
>
>     <field name="content"
>            type="java.lang.String"
>            required="true"
>            get-method="getContent"
>            set-method="setContent">
>       <sql name="content"
>            type="clob" />
>     </field>
>
>     <field name="heading"
>            type="java.lang.String"
>            required="true"
>            get-method="getHeading"
>            set-method="setHeading">
>       <sql name="heading"
>            type="char" />
>     </field>
>
>     <field name="id"
>            type="integer"
>            get-method="getId"
>            set-method="setId">
>       <sql name="id"
>            type="integer" />
>     </field>
>
>     <field name="newsletterDate"
>            type="java.util.Date"
>            required="true"
>            get-method="getNewsletterDate"
>            set-method="setNewsletterDate">
>       <sql name="newsletterDate"
>            type="date" />
>     </field>
>
>   </class>
>
> </mapping>
>
> Here is my database schema:
> DROP TABLE IF EXISTS Administrator;
> CREATE TABLE Administrator (
>     id                int             PRIMARY KEY,
>     encryptedPassword varchar(255)    NOT NULL,
>     INDEX (encryptedPassword)
> ) TYPE = InnoDB;
>
> DROP TABLE IF EXISTS NewsletterContent;
> CREATE TABLE NewsletterContent (
>     id                int             PRIMARY KEY,
>     newsletterDate    DATE            NOT NULL,
>     heading           varchar(255),
>     content           longtext,
>     active            bool
> ) TYPE = InnoDB;
>
> DROP TABLE IF EXISTS Subscriber;
> CREATE TABLE Subscriber (
>     id                int             PRIMARY KEY,
>     emailAddress      varchar(255)    NOT NULL,
>     subscriptionDate  DATE            NOT NULL,
>     subscriptionSource  varchar(255)    NOT NULL,
>     INDEX (emailAddress)
> ) TYPE = InnoDB;
>
> Here is the source for the Subscriber class:
> /*
>  * Subscriber.java
>  */
> package persistent;
>
> import com.jammconsulting.db.castor.*;
> import com.jammconsulting.db.exceptions.*;
> import java.util.*;
>
> /**
>  * Class to hold information on a newsletter subscriber
>  *
>  * @castor:class table="Subscriber" id="id" key-generator="MAX"
>  */
> public class Subscriber extends DbObject {
>   /**
>    * The subscriber's email address
>    */
>   private String emailAddress;
>   /**
>    * The date this user subscribed
>    */
>   private Date subscriptionDate = new Date();
>   /**
>    * How we got this user into the newsletter
>    */
>   private String subscriptionSource;
>
>   /**
>    * Get the id
>    *
>    * @castor:field type="integer" set-method="setId"
>    * @castor:field-sql name="id" type="integer"
>    */
>   public int getId() {
>     return super.getId();
>   }
>   /**
>    * Set the id
>    */
>   public void setId(int id) {
>     super.setId(id);
>   }
>
>   /**
>    * Get the emailAddress
>    *
>    * @castor:field required="true" set-method="setEmailAddress"
>    * @castor:field-sql type="char" name="emailAddress"
>    */
>   public String getEmailAddress() {
>     return emailAddress;
>   }
>
>   /**
>    * Set the emailAddress
>    */
>   public void setEmailAddress(String emailAddress) {
>     this.emailAddress = emailAddress;
>   }
>
>   /**
>    * Get the subscriptionDate
>    *
>    * @castor:field required="true" set-method="setSubscriptionDate"
>    * @castor:field-sql type="date" name="subscriptionDate"
>    */
>   public Date getSubscriptionDate() {
>     return subscriptionDate;
>   }
>
>   /**
>    * Set the subscriptionDate
>    */
>   public void setSubscriptionDate(Date subscriptionDate) {
>     this.subscriptionDate = subscriptionDate;
>   }
>
>   /**
>    * Get the subscriptionSource
>    *
>    * @castor:field required="true" set-method="setSubscriptionSource"
>    * @castor:field-sql type="char" name="subscriptionSource"
>    */
>   public String getSubscriptionSource() {
>     return subscriptionSource;
>   }
>
>   /**
>    * Set the subscriptionSource
>    */
>   public void setSubscriptionSource(String subscriptionSource) {
>     this.subscriptionSource = subscriptionSource;
>   }
>
>   /**
>    * Validate this object
>    */
>   public void validate() throws ValidationException {
>     if( (emailAddress==null) || (emailAddress.length()<=0) )
>       throw new ValidationException( "You must give an email address" );
>
>     // Make sure the email address has an '@' in it
>     int atIndex = emailAddress.indexOf('@');
>     if( atIndex <= 0 )
>       throw new ValidationException("Your email address appears to be
> invalid");
>
>     // Make sure the email address has an '.' in it after the '@'
>     int dotIndex = emailAddress.lastIndexOf('.');
>     if( dotIndex <= atIndex )
>       throw new ValidationException("Your email address appears to be
> invalid");
>   }
> }
>
> Here is the source for the Administrator class:
> /*
>  * Administrator.java
>  */
> package persistent;
>
> import com.jammconsulting.utils.*;
> import java.security.*;
>
> /**
>  * Class to hold information on an administrator
>  *
>  * @castor:class table="Administrator" extends="persistent.Subscriber"
> id="id"
>  */
> public class Administrator extends Subscriber {
>   /**
>    * The administrator's encyprted password
>    */
>   private String encryptedPassword;
>
>   /**
>    * Get the id
>    *
>    * @castor:field type="integer" set-method="setId"
>    * @castor:field-sql name="id" type="integer"
>    */
>   public int getId() {
>     return super.getId();
>   }
>   /**
>    * Set the id
>    */
>   public void setId(int id) {
>     super.setId(id);
>   }
>
>   /**
>    * Get the encryptedPassword
>    *
>    * @castor:field required="true" set-method="setEncryptedPassword"
>    * @castor:field-sql type="char" name="encryptedPassword"
>    */
>   public String getEncryptedPassword() {
>     return encryptedPassword;
>   }
>
>   /**
>    * Set the encryptedPassword
>    */
>   public void setEncryptedPassword(String encryptedPassword) {
>     this.encryptedPassword = encryptedPassword;
>   }
>
>   /**
>    * Set the administrator's password with an unencrypted password.
>    * The password will be encrypted before it is set.
>    */
>   public void setPassword(String password) throws
> NoSuchAlgorithmException {
>     setEncryptedPassword(StringUtils.encrypt(password));
>   }
> }
>
> Any ideas?
> Is there anything else you need?
>
> Thanks,
>       Neil.
>
> --
> Neil Aggarwal
> JAMM Consulting, Inc.    (972) 612-6056, http://www.JAMMConsulting.com
> Custom Internet Development    Websites, Ecommerce, Java, databases
>
> -----------------------------------------------------------
> If you wish to unsubscribe from this mailing, send mail to
> [EMAIL PROTECTED] with a subject of:
>       unsubscribe castor-dev

----------------------------------------------------------- 
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
        unsubscribe castor-dev

Reply via email to