Newsgroup: it.comp.java
Titolo: OutOfMemoryError alla openSession in una transazione JTA

Salve a tutti.
Per una applicazione ho implementato una architettura hibernate-based.
Hibernate gestisce cioè sia le transazioni JTA che l'accesso ai dati.
Il tutto su JBoss 4.2.1 e con MySql 5.
Funziona tutto egregiamente sulla mia macchina (equipaggiata con
Vista).
Dal cliente, invece, pur con un utente solo, ogni tanto si becca un
bel OutOfMemoryError
	at org.hibernate.impl.SessionFactoryImpl.openSession
(SessionFactoryImpl.java:535)
Cerco di illustrarvi adesso o file di configurazione e le classi basi
che uso.
L'hibernate.cfg.xml, tralasciando il puntamento a tutti gli hbm di
mappatura della base dati è molto semplice ed è fatto così:
<hibernate-configuration>
    <session-factory name="java:hibernate/SessionFactory">
        <property
name="hibernate.connection.datasource">java:SicrelDS</property>
       	<property
name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</
property>
		<property
name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</
property>
        <property
name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</
property>
        <property name="show_sql">true</property>
    </session-factory>
</hibernate-configuration>
Questa è invece la classe che gestisce la transazione
public class HibernateTransaction implements TransactionHelper{
	private static Transaction transaction;
	public void commitTransaction() throws ProjectException{
		try {
			transaction.commit();
		} catch (Exception e) {
			ProjectLogger.getLogger().error("Errore di commit",e);
			throw new ProjectException(e,"Errore di
commit",ProjectException.TypeOfException.HIBERNATE_EXCEPTION);
		}
	}
	public void rollbackTransaction() throws ProjectException{
		try {
			transaction.rollback();
		} catch (Exception e) {
			ProjectLogger.getLogger().error("Errore di rollback",e);
			throw new ProjectException(e,"Errore di
rollback",ProjectException.TypeOfException.HIBERNATE_EXCEPTION);
		}
	}
	public void startTransaction() throws ProjectException{
		try {
			Session session = HibernateSession.getIstance().createSession();
			transaction = session.beginTransaction();
		} catch (Exception e) {
			ProjectLogger.getLogger().error("Errore di beginTransaction",e);
			throw new ProjectException(e,"Errore di
beginTransaction",ProjectException.TypeOfException.HIBERNATE_EXCEPTION);
		}
	}
	public void endTransaction() throws ProjectException{
		try{
			transaction = null;
			HibernateSession.getIstance().closeSession();
		}catch(Exception e){
			ProjectLogger.getLogger().error("Errore di closeSession",e);
			throw new ProjectException(e,"Errore di
closeSession",ProjectException.TypeOfException.HIBERNATE_EXCEPTION);
		}
	}
}
Il metodo startTransaction utilizza la seguente classe
HibernateSession
public class HibernateSession {
	private static HibernateSession instance;
	private Session session = null;
	public static HibernateSession getIstance(){
		if (instance == null) {
			synchronized (HibernateSession.class) {
				if (instance == null) {
					instance = new HibernateSession();
				}
			}
		}
		return instance;
	}
	/**
	 *
	 * @return org.hibernate.Session
	 */
	public Session createSession() {
		session = HibernateUtil.getSessionFactory().openSession();
	    return session;
	}
	public Session currentSession() {
		return session;
	}
   /**
    * Distrugge l'oggetto org.hibernate.Session
    *
    */
	public void closeSession() {
	    if (session != null){
		      session.close();
	    }
	}
}
che a sua volta si fa dare la SessionFactory dalla HibernateUtil che
come vedrete carica una sola volta la configurazione di Hibernate
public class HibernateUtil {
	private static Logger log = Logger.getLogger(HibernateUtil.class);
	private static final SessionFactory sessionFactory;
	private static final Configuration configuration;
	static {
		try {
			// Create the SessionFactory from hibernate.cfg.xml
			String hibernateCfgPath = Configurator.getHibernateConfigPath() +
"hibernate.cfg.xml";
			String hibernateHbmPath = Configurator.getHibernateConfigPath() +
"hbm";
			// Passo il file hibernate.cfg.xml per la configurazione
			File hibernateFile = new File(hibernateCfgPath);
			configuration = new Configuration().configure(hibernateFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Throwable ex) {
			// Make sure you log the exception, as it might be swallowed
			log.error("Initial SessionFactory creation failed." /* +
Utility.getStackTrace(ex)*/);
			throw new ExceptionInInitializerError(ex);
		}
	}
	private static void addFileToConfiguration(File[] listaFilesHbm){
		for (File fileHbm : listaFilesHbm) {
			if (fileHbm.isFile()){
				configuration.addFile(fileHbm);
			}else{
				addFileToConfiguration(fileHbm.listFiles());
			}
		}
	}
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}
Infine, questa è la classe di Business che richiama il metodo
startTransaction()
public class BusinessDispatcher {
	private TransactionHelper transaction;
	public Command executeCommand(Command command, Strategie strategia)
throws ProjectException {
		ProjectLogger.getLogger().debug("Start");
		Strategy strategy = StrategyFactory.getStrategy(strategia,
command.getRisorsa());
		Command result = null;
		transaction = new HibernateTransaction();
		try{
			transaction.startTransaction();
			StandardDTO sigemiDTO = command.getRecord();
			if(sigemiDTO !=null){
				result = strategy.execute(command);
			}
			transaction.commitTransaction();
		}catch(ProjectException e){
			transaction.rollbackTransaction();
			throw e;
		}catch(Exception e){
			transaction.rollbackTransaction();
			throw new ProjectException
(e,ProjectException.TypeOfException.APPLICATION_EXCEPTION);
		}finally{
			transaction.endTransaction();
		}
		ProjectLogger.getLogger().debug("Finish");
		return result;
	}
}
Ebbene, come ho detto, ogni tanto dal cliente, anche (a quanto mi
dicono) con un'ampia sezione di memoria impostata sui parametri JVM,
il server restituisce un OutOfMemoryError con il seguente stacktrace.
java.lang.OutOfMemoryError: PermGen space
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:637)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:
142)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal
(WebappClassLoader.java:1814)
	at org.apache.catalina.loader.WebappClassLoader.findClass
(WebappClassLoader.java:872)
	at org.jboss.web.tomcat.service.WebAppClassLoader.findClass
(WebAppClassLoader.java:75)
	at org.apache.catalina.loader.WebappClassLoader.loadClass
(WebappClassLoader.java:1325)
	at org.apache.catalina.loader.WebappClassLoader.loadClass
(WebappClassLoader.java:1204)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
	at org.hibernate.impl.SessionFactoryImpl.openSession
(SessionFactoryImpl.java:503)
	at org.hibernate.impl.SessionFactoryImpl.openSession
(SessionFactoryImpl.java:527)
	at org.hibernate.impl.SessionFactoryImpl.openSession
(SessionFactoryImpl.java:535)
	at it.xxx.web.connector.HibernateSession.createSession
(HibernateSession.java:39)
	at it.xxx.web.connector.HibernateTransaction.startTransaction
(HibernateTransaction.java:36)
	at it.xxx.web.connector.BusinessDispatcher.executeCommand
(BusinessDispatcher.java:46)
Possibili suggerimenti?
Grazie in anticipo

Aggiungo un'altra informazione (intanto, se qualcuno vuole leggere la
parte di codice più comodamente può farlo a
http://www.coderanch.com/t/462951/Object-Relational-Mapping/java/OutOfMemoryError-at-openSession-JTATransaction#2067368
)
Nello stesso server è deployato anche un secondo war identico al primo
tranne che per il web.xml
Questa cosa mi diede già dei problemi perchè prima la classe
HibernateUtil mi restituiva la SessionFactory puntando al nome JNDI
dentro l'hibernate.cfg.xml in questo modo
   public static SessionFactory getSessionFactory() {
      try {
         return (SessionFactory)new InitialContext().lookup
("java:hibernate/SessionFactory");
      } catch (NamingException e) {
         e.printStackTrace();
         return sessionFactory;
      }
   }
e quando il secondo war lanciava il metodo prendeva un errore sulla
lookup.
Così ho cambiato ed utilizzosempre la sessionfactory ottenuta leggendo
direttamente la configurazione.
Però, può esserci qualcos'altro nella presenza di questi due war
gemelli a combinare il pastrocchio?