JBoss classloading demystified!
When things get to go wrong couple of days before production, you tend to understand how JBoss classloading works.
This is with JBoss 4.2.2GA
You have two EARs, a.ear and b.ear. Both have c.jar in their libs.
Case 1: Both EARs dont do a scoped classloading
- What happens at server startup:
Both a.ear and b.ear use the same UnifiedLoadedRepository3 instance.
a.ear gets loaded first.
a.ear puts c.jar into the repository.
Now a.ear/b.ear and c.jar are called as UCL’s (Unified class loaders). All these UCLs are listed in the order of the deployment.
If C.class is in c.jar, then when asked for C.class, it is picked up from c.jar of a.ear. ie JBoss goes thru the list of the UCLs with the ULR. And the it finds C.class @ c.jar of a.ear first, and it returns the same.
When you hot undeploy a.ear, then any code calling b.ear gets C.class from b.ear. The only difference is that c.jar is out of the ULR. You get a “Not loaded in repository cache” message in the JMX window.
Now do a hot deploy of a.ear, this time you get java.lang.VerifyError for some class in c.jar.
When you redeploy the common jars, you need to redeploy everything.
Case 2: b.ear has the isolation part and also java2ParentDelegation to true
- What happens at server startup:
Calling b.ear will fail due to Classcastexception on the shared classes.
Why? The scoped application will use the already loaded class from the parent repository’s class cache.
We will go over these scenarios:
1. Deploy A, Deploy B, startserver, undeploy A, Access B
2. Deploy A, Deploy B, startserver, Access App A , undeploy A, Access App B
3. Deploy A, Deploy B, startserver, Access App A , undeploy B, Access App A
4. Deploy A, Deploy B, startserver, Access App A , Access App B, undeploy A, Access App B
Case 1: Deploy A, Deploy B, startserver, undeploy A, Access B
displayClassInfo:
com.noelios.restlet.ext.servlet.ServerServlet Information
Repository cache version:
com.noelios.restlet.ext.servlet.ServerServlet(11c5b4).ClassLoader=org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
..org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet-1.1.1.jar
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar
..org.jboss.system.server.NoAnnotationURLClassLoader@fcfa52
..sun.misc.Launcher$AppClassLoader@7172ea
….file:/Volumes/Mustang/branch/JBoss_POS_20081204/jboss-4.2.2.GA-pos/bin/run.jar
..sun.misc.Launcher$ExtClassLoader@b169f8
….file:/Library/Java/Extensions/jspComm.jar
++++CodeSource: (file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar )
Implemented Interfaces:
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
### Instance1 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@9c5cf5{ url=file:abc/deploy/tmp6517201656953000171B-0.0.1-SNAPSHOT.ear ,addedOrder=48}
->undeploy A
com.noelios.restlet.ext.servlet.ServerServlet Information
Not loaded in repository cache
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@151ce0{ url=file:abc/deploy/tmp3581146229639141667B-0.0.1-SNAPSHOT.ear ,addedOrder=48}
->Access AppB via
2009-09-26 19:46:28,567 ERROR [http-127.0.0.1-8080-1 – [ServerServlet]] – Allocate exception for servlet ServerServlet
java.lang.NullPointerException
at org.jboss.mx.loading.RepositoryClassLoader.findClass(RepositoryClassLoader.java:630)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:474)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
What happened here?? JBoss maps up A.ear to be the classloader for ServerServlet. JBoss hasnt loaded the ServerServlet yet. When B.ear wants ServerServlet class, JBoss checks its UCL’s and sees that A.ear can load it. Since we undeloyed A.ear, we get this nullptrexception
Case 2: Deploy A, Deploy B, startserver,Access App A , undeploy A, Access App B
displayClassInfo:
com.noelios.restlet.ext.servlet.ServerServlet Information
Repository cache version:
com.noelios.restlet.ext.servlet.ServerServlet(11c5b4).ClassLoader=org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
..org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet-1.1.1.jar
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar
..org.jboss.system.server.NoAnnotationURLClassLoader@fcfa52
..sun.misc.Launcher$AppClassLoader@7172ea
….file:/Volumes/Mustang/branch/JBoss_POS_20081204/jboss-4.2.2.GA-pos/bin/run.jar
..sun.misc.Launcher$ExtClassLoader@b169f8
….file:/Library/Java/Extensions/jspComm.jar
++++CodeSource: (file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar )
Implemented Interfaces:
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
### Instance1 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@9c5cf5{ url=file:abc/deploy/tmp6517201656953000171B-0.0.1-SNAPSHOT.ear ,addedOrder=48}
->Access AppA via
->undeploy A
com.noelios.restlet.ext.servlet.ServerServlet Information
Not loaded in repository cache
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@151ce0{ url=file:abc/deploy/tmp3581146229639141667B-0.0.1-SNAPSHOT.ear ,addedOrder=48}
->Access AppB via
java.lang.ClassCastException: com.apple.ist.retail.pos.b.restlet2.BApplication
com.noelios.restlet.ext.servlet.ServerServlet.createApplication(ServerServlet.java:282)
com.noelios.restlet.ext.servlet.ServerServlet.getApplication(ServerServlet.java:703)
com.noelios.restlet.ext.servlet.ServerServlet.init(ServerServlet.java:820)
com.apple.ist.retail.pos.b.servlet2.BServlet.init(BServlet.java:24)
javax.servlet.GenericServlet.init(GenericServlet.java:212)
What happened here? B.ear was linked up with the ServerServlet from A.ear. When A.ear was undeployed, the ServerServlet got loaded from B.ear and thus this ClassCastException
Case 3: Deploy A, Deploy B, startserver,Access App A , undeploy B, Access App A
displayClassInfo:
com.noelios.restlet.ext.servlet.ServerServlet Information
Repository cache version:
com.noelios.restlet.ext.servlet.ServerServlet(11c5b4).ClassLoader=org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
..org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet-1.1.1.jar
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar
..org.jboss.system.server.NoAnnotationURLClassLoader@fcfa52
..sun.misc.Launcher$AppClassLoader@7172ea
….file:/Volumes/Mustang/branch/JBoss_POS_20081204/jboss-4.2.2.GA-pos/bin/run.jar
..sun.misc.Launcher$ExtClassLoader@b169f8
….file:/Library/Java/Extensions/jspComm.jar
++++CodeSource: (file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar )
Implemented Interfaces:
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
### Instance1 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@9c5cf5{ url=file:abc/deploy/tmp6517201656953000171B-0.0.1-SNAPSHOT.ear ,addedOrder=48}
->Access AppA via
->undeploy B
displayClassInfo:
com.noelios.restlet.ext.servlet.ServerServlet Information
Repository cache version:
com.noelios.restlet.ext.servlet.ServerServlet(11c5b4).ClassLoader=org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
..org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet-1.1.1.jar
….file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar
..org.jboss.system.server.NoAnnotationURLClassLoader@fcfa52
..sun.misc.Launcher$AppClassLoader@7172ea
….file:/Volumes/Mustang/branch/JBoss_POS_20081204/jboss-4.2.2.GA-pos/bin/run.jar
..sun.misc.Launcher$ExtClassLoader@b169f8
….file:/Library/Java/Extensions/jspComm.jar
++++CodeSource: (file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear-contents/lib/com.noelios.restlet.ext.servlet-1.1.1.jar )
Implemented Interfaces:
### Instance0 found in UCL: org.jboss.mx.loading.UnifiedClassLoader3@5a84be{ url=file:abc/deploy/tmp7314601894329309101A-0.0.1-SNAPSHOT.ear ,addedOrder=47}
->Access AppA : No issues
hibernate caching
Original Post
# load will load the object from the cache if it exists and the database otherwise. If it loads the object from the database, it populates the cache.
# createQuery with setCacheable=false. This will get every object and populate the cache. If an object was already in the cache, it will use that. So, if you specify “from foo” with an empty cache, and there are 10 foo objects, it will first grab all 10 objects from the database, and populate the cache with them. In the meantime, if foo#2 is changed in the database, but not the cache, “from foo” will get the cached version. If foo#2 is eliminated from the cache, “from foo” will get 1 and 3-10 from the cache, but will get foo#2 from the database and repopulate the cache.
# createQuery with setCacheable=true. This is basically the same as createQuery with setCacheable=false, with a few differences. First, an extra entry will be made into the query cache. Second, if you issued a query with “from foo”, and then manually removed foo#2 from the cache, and then changed foo#2, and then redid the query, “from foo”, would it still hold the old foo#2? That is what I expected, but no! It uses the query results from “from foo”, but, those only have the keys. A lookup is performed on each key. Since the key does not exist anymore, it goes back to the database and repopulates the cache.
# If one issues a createQuery with “FROM foo WHERE name=?”, and the name changes, there will be 2 queries in the query cache, and both will point to the same id. The query cache with the original name is not automatically notified. This means, I think, one must manually do this and organize one’s code well, or understand that the query cache should only be used for an acceptable time period whereby it can be slightly incorrect. For example, a report that has to be up to date for the last 10 minutes. Or, one can live with only having the objects cached but not the query cache itself…it is hinted at that caching with the query cache is a bit rare.
# createSQLQuery with a partial list of mapped columns fails (as it should), so that means that if you use custom sql to populate something with addEntity, it will always be fully cached.
# createQuery with a left join fetch adds everything to the cache. This means that explict set caching will probably not be necessary, which is good. Eager fetching with the left join is naturally synchronized with what goes into the cache.
# When using createSQLQuery, one must use an explicit .addScalar or .addEntity if setCacheable is true, or hibernate gets confused on casting.
# To set an expiration time on custom sql which has no class mapping, use setCacheRegion on createSQLQuery, and then set that in the eviction policy.
# If one uses the eviction policy code, the /default must be set
Hibernate issues
Ignorance from myside and lack of meaningful exceptions thrown by hibernate took me a day to a simple save.
I have been trying to deploy a hibernate application in JBOSS and I have run into enough issues to write a book.
Tried doing the SessionFactory JNDI thing..didnt work out. Went back to hibernate.cfg.xml
Configurations needed
Issue 1: No solution still
Related issue
2009-09-13 00:37:22,837 WARN [http-17.223.23.143-8080-1 – WrappedConnection] – Closing a result set you left open! Please close it yourself.
java.lang.Throwable: STACKTRACE
at org.jboss.resource.adapter.jdbc.WrappedStatement.registerResultSet(WrappedStatement.java:617)
at org.jboss.resource.adapter.jdbc.WrappedStatement.getGeneratedKeys(WrappedStatement.java:533)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.hibernate.util.GetGeneratedKeysHelper.getGeneratedKey(GetGeneratedKeysHelper.java:69)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:74)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
Issue 2: ehcache
Solution
Caused by: java.lang.NullPointerException
at org.jboss.mx.loading.RepositoryClassLoader.findClass(RepositoryClassLoader.java:630)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:474)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
at net.sf.ehcache.CacheManager.detectAndFixDiskStorePathConflict(CacheManager.java:270)
at net.sf.ehcache.CacheManager.configure(CacheManager.java:252)
at net.sf.ehcache.CacheManager.init(CacheManager.java:196)
at net.sf.ehcache.CacheManager.(CacheManager.java:157)
at org.hibernate.cache.EhCacheProvider.start(EhCacheProvider.java:127)
at org.hibernate.impl.SessionFactoryImpl.(SessionFactoryImpl.java:183)
– at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
web.xml, CONFIDENTIAL, redirectPort,HTTP, HTTPS, 302
Copied stuff:
That’s expected:
– The page submits to http://server:port/page2.jsp
– The server issues a 302 redirect to https://server:port/page2.jsp – before examining any page content to find out there’s a POST. As your requirement is for confidentiality, this is correct – the server *must not* require any of the content to be sent before making the decision to redirect, or confidentiality could be broken.
– The browser acts on the redirect and issues a GET for the redirected page, hence without the POST data.
> Without the constraint everything works,
> when changing action to https://server:port/page2.jsp it works too.
Yes, as the intermediate redirect will be missing.
> I’m wondering whether this could be a tomcat bug?
No, it’s a feature of HTTP. Change your form action (or set the entire site to be SSL).
SQL JOINS
INNER JOIN:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
It will return only those rows in person which have mapping in orders.
LEFT OUTER JOIN/LEFT JOIN:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
It will return all the rows in person with mapping from orders(if available)
INNER JOIN: Is the N+1 issue I guess. Where each row from table A is searched for in table B and if matched is shown.
Hibernate Statistics JMX
Couple of articles abt Hibernate statistics:
Hibernate Concurrency bugs
Nitty gritties of the Statistics MBean
To enable Statistics Mbean via the jboss-service.xml
<mbean code="org.hibernate.jmx.StatisticsService"
name="xyz:service=HibernateStatistics">
<attribute name="SessionFactoryJNDIName">java:/xyz/SessionFactory</attribute>
<attribute name="StatisticsEnabled">true</attribute>
<depends>jboss:service=Naming</depends>
</mbean>
Explain plan for Oracle
explain plan set statement_id = 'name' for select....
select * from table(dbms_xplan.display);
Unix shell scripts
I suck at shell scripting. So I write to remember.
#!/bin/sh
LOG_DIR=.
fileCount=`ls -latr ${LOG_DIR}/prod* | wc -l`
#If no files found then exit.
if [ ${fileCount} -eq 0 ]
then
echo "what the F man!"
exit
fi
LASTHOUR=`expr \`date +%s\` - 3600`
scanStartDate=`date -r $LASTHOUR '+%Y-%m-%d %H:'`
echo "Current time: $(date)"
fileList=`ls -latr ${LOG_DIR}/prod* | tail -3 | awk '{print $9}'`
#Send mail
if [ ${a} -eq ${b} ]
then
echo -e "xyz\neer" | mail -s "STATS - $(hostname) - ${scanStartDate}" xyz@gmail.com
else
exit
fi
Threadpool and apache mina
Another link: Mina and threadpools
Found this info at : Link
The processorCount parameter specifies the number of SocketIoProcessors
the SocketAcceptor should use. Each SocketIoProcessor owns a
java.nio.channels.Selector. When the SocketAcceptor accepts a new
connection it will add the new connection to the next SocketIoProcessor
in a round-robin fashion. The default is 1 which is fine if you’re
running on single CPU hardware.
The Executor specified in the SocketAcceptor constructor will be used by
the SocketAcceptor to run its internal Worker thread which listens for
new connections. If you don’t need 100% control over the threads created
in your application you won’t have to bother about this.
If you specify the ThreadModel.MANUAL thread model MINA won’t create an
ExecutorFilter for your sessions’ filter chains. If you use MANUAL and
you don’t add an ExecutorFilter yourself all processing will take place
in a single SocketIoProcessor Worker thread (or processorCount threads
if processorCount > 1).
If you want to add your own ExecutorFilter explicitly (like in c) you
should specify ThreadModel.MANUAL otherwise you will end up with two
ExecutorFilters.
A ThreadModel can be specified for all ports your SocketAcceptor is
listening on by using acceptor.getDefaultConfig().setThreadModel(…) or
on a port by port basis by specifying a SocketAcceptorConfig when
calling acceptor.bind(…).
More readings:
ThreadPool in Mina with concurrent from Java5