Just a suggestion for tracking down the bug.
Patrick
Neil Aggarwal wrote:
Hello again:----------------------------------------------------------- If you wish to unsubscribe from this mailing, send mail to
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---------------------------------------------------------------- If you wish to unsubscribe from this mailing, send mail to
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
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev
