Mostrando entradas con la etiqueta weblogic. Mostrar todas las entradas
Mostrando entradas con la etiqueta weblogic. Mostrar todas las entradas

jueves, 21 de octubre de 2021

Desarrollo y despliegue de un servicio en Weblogic 14c

Hoy vamos a ver como crear un web service (tanto SOAP como REST), que debe desplegarse en un contenedor de aplicaciones empresariales. Concretamente en Weblogic. En apariencia es algo sencillo, pero también es verdad que al ser un servidor propiedad de Oracle y no Open Source, a veces es un poco difícil encontrar información. Así que esperamos aclarar un poco su funcionamiento básico a través de este post. 

Debemos recordar que este tipo de servidores vienen con un conjunto de librerías que implementan las especificaciones de Java y Jakarta EE. Esta es una de las razones por los que son más pesados, que un simple contenedor de servlet. Aparte de que incluyen bastante más funcionalidades asociadas a dichas especificaciones. 

Por tanto a la hora de crear una aplicación que vayamos a desplegar en Weblogic o otro tipo de contenedor de aplicaciones empresariales, debemos indicar cuales son las API que implementa. Con el beneficio de que además no es necesario añadir dichas implementaciones, puesto que ya se encuentran en el servidor. Debido a eso, simplemente deberemos indicar en el fichero pom.xml cuales son dichas interfaces y que todas tienen de ámbito provided, puesto que se encuentran en el servidor. 

<!-- weblogic dependencies -->
<dependency>    <!-- Java EE -->
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE EJB -->
    <groupId>javax.ejb</groupId>
    <artifactId>javax.ejb-api</artifactId>
    <version>3.2.2</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE Servlet -->
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE JSP -->
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE JSF -->
    <groupId>javax.faces</groupId>
    <artifactId>javax.faces-api</artifactId>
    <version>2.3</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE Common Annotationss -->
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java EE Bean Validation -->
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.0.Final</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java API for JSON Processing -->
    <groupId>javax.json</groupId>
    <artifactId>javax.json-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java API for JSON Binding -->
    <groupId>javax.json.bind</groupId>
    <artifactId>javax.json.bind-api</artifactId>
    <version>1.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java API for XML-Based Web Services -->
    <groupId>javax.xml.ws</groupId>
    <artifactId>jaxws-api</artifactId>
    <version>2.3.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Java API for RESTful Web Services (JAX-RS) -->
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Contexts and Dependency Injection for Java EE -->
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>
<dependency>    <!-- Expression Language (EL) -->
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>3.0.0</version>
</dependency>

Para la creación de los web services en verdad no necesitamos tantas librerías, pero este listado nos puede servir de referencia. Para el servicio SOAP requeriremos de la librería jaxws-api y para el servicio REST de la librería javax.ws.rs-api. 

La idea principal es que ambos servicios sean muy básicos y funcionen prácticamente igual. Con la única diferencia de las anotaciones que permitirán que un servicio se genere como SOAP o REST. 

Empezaremos primero por el más antiguo, el servicio SOAP. La clase que implemente nuestro servicio debe tener la anotación @WebService. A la cual le podemos indicar el nombre de dicho servicio. Y cada uno de los métodos que queramos exponer deberán llevar la anotación @WebMethod, a los cuales también le podemos indicar los nombres asociados. Ejemplo:

@WebService(serviceName = "BookSoapService")
public class BookServiceImpl implements BookService {

    private static Map<Integer, Book> books = new HashMap<>();

    static {
	books.put(1, new Book(1, "Dune", "Frank Herbert"));
	books.put(2, new Book(2, "The stars my destination", "Alfred Bester"));
	books.put(3, new Book(3, "Ender's game", "Orson S. Card"));
    }

    @Override
    @WebMethod(operationName = "getById")
    public Book getById(final Integer id) {
	return books.get(id);
    }
}

Una vez desplegado el servicio, podremos acceder a su WSDL, generado automáticamente, a través de la siguiente URL: http://localhost:7001/weblogicWS/BookSoapService?wsdl.

Ahora veremos como hacer el servicio REST. Para ello deberemos añadir a nivel de clase la anotación @Path e indicar la ruta principal de acceso a dicho servicio. Este paso no es del todo necesario, puesto que podemos poner directamente dicha anotación a cada método, pero poniéndolo a nivel de clase evitamos repetir parte de dicha ruta. Luego en cada método, y en función de la operación que vaya a realizar, deberemos indicar la anotación asociada al método HTTP a utilizar. Puede ser @DELETE, @GET, etc. Hay otras anotaciones que nos pueden ayudar a obtener la información que viaja en la llamada. Como pueden ser @CookieParam, @HeaderParam, @PathParam o @QueryParam. 

@Path("/book")
public class BookRestServiceImpl implements BookService {

    private static Map<Integer, Book> books = new HashMap<>();

    static {
	books.put(1, new Book(1, "Dune", "Frank Herbert"));
	books.put(2, new Book(2, "The stars my destination", "Alfred Bester"));
	books.put(3, new Book(3, "Ender's game", "Orson S. Card"));
    }

    @Override
    @GET
    @Path("/{id}")
    @Produces("application/json")
    public Book getById(@PathParam("id") final Integer id) {
	return books.get(id);
    }
}

Una vez desplegado el servicio, podremos invocarlo a través de la siguiente URL: http://localhost:7001/weblogicWS/resources/book/1.

Y una vez que tenemos nuestros web services, vamos a desplegarlos. Para ello lo primero será poner en marcha el servidor. Esto podemos hacerlo descargándonoslo e instalándolo en nuestra máquina, a través de este enlace. O como es habitual hoy en día y para pruebas en desarrollo, levantarlo como una instancia de Docker. Este último será el método que veremos. 

Pero para poder utilizar una instancia de docker del servidor necesitaremos realizar los siguientes pasos:

  • Crear una cuenta en en Oracle.com Network
  • Acceder a la página de Oracle Container Registry, lógate con la cuenta creada en el paso anterior y acepta la licencia de usuario. Si no ves dicha licencia directamente, accede a una de las imágenes y aparecerá en la parte superior derecha. 
  • Logate en el Hub de Oracle a través del comando docker login container-registry.oracle.com.
  • Descarga la imagen deseada a través del comando docker pull container-registry.oracle.com/middleware/weblogic:${TAG}. Puedes ver los distintos tags aquí. 
Ahora que tenemos la imagen descargada necesitamos montar un volumen que nos permita indicar donde se encuentra nuestro fichero domain.properties. Este fichero de configuración nos permitirá principalmente el usuario y contraseña. A través de un comando similar a este:

docker run -p 7001:7001 -p 9002:9002 --name wl14c \
-v ${PATH_TO_DOMAIN_PROPERTIES}:/u01/oracle/properties \
container-registry.oracle.com/middleware/weblogic:14.1.1.0-dev-8

Una vez arrancado, podemos acceder a la consola de administración a través de la URL: https://localhost:9002/console/ y acceder a ella con el usuario y contraseña indicado en el fichero de configuración. 

Ya solo quedaría desplegar el servicio. Lo podemos hacer de varias formas, incluso a través de una API REST. Pero las más sencillas pasan por copiar el war o ear a una carpeta del servidor dentro de la instancia de Docker. Lo cual podemos realizar con un comando similar a este:

docker cp weblogicWS.war wl14c:/tmp/weblogicWS.war

 Como comentábamos anteriormente, lo podemos hacer de varias formas:
  1. Si el fichero lo pegamos en la carpeta /u01/oracle/user_projects/domains/base_domain/autodeploy el fichero se desplegará automáticamente. 
  2. Si lo pegamos en otra carpeta a través de la consola de Administración y la opción Despliegues tras pulsar el botón Instalar. Podremos seleccionar la ruta y fichero que hemos copiado anteriormente e instalarlo tras seleccionar unas opciones de despliegues. 
  3. También podemos desplegarlo a través de la utilidad weblogic.Deployer. Tener en cuenta que esta opción no esta disponible en la versión para desarrollo.  

docker exec -it wl14c sh
$ cd /u01/wlsdomain/base_domain/bin
$ . setDomainEnv.sh
$ java weblogic.Deployer -adminurl t3://localhost:7001 -user user1 -password welcome1 \
-name weblogicWS -targets base_domain -deploy /tmp/weblogicWS.war

Por último, vamos a indicar como debemos configurar el repositorio de Oracle si deseamos utilizarlo. Para ello primero debemos tener un usuario de acceso a Oracle.com Network, puede ser el mismo que utilizamos para descargas las imágenes del hub de Oracle. 

Ese usuario debemos configurarlo asociado al servidor en el fichero settings.xml que se encuentra en la ruta: ~/.m2/settings.xml. Tal y como mostramos a continuación:

<!-- https://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9017 -->
<server>
    <id>maven.oracle.com</id>
    <username>user@mail.com</username>
    <password>{Z8Gn4wUfjN0Hsiu44T+FwfAjpRYY62ycDxKU9V7u/ps=}</password>   
        <configuration>
        <basicAuthScope>
            <host>ANY</host>
            <port>ANY</port>
            <realm>OAM 11g</realm>
        </basicAuthScope>
        <httpConfiguration>
            <all>
                <params>
                    <property>
                        <name>http.protocol.allow-circular-redirects</name>
                        <value>%b,true</value>
                    </property>
                </params>
            </all>
        </httpConfiguration>
    </configuration>
</server>

Y luego deberemos añadir los repositorios de Oracle. Estos podemos indicarlos también de forma global en el fichero settings.xml o de forma específica en cada uno de los pom.xml de los proyectos que vayan a usarlo. 

<repositories>
	<repository>
		<id>maven.oracle.com</id>
		<releases>
			<enabled>true</enabled>
		</releases>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
		<url>https://maven.oracle.com</url>
		<layout>default</layout>
	</repository>
</repositories>
<pluginRepositories>
	<pluginRepository>
		<id>maven.oracle.com</id>
		<url>https://maven.oracle.com</url>
	</pluginRepository>
</pluginRepositories>

Y esto es todo. Aunque no hemos hecho gran cosa, hemos tenido que autenticarnos en Oracle, y configurar varios aspectos para el correcto desarrollo y despliegue de nuestra aplicación, además hemos recopilado como realizar un proceso completo para hacerlo en un servidor Weblogic. Si queréis ver el código de la aplicación, lo tenéis aquí. 

lunes, 23 de abril de 2012

Problema con Hibernate y Weblogic y su classloader

Al utilizar weblogic con un proyecto que contiene hibernate y que es operativo en otros servidores, se me ha dado el siguiente fallo:
org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken
Lo que en un principio parece que es falta de una librería, se trata en realidad de un conflicto de librerías entre las propias del weblogic y las del proyecto. La aplicación utiliza una librería del servidor que es más antigua que la necesaria por Hibernate y de ahí el fallo.

Para solucionarlo he encontrado por la web varias formas de resolver el conflicto, aquí dejo las más interesantes y menos intrusivas.

1. Indicar a Hiberante que haga uso de otra clase para la función que falla. Para ello es necesario modificar el fichero de configuración, en mi caso persistence.xml y añadir la siguiente propiedad:

2. Indicar al servidor que primero cargue las librerías de la aplicación. Para ello es necesario modificar el fichero de configuración del servidor weblogic añadiendo la siguiente propiedad:

  
    true
  

Crear adaptador de servidor weblogic en eclipse

Tras tener el weblogic preparado, lo siguiente es crear un nuevo adaptador en el eclipse que nos permita el manejo del servidor a través de el.

La versión utilizada es eclipse indigo, y por defecto no incluye ningún adaptador para servidores weblogic, para que se muestren estos adaptadores debemos instalarlos antes. Para ello, en la pantalla de definición de un nuevo servidor hay un enlace en la esquina superior derecha, el cual abrirá una nueva ventana donde seleccionaremos el servidor que nos interesa, weblogic en nuestro caso.

Se ha usado la versión indigo de eclipse, porque es posible que en versiones anteriores estos adaptadores no se ecuentren disponibles ni para descargarse o no se encuentre la versión.

Una vez seleccionado el servidor e instalado pasamos a crear el adaptador para usar nuestro servidor.

Sobre la ventana de server, pulsamos con el botón derecho y seleccionamos la opcion new>server. Dentro de la lista de opciones que incluye seleccionamos oracle weblogic 12c. Pulsamos next y vamos a la siguiente pantalla.

En la pantalla de creación del servidor debemos indicar donde se encuentra el servidor y el jdk. Aunque lo hagamos correctamente es posible que eclipse no nos permita seguir en la creación del adaptador, y esto es debido a un bug. Para conseguir instalar el adaptador seguimos los siguientes pasos.

En weblogic home seleccionamos donde instalamos en el servidor y posteriormente escribimos a mano "/wlserver". Seleccionamos la carpeta donde se encuentra la jdk y ya podemos seguir con el proceso.

En la siguiente pantalla seleccionamos donde hemos puesto el dominio y ya esta instalado el servidor

Problemas en la instalación de weblogc 12c

Estaba intentando instalar un servidor wweblogic 12c. Y si se siguen los pasos de instalación que vienen en el archivo README.txt es bastante sencillo. Pero me ha fallado en los dos ultimos pasos. Los pasos son los siguientes:

1. Extraer el contenido del zip en un directorio y referirse a el como MW_HOME (ej: /home/myhome/mywls).

2. Establecer las variables de entorno JAVA_HOME y MW_HOME
    $ export JAVA_HOME=/home/myhome/myjavahome
    $ export MW_HOME=/home/myhome/mywls
3. Ejecutar el script de configuración. Solo debe ser ejecutado una vez a menos que se cambie la localización del servidor.
    $ . ./configure.sh
4. Ejecuta el archivo para establecer las variables de entorno de WLS.
    $ . $MW_HOME/wlserver/server/bin/setWLSEnv.sh
5. Crea un nuevo dominio WLS y arranca la máquina. El dominio es recomendable tenerlo fuera de MW_HOME.
    $ mkdir /home/myhome/mydomain
    $ cd /home/myhome/mydomain
    $ $JAVA_HOME/bin/java $JAVA_OPTIONS -Xmx1024m -XX:MaxPermSize=128m weblogic.Server
Para empezar cuando intentaba ejecutar weblogci.Server, me indicaba que las no encontraba la clase definida:
java.lang.NoClassDefFoundError: weblogic/Server
Caused by: java.lang.ClassNotFoundException: weblogic.Server
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
A pesar de que estaba realizando el paso 4, las variables de entorno no se guardaban correctamente. Como al ejecutar el paso 4 se muestran como deben de quedar las variables CLASSPATH y PATH, las copie y edite yo mismo en el fichero .bashrc. Así al abrir una nueva consola, las variables de entorno están correctamente.

Despues de este fallo, daba problemas al arrancar el servidor:
    
Osea, que cuando se debe de ingresar la contraseña del usuario. Para evitar este problema debemos de indicar la siguiente JAVA_OPTIONS, que nos permitira introducir la contraseña.
    $ $JAVA_HOME/bin/java -Dweblogic.management.allowPasswordEcho=true -Xmx1024m -XX:MaxPermSize=128m weblogic.Server
Tras esto solo tendremos que acceder a la siguiente URL y empezar a disfrutar de weblogic http://localhost:7001/console