I’m resurrecting an old application that worked with WildFly 8 / HornetMQ / Log4J. It is a remote Java GUI Client that swaped JMS ObjectMessages.
So far everything works again when reconfigured for WildFly 10 / ActiveMQ / Slf4j, except one thing:
After my MDB receives an ObjectMessage (whose Object is an ArrayList) it throws a JMSException error when the MDB calls getObject() on the message. JMSExcetion. e.getMessage() returns:
org.slf4j.log4j12.Log4jLoggerAdapter from
[Module "org.apache.activemq.artemis:main" from local module loader @1c2c22f3
(finder: local module finder @18e8568
(roots: C:\ProgramFilesGeo\Wildfly\wildfly-10.1.0.Final\modules,
C:\ProgramFilesGeo\Wildfly\wildfly-10.1.0.Final\modules\system\layers\base)
But if I remove Slf4J logging from the EntityParent instances in the ArrayList all works correctly … except I then can’t log from the EntityParent subclass the MDB extracts from the ObjectMessage.
Here’s what I know so far:
It's clearly is an issue with Slf4j and I guess Serialization. Because otherwise, Slf4j works fine on the server side. I mean the message above was written to the WF log with this logger code in the MDB:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final Logger logger = Logger.getLogger(GoMsgBean.class.getName());
My MDB confirms the message arrives as: ActiveMQObjectMessage
Before transmitting the ObjectMessage I tested the instance of EntityParent and the ArrayList for Serialization – ability with:
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(each of the above objects separately);
A web search brings up one match to my issue – getObject() throwing a JMSException. But its marked as Not Answered. And what was posted was so wrapped in a discussion of a proxy servers and class loaders as to be unhelpful.
I found other discussions related to this problem with a Log4j logger. They suggested annotating the logger as @Transient. But then claimed switching to slf4j “solved” that problem without making it @Transient. So I both switched to slf4j and marked it @Transient. No all loggers in all subclasses of EntityParent in the ArrayList used:
@Transient
final Logger logger = LoggerFactory.getLogger(LoggedIn.class);
The slf4j website discusses other problems, but they all seem to involve cases where the application tries to retain log4j logging. Not my case anymore.
So I hope someone can help, because I’m not sure where else to look … my real job is to deal with the data base once the MDB can extract the entities.
In case it’s of any use, here’s the activeMQ subsystem of standalone-full.xml
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
<server name="default">
<security enabled="false"/>
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0"/>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<jms-queue name="SendToServerQueue" entries="java:jboss/exported/jms/queue/sendToServerQueue java:/jms/queue/sendToServerQueue"/>
<jms-queue name="SendToClientQueue2" entries="java:jboss/exported/jms/queue/sendToClientQueue2"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
</subsystem>
This is added for the bounty: It is a copy of my current JPA Entity (POJO) class. It works perfectly w/ all logging commented out. But it fails with the error above when the slf4j logger is added back in. Even though slf4j loggers work fine for the MDB, and Session Beans, I deploy with the ear package.
package org.america3.gotest.shared.jpa;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.america3.gotest.shared.interfaces.DataItemKeyValues;
import org.america3.gotest.shared.tools.Utility;
@NamedQueries(
{@NamedQuery(name="LoggedIn.findLoggedInbyId",
query = "SELECT li " +
"From LoggedIn li " +
"WHERE li.memberId = :memberIdP"),
@NamedQuery(name="findLoggedInByAll",
query = "DELETE FROM LoggedIn li " +
"WHERE li.memberId = :memberIdP " +
"AND li.memberPw = :memberPwP " +
"AND li.clientHash = clientHashP")
})
@Entity(name="LoggedIn")
@Table(name="loggedins")
public class LoggedIn extends EntityParent implements Serializable, DataItemKeyValues {
/* See EntityParent for explanation of 9 fields
* This subclass only persists memberId, memberPW, and clientHash
*/
//@Transient
//final Logger logger = LoggerFactory.getLogger(LoggedIn.class);
//constructors
public LoggedIn() {
this.setMemberId(NOT_APPLICABLE);
this.setMemberPw(NOT_APPLICABLE);
this.SetClientHash(NOT_APPLICABLE);
this.setClientUserId(NOT_APPLICABLE);
this.setClientUserPw(NOT_APPLICABLE);
this.setOwnerId(NOT_APPLICABLE);
this.setOwnerPw(NOT_APPLICABLE);
this.setOpponentId(NOT_APPLICABLE);
this.setOpponentPw(NOT_APPLICABLE);
};
public LoggedIn(String hash, String id, String pw) {
this();
if (id != null && pw !=null && hash != null) {
this.setMemberId(id);
this.setMemberPw(pw);
this.SetClientHash(hash);
} else {
//logger.error("Log in was attempted with: id \"" + id + "\" pw \"" + hash + "\"");
String iAmM = Utility.getIAmM(Thread.currentThread().getStackTrace());
System.err.println(iAmM + "Log in was attempted with: id \"" + id + "\" pw \"" + hash + "\"");
}
}
public LoggedIn(EntityParent loggedIn) {
this();
this.memberId = loggedIn.getMemberId();
this.memberPw = loggedIn.getMemberPw();
this.clientHash = loggedIn.getClientHash();
}
// persisted fields
@Id @Column(name="PK")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer pk;
@Column(name="MBR_ID")
private String memberId;
@Column(name="MBR_PW")
private String memberPw;
@Column(name="HASH")
private String clientHash;
// Transient fields
@Transient
private String clientUserId;
@Transient
private String clientUserPw;
@Transient
private String ownerId;
@Transient
private String ownerPw;
@Transient
private String opponentId;
@Transient
private String opponentPw;
private static final long serialVersionUID = 1L;
// get set methods
public Integer getPk () {return this.pk;}
public void setPk (Integer pk) {this.pk = pk;}
public String getMemberId () {return memberId;}
public void setMemberId (String memberId) {this.memberId = (memberId == null? "" : memberId);}
public String getMemberPw () {return this.memberPw;}
public void setMemberPw (String memberPw) {this.memberPw = (memberPw == null? "" : memberPw);}
public String getClientHash () {return clientHash;}
public void SetClientHash (String clientHash) {this.clientHash = (clientHash == null? "" : clientHash);}
public boolean equals (LoggedIn otherLoggedIn) {
if (otherLoggedIn == null) return false;
if (this.pk == otherLoggedIn.getPk()) {
return true;
} else {
return false;
}
}
// other methods
@Transient
public String getClientUserId () {return this.clientUserId;}
public void setClientUserId (String clientUserId) {this.clientUserId = (clientUserId == null? "" : clientUserId);}
@Transient
public String getClientUserPw () {return this.clientUserPw;}
public void setClientUserPw (String clientUserPw) {this.clientUserPw = (clientUserPw == null? "" : clientUserPw);}
@Transient
public String getOwnerId () {return this.ownerId;}
public void setOwnerId (String ownerId) {this.ownerId = (ownerId == null? "" : ownerId);}
@Transient
public String getOwnerPw () {return ownerPw;}
public void setOwnerPw (String ownerPw) {this.ownerPw = (ownerPw == null? "" : ownerPw);}
@Transient
public String getOpponentId () {return opponentId;}
public void setOpponentId (String opponentId) {this.opponentId = (opponentId == null? "" : opponentId);}
@Transient
public String getOpponentPw () {return opponentPw;}
public void setOpponentPw (String opponentPw) {this.opponentPw = (opponentPw == null? "" : opponentPw);}
public void writeEntity () {
//String iAmS = Utility.getIAmS(Thread.currentThread().getStackTrace());
//logger.info(iAmS + this.getClass().getSimpleName() + " contains these values");
//logger.info(iAmS + " PK (pk) : " + this.pk);
//logger.info(iAmS + " MBR_ID (memberId) : " + this.memberId);
//logger.info(iAmS + " MBR_PW (memberPw) : " + this.memberPw);
//logger.info(iAmS + " HASH (clientHash) : " + this.clientHash);
//logger.info(iAmS + " Trans (clientUserId): " + this.clientUserId);
//logger.info(iAmS + " Trans (clientUserPw): " + this.clientUserPw);
}
}