Buscar este blog

viernes, 26 de junio de 2015

Apache Camel DSL - Spring - Inject bean in message body

What I want to do is to set one bean directly in the message Body inside a Camel Route. This could be very useful, for example, if you need to have a default response message in your route, when an error occurs or under some business circumstances.

There are two ways of doing this: Using Spring Expression Language or usign Simple component.

Camel allows you integrate multiples languages in your routes, for example, Groovy Javascript, or Spring. More precisely, you can use SpEL (Spring Expression Language) so you can work with beans as in java class. In this way you can create a new instance of a bean (in this case it's not a bean, just a simple POJO) and put it in the body.

The other way is declaring a bean as usual and ref it from inside a simple expression.


This is my class:
import java.io.Serializable;

public class User implements Serializable{
    private static final long serialVersionUID = -8687467303034052162L;
    private String nombre;
    private String nif;

    public User() {
    }

    public User(final String nombre, final String nif) {
        this.nombre = nombre;
        this.nif = nif;
    }

    public String getNombre() {
        return nombre;
    }
    public void setNombre(final String nombre) {
        this.nombre = nombre;
    }
    public String getNif() {
        return nif;
    }
    public void setNif(final String nif) {
        this.nif = nif;
    }

    @Override
    public String toString() {
        return "User [nombre=" + nombre + ", nif=" + nif + "]";
    }
}

Then I create an instance of this class in Spring XML config file:
<bean id="alice" class="es.pruebas.modelo.User">
 <constructor-arg name="nombre" value="Alice"/>
 <constructor-arg name="nif" value="00000001R"/>
</bean>

And finally, this is my route in wich the body is set by using the two ways presented:
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
 <route id="myRoute">
  <from uri="timer://foo?fixedRate=true&amp;period=5000"/>     

  <setBody>
   <simple>ref:alice</simple> 
  </setBody>
  <log message="The body should be Alice: ${body}" loggingLevel="INFO"/>         

  <setBody>
   <spel>#{new es.pruebas.modelo.User('Bob', '12345678Z')}</spel>
  </setBody>
  <log message="The body should be Bob: ${body}" loggingLevel="INFO"/>
 </route>
</camelContex>

The outcome of this execution will be:
2015-06-26 16:39:04 INFO  myRoute:96 - New execution starts
2015-06-26 16:39:04 INFO  myRoute:96 - The body should be Alice: User [nombre=Alice, nif=00000001R]
2015-06-26 16:39:04 INFO  myRoute:96 - The body should be Bob: User [nombre=Bob, nif=12345678Z]

miércoles, 24 de junio de 2015

Integrate JAX-WS in Spring Context

Creating a JAX-WS client with javax.xml.ws.Service is very simple, but if you are working with spring, then you would like to integrate it in Spring Context. In this way, you can get your client by using @Autowired.

The solution is to create a Factory Class responsible for instanciate the client.

Other common requirement is to read the service endpoing from a config file, so it could vary from enviroment.

Factory code:
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import es.sisifo.test.ws.webservices.UsuarioWebService;
import es.sisifo.test.ws.webservicesimpl.UsuarioService;



public class UsuariosWebServiceFactoryBean implements FactoryBean<UsuarioWebService> {

 private final String namespaceUri;
 private final String serviceName;
 private final String wsdlLocation;
 private final String serviceEndPoint;


 public UsuariosWebServiceFactoryBean(final String namespaceUri, final String serviceName, final String wsdlLocation, final String serviceEndPoint) {
  this.namespaceUri = namespaceUri;
  this.serviceName = serviceName;
  this.wsdlLocation = wsdlLocation;
  this.serviceEndPoint = serviceEndPoint;
 }


 @Override
 public UsuarioWebService getObject() throws Exception {
  final QName serviceQName = new QName(namespaceUri, serviceName);
  final Resource serviceWSDLResource =  new ClassPathResource(wsdlLocation);

  final UsuarioService service = new UsuarioService(serviceWSDLResource.getURL(), serviceQName);
  final UsuarioWebService port = service.getUsuarioWebServiceImplPort();

  final BindingProvider bindingProvider = (BindingProvider)port;
  bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceEndPoint);

  return port;
 }


 @Override
 public Class<?> getObjectType() {
     return UsuarioWebService.class;
 }


 @Override
 public boolean isSingleton() {
  return true;
 }
}

To use this class, you only need to declare this factory as a normal bean, for example, in the application-context.xml:
<bean id="usuarioService" class="es.sisifo.test.usuarios.webservice.UsuariosWebServiceFactoryBean">   
 <constructor-arg name="namespaceUri"      value="${webService.usuarios.namespaceUri}" />
 <constructor-arg name="serviceName"       value="${webService.usuarios.serviceName}" />
 <constructor-arg name="wsdlLocation"      value="${webService.usuarios.wsdlDocumentLocation}" />
 <constructor-arg name="serviceEndPoint"   value="${webService.usuario.serviceEndPoint}" />
</bean>

And this would be the properties file:
webService.usuarios.namespaceUri     = http://webservicesimpl.ws.testc.es/
webService.usuarios.serviceName      = usuarioService
webService.usuarios.wsdlLocation     = /wsdl/UsuarioService.wsdl
webService.usuarios.serviceEndPoint  = http://localhost:8080/test-ws/servizos/UsuarioService

Note that the WSDL file is in the application classpath, i.e, in main/resources folder, inside wsdl directory.
You can check how to create all necesary classes for the client in this post: http://trabajosdesisifo.blogspot.com.es/2015/04/eclipse-maven-configure-wsdl2java.html 

martes, 23 de junio de 2015

JBoss - Unable to authenticate cluster user: HORNETQ.CLUSTER.ADMIN.USER

Environment:
  • JBoss EAP 6.2.0
  • Domain configuration
  • One Domain Controller and multiple Host Controllers
Just to remind, in domain mode with cluster configuration you usually have the following structure:
Domain Controller. 
This node is the centralized administrion hub of configuration for the rest of the nodes.
In this node you configure host.xml (copied from host-master.xml) and domain.xml.
In domain.xml is where all servers and profiles are configured.

Host Controllers.
There would be multiple host controllers, one per node. These are the worker nodes of the domain.
In this node you configure only host.xml (copied from host-slave.xml) and point it to the domain controller IP.


So, you get this error in profile full-ha, which is the one with de cluster configuration (remember domain is not cluster), because HornetQ needs to share configuration across the rest of the nodes.

HORNETQ.CLUSTER.ADMIN.USER is the default user used in the cluster configuration.

Solution: 
Modify  hornetq-server tag, inside profile full-ha, in domain.xml of Domain Controller and add a user and password to it.

Defaults values:
<hornetq-server>
 <cluster-password>${jboss.messaging.cluster.password:CHANGE ME!!}</cluster-password>
 <persistence-enabled>true</persistence-enabled>
 <journal-type>NIO</journal-type>
 <journal-min-files>2</journal-min-files>
 
 (...)
</hornetq-server>

Change for this:
<hornetq-server>
 <cluster-user>adminCluster</cluster-user>
 <cluster-password>supersecretpass</cluster-password>
 <persistence-enabled>true</persistence-enabled>
 <journal-type>NIO</journal-type>
 <journal-min-files>2</journal-min-files>
 
 (...)
</hornetq-server>

CentOS - Virtual Box - Multiple network interfaces

I want to have my virtual machine with three different IPs.

First, you have to configure Virtual Box in host-only mode in order to create a private network between host and guest.



In this case I also configured a NAT adapter, because I also wanted to download some packages from internet, but for the purpose of this blog, this is not required.

The Virtual Box configuration was left by default, so in my case, the IP base  will be 192.168.56.1.





In CentOS you have to configure three network interfaces in /etc/sysconfig/network-scripts dir:

ifcfg-eth1:1
DEVICE=eth1:1
HWADDR=08:00:27:6D:9D:BC
TYPE=Ethernet
UUID=c67f2833-f261-456b-ac86-ab2635ea5432
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.56.102
NETMASK=255.255.255.0

ifcfg-eth1:2
DEVICE=eth1:2
HWADDR=08:00:27:6D:9D:BC
TYPE=Ethernet
UUID=c67f2833-f261-456b-ac86-ab2635ea5432
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.56.101
NETMASK=255.255.255.0

ifcfg-eth1:3
DEVICE=eth1:3
HWADDR=08:00:27:6D:9D:BC
TYPE=Ethernet
UUID=c67f2833-f261-456b-ac86-ab2635ea5432
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.56.103
NETMASK=255.255.255.0

HWADDR represent de MAC address of the virtual machine (the same asigned by Virtual Box in the Host-only Adapter).

And last, manually enable these interfaces:

[root@localhost ~]# ifup eth1:1
[root@localhost ~]# ifup eth1:2
[root@localhost ~]# ifup eth1:3
[root@localhost ~]# ifconfig -a
eth0      Link encap:Ethernet  HWaddr 08:00:27:A0:8B:F2
          inet addr:10.0.3.15  Bcast:10.0.3.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fea0:8bf2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3678 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1921 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:4290059 (4.0 MiB)  TX bytes:107006 (104.4 KiB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:6D:9D:BC
          inet6 addr: fe80::a00:27ff:fe6d:9dbc/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:275178 errors:0 dropped:0 overruns:0 frame:0
          TX packets:142674 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:174304706 (166.2 MiB)  TX bytes:8161346 (7.7 MiB)

eth1:1    Link encap:Ethernet  HWaddr 08:00:27:6D:9D:BC
          inet addr:192.168.56.102  Bcast:192.168.56.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth1:2    Link encap:Ethernet  HWaddr 08:00:27:6D:9D:BC
          inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth1:3    Link encap:Ethernet  HWaddr 08:00:27:6D:9D:BC
          inet addr:192.168.56.103  Bcast:192.168.56.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

domingo, 21 de junio de 2015

Spring MVC Portlet Interceptor

How to create a interceptor in Spring MVC Portlet

<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
 <property name="portletModeMap">
  <map>
   <entry key="view" value-ref="oneController" />
  </map>
 </property> 
 
 <property name="interceptors">
  <list>
   <ref bean="pruebaCustomInterceptor" />
  </list>
 </property>
</bean>
    
<bean id="pruebaCustomInterceptor" class="es.pruebas.portlet.cve.controller.CustomInterceptor"/>

The bean "oneController" is just a MVC Portlet controller, a class annotated with @Controller.

public class CustomInterceptor extends org.springframework.web.portlet.handler.HandlerInterceptorAdapter {

   @Override
    protected boolean preHandle(final PortletRequest request, final PortletResponse response, final Object handler) throws Exception {      
        return super.preHandle(request, response, handler);
    }
}

sábado, 6 de junio de 2015

JQuery - Clear all form fields

This function clears all fields in a form, keeping in mind these points:
  • It does not touch disabled or readonly elements.
  • It does not touch hidden inputs
  • In select elements, it selects the first option
  • In checkbox, it unchecks them

Code:
<script type="text/javascript">     
 var limpiar = function (form) {
  form.find(':input').each(function(){    
   if (esUnInputBorrable($(this))) {
    if ($(this).attr('type') == 'checkbox') {
     $(this).prop('checked', false);
    }
    else {
     $(this).val('');
    }
   }
  }); 
     
  form.find('select').each(function(){
   if (esUnSelectBorrable($(this))) {
    $(this).prop('selectedIndex',0);
   }
  });
   
  form.find('textarea').each(function(){
   if (esUnTextAreaBorrable($(this))) {
    $(this).val('');
   }
  });   
 }
 
 var esUnInputBorrable = function (input){   
  if (estaDeshabilitado(input)) {
   return false;
  }
  var tipo = input.attr('type');   
  return tipo != 'hidden' && tipo != 'submit' && tipo != 'reset' && tipo != 'radio' && tipo != 'button';
 }
 
 var esUnSelectBorrable = function (select){   
  if (estaDeshabilitado(select)) {
   return false;
  }
  return true;
 }
 
 var esUnTextAreaBorrable = function (textarea){   
  if (estaDeshabilitado(textarea)) {
   return false;
  }
  return true;
 }
 
 var estaDeshabilitado = function (elemento) {  
  return elemento.attr('disabled') != null || elemento.attr('readonly') != null;   
 }
</script>

And here is a HTML snippet to test it:
<form id="miForm" action ="#" method = "POST">
 <input type="hidden" value="One secret"/>
 
 <div>
  <label>Marca coche</label>
  <select name="marcas">
    <option value="">seleccione...</option>
    <option value="tesla">tesla</option>
    <option value="otherPoisonCompany1">Saab</option>
    <option value="otherPoisonCompany2">Mercedes</option>
    <option value="otherPoisonCompany3">Audi</option>
  </select>
 </div>
 <br/> 
 
 <div>
  <label>Marca coche deshabilitada</label>
  <select name="marcas" disabled>
    <option value="">seleccione...</option>
    <option value="tesla" selected="selected">tesla</option>
    <option value="otherPoisonCompany1">Saab</option>
    <option value="otherPoisonCompany2">Mercedes</option>
    <option value="otherPoisonCompany3">Audi</option>
  </select>
 </div>
 <br/> 
 
 <div>
  <label>Un campo de texto</label>
  <input type="text" id="nombre" name="nombre">
 </div>
 <br/>
 
 <div>
  <label>Un campo de texto deshabilitado</label>
  <input type="text" id="nombre2" name="nombre2" disabled="disabled" value="oops, disabled">
 </div>
 <br/>
 
 <div>
  <label>Un campo de texto readonly</label>
  <input type="text" id="nombre3" name="nombre3" readonly="readonly" value="I am read only">
 </div>
 <br/>
 
 <div>
  <input type="submit" id="submit" name="unSubmit" value="Un submit">
  <input type="reset" id="reset" name="unReset" value ="Un reset">
  <input type="button" id="buttton" name="nombre" value="Un button">
 </div>
 <br/>
 
 <div>     
  <label style="display: block">Why Tesla is the best car in the world</label>    
  <input type="checkbox" name="option1" value="eco"    checked>does not poison the world<br>
  <input type="checkbox" name="option2" value="Butter" checked>it rocks<br>
  <input type="checkbox" name="option3" value="Cheese" checked>has a lot of IT<br>
  <br/>
 </div>
 <br/>
 
 <div>
  <textarea rows="4" cols="50">Tesla rocks</textarea>
  <br/>
  <textarea rows="4" cols="50" readonly="readonly">Some readonly text</textarea>
  <br/>
  <textarea rows="4" cols="50" disabled>Tesla rocks</textarea>
 </div>
 
 <br/> 
 
 <!-- This is the triger button -->
 <button type="button" name="accion" value="clean" onclick="limpiar($(this).closest('form'))">Clean</button>
</form>