NiLUS
22-11-2007, 10:29
Rapida panoramica della situazione:
Sto usando Jasper (http://jasperreports.sourceforge.net/) per creare dei Reports via Java in ambiente Lotus Notes (quindi JVM della IBM).
Il codice è molto semplice, e sono riuscito a restringere il problema alla classe JRXmlDataSource (http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/data/JRXmlDataSource.html), che non mi pare disponga di metodi particolari per chiuderla, terminarla o quant'altro. Nello specifico, sto usando il costruttore a cui passo un InputStream (chiuso più avanti).
Il messaggio d'errore è il seguente:
Error cleaning up agent threads
In pratica dopo 4 o 5 esecuzioni la RAM si riempie e si scaturisce l'eccezione OutOfMemoryError.
Ho trovato sul sito IBM (http://www-1.ibm.com/support/docview.wss?uid=swg21090031) questa funzione che ritorna i thread attivi:
public static void dumptg (ThreadGroup tg) {
// First, get our thread group
if (tg == null) {
// none specified, assume current thread group
tg = Thread.currentThread().getThreadGroup();
}
// display the threadgroup name and object id
System.out.println("ThreadGroup "+tg.getName()+ ", objid = "+tg.hashCode());
// display the threadgroup's number of active subgroups
System.out.println(" subgroups = "+tg.activeGroupCount());
// get and display the number of active threads in this threadgroup and all subgroups
int tcount = tg.activeCount();
System.out.println(" total threads = "+tcount);
// allocate an array big enough to hold the number of threads
Thread[] arr = new Thread[tcount];
// fill in the array with the active threads (include subgroups)
int num = tg.enumerate(arr,true);
// display how many were stored.
System.out.println("\nThread Name, ThreadID, ThreadGroup");
// display the name, id and owning threadgroup of each thread
for (int i = 0; i<num; i++) {
System.out.println(arr[i].getName()+", "+
arr[i].hashCode()+", "+
arr[i].getThreadGroup().getName());
try {
arr[i].join(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
L'output che mi torna, quando richiamata in ultimo prima del termine della funzione che utilizza la JRXmlDataSource è:
ThreadGroup UTG: JavaAgent, objid = 127294134
subgroups = 0
total threads = 2
Thread Name, ThreadID, ThreadGroup
AgentThread: JavaAgent, 14883511, UTG: JavaAgent
Questo alla prima esecuzione. All'output di cui sopra segue il "Error cleaning up agent threads". In una esecuzione successiva (senza chiudere e riaprire Lotus) mi dice che il numero totale di thread è pari a 1, anziché 2.
I sorgenti Java in Lotus differiscono un po' dagli standard. Funzionano in questo modo:
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
...
}
catch (Exception e) { e.printStackTrace(); }
}
}
Ho provato a terminare il Thread manualmente (destroy), o con il join a dargli qualche secondo di tempo, ma l'errore persiste.
Non so se possa centrare, ma per far girare il tutto nella JVM di IBM ho dovuto aggiungere al java.policy, nel grant:
permission java.lang.RuntimePermission "createClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";
Siccome Jasper sfrutta il ClassLoader per generare i report, anche se non è la JRXmlDataSource a richiedere il ClassLoader bensì la JasperRunManager.
Qualche idea? Il sorgente simile (dico simile perché senza AgentBase) eseguito su JVM Sun non mi crea di questi problemi, e non ho dovuto mettere mani alle autorizzazioni del ClassLoader. Che dipenda da questioni di sicurezza? Magari è necessario mettere mani ai permessi per "autorizzare" la JVM a terminare determinati Thread?
Provando ad aggiungere:
permission java.lang.RuntimePermission "stopThread";
permission java.lang.RuntimePermission "modifyThreadGroup";
permission java.lang.RuntimePermission "modifyThread";
Al java.policy ma nulla cambia.
Grazie in anticipo.
Ciao.
Sto usando Jasper (http://jasperreports.sourceforge.net/) per creare dei Reports via Java in ambiente Lotus Notes (quindi JVM della IBM).
Il codice è molto semplice, e sono riuscito a restringere il problema alla classe JRXmlDataSource (http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/data/JRXmlDataSource.html), che non mi pare disponga di metodi particolari per chiuderla, terminarla o quant'altro. Nello specifico, sto usando il costruttore a cui passo un InputStream (chiuso più avanti).
Il messaggio d'errore è il seguente:
Error cleaning up agent threads
In pratica dopo 4 o 5 esecuzioni la RAM si riempie e si scaturisce l'eccezione OutOfMemoryError.
Ho trovato sul sito IBM (http://www-1.ibm.com/support/docview.wss?uid=swg21090031) questa funzione che ritorna i thread attivi:
public static void dumptg (ThreadGroup tg) {
// First, get our thread group
if (tg == null) {
// none specified, assume current thread group
tg = Thread.currentThread().getThreadGroup();
}
// display the threadgroup name and object id
System.out.println("ThreadGroup "+tg.getName()+ ", objid = "+tg.hashCode());
// display the threadgroup's number of active subgroups
System.out.println(" subgroups = "+tg.activeGroupCount());
// get and display the number of active threads in this threadgroup and all subgroups
int tcount = tg.activeCount();
System.out.println(" total threads = "+tcount);
// allocate an array big enough to hold the number of threads
Thread[] arr = new Thread[tcount];
// fill in the array with the active threads (include subgroups)
int num = tg.enumerate(arr,true);
// display how many were stored.
System.out.println("\nThread Name, ThreadID, ThreadGroup");
// display the name, id and owning threadgroup of each thread
for (int i = 0; i<num; i++) {
System.out.println(arr[i].getName()+", "+
arr[i].hashCode()+", "+
arr[i].getThreadGroup().getName());
try {
arr[i].join(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
L'output che mi torna, quando richiamata in ultimo prima del termine della funzione che utilizza la JRXmlDataSource è:
ThreadGroup UTG: JavaAgent, objid = 127294134
subgroups = 0
total threads = 2
Thread Name, ThreadID, ThreadGroup
AgentThread: JavaAgent, 14883511, UTG: JavaAgent
Questo alla prima esecuzione. All'output di cui sopra segue il "Error cleaning up agent threads". In una esecuzione successiva (senza chiudere e riaprire Lotus) mi dice che il numero totale di thread è pari a 1, anziché 2.
I sorgenti Java in Lotus differiscono un po' dagli standard. Funzionano in questo modo:
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
...
}
catch (Exception e) { e.printStackTrace(); }
}
}
Ho provato a terminare il Thread manualmente (destroy), o con il join a dargli qualche secondo di tempo, ma l'errore persiste.
Non so se possa centrare, ma per far girare il tutto nella JVM di IBM ho dovuto aggiungere al java.policy, nel grant:
permission java.lang.RuntimePermission "createClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";
Siccome Jasper sfrutta il ClassLoader per generare i report, anche se non è la JRXmlDataSource a richiedere il ClassLoader bensì la JasperRunManager.
Qualche idea? Il sorgente simile (dico simile perché senza AgentBase) eseguito su JVM Sun non mi crea di questi problemi, e non ho dovuto mettere mani alle autorizzazioni del ClassLoader. Che dipenda da questioni di sicurezza? Magari è necessario mettere mani ai permessi per "autorizzare" la JVM a terminare determinati Thread?
Provando ad aggiungere:
permission java.lang.RuntimePermission "stopThread";
permission java.lang.RuntimePermission "modifyThreadGroup";
permission java.lang.RuntimePermission "modifyThread";
Al java.policy ma nulla cambia.
Grazie in anticipo.
Ciao.