1> Resumen
Inicialmente, probé esta clase cargando aislamiento para cargar tarros de Hibernate 3.6.4 con JBoss 5.1.0.GA.
Definitivamente NO es posible. Hay algo mágico debajo del capó que le impide usar cualquier versión de Hibernate con soporte JPA2.
Estoy realmente decepcionado que el proyecto JBoss no proporcionó algún tipo de parche o service pack para admitir JPA2 en 5.1.0.GA.
2> Solución: "El Kernel solución"
que han logrado utilizar JPA2 con JBoss 5.1.0.GA describo aquí mi receta. Es más una prueba de concepto que puedes usar para crear tu propia solución.
Ingredientes:
- 1 Archivo de la Guerra
- 1 servlet
- 1 aplicación independiente de Java (J2SE)
Receta:
Paso 1: cree la aplicación independiente (APP)
Esta aplicación recibirá instrucciones del servlet para usar Hibernate.
Te dejo la elección del método de comunicación. Como la aplicación utiliza JPA2, necesitará un archivo persistence.xml
ubicado en una carpeta META-INF
. Desde JBoss 5.x, cuando implementa un WAR, JBoss escaneará el WAR y todas sus sub-implementaciones para encontrar y desplegar ciegamente persistence.xml
archivos. Cambie el nombre de su archivo persistence.xml
en my-persistence.xml
por ejemplo. Use el siguiente código cuando construya su EntityManagerFactory
(evite que JBoss implemente persistence.xml).
ACTUALIZACIÓN: Este método funciona, pero Hibernate genera algunas advertencias extrañas. Para detener esas advertencias, he decidido colocar la carpeta META-INF
y el archivo de persistencia (renombrado de nuevo a persistence.xml
) fuera del WAR. En mi caso, elegí una carpeta de configuración especial en el disco duro y la agregué al classpath. No más advertencias extrañas y no se requiere un cargador de clases personalizado para cargar el archivo de persistencia.
Dejo que usted elija entre usar un cargador de clases personalizado o cambiar la ubicación del archivo de persistencia. En ambos casos, JBoss no encontrará el archivo de persistencia.
Paso 2: Construir el servlet
Cuando el servlet necesita tener acceso a la base de datos, se lanza la aplicación y le dice qué hacer.
Para lanzar la aplicación, el servlet es responsable de generar una nueva JVM y construir el classpath de la aplicación. Lea el siguiente código para (Engendrar una JVM). La ruta de clases es fácilmente edificable ya que todos los frascos necesarios estarán en el directorio /lib
del Archivo de la Guerra ...
Paso 3: Construir el archivo WAR
construir un archivo WAR donde pones el servlet y la aplicación independiente empaquetada como un JAR. La aplicación será una dependencia de la GUERRA.
Prevenir JBoss con la implementación de persistence.xml
// Install a proxy class loader for adding renamed persistence.xml file
Thread t = Thread.currentThread();
ClassLoader clOriginal = t.getContextClassLoader();
t.setContextClassLoader(new SpecialClassLoader(clOriginal, "META-INF/my-persistence.xml"));
// Build EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
// Restore original class loader
t.setContextClassLoader(clOriginal);
//...
private class ProxyClassLoader extends ClassLoader {
private ClassLoader realClassLoader;
private String hiddenFromJBossPersistenceFile;
public ProxyClassLoader(ClassLoader realClassLoader, String hiddenFromJBossPersistenceFile) {
this.realClassLoader = realClassLoader;
this.hiddenFromJBossPersistenceFile = hiddenFromJBossPersistenceFile;
}
public void clearAssertionStatus() {
realClassLoader.clearAssertionStatus();
}
public boolean equals(Object obj) {
return realClassLoader.equals(obj);
}
public URL getResource(String name) {
return realClassLoader.getResource(name);
}
public InputStream getResourceAsStream(String name) {
return realClassLoader.getResourceAsStream(name);
}
public Enumeration<URL> getResources(String name) throws IOException {
ArrayList<URL> resources = new ArrayList<URL>();
if (name.equalsIgnoreCase("META-INF/persistence.xml")) {
resources.add(getResource(this.hiddenFromJBossPersistenceFile));
}
resources.addAll(Collections.list(realClassLoader.getResources(name)));
return Collections.enumeration(resources);
}
public int hashCode() {
return realClassLoader.hashCode();
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return realClassLoader.loadClass(name);
}
public void setClassAssertionStatus(String className, boolean enabled) {
realClassLoader.setClassAssertionStatus(className, enabled);
}
public void setDefaultAssertionStatus(boolean enabled) {
realClassLoader.setDefaultAssertionStatus(enabled);
}
public void setPackageAssertionStatus(String packageName, boolean enabled) {
realClassLoader.setPackageAssertionStatus(packageName, enabled);
}
public String toString() {
return realClassLoader.toString();
}
}
desove una JVM
public static Process createProcess(final String optionsAsString, final String workingDir, final String mainClass, final String[] arguments) throws IOException {
String jvm = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
String[] options = optionsAsString.split(" ");
List<String> command = new ArrayList<String>();
command.add(jvm);
command.addAll(Arrays.asList(options));
command.add(mainClass);
command.addAll(Arrays.asList(arguments));
//System.out.println(command);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.directory(new File(workingDir));
return processBuilder.start();
}
public static void makeItRun() {
try {
// Start JVM
String classPath = buildClassPath();
String workingDir = getSuitableWorkingDir();//or just "."
Process java = createProcess("-cp \"" + classPath + "\"", workingDir, my.package.APP.class.getCanonicalName(), "-the -options -of -my -APP");
// Communicate with your APP here ...
// Stop JVM
java.destroy();
} catch(Throwable t) {
t.printStackTrace();
}
}
¿Cómo sabes que está utilizando sus propias jarras? – gkamal
@gkamal Cuando mi aplicación se ejecuta, recibí una excepción 'NoSuchMethod'. – Stephan
¿Se despliega el WAR por sí solo o es parte de un EAR? – CoolBeans