Buscar este blog

domingo, 21 de agosto de 2016

CXF - Determine conduit name

If you need to know the conduit name that Apache CXF uses with some webservice, the easiest way is to let him to tell you.
Conduit configuration allows you to define some useful parameters, like proxy configuration, http authentication, SSL configuration, etc.

For example, I want to determine the condouit name for the currency convertor service http://www.webservicex.com/CurrencyConvertor.asmx. My CXF configuration looks like this:

<jaxws:client id="currencyConversorClient"
 name="{http://www.webserviceX.NET}CurrencyConvertorSoap12" 
 serviceClass="net.webservicex.CurrencyConvertorSoap"
 address="http://www.webservicex.com/CurrencyConvertor.asmx"> 
</jaxws:client>


<http:conduit name="???????.http-conduit">
 <http:client ReceiveTimeout="60000" ConnectionTimeout="30000">
 (...)
</http:conduit>

So, how do I know the conduit name? Just put CXF in debug I look for a message like "Could not find a definition for bean with id ...". This is the name CXF is trying to use.

17:23:35,516 INFO  [stdout] (http-localhost/127.0.0.1:8080-5) [2016-08-21 17:23:35,515] (ConfigurerImpl.java:179) DEBUG http-localhost/127.0.0.1:8080-5 org.apache.cxf.configuration.spring.ConfigurerImpl Could not find a definition for bean with id {http://www.webserviceX.NET/}CurrencyConvertorSoapPort.http-conduit - no injection will be performed.

17:23:35,517 INFO  [stdout] (http-localhost/127.0.0.1:8080-5) [2016-08-21 17:23:35,516] (ConfigurerImpl.java:179) DEBUG http-localhost/127.0.0.1:8080-5 org.apache.cxf.configuration.spring.ConfigurerImpl Could not find a definition for bean with id http://www.webservicex.com/CurrencyConvertor.asmx - no injection will be performed.

sábado, 20 de agosto de 2016

Apache HTTP Server - My mini cheat sheet

Not big deal. Just in case I need it someday.

Redirect from HTTP to HTTPS

<VirtualHost *:80>
 Servername cool.sisifo.es

 RewriteEngine on
 RewriteCond %{SERVER_PORT} !^443$
 RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]

 (...)

</VirtualHost>


<VirtualHost *:443>
 Servername cool.sisifo.es

 (...)

</VirtualHost>

Remove "WWW" from domain

<VirtualHost *:443>
 Servername cool.sisifo.es

 RewriteEngine on
 RewriteCond %{HTTP_HOST} ^www\.
 RewriteRule ^(.*)$ https://cool.sisifo.es/$1 [R=301,L]
   
 (...)

</VirtualHost>

Restrict access in certain application paths

Remember, the last one match location has precedence over the others.
<VirtualHost *:443>
 Servername cool.sisifo.es

 <Location />
    Order Deny,Allow
           Allow from all
 </Location>


 <location /myApp/secure/path>
           Order Allow,Deny
           Allow from 127.0.0.1
 </location>

 <location /myApp/othersecure/path>
           Order Allow,Deny
           Allow from 127.0.0.1
 </location>

 (...)
</VirtualHost>

lunes, 15 de agosto de 2016

JBoss - Virtual Servers - Mod_cluster

In JBoss, a virtual server is like a virtual host in apache (httpd). There is always a default virtual server that handles all requests received by the server. So, for each request this is what can happend:
  1. If the request points to the root context ("/"), you get the default welcome application. In this case the ROOT.war
  2. If the request points to a valid context (i.e, the context of a deployed web app), you get the response of this web app.
  3. If the request points to a invalid context, you get a 404

Besides the default virtual server, you can also define your own, by specifying a group of alias (domains) which will be handled in this virtual server.

For example, I have two web apps, /app1 and /app2 deployed, each one in its own context, among other webapps (/app3, /app4, etc.). The absolute URL would by:
  • app1: https://domain1/app1
  • app2: https://domain2/app2
  • app3: https://domain3/app3
  • app4: https://domain4/apps
There is a apache front-end configured with mod cluster. Each domain is a apache virtual host with forward the requests to the JBoss backends (a server cluster).

Now, I want to reconfigure this situation in order to get the following URLs:
  • app1: https://myCommonDomain/
  • app2: https://myCommonDomain/app2
  • app3: https://domain3/app3
  • app4: https://domain4/apps
So, app1 and app2 will be in the same domain, and app1 will be the root context of this domain. In this way, a user will think that both applications are just the same. In other way, I´m merging two web apps in one.

JBoss configuration

The first step is to create a new virtual server in JBoss, in the web subsystem:
<subsystem xmlns="urn:jboss:domain:web:1.5"
 default-virtual-server="default-host" native="false">
 <configuration>
  <jsp-configuration development="true"
   check-interval="2000" />
 </configuration>
 <connector name="http" protocol="HTTP/1.1" scheme="http"
  socket-binding="http" />
 <connector name="ajp" protocol="AJP/1.3" scheme="http"
  socket-binding="ajp" />
 <virtual-server name="default-host"
  enable-welcome-root="true">
  <alias name="localhost" />
  <alias name="example.com" />
 </virtual-server>
 <virtual-server name="myNewVirtualServer" default-web-module="app1.war">
  <alias name="myCommonDomain"/>
 </virtual-server>
</subsystem>

I created a virtual server named myNewVirtualServer, which default root will be app1.war (this is de runtime name of the deployment). This virtual server will be "listening" in myCommonDomain.

Web apps configuration

Inside app1 and app2, you need to include a jboss-web.xml file. In this file, each application declares its root context and references the virtual server created before.

jboss-web.xml in app1.war:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
 <context-root>/</context-root>
 <virtual-host>myNewVirtualServer</virtual-host>
</jboss-web>

jboss-web.xml in app2.war:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
 <context-root>/app2</context-root>
 <virtual-host>myNewVirtualServer</virtual-host>
</jboss-web>

Web apps configuration

Finally, you need to declare a new apache virtual host for this domain.
<VirtualHost *:443> 
 ServerName myCommonDomain
 (...) 
</VirtualHost>


domingo, 7 de agosto de 2016

JBoss - IllegalArgumentException: warning no match for this type name - Error creating bean with name 'dataSource'

I had a JEE 6 application using JPA in persistence tier, Spring in business tier, and that was being deployed in JBoss. Everything was working fine.

Then, I configured a business cache as explained in one of my previous posts, http://trabajosdesisifo.blogspot.com.es/2016/07/jboss-spring-infinispan-cache.html (well, at that time it was not a distributed cache, but that doesn't matter). Everything was working fine, too.

My application had a web service client, so I configured a web service cache as explained in other of my previous posts, http://trabajosdesisifo.blogspot.com.es/2016/07/web-service-client-spring-cache.html.  And this didn't work.

When I tried to deploy the application, I got this error:
10:32:35,429 ERROR [org.springframework.web.context.ContextLoader] (ServerService Thread Pool -- 232) Context initialization failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/config/data-access-config.xml]: Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Post-processing of the FactoryBean's object failed; nested exception is java.lang.IllegalArgumentException: warning no match for this type name: org.tempuri.EntradaSoap [Xlint:invalidAbsoluteTypeName]
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1387) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117) [spring-context-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:922) [spring-context-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) [spring-context-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) [spring-web-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) [spring-web-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:3339) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:3777) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
 at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:156) [jboss-as-web-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
 at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:60) [jboss-as-web-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
 at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:93) [jboss-as-web-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [rt.jar:1.7.0_21]
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) [rt.jar:1.7.0_21]
 at java.util.concurrent.FutureTask.run(FutureTask.java:166) [rt.jar:1.7.0_21]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_21]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_21]
 at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_21]
 at org.jboss.threads.JBossThread.run(JBossThread.java:122)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Post-processing of the FactoryBean's object failed; nested exception is java.lang.IllegalArgumentException: warning no match for this type name: org.tempuri.EntradaSoap [Xlint:invalidAbsoluteTypeName]
 at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:165) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1454) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:306) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 ... 27 more
Caused by: java.lang.IllegalArgumentException: warning no match for this type name: org.tempuri.EntradaSoap [Xlint:invalidAbsoluteTypeName]
 at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301) [aspectjweaver-1.6.11.jar:1.6.11]
 at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:208) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.aspectj.AspectJExpressionPointcut.getFallbackPointcutExpression(AspectJExpressionPointcut.java:359) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:256) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:208) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:262) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:294) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:359) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322) [spring-aop-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1625) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162) [spring-beans-3.2.3.RELEASE.jar:3.2.3.RELEASE]
 ... 32 more

The first error that I tried to solve was this:
java.lang.IllegalArgumentException: warning no match for this type name: org.tempuri.EntradaSoap [Xlint:invalidAbsoluteTypeName]
Note: org.tempuri.EntradaSoap was the web service interface which had the method that I was trying to add to the cache.
This problem was related with Spring AOP configuration, like my pointcut was wrong. But after a while, I didn't discover anything.


Then I focused on the second error:
Error creating bean with name 'dataSource': Post-processing of the FactoryBean's object failed;
My datasource was defined as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
 <property name="jndiName">
  <value>java:jboss/datasources/myAppDS</value>
 </property>
</bean>
So, it was created by JBoss and the application retrieves it via JNDI.

As I found in this stackoverflow answer, http://stackoverflow.com/questions/12804049/warning-no-match-for-this-type-name-when-deploying-to-jboss-dispite-deploying, When spring aop tried to inspect this class, it was not able to load it.

The solution is to add the a dependency with the module org.jboss.ironjacamar.jdbcadapters in the META-INF/jboss-deployment-structure.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
 <deployment>
  <dependencies>
   <module name="org.infinispan"/>
   <module name="org.jboss.ironjacamar.jdbcadapters"/>   
  </dependencies>
 
 </deployment>
</jboss-deployment-structure>

jueves, 28 de julio de 2016

Web service client - Spring cache

This is the third post about cache. The first one was about how to configure persistence cache with Hibernate, and the second one about how to configure a business cache with Spring, both of then by using Infinispan embbede in JBoss.

The objective of this post is to show how to configure the bussines cache with web services clients generated with maven cxf-codegen-plugin. The only special feature here is that you can not use the cache annotations (@Cacheable, @CacheEvict, etc.) because you have not access to the web service client source code. This code is generated by Maven in the compile phase.

In this example I will use the famous currency converter service: http://www.webservicex.com/CurrencyConvertor.asmx?wsdl

The first step is to configure pom.xml in order to parse the WSDL and to generate all needed classes.
<plugin>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-codegen-plugin</artifactId>
 <version>2.7.18</version>
 <executions>
  <execution>
   <id>generate-sources-wsdl</id>
   <phase>generate-sources</phase>
   <configuration>
    <wsdlOptions>
     <wsdlOption>
      <wsdl>${basedir}/src/main/resources/META-INF/wsdl/CurrencyConvertor.wsdl</wsdl>
      <extraargs>
       <extraarg>-xjc-XhashCode</extraarg>
       <extraarg>-xjc-Xequals</extraarg>
       <extraarg>-xjc-XtoString</extraarg>
      </extraargs>
     </wsdlOption>
    </wsdlOptions>
   </configuration>
   <goals>
    <goal>wsdl2java</goal>
   </goals>
  </execution>
 </executions>
 <dependencies>
  <dependency>
   <groupId>org.jvnet.jaxb2_commons</groupId>
   <artifactId>jaxb2-basics</artifactId>
   <version>1.11.1</version>
  </dependency>
 </dependencies>
</plugin>

I have downloaded the wsdl file and have put it inside the project in /resources/META-INF/wsdl directory.

Next, you have to configure de jaxws client, so you could use this client as a managed spring bean. In a context config file (for example, cxf-config.xml) I have this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">


 <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor">
    <property name="prettyLogging" value="true"/>
 </bean>

 <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor">
    <property name="prettyLogging" value="true"/>
 </bean>


 <jaxws:client id="currencyConversorClient"
  name="{http://www.webserviceX.NET}CurrencyConvertorSoap12" 
  serviceClass="net.webservicex.CurrencyConvertorSoap"
  address="http://www.webservicex.com/CurrencyConvertor.asmx">

  <jaxws:outInterceptors>
   <ref bean="loggingOutInterceptor" />
  </jaxws:outInterceptors>

  <jaxws:inInterceptors>
   <ref bean="loggingInInterceptor" />
  </jaxws:inInterceptors>
 </jaxws:client>

</beans>

With this configuration you can use the currencyConversorClient injected in other Spring managed beans, for example:
@Autowired    
private net.webservicex.CurrencyConvertorSoap currencyService;

And finally, you have to configure the cache in a declarative way, by using another context config file, as is explained in the reference documentation.
<!-- cache manager and  annotation-driven configuration omited-->

<!-- cache definitions -->
<cache:advice id="currencyConversorWebServiceCacheAdvice" cache-manager="cacheManager">
 <cache:caching cache="currency">
  <cache:cacheable method="conversionRate"/>
 </cache:caching>
</cache:advice>

<aop:config>
 <aop:advisor advice-ref="currencyConversorWebServiceCacheAdvice" pointcut="execution(* net.webservicex.CurrencyConvertorSoap.*(..))"/>
</aop:config>

In this snippet you declare a cache named "currency" over the conversionRate method in the CurrencyConvertorSoapCurrencyConvertorSoap service. Note that this is actually an interface which was generated by Maven.


Updated 1
Ultimately, a cache is just a hashmap like structure which store keys (the methods parameters) and values (the method return). In order to work properly, the cache keys must override the equals and hashcode methods, because two instances of a class with the same properties may not be equals.

So, when creating the web service class, you need to configure the cxf-codegen-plugin to add equals and hashcode methods to the DTOs. You get this by using the extra args tag, and by importing jaxb2-basics dependencies.

The currency example is very basic and the method params are simple types, which don't require this approximation, but for complex scenarios this would be mandatory.

Updated 2
Under some circumstances (I don't know exactly when) you need to add a dependency with org.jboss.ironjacamar.jdbcadapters module in the jboss-deployment-structure.xml file. Otherwise you will get a very confusing error.

Check this post: http://trabajosdesisifo.blogspot.com.es/2016/08/jboss-illegalargumentexception-warning.html