jueves, 16 de diciembre de 2021

La API de JPA 2.1 (IX) JPA-JNDI sin persistence.xml

 0. Introducción

Continuamos del post anterior, pero ahora tenemos que utilizar JNDI en una aplicación web, en este caso Vaadin.

Veamos la estructura de ficheros ya vista en otro blog

src
   |->main
   |   |->webapp
   |   |   |->WEB-INF       Not used (can be deleted)
   |   |   |   |->beans.xml Not used 
   |   |   |->skins
   |   |   |   |->ui
   |   |   |   |->content
   |   |   |->META-INF
   |   |   |   |>context.xml (JNDI pool of connections)
   |   |   |->imgs
   |   |   |   |->enterprise (or any particular folder with images)
   |   |   |->icons
   |   |   |   |->flags (or any particular folder with icons)
   |   |->resources
   |   |   |->view (in yaml or any partiular folder with some info)
   |   |   |->reports (or any partiular folder with jasper reports)
   |   |   |->readme (or any partiular folder with some info)
   |   |   |->properties (property files)
   |   |   |   ->control_post.properties
| | |->META-INF | | | |->services | | | |->com.vaadin.flow.server.VaadinServiceInitListener | | | |->persistence.xml | | |->i18n (all teh internationalization resources) | | | |->file_en.properties ; file_es.properties | | |->docs (any doc ) | | |->simplelogger.properties | |->java | | |->ui | | |->openadmin |->test frontend |->tone-edu (test with js) | |->tone-test.js |->three-edu (test with js) | |->three-test.js |->apex-charts (test with js) | |->apex-charts-test.js |->styles (all the css defined) | |->my-defined.css.css |->src (empty) |->generated | |->vaadin.ts |->font-awesome | |->webfonts, svgs, sprites, scss, metadata, less, js, css.. gradle.properties build.gradle

En este caso com es lógico no utilizaremos el presistence.xml


1. Ficheros importantes


En src/main/webapp/META-INF tenemos context.xml. En este ejemplo solo utilizaremos solo el recurso "control_post"

 
<Context path="/openweb" docBase="openweb"
        debug="5" reloadable="true" crossContext="true">
    <Resource 
      name="control_post"
      auth="Container"
      type="javax.sql.DataSource"
      username="my_user"
      password="my_password"
      maxTotal="50"
      maxIdle="20"
      maxWait="10000"
      timeBetweenEvictionRunsMillis="180000"
      removeAbandonedOnMaintenance="true"
      removeAbandonedOnBorrow="true"
      driverClassName="org.postgresql.Driver"
      url="jdbc:postgresql://192.1.1.1:5432/openweb" 
    />
    
    <Resource 
      name="other-persistence-unit"
      auth="Container"
      type="javax.sql.DataSource"
      username="other_user"
      password="other_password"
      maxTotal="50"
      maxIdle="20"
      maxWait="10000"
      timeBetweenEvictionRunsMillis="180000"
      removeAbandonedOnMaintenance="true"
      removeAbandonedOnBorrow="true"
      driverClassName="org.postgresql.Driver"
      url="jdbc:postgresql://192.1.1.2:5432/other_db" 
    />
        
</Context>



En src/resources/properties metemos este fichero control_post.properties

#-----------------------------------------------------------------------------
#1. General Properties
persistence.unit.name=            control_post
persistence.provider.class.name=  org.hibernate.jpa.HibernatePersistenceProvider
jta.datasource.name=              control_post
#non.jta.datasource=               
#mapping.file.names=
#jar.file.urls=
#persistence.unit.root.url
managed.classes=                  openadmin.model.csv.AytosCSV;\
                                  openadmin.model.csv.CSVLog;\
                                  openadmin.model.sedipualba.Expedient;\
                                  openadmin.model.sedipualba.Document

exclude.unlisted.classes=         true	
#shared.cache.mode=
#-----------------------------------------------------------------------------
#Properties not included in datasource
hibernate.dialect=                org.hibernate.dialect.PostgreSQLDialect
#hibernate.hbm2ddl.auto=           update
hibernate.hbm2ddl.auto=           none
hibernate.show_sql=               true


En src/main/java/utils tenemos PersistenceUnitInfoEdu que es la clase que va a recoger todas las propiedades de la conexión e hibernate. Observar la línea con el fondo amarillento que es la que se encarga de recoger el recurso JNDI de Tomcat. Observar tambien la ruta en rojo para buscar el recurso que quedaría: "java:/comp/env/control_post"


package utils;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;

import lombok.Getter;
import lombok.Setter;
import openadmin.utils.basic.StringUtilsEdu;

public class PersistenceUnitInfoEdu implements PersistenceUnitInfo {
    
    public static String JPA_VERSION = "2.2";
    @Getter @Setter private String persistenceUnitName; //OK
    @Getter @Setter private PersistenceUnitTransactionType transactionType   = PersistenceUnitTransactionType.RESOURCE_LOCAL; //OK
    @Getter @Setter private String persistenceProviderClassName="org.hibernate.jpa.HibernatePersistenceProvider"; //OK
    @Getter @Setter private DataSource jtaDataSource=null; //OK a falta de JNI
    @Getter @Setter private DataSource nonJtaDataSource=null; //OK a falta del no JNI
    @Getter @Setter private List<String> mappingFileNames = new ArrayList<>(); //OK
    @Getter @Setter private List<URL> jarFileUrls=null; //OK
    @Getter @Setter private URL persistenceUnitRootUrl=null; //OK
    @Getter @Setter private List<String> managedClassNames = new ArrayList<>(); //OK
    @Getter @Setter private boolean excludeUnlistedClasses=false; //OK
    @Getter @Setter private SharedCacheMode sharedCacheMode=null; //OK
    @Getter @Setter private ValidationMode validationMode=ValidationMode.AUTO; //OK
    @Getter @Setter private Properties properties=null; //OK
    @Getter @Setter private String persistenceXMLSchemaVersion=JPA_VERSION; //OK
    @Getter @Setter private ClassLoader classLoader=null; //OK
    @Getter @Setter private List<ClassTransformer> transformers = new ArrayList<>(); //OK addTransformes
    @Getter @Setter private ClassTransformer transformer=null;
    @Getter @Setter private ClassLoader newTempClassLoader=null; //OK
    
    public PersistenceUnitInfoEdu(String persistenceUnitName, List<String> managedClassNames, boolean excludeUnlistedClasses, Properties properties) {
        this.persistenceUnitName = persistenceUnitName;
        this.managedClassNames = managedClassNames;
        this.excludeUnlistedClasses=excludeUnlistedClasses;
        this.properties = properties;
    }

	@Override
	public boolean excludeUnlistedClasses() {
		return excludeUnlistedClasses;
	}

	@Override
	public void addTransformer(ClassTransformer transformer) {
		// TODO Auto-generated method stub
	}

	public PersistenceUnitInfoEdu(Properties props) throws Exception {
        this.persistenceUnitName = props.getProperty("persistence.unit.name").trim();
        this.persistenceProviderClassName=props.getProperty("persistence.provider.class.name").trim();
        
        String dtSrc=props.getProperty("jta.datasource.name","").trim();
        /*
        if (dtSrc.length()>0) { 
        	Context initContext = new InitialContext();
        	Context envContext  = (Context)initContext.lookup("java:/comp/env");
        	//DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
        	this.jtaDataSource=(DataSource)envContext.lookup(dtSrc);
        }
        */	
        if (dtSrc.length()>0) { 
        	InitialContext cxt = new InitialContext();
        	if ( cxt == null ) {
        	   throw new Exception("Uh oh -- no context!");
        	}

        	this.jtaDataSource= (DataSource) cxt.lookup( "java:/comp/env/"+dtSrc );

        	if ( this.jtaDataSource == null ) {
        	   throw new Exception("Data source not found!");
        	}
        	
        }
        
        String[] managedCls=StringUtilsEdu.splitAndTrim(props.getProperty("managed.classes"),";");
        this.managedClassNames =  Arrays.asList(managedCls);
        
        this.excludeUnlistedClasses=Boolean.parseBoolean(props.getProperty("exclude.unlisted.classes").trim());
     
        this.properties = props;
    }
	
	
}


En src/main/java/utils tenemos JPANoPersistenceUtils que permite obtener las EntitymanagerFactory


package utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.spi.PersistenceUnitInfo;

import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;



public class JPANoPersistenceUtils {
	
	public static PersistenceUnitInfoEdu getPsUnitInfo(String persistenceUnitName, List<String> managedClassNames, boolean excludeUnlistedClasses, Properties properties) {
		return new PersistenceUnitInfoEdu(persistenceUnitName, managedClassNames, excludeUnlistedClasses, properties);
	}
	
	public static PersistenceUnitInfoEdu getPsUnitInfo (Properties properties) throws Exception {
		return new PersistenceUnitInfoEdu(properties);
	}
	
	public static EntityManagerFactory getEntityManagerFactory(PersistenceUnitInfo psUnitInfo) {
		Map<String, Object> configuration = new HashMap<>();
		return new EntityManagerFactoryBuilderImpl(
		          new PersistenceUnitInfoDescriptor(psUnitInfo), configuration)
		          .build();
	}
	
	public static EntityManagerFactory getEntityManagerFactory(String persistenceUnitName, List<String> managedClassNames, boolean excludeUnlistedClasses, Properties properties) {
		PersistenceUnitInfo persistenceUnitInfo = getPsUnitInfo(persistenceUnitName,managedClassNames,excludeUnlistedClasses,properties);
		return getEntityManagerFactory(persistenceUnitInfo);
	}
	
	public static EntityManagerFactory getEntityManagerFactory(Properties properties) throws Exception {
		PersistenceUnitInfo persistenceUnitInfo = getPsUnitInfo(properties);
		return getEntityManagerFactory(persistenceUnitInfo);
	}
	
	

	public static void main(String[] args) {
		List<String>classes=new ArrayList<String>();
		classes.add("openadmin.utils.nopersistencexml.Test");
		EntityManagerFactory emf=getEntityManagerFactory("my-h2",classes,true,MyConnectionProps.getPropsH2());
		
		
		EntityManager em=emf.createEntityManager();
		
		//Query q=em.createNativeQuery("SELECT * FROM TEST");
		Query q=em.createQuery("SELECT t FROM Test t WHERE t.id<1000");
		List<Test> ltest=q.getResultList();
		for (Test t:ltest) System.out.println(t.getId()+"-"+ t.getName());
			
		em.close();
		emf.close();
	}

}


Veamos una clase de prueba para abrir una conexión.OJO, está clase se debe de llamar dentro de una aplicacion web en marcha. Observar como se obtiene la ruta al fichero de propiedades "control_post.properties" que se encuentra dentro del directorio "properties". Solamante se crea una EntityManagerFactory y a partir de esta una EntityManager. 


 package utils;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;


import openadmin.utils.nopersistencexml.JPANoPersistenceUtils;

public class Test {

  public static void main(String[] args) {
      String propsPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
      propsPath += File.separator + "properties"+File.separator+ "control_post.properties";
      Properties controlProps=new Properties();
      try {
          controlProps.load(new FileInputStream(propsPath));
          EntityManagerFactory factory = JPANoPersistenceUtils.getEntityManagerFactory(controlProps);
          EntityManager em = factory.createEntityManager();
          em.close();
          //Do some stuff
          factory.close();
      } catch (Exception e) {
          e.printStackTrace();
      }	
    }
}


No hay comentarios :

Publicar un comentario