Local interface not working

I am developing a browser-based app which uses a JSF/JSP/JS/CSS/etc front-end, EJBs with business logic in the middle & CMP entity beans in the back-end. I'm using a MySQL database, netbeans 5.0 IDE and SJAS 8.2 as the app server.

So far, my app has a login which looks up the database and retrieves the user's authorised options to produce a menubar and this works fine. Different users get different menu options depending on the setup in the authorisations table. The menu also gets the urls from the table.

One of the options is User (maintenance) which retrieves all the user IDs into a dropdown html select. This works fine.

Another option on my menu is Company (maintenance) which shows nothing in the dropdown. Similar thing happens with another option Contracts. When I look in the sjas server logs. I see the following :

Bean 'ContractBean' method ejbLoad:

com.sun.jdo.api.persistence.support.JDOObjectNotFoundException: JDO76210: Object does not exist in the data store.

FailedObjectArray: [db.ContractBean_1975525749_JDOState@14c009f]

at com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager.retrieve(SQLStateManager.java:2035)

at com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager.reload(SQLStateManager.java:1162)

at com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager.reload(SQLStateManager.java:1118)

at com.sun.jdo.spi.persistence.support.sqlstore.impl.PersistenceManagerImpl.getObjectById(PersistenceManagerImpl.java:633)

at com.sun.jdo.spi.persistence.support.sqlstore.impl.PersistenceManagerWrapper.getObjectById(PersistenceManagerWrapper.java:245)

at db.ContractBean_1975525749_ConcreteImpl.jdoGetInstance(ContractBean_1975525749_ConcreteImpl.java:1422)

at db.ContractBean_1975525749_ConcreteImpl.ejbLoad(ContractBean_1975525749_ConcreteImpl.java:1466)

at com.sun.ejb.containers.EntityContainer.callEJBLoad(EntityContainer.java:2258)

at com.sun.ejb.containers.EntityContainer.afterBegin(EntityContainer.java:1325)

at com.sun.ejb.containers.BaseContainer.useClientTx(BaseContainer.java:2396)

at com.sun.ejb.containers.BaseContainer.preInvokeTx(BaseContainer.java:2251)

at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:782)

at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:126)

at $Proxy96.getCode(Unknown Source)

at biz.ContractFacadeBean.getAllContracts(ContractFacadeBean.java:88)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

(....the rest omitted)

the next server log is:

An exception was thrown during an ejb invocation on [ContractBean]

The point where this fails is (in my ContractsFacadeBean):

79public ArrayList getAllContracts(Integer active)throws FinderException{

80ArrayList contracts =new ArrayList();

81Collection c = contractHome.findByActive(active);

82Iterator i = c.iterator();

83// Get all con tract codes (string) into arraylist users

84String savecode ="";

85String contractcode ="";

86while (i.hasNext()){

87ContractLocal cl = (ContractLocal) i.next();

88contractcode = cl.getCode();<--here

89if (!contractcode.equals(savecode)){

90contracts.add(contractcode);

91savecode = contractcode;

92}

93}

94return contracts;

95}

(findByActive - the 'active' field is Integer 1=active record, 0='deleted'. This is a convention I use. My user, company, contracts tables have this flag. I am also aware that MySQL has a 'user' table, but that is in a different schema, and the field names are different from mine.)

It seems like the correct number of objects are retrieved by the finder method (I added some code to find this out), but the objects retrieved don't exactly match ContractLocal. I have used the java reflect class to find out what objects are in that collection. The object's class is something like "$Proxy96" as in the error log above. The getters & setters are same as ContractLocal but there are some additional methods.

The mystery is that the exact same setup works for the UserBean, MenuBean & AuthorisationsBean which all work correctly with their respective local interface to give a working login, as well as the correct values retrieved for the user maintenance dropdown box.

All the entity beans were automatically generated by netbeans. I have searched the configuration files ejb-jar.xml etc but can't find anything different between the setup for UserBean and that for ContractsBean, CompanyBean. I haven't changed anything in the config files.

This problem has basically brought me to my knees, and I would really appreciate any help I can get. I'd be happy to provide any additional info if it helps.

Thanks.

[5362 byte] By [Joe_Goea] at [2007-10-3 5:21:39]
# 1

I think what happens is that by

cl..getCode()

CMP tries to select the Contract from the database. The Contract object is not initialized before the first access, only the key fields are populated. The retrieval of the remaining fields from the database doesn't find the row with the specified key, and the exception is thrown. A reason may be:

Contract's primary key contains a Date, or another java type that can't be compared exactly (on the database) like Float, etc.

You can log the SQL generated by CMP by increasing the loglevel for the JDO component to FINEST. See which primary key is issued and try the same query directly on the database.

How is ContractHome.findByActive(active) implemented?

m_fuchsa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 2

As ejbLoad is called, it means that a new transaction is being started. Is the code snippet part of a session bean or a client invocation? Please check your transaction attribute settings on the CMP methods that you call - local interface is not a guarantee for transaction settings.

thanks,

-marina

jdcmarinaa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 3

Thanks for your reply.

The implementation is:

In ContractLocalHome,

Collection findByActive(Integer active) throws FinderException;

in ejb-jar.xml,

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.active = ?1</ejb-ql>

How do I initialise the Contract object (or should that be the ContractLocal)? That may be the difference with the UserBean which works - because my first call to UserFacadeBean is a findByPrimaryKey in a password validation method using the user id as the key value. The subsequent call to retrieve all the user ID's works fine.

But to do a finByPrimaryKey for the contracts I need a key value. What I'm trying to achieve here is to display a dropdown box with all key values so that the user can choose one for maintenance.

Contract has 2 keys: contract ID (string) and renewalsequence(Integer)

However I have the same problem with Company, where the key is just 'code' (string). And no problem with User - key is 'user' (string).

Thanks again.

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 4

Thanks for your reply. I have to admit I'm pretty new to j2ee, and I'm quite dependent on my IDE, netbeans which does a lot of things behind the scenes.

The code I posted is in my stateless session bean ContractFacadeBean. The client calls this bean and gets an ArrayList which is supposed to contain the key values (string) from contract table.

The session bean uses findByActive which uses ejb-ql to retrieve a Collection of <some strange objects> which doesn't match up with the ContractLocal interface?

The transaction settings in ejb-jar.xml for the ContractFacadeBean are:

<container-transaction>

<method>

<ejb-name>ContractFacadeBean</ejb-name>

<method-name>*</method-name>

</method>

Thanks again.

<trans-attribute>Required</trans-attribute>

</container-transaction>

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 5
May be something wrong with the PK Class? Or may be the mapping is not quite right.Can you please post the ejb-jar.xml parts that define the PKs of the problematic beans and the PK class code where you use it?thanks,-marina
jdcmarinaa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 6

Thanks for your patience.

ejb-jar.xml:

<ejb-jar ....

><enterprise-beans>

..

<session>

<display-name>ContractFacadeSB</display-name>

<ejb-name>ContractFacadeBean</ejb-name>

<home>biz.ContractFacadeRemoteHome</home>

<remote>biz.ContractFacadeRemote</remote>

<ejb-class>biz.ContractFacadeBean</ejb-class>

<session-type>Stateless</session-type>

<transaction-type>Container</transaction-type>

<ejb-local-ref>

<ejb-ref-name>ejb/ContractBean</ejb-ref-name>

<ejb-ref-type>Entity</ejb-ref-type>

<local-home>db.ContractLocalHome</local-home>

<local>db.ContractLocal</local>

<ejb-link>ContractBean</ejb-link>

</ejb-local-ref>

</session>

<session>

..

<entity>

<description>jdbc:mysql://localhost:3306/kitpldb [root on Default schema]</description>

<display-name>ContractEB</display-name>

<ejb-name>ContractBean</ejb-name>

<local-home>db.ContractLocalHome</local-home>

<local>db.ContractLocal</local>

<ejb-class>db.ContractBean</ejb-class>

<persistence-type>Container</persistence-type>

<prim-key-class>db.ContractPK</prim-key-class>

<reentrant>false</reentrant>

<abstract-schema-name>Contract</abstract-schema-name>

<cmp-field>

<field-name>code</field-name>

</cmp-field>

<cmp-field>

<field-name>renewalseq</field-name>

</cmp-field>

<cmp-field>

<field-name>invcompany</field-name>

</cmp-field>

<cmp-field>

<field-name>workcompany</field-name>

</cmp-field>

<cmp-field>

<field-name>startdate</field-name>

</cmp-field>

<cmp-field>

<field-name>enddate</field-name>

</cmp-field>

<cmp-field>

<field-name>rate</field-name>

</cmp-field>

<cmp-field>

<field-name>createuser</field-name>

</cmp-field>

<cmp-field>

<field-name>createdate</field-name>

</cmp-field>

<cmp-field>

<field-name>createtime</field-name>

</cmp-field>

<cmp-field>

<field-name>active</field-name>

</cmp-field>

<query>

<description>auto generated method</description>

<query-method>

<method-name>findByCode</method-name>

<method-params>

<method-param>java.lang.String</method-param>

</method-params>

</query-method>

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.code = ?1</ejb-ql>

</query>

<query>

<description>auto generated method</description>

<query-method>

<method-name>findByRenewalseq</method-name>

<method-params>

<method-param>java.lang.Integer</method-param>

</method-params>

</query-method>

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.renewalseq = ?1</ejb-ql>

</query>

..

<query>

<description>auto generated method</description>

<query-method>

<method-name>findByActive</method-name>

<method-params>

<method-param>java.lang.Integer</method-param>

</method-params>

</query-method>

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.active = ?1</ejb-ql>

</query>

</entity>

..

</enterprise-beans>

<assembly-descriptor>

..

<container-transaction>

<method>

<ejb-name>ContractBean</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

..

<container-transaction>

<method>

<ejb-name>ContractFacadeBean</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

..

</assembly-descriptor>

</ejb-jar>

-Contract's PK class (auto-generated by netbeans)

package db;

import javax.ejb.*;

/**

* This is the bean class for the ContractBean enterprise bean.

* Created 17/09/2006 09:18:34

* @author kit

*/

public final class ContractPK implements java.io.Serializable {

public java.lang.String code;

public java.lang.Integer renewalseq;

/**

* @see java.lang.Object#equals(java.lang.Object)

*/

public boolean equals(java.lang.Object otherOb) {

if (this == otherOb) {

return true;

}

if (!(otherOb instanceof db.ContractPK)) {

return false;

}

db.ContractPK other = (db.ContractPK) otherOb;

return (

(code==null?other.code==null:code.equals(other.code))

&&

(renewalseq==null?other.renewalseq==null:renewalseq.equals(other.renewalseq))

);

}

/**

* @see java.lang.Object#hashCode()

*/

public int hashCode() {

return (

(code==null?0:code.hashCode())

^

(renewalseq==null?0:renewalseq.hashCode())

);

}

}

SJAS Logging level set to FINEST for CMP.

Can see that the PK's are being retrieved, there are 22 log entries (in the contract table there are 11 records).

Similar thing happens for Company table, except, the actual key value (string) is shown. Company's is just one string field (code).

Both fail when, after casting the object in the collection to the local interface, the "getCode" method is called - resulting in the errors shown in my original post.

For the user table, the records are retrieved, and after casting the object in the collection to UserLocal and calling the "getUser" method doesn't generate errors. (Also - in the login there are CMP lookups on Authorisations & Menu tables, to retrieve records. None of these fail/generate errors.

Let me know if there's any more info I can provide.

Thanks.

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 7

The equals() and hashCode() implementations in ContractPk look ok.

Please post your sun-cmp-mappings.xml file, which contains the mapping btw. fields and the columns in the database. Please also post the SQL statement that is executed before the exception occurs. It should be something like

Select t0.field1, t0.field2... from CONTRACT t0 where t0.CODE = ? and t0.RENEWALSEQ = ?

Consider trying to execute this statement directly on the database and check, if a row is returned.

Can it be a case-sensitivity issue? Or is CONTRACT.RENEWALSEQ defined as an auto-increment column in the database?

m_fuchsa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 8

(thanks - here's the additional info)

sun-cmp-mappings.xml for contract:

<sun-cmp-mappings>

<sun-cmp-mapping>

<schema> ..

..

<entity-mapping>

<ejb-name>ContractBean</ejb-name>

<table-name>contract</table-name>

<cmp-field-mapping>

<field-name>code</field-name>

<column-name>contract.code</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>renewalseq</field-name>

<column-name>contract.renewalseq</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>invcompany</field-name>

<column-name>contract.invcompany</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>workcompany</field-name>

<column-name>contract.workcompany</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>startdate</field-name>

<column-name>contract.startdate</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>enddate</field-name>

<column-name>contract.enddate</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>rate</field-name>

<column-name>contract.rate</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>createuser</field-name>

<column-name>contract.createuser</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>createdate</field-name>

<column-name>contract.createdate</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>createtime</field-name>

<column-name>contract.createtime</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

<cmp-field-mapping>

<field-name>active</field-name>

<column-name>contract.active</column-name>

<fetched-with>

<default/>

</fetched-with>

</cmp-field-mapping>

</entity-mapping>

..

</sun-cmp-mapping>

</sun-cmp-mappings>

(2) the sql statement would be the ejb-ql in the ejb-jar.xml:

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.active = ?1</ejb-ql>

I guess the equivalent in MySQL would be "select * from contract c where c.active = 1" - returns 11 rows.

(3) From what I see in the server logs and the exception stacktrace, the finder method correctly returns the 11 rows in a Collection object, but when the "getCode" method is called it crashes

ArrayList contracts = new ArrayList();

Collection c = contractHome.findByActive(active);> this works,

returns 11 rows

but what's in the Collection?

Iterator i = c.iterator();

// Get all user codes (string) into arraylist users

..

while (i.hasNext()){

ContractLocal cl = (ContractLocal) i.next();> no crash here

contractcode = cl.getCode(); > crashes here -- why?

(4) There is no auto number used. The table def in MySQL:

CREATE TABLE `kitpldb`.`contract` (

`code` varchar(20) NOT NULL default '' COMMENT 'identifier',

`renewalseq` int(10) unsigned NOT NULL default '0' COMMENT 'renewal sequence no',

`invcompany` varchar(10) NOT NULL default '' COMMENT 'company to invoice',

`workcompany` varchar(10) NOT NULL default '' COMMENT 'work site company',

`startdate` date NOT NULL default '0000-00-00',

`enddate` date NOT NULL default '0000-00-00',

`rate` float NOT NULL default '0' COMMENT 'AUD per hour',

`createuser` varchar(10) NOT NULL default '',

`createdate` date NOT NULL default '0000-00-00',

`createtime` time NOT NULL default '00:00:00',

`active` int(10) unsigned NOT NULL default '0' COMMENT '0=inactive 1=active',

PRIMARY KEY (`code`,`renewalseq`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

As a comparison, the "user" table's definition:

CREATE TABLE `kitpldb`.`user` (

`user` varchar(10) NOT NULL default '' COMMENT 'user or class',

`password` varchar(45) default NULL COMMENT 'null if class',

`type` int(10) unsigned NOT NULL default '0' COMMENT '1=user or 2=class',

`name` varchar(45) NOT NULL default '' COMMENT 'description if class',

`surname` varchar(45) NOT NULL default '' COMMENT 'more description if class',

`userclass` varchar(10) default NULL,

`createuser` varchar(10) NOT NULL default '',

`createdate` date NOT NULL default '0000-00-00',

`createtime` time NOT NULL default '00:00:00',

`active` int(10) unsigned NOT NULL default '0' COMMENT '0=inactive 1=active',

PRIMARY KEY (`user`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 9

Thanks for providing the additional information! To your comments:

> (2) the sql statement would be the ejb-ql in the ejb-jar.xml:

> <ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.active = ?1</ejb-ql>

> I guess the equivalent in MySQL would be "select * from contract c where c.active = 1" - returns 11 rows.

What I meant is that CMP executes another select, when following line is executed:

contractcode = cl.getCode(); > crashes here -- why?

The SQL should be:

select t0.`code`, t0.`renewalseq`, t0.`invcompany`, t0.`workcompany`, t0.`startdate`, t0.`enddate`, t0.`rate`, t0.`createuser`, t0.`createdate`, t0.`createtime`, t0.`active` from `contract` t0 where t0.`code` = ? and t0.`renewalseq` = ? with input values ...

This select is executed to re-load the contract fields, and it's this statement that crashes. Can you see a similar statement in your log file? Please post the exact excerpt from your log file here. The excerpt should start from where the initial finder, i.e.

<ejb-ql>SELECT OBJECT(c) FROM Contract AS c WHERE c.active = ?1</ejb-ql>

is executed, until the exception occurs. If the log is too long, please send the excerpt, or the entire log file to: markus<dot>fuchs<at>sun<dot>com

m_fuchsa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 10

OK - found that statement by changing JDO logging level to FINEST on SJSAS.

Another quirk - I changed the 'active' field on one of the records in contract table to 0 and to my surprise it appeared in the "inactive contracts" select dropdown box. So it made the long trip from ejb-->jsp while the other records with 'active' = 1 didn't appear in the "active contracts". Both dropdown boxes call the same method btw.

I tried to figure out the server log, but couldn't. I can see the action going on, but can't pinpoint the problem. Wonder if it is a mysql jdbc driver issue? I shall take up your kind offer, Mr.Fuchs and e-mail the server log to you. Hope it makes it past yr spam-blocker.

Thanks very much.

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 11

Thanks for providing the log file. I can see in the log that the

following query is executed and doesn't return a result:

select t0.`renewalseq`, t0.`code`, t0.`invcompany`, t0.`workcompany`,

t0.`startdate`, t0.`enddate`, t0.`rate`, t0.`createuser`,

t0.`createdate`, t0.`createtime`, t0.`active` from `contract` t0 where

t0.`renewalseq` = 1 and t0.`code` = 'AADGEN'

Please execute this select from the command line. If it doesn't return a

result, I'd say that the database is corrupted. If it does return a

result, please also try executing the query via JDBC.

m_fuchsa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 12

Hi m_fuchs

The sql statement worked in mysql's commandline without a problem. JDBC test - I had to remove the ` characters to make it work. I don't think this is the problem because all the sql's would have these. Otherwise, it worked allright. In both cases 1 row was returned. I suppose these sql statements are generated by the cmp container? How does one have control over what happens here?

arrgh

Thanks for your help. Hope this isn't the end of the road

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 13

First, the "offending" instance is bound from the database as result from findByActive:

code = AADGEN .|#]

renewalseq = 1.|#]

Note, that the code field is *padded with blanks*. But when the second query for

cl.getCode();

is fired, the parameters are:

code = AADGEN.|#]

renewalseq = 1.|#]

I.e. the code field is truncated. That's the reason, why the instance is not found the second time. There are padded code values for the following instances:

code = AADGEN .|#]

renewalseq = 1.|#]

code = AADGEN .|#]

renewalseq = 2.|#]

code = IDSC.|#]

renewalseq = 1.|#]

code = PFIZERPGM.|#]

renewalseq = 1.|#]

The other instances aren't padded:

code = 004363.|#]

renewalseq = 1.|#]

code = 004363.|#]

renewalseq = 2.|#]

code = 111762183/999947/VZV.|#]

renewalseq = 1.|#]

code = DES_PFI.|#]

renewalseq = 2.|#]

code = DES_SAN.|#]

renewalseq = 1.|#]

Please check, why some of the code values are padded, and otheres aren't.

m_fuchsa at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 14

Mr Fuchs

thanks very much, I believe that is the answer. The tables where data is padded with blanks were migrated from an old MS-Access db, whereas the data in the User table was entered fresh into MySQL. Blanks probably got in during the migration process from access-->csv-->mysql. But I did manage to get the method to work by doing this:

ContractLocal cl = (ContractLocal) i.next();

ContractPK cpk = (ContractPK) cl.getPrimaryKey();

contractcode = cpk.code;

Without fixing the data, this change makes it work. Well I'm not totally lost anymore. Thanks very much for your help & thanks to jdcmarina, too.

Thankyouthankyoubye.

Joe_Goea at 2007-7-14 23:28:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...