How to Configure a Spring Boot CXF Configuration with more that one service wsdl - spring

I have the challenge that I have a WSDL file with more that one service definiton inside
----- Customer WSDL file, can not change it ----
<service name="DocumentOperationService">
<port name="DocumentOperationPort" binding="tns:DocumentOperationBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL" />
</port>
</service>
<service name="PermissionEvaluatorService">
<port name="PermissionEvaluatorPort" binding="tns:PermissionEvaluatorBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL" />
</port>
</service>
<service name="ConfigurationResolverService">
<port name="ConfigurationResolverPort" binding="tns:ConfigurationResolverBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL" />
</port>
</service>
------
How can I configure the Spring Configuration Class
import org.springframework.context.annotation.Configuration;
#Configuration
public class WebServiceConfiguration {
...
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), dmsPortService());
// CXF JAX-WS implementation relies on the correct ServiceName as QName-Object with
// the name-AttributeĀ“s text <wsdl:service name="Weather"> and the targetNamespace
// "http://www.codecentric.de/namespace/weatherservice/"
// Also the WSDLLocation must be set
endpoint.setServiceName(dmsOperationService().getServiceName());
endpoint.setWsdlLocation(dmsOperationService().getWSDLDocumentLocation().toString());
// endpoint.setWsdlLocation("classpath:/service-api-definition/journalexportservice.wsdl");
endpoint.publish("/DocumentOperation");
return endpoint;
}
#Bean
public DocumentOperationService dmsOperationService() {
// Needed for correct ServiceName & WSDLLocation to publish contract first incl. original WSDL
return new DocumentOperationService();
}
That all 3 Services are loaded.
In the moment I can only load one Service, I could not find any example how this could be done.
I triad with 3 config files, but then only the last is active, and how to configure 3 services in the same config file I could not figure out.

You might want to take a look at this tutorial describing your exact use case with exactly your stack.
In short:
Your Configuration Bean needs to provide a ServletRegistrationBean with a cxfServlet, a SpringBus and an Endpoint. (Pretty much like your posted code. Juding from the comments it might even be from this very tutorial)
Your Endpoint should point to the overall wdsl location
Then you need to implement a Service that encomapsses all of your intended webservices
In this service you need one method per webservice

Related

How to implement SmartLifecycleRoleController in Spring Integration application

I am writing client-server application on base of int-ip:tcp endpoints. Code written in Kotlin.
Application contains two tcp clienst which should make connection to server in sertain sequence,
one after each other, when first cleint already establised connection to server and made some initialisation.
As a solution for this synchronisation I suppose to use a SmartLifecycleRoleController to start group of endpoints of a dependent tcp client.
To that end in depended (second) client I add role="rcCluster" and auto-startup="false" attributes to tcp-outbound-channel-adapter and tcp-inbound-channel-adapter
<int-ip:tcp-connection-factory id="rcClientConnectionFactory"
type="client"
host="${tdirelay.host}"
port="${tdirelay.rcPort}"
single-use="false"
so-timeout="10000"
so-keep-alive="false"
serializer="rawSerializerDeserializer"
deserializer="rawSerializerDeserializer"
ssl-context-support="sslContext"/>
<int-ip:tcp-outbound-channel-adapter id="rcOutBoundAdapter"
channel="rcPacketQueueChannel"
phase="5000"
connection-factory="rcClientConnectionFactory"
role="rcCluster"
auto-startup="false"
/>
<int-ip:tcp-inbound-channel-adapter id="rcInboundAdapter"
channel="rcFromServer"
client-mode="true"
retry-interval="5000"
connection-factory="rcClientConnectionFactory"
role="rcCluster"
auto-startup="false"
/>
The leading (first) tcp client uses interceptor endpoint to make a prologue exhange with server in accordance with the protocol:
<bean id="dcInterceptorFactoryChain"
class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
<property name="interceptors">
<array>
<bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
</bean>
</array>
</property>
</bean>
<int-ip:tcp-connection-factory id="dcClientConnectionFactory"
type="client"
host="${tdirelay.host}"
port="${tdirelay.dcPort}"
single-use="false"
so-timeout="10000"
so-keep-alive="false"
interceptor-factory-chain="dcInterceptorFactoryChain"
serializer="rawSerializerDeserializer"
deserializer="rawSerializerDeserializer"
ssl-context-support="sslContext"
/>
I am planning to call startLifecyclesInRole(String role) and stopLifecyclesInRole(String role) methods of the SmartLifecycleRoleController inside my Interceptor class.
So, I added #Autowired private val roleController: SmartLifecycleRoleController to InterceptorFactory as explained in spring-integration/docs
My InterceptorFactory is:
class DCConnectionInterceptorFactory() : TcpConnectionInterceptorFactory, ApplicationEventPublisherAware {
#Autowired
private val roleController: SmartLifecycleRoleController? = null
#Volatile
private var applicationEventPublisher: ApplicationEventPublisher? = null
override fun setApplicationEventPublisher(applicationEventPublisher: ApplicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher
}
override fun getInterceptor(): TcpConnectionInterceptorSupport {
return DCConnectionInterceptor(this.applicationEventPublisher!!, roleController!!)
}
}
IntelliJ IDEA gives warning:
Could not autowire. No beans of 'SmartLifecycleRoleController' type found
And building gives error:
[task-scheduler-2] ERROR org.springframework.integration.ip.tcp.connection.ClientModeConnectionManager - Could not establish connection using dcClientConnectionFactory, host=localhost, port=9001
kotlin.KotlinNullPointerException
at com.tcpclient.DirectCannel.DCConnectionInterceptorFactory.getInterceptor(DCConnectionInterceptorFactory.kt:25)
I suppose that I need to define SmartLifecycleRoleController type bean in xml configuration file
(that is not mentioned in the docs: https://docs.spring.io/spring-integration/docs/4.3.4.RELEASE/reference/html/messaging-endpoints-chapter.html#endpoint-roles).
The constructor of this class has arguments:
public SmartLifecycleRoleController(List roles, List lifecycles)
which I do not know how to fill in my case in xml file:
If you know how to do this, please provide a live example of using bean of the SmartLifecycleRoleController class in the xml configuration file.
First of all it would be better do not use #Autowired there at all, since it isn't clear if an annotation configuration is enabled in your application context or not. Just because you show only XML config for Spring.
Therefore your DCConnectionInterceptorFactory should have a setter for that roleController property instead. Or what is the proper way to declare Java bean properties in Kotlin...
Then you need to use something like this in your XML config:
<bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
<property name="roleController" ref="integrationLifecycleRoleController"/>
</bean>
The Framework creates for your a SmartLifecycleRoleController automatically and registers it with the mentioned IntegrationContextUtils.INTEGRATION_LIFECYCLE_ROLE_CONTROLLER bean name.
Please, raise a JIRA on the matter to improve documentation to make since much cleaner.
Your approach, by the way, is correct.

IDempiere Service Integration

I need to call Idempiere Business Modules (ex. Creating Purchase Order process) , not tables via a web services, Is there any way to do this without going through the source code of Idempiere, I don't want to use RESTful methods that will deal with tables directly
You are probably referring to improvements on iDempiere's Web Services where composite (master-detail) and CRUD actions are now possible. Complete description at the project wiki: http://wiki.idempiere.org/en/NF1.0_Web_Services_Improvements
Below I paste results of https://test.idempiere.org/ADInterface/services
Available SOAP services:
CompositeService
compositeOperation
Endpoint address: http://test.idempiere.org/ADInterface/services/compositeInterface
WSDL : {http://idempiere.org/ADInterface/1_0}compositeInterface
Target namespace: http://idempiere.org/ADInterface/1_0
ModelADService
setDocAction
createUpdateData
getList
readData
createData
runProcess
queryData
deleteData
updateData
Endpoint address: http://test.idempiere.org/ADInterface/services/ModelADService
WSDL : {http://idempiere.org/ADInterface/1_0}ModelADService
Target namespace: http://idempiere.org/ADInterface/1_0
Available RESTful services:
Endpoint address: http://test.idempiere.org/ADInterface/services/rest
WADL : http://test.idempiere.org/ADInterface/services/rest?_wadl
You can use create a provide service interface from org.adempiere.base plugin, invoke this service inside your code and invoke the constructor for class MOrder extends X_C_Order and for class MOrderLine extends X_C_OrderLine.
Here you have the example from IProcessFactory (you can create your factory like ICreateOrderFactory , or just IInsertFactory ( for a generic factory constructor you can set the table id ) :
This is a interface declaration
public interface IProcessFactory {
/**
* Create new process instance
* #param className
* #return new process instance
*/
public ProcessCall newProcessInstance(String className);
}
This is a evocation method
public class ProcessFactory implements IProcessFactory {
#Override
public ProcessCall newProcessInstance(String className) {
if (className.equals("com.com.nexus.webservice.client.process.IntegratorWS"))
return new IntegratorWS();
else
return null;
}
}
Now you need to create .xml of this factory like that : (pay attention in provided interface)
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.nexus.integrator.ProcessFactory">
<implementation class="com.nexus.webservice.client.process.ProcessFactory"/>
<property name="service.ranking" type="Integer" value="5"/>
<service>
<provide interface="org.adempiere.base.IProcessFactory"/>
</service>
</scr:component>
To use this in OSGI architecture, you need to configure your MANIFEST file to import this
Service-Component: ( I always use osgi-inf directory for my factories xml)
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.nexus.webservice.client
Bundle-SymbolicName: com.nexus.webservice.client;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: Macrosoftware
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.adempiere.base
Service-Component: OSGI-INF/ProcessFactory.xml
Import-Package: org.osgi.framework
You can do this , or you can use composite webservice .
I consider the second most safe and effective method

Why is Mybatis mapper scanner picking up wrong class

I use Spring with Mybatis. I have it configured to scan for mappers in my whole project and I assumed it determined a mapper because it found an XML file which has reference to a java interface.
But this is proven incorrect today because I had to add a new interface which is not a mapper class and Mybatis thinks it is, so it is causing problems in my app due to this error:
Mapped Statements collection does not contain value for com.blah.MyInterface.someMethod
com.blah.MyInterface is just a simple interface which I needed to be included in Spring context so I gave it the #Component tag. Is that the wrong tag to use? Is that where the confusion comes from?
I just needed to create this interface so that I can have a proxy wrap my database calls in one place where I can put a #Transactional tag, since Spring ignores it when it is in my Controller method.
Sample code
package com.blah.something;
#Component public interface MyInterface {
public void someMethod( SomeObject obj) throws Exception;
}
package com.blah.something;
public class MyImplementation implements MyInterface {
#Transactional
public void someMethod( SomeObject obj) throws Exception {
... do a whole bunch of stuff
}
}
I dont want this included in the MyBatis mappers!
Edit: added the mybatis config xml as requested:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="defaultStatementTimeout" value="60"/>
</settings>
<typeAliases>
<typeAlias alias="StripTrailingZerosBigDecimalTypeHandler" type="com.blah.typehandlers.StripTrailingZerosBigDecimalTypeHandler"/>
</typeAliases>
</configuration>
This is the part of my spring xml config which calls the mybatis mapper scanner:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.blah" />
</bean>
So I set it to scan the whole project which includes my interface above but I can't imagine it just grabs every single interface and considers them all mappers!
In my debug log I see mybatis picking up my interface:
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Scanning file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyInterface.class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Identified candidate component class: file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyInterface.class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Scanning file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyImplementation .class]
12/9/13 11:18:44 904 [org.mybatis.spring.mapper.MapperScannerConfigurer$Scanner.findCandidateComponents:4125] - Ignored because not a concrete top-level class: file [D:\Weblogic\wls11\domains\ldapdomain\autodeploy\default\WEB-INF\classes\com\blah\MyImplementation .class]
There is no XML for this interface, there is no mapper namespace for it, it's just a plain old regular interface and MyBatis should not be thinking it is a mapper service
Ok it looks like MyBAtis scanner does indeed take every interface, it does not have any "smarts" in it to identify mapper interfaces as I thought it would - based on finding matching XML or namespaces. I had to add a filter to the mapper configuration and then introduce a new annotation to annotate my mapper interfaces.

Bypassing ViewResolver using #ResponseBody & Method Converters for JSON and XML only works for JSON

I'm creating a RESTful API that returns JSON or XML depending on the Accept header (application/json vs text/xml). I have this working fine for JSON but can't seem to get it working when for XML. I am testing using the Poster plugin client for Firefox.
I was under the impression that I just needed to add the Jackson and JAXB libraries to the app's classpath. Again, it works for JSON but not XML.
Originally I was getting 406 error when sending the Accept "text/xml" header. Then I added #XmlRootElement(name="contact") to my entity and now I'm getting a 500 error. Should I need to put #XmlRootElement on every entity?
Although the response is a 500 error, I don't see any errors reported in the console. I'm testing in Eclipse running Tomcat 7. Shouldn't i see some error in the console when i receive a 500 error?
My "mvc-dispatcher-servlet.xml" has <mvc:annotation-driven />
Here's the relevant code from my controller:
#Controller
#RequestMapping("/contacts")
public class ContactsController {
#Autowired
ContactsService contactsService;
#RequestMapping(value="/{id}",
method=RequestMethod.GET,
headers = {"Accept=application/json, text/xml"})
public #ResponseBody Contact getContact(#PathVariable("id") int id) {
Contact queryContact = new Contact(id);
Contact result = contactsService.getContact(queryContact);
return result;
}
}
The "mvc-dispatcher-servlet.xml" is really simple. Do I need anything other than:
<context:component-scan base-package="contactsapp.web.controller" />
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/"/>
I'm using Spring 3.1 and the following:
<dependency org="com.sun.xml.bind" name="jaxb-impl" rev="2.2.5-b10" conf="runtime->default"/>
<dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.7.1" conf="runtime->default"/>
You should put
#XmlRootElement on Contact class to tell jackson how to parse.
It turns out I had it configured correctly. Once I enabled more verbose logging I realized I had circular dependencies in my entity classes and had to add #XmlTransient on those fields

Spring integration : replace xml configured bean property dynamically?

I'm trying to do a ftp poller with the help of Spring integration and the poller works great with the xml configuration. Now I would like to be able to dynamically set some properties of the poller like the cron-expression or the polling rate to make it configurable by java code and link it to a web interface.
I have seen a lot of topics around the subject but nothing really clear to do that.
Is there a classic way of doing that ?
Can it be done with SpeL ?
My bean poller declaration in XML is as follows :
<int-ftp:inbound-channel-adapter id="ftpInbound"
channel="ftpChannel" session-factory="ftpClientFactory"
filename-regex=".*\.tmp$" auto-create-local-directory="true"
delete-remote-files="false" remote-directory="/cft-polling" local-directory="file:target/ftp-output" >
<int:poller fixed-rate="1000" />
</int-ftp:inbound-channel-adapter>
<int:channel id="ftpChannel">
<int:queue />
</int:channel>
I'm not sure there is enough here for a solid answer, but assuming that the ftp poller is defined and managed in the spring container, and assuming there are proper accessores to modify it's properties...that you will be able to change it's setting just like you would any other object.
First you would have to get a reference of the spring managed object, you can do this by having one of your classes implement ApplicationContextAware thereby exposing the Spring context.
Then it's just a matter of getting the bean from the context and updating it's property.
public class MyManagedClass implements ApplicationContextAware {
private ApplicationContext springContext;
public void changeBeansProperty(){
MyFtpPoller poller = (MyFtpPoller) springContext.getBean("ftpInbound");
poller.setCronExpress("12 12 * * * *");
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.springContext = applicationContext;
}
}

Resources