Affichage des articles dont le libellé est Jonas. Afficher tous les articles
Affichage des articles dont le libellé est Jonas. Afficher tous les articles

mercredi 19 février 2014

JSP, JS, CSS hot-deployment with Maven in Eclipse WTP

Eclipse WTP use Adtaper to provide hot deploy fonctionnalities with JEE application servers or web containers. Depending on the configuration, the adapter may reload the whole .war or .ear and take several seconds when not minutes to do so.

While WTP adatpers hot deployment is a time-saver as it rely on the Eclipse incremental compiler and does not pass through all the maven build phase to package the final .war or .ear, this is not the good choice when you work with resources like .jsp, .js, .css, .html, .tag, ...

For those static resources that don't need the whole application context to be reloaded a faster way is to copy themn automatically to the application server work directory. Some benefits are :
  • save time : no .war or .ear undeploy/redeploy
  • use [F5] to reload your resource instantly
    • the session is kept
    • the context is alive (jBPM, Spring web flow, DROOLS)
  • no more OutOfMemory or PermGenSpace when redeploying...
Next lines will show you how to set it up under JonAS. This HowTo is based on JonAS 5.2.4, Sun JKD 1.7, Maven 3.1.1, Windows 7 and Eclipse Juno. This should work on other OS as long as you go with Maven 3 and might be ported to other application servers...

WTP Adapter configuration

First of all, you need to tell JonAS WTP adatper not to publish automatically. The option is available when you double-click on the application server icons in the Eclipse "Servers" view :


Choose "Never publish automatically"... You'll then need to undeploy/deploy manually (remove and publish from the Eclipse "servers" view) when you want a code change to be taken in account or setup Cargo and configure the cargo:deploy goal to publish changes for you.

JonAS configuration

By default, JonAS will create a new directory each time an EAR or WAR is deployed. What we want is JonAS to use the same directory each time it deploys the same file, so we need to set the jonas.development property to false in the jonas.properties configuration file :

#  Set to true in order to execute the JOnAS Server in development mode.
#
#  WAR archive deployment case in development mode (for single or EAR packaged WARs):
#  Each modified WAR archive will be unpacked in the working directory of the 
#  JOnAS Server in a different folder to avoid file locks. 
#  This is especially useful in a Windows environment.
jonas.development    false
JonAS will then use a directory named against Eclipse project name.

Maven settings.xml configuration

As of Maven 3.0, profiles in the POM can also be activated based on properties from active profiles from the settings.xml.
As we want this trick to be a per user configuration we are going to rely on a property defined in the user's settings.xml to activate the static resource hot deployment :
<profile>
    <id>project-static-resources-hot-deploy</id>
    <activation>
        <activeByDefault>true</activeByDefault>
        <file>
            <exists>D:\PROJECT\jonas-full-5.2.4</exists>
        </file>
    </activation>
    <properties>
        <project.static.resources.hot.deploy.path>D:\PROJECT\jonas-full-5.2.4\work\webapps\jonas\single\{directory}</project.static.resources.hot.deploy.path>
    </properties>
</profile>
The {directory} part of the property must point to the WTP adapter deploy path for the desired Eclipse project.

Project configuration

Then we just need to add a profile activated based on the property defined in the user settings.xml that will trigger the use of the maven-resources-plugin to copy selected static resources to the application deployment path under JonAS. The copy is executed each time a static resource is saved in Eclipse and rely on the Maven Integration (m2e) for Eclipse.
<profile>
    <id>static-resources-hot-deploy</id>
    <activation>
        <property>
            <name>project.static.resources.hot.deploy.path</name>
        </property>
    </activation>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>static-resources-hot-deploy</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.static.resources.hot.deploy.path}</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/webapp</directory>
                                    <!-- if you use filtering in your build use true -->
                                    <filtering>false</filtering>
                                    <!-- whatever extension you want to copy -->
                                    <includes>
                                        <include>**/*.css</include>
                                        <include>**/*.jsp</include>
                                        <include>**/*.js</include>
                                        <include>**/*.tag</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Troubleshooting

Sometimes, Eclipse ignore user settings.xml and does not activate project profiles based on settings.xml properties. As a workaround, you can :
  1. verify that Eclipse points to the correct user settings.xml in the following Eclipse menu Settings -> Maven -> Installations (you may need to restart Eclipse after changing this setting).
  2. add the profile that set the property directly in the project pom. 

vendredi 10 juin 2011

Déployer un Webservice avec la JSR-181 et CXF

La JSR-181 a facilité l'exposition de méthodes JAVA par webservice. Avec les outils et frameworks actuels, il n'a jamais été aussi simple de créer et d'exposer un service SOAP en JAVA. Voyons en pratique comment s'y prendre pour deployer un service SOAP en utilisant CXF, Maven, et n'importe quel serveur d'application (Jonas, JBoss, Websphere, Glassfish) ou conteneur de Servlet (Tomcat, Jetty).

La solution présentée est indépendante du serveur d'application utilisé et pourra être optimisée en fonction du serveur JEE cible.

La méthode que nous allons exposer permet de récupérer le résultat de la multiplication des nombres qui lui sont passés en paramètres :
package com.googlecode.avianey.cxf.v1;

public class Multiplier {

    public Long multiply(Long...in) {
        long result = 1l;
        for (long mult : in) {
            result *= mult;
        }
        return Long.valueOf(result);
    }

}

Quelques annotations suffisent...

Pour exposer la méthode en utilisant la JSR-181, il suffit de trois annotations :
WebService
Cette annotation permet de déclarer la classe comme webservice et et de configurer certains attributs du WSDL (portType, service et targetNamespace).
SOAPBinding
Cette annotation permet de spécifier le type d'encodage des messages SOAP encapsulés en HTTP.
WebMethod
Cette annotation permet de rendre visible une méthode de la classe. Une opération est associée à la méthode au niveau du WSDL.
package com.googlecode.avianey.cxf.v1;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

@WebService(
    name = "multiplier",
    serviceName="multiplier",
    targetNamespace = "http://cxf.avianey.googlecode.com/V1")
@SOAPBinding(
    style = SOAPBinding.Style.DOCUMENT,
    use = SOAPBinding.Use.LITERAL,
    parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class Multiplier {

    @WebMethod( operationName = "multiply" )
    public Long multiply(Long...in) {
        long result = 1l;
        for (long mult : in) {
            result *= mult;
        }
        return Long.valueOf(result);
    }

}

...ou presque

Il nous reste à configurer CXF pour que le service soit exposé à l'adresse souhaitée. CXF s'appuyant sur Spring, il faut déclarer le ContextLoaderListener Spring au niveau du web.xml de l'application, puis paramétrer la Servlet CXF sur une URL. Veillez à bien être en Servlet Specification 2.4 au minimum, sans quoi le contexte Spring ne sera pas chargé avant l'initialisation de la Servlet CXF.

    contextConfigLocation/WEB-INF/beans.xml

    
        org.springframework.web.context.ContextLoaderListener
    



    CXFServlet
    
        org.apache.cxf.transport.servlet.CXFServlet
    
    1



    CXFServlet
    /services/*
Le fichier de configuration Spring permet de déclarer la classe Multiplier en tant que bean et de l'exposer en tant que endpoint sur une adresse précise au moyen des extensions JAX-WS.


    
    
    

    

    
    

Configuration Maven

La configuration des dépendances Maven est minimaliste :

    
        org.apache.cxf
        cxf-rt-frontend-jaxws
        ${cxf.version}
    
    
        org.apache.cxf
        cxf-rt-transports-http
        ${cxf.version}
    
    
        javax
        javaee-api
        6.0
        compile
    
Toutefois, CXF propose un plugin Maven (cxf-java2ws-plugin) permettant de générer le WSDL du service au moment de la compilation. Dans l'exemple ci dessous, le WSDL du service sera créé dans le répertoire :
  • /src/main/webapp/WEB-INF/wsdl/

    org.apache.cxf
    cxf-java2ws-plugin
    ${cxf.version}
    
        
            org.apache.cxf
            cxf-rt-frontend-jaxws
            ${cxf.version}
        
        
            org.apache.cxf
            cxf-rt-frontend-simple
            ${cxf.version}
        
    
    
        
            process-classes
            process-classes
            
                ${basedir}/src/main/webapp/WEB-INF/wsdl/multiplier.wsdl
                multiplier
                com.googlecode.avianey.cxf.v1.Multiplier
                true
                true
            
            
                java2ws
            
        
    

Déploiement sous Tomcat

Il ne reste plus qu'à démarrer notre serveur d'application. Le service est accessible à l'adresse {context-root}/{url-pattern}/{adresse} où :
  • context-root - Le contexte de la webapp
  • url-pattern - Le mapping de la Servlet CXF tel que défini dans le web.xml
  • adresse - L'adresse du endpoint telle que définie dans le fichier de configuration Spring/CXF

Liste des services exposés par CXF
Fork me on GitHub