I wrote a simple client server architecture that helps me producing PDF files out of MS Office documents. The communication is handled via RMI and Spring wraps the entire complexity on the server side.
I cannot use Spring on the client side, because I call the methods from Matlab 2007b. A Jar with dependencies to spring produces exceptions due to the special handling of static and dynamic classpaths in Matlab.
Long story short: I wrote a simple RMI client in plain java:
import com.whatever.PDFCreationService;
Object service = Naming.lookup("rmi://operations:1099/pdfCreationService");
System.out.println((PDFCreationService)service); //produces ClassCastException
Interface:
public interface PDFCreationService {
public PDFCreationConfig createPDF(PDFCreationConfig config) throws IOException, InterruptedException, OperationInterruptionException;
}
Extracted out of my "former" spring config (client side):
<bean id="pdfCreationService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://operations:1099/pdfCreationService"/>
<property name="serviceInterface" value="com.whatever.creator.PDFCreationService"/>
</bean>
and on the server side :
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="pdfCreationService"/>
<property name="service" ref="pdfCreationService"/>
<property name="serviceInterface" value="com.whatever.creator.PDFCreationService"/>
<!-- defaults to 1099 -->
<property name="registryPort" value="1099"/>
</bean>
When I run the code the following exception is thrown:
Exception in thread "main" java.lang.ClassCastException: $Proxy0 cannot be cast to com.whatever.creator.PDFCreationService
I am 100% sure that I do not try to cast to a class like in this post: "ClassCastException: $Proxy0 cannot be cast" error while creating simple RMI application
Does spring encapsulate my interface in a different interface? Is there a way to find out which interface the Proxy hides?
Please let me know if you need more details to clarify my issue.
The RmiServiceExporter exports a RmiInvocationHandler if the remote service don't implements Remote, (ie, not is a traditional RMI Server)
If you can't use a RmiProxyFactoryBean in the client side, that is a bean factory for service interface proxies that convert service calls to RemoteInvocations, seems better option to use traditional RMI instead.
You can use the RmiServiceExporter to export tradional RMI Services too, like
public interface PDFCreationService extends Remote {
public PDFCreationConfig createPDF(PDFCreationConfig config) throws RemoteException;
}
Related
I implement a Spring Boot (1.5.x) application with Apache Camel (2.19)
For integration purposes I need to use three data sources (see for more about multi-data-sources here: https://github.com/spring-projects/spring-data-examples/tree/master/jpa/multiple-datasources).
One of the routes I have marked with .transacted():
from(Consts.DIRECT_ROUTE + routeId)
.routeId(routeId)
.startupOrder(loadRouteParameters.getStartupOrderTransformAndLoad())
.autoStartup(true)
.transacted()
however, when I start the app I get:
Caused by: java.lang.IllegalArgumentException: Found 3 PlatformTransactionManager in registry. Cannot determine which one to use. Please configure a TransactionTemplate on the transacted policy.
How to handle it? How to fulfill "Please configure a TransactionTemplate". I was not able to find any example for this special case.
Sounds like you have multiple TransactionManager beans in your Spring context. Camel does not know which one to take. You have to help your Camel a bit.
Define a SpringTransactionPolicy and reference the TransactionManager to be used in the Camel route.
<bean id="txPolicyName" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="[yourTxManagerBeanId]" />
</bean>
Then you can set the policy as argument to your transacted() in the Camel route:
.transacted("txPolicyName") // txPolicyBeanId as String
I am currently trying to test my web service clients with spring MockWebServiceServer as the real web service servers are not exposed yet. I have been following the spring doc http://docs.spring.io/spring-ws/site/reference/html/client.html but still getting some issue like below:
org.springframework.ws.client.WebServiceIOException: I/O error: Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:545)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:386)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:380)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:372)
I believe the error has something to do with the WebServiceTemplate I autowired into my WS client as below. Since I am using a MockWebServiceServer, I do not think a real HTTP connection is needed, but why it is complaining as such? Do I still need to start up my tomcat server to make the localhost:8080 accessible even using the MockWebServiceServer?
<bean id="vehicleOrderConfirmationWebServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="marshaller" ref="vehicleOrderConfirmationMarshaller" />
<property name="unmarshaller" ref="vehicleOrderConfirmationMarshaller" />
<property name="defaultUri" value="http://localhost:8080"/>
</bean>
Anyone could suggest?
the mocked server does not need a real http connection. it mocks the MessageSender.
how did you create you mocked web server ? below usage must be enough a real mocked server
MockWebServiceServer.createServer(vehicleOrderConfirmationWebServiceTemplate);
If your client class extends the WebServiceGatewaySupport like the example given by the Spring reference documentation, make sure you have set the WebServiceTemplate by using the inherited setWebServiceTemplate() method.
#Autowired
public CustomerClient (WebServiceTemplate customerClientWebServiceTemplate) {
setWebServiceTemplate(customerClientWebServiceTemplate);
}
Greetings dear Stackoverflow users, I have been lately in lots of pain with one specific problem with axis2 web services with Spring framework. I have read lots of different guides and read different forums but found people with the same problems but with no solutions. Basically ended up holding the monitor with both of my hands and yelling "What did you find out BudapestHacker938?". Anyway my axis2 web service class needs Spring beans and therefore they are autowired inside the web service class. Everything works so well inside the jetty server where I have servletContext. Just define needed listeners in web.xml and it works. Such a bliss. But unfortunately all good things come to the end in some point, for me, the devil is CICS environment inside of mainframe. There is no servletcontext like in Jetty/Tomcat, luckily it still has axis2 support. So according to the different user-guides I decided to archive my web-service into .aar and added it under the services folder. Axis2 folder structure is the following:
repository/
modules
services
When I am building this .aar archive then I am also generating my own wsdl, not using axis2 inbuilt wsdl generator which according to services.xml generates the services out of the given class (when I am running the axis2server, not using because doesn't like JAX-WS annotations as far as I know). To initialize Spring framework, I needed to write little SpringInit class which initializes Spring beans. Unfortunately it also for some reason initializes my web-service class according to its annotations and then occupies the main port(suspect that SpringInit intializes by its own the web service class since it is also defined as a Spring bean and SpringInit extends Axis2 class ServiceLifeCycle) and I get JVM BIND exception where it is stating that address is already in use. I would like to have the service built up according to the wsdl which is stored inside of the WSDL rather than generate new one, because I have various environments: 1) local machine - Jetty 2) mainframe. Anyway I give an insight to my services.xml:
<service name="Absence" class="org.services.SpringInit">
<description>
random description
</description>
<parameter name="ServiceTCCL">composite</parameter>
<parameter name="useOriginalwsdl" locked="false">true</parameter>
<parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier</parameter>
<parameter name="ServiceClass">org.services.Absence</parameter>
<parameter name="SpringBeanName">absence</parameter>
<parameter name="SpringContextLocation">META-INF/applicationContextAar.xml</parameter>
</service>
Spring applicationContextAar.xml, little bit refactored it for dear Stack community:
<beans>
<bean id="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:tcp://localhost/~/devDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="absence" class="org.services.Absence"></bean>
<bean id="jtemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="ds"></constructor-arg>
</bean>
<bean id="datasetFactory" class="org.vsam.DataSetFactory"></bean>
<bean id="dataManagerFactory" class="org.datamanager.DataManagerFactory"></bean>
<bean id="absenceFactory" class="org.services.AbsenceFactory"></bean>
<bean id="h2Database" class="org.dataset.H2Database"><constructor-arg ref="jtemplate"></constructor-arg>
</bean>
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"></bean>
</beans>
My SpringInit class looks something like that:
public class SpringInit implements ServiceLifeCycle {
public void startUp(ConfigurationContext ignore, AxisService service) {
try {
ClassLoader classLoader = service.getClassLoader();
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContextAar.xml"}, false);
appCtx.setClassLoader(classLoader);
appCtx.refresh();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void shutDown(ConfigurationContext ctxIgnore, AxisService ignore) {}
}
Now we are moving to org.services.Absence.class, it is an ordinary JAX-WS web-service class with following header (contains JAX-WS annotations):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
#Autowired
private AbsenceFactory absenceFactory;
#Autowired
private DataManagerFactory dataManagerFactory;
#Autowired
private DataSetFactory dataSetFactory;
...
}
Containing methods like that:
#WebMethod
#WebResult(name = "AbsenceResponse")
public SearchAbsenceRecordsResponse invokeSearchAbsenceRecords(
#WebParam ServiceRequest request,
#WebParam SearchAbsenceRecordsRequest absenceRequest) {...}
One alternative is to add "servicejars" folder into "repository" folder and populate it with absence.jar which has all its dependencies in the sub-folder "lib". Axis2 then automatically runs absense.jar since it has JAX-WS annotation. But in there when I call out the web-service for example with SOAP-UI, it doesn't have Spring initialized since I don't know how to initialize Spring in that solution. Maybe someone has any expertise about that.
TL;DR
How do I get my Spring beans initialized in manner that it doesn't start the services in the web service class according to the annotation and would rather build up services according to the wsdl?
You are welcome to ask questions.
How I initialized Spring inside of CICS without servletcontext?
Basically until today the SOAP web services have been published through servicejars which means into the repository folder has been created "servicejars" folder which cointains jars which have been built from the web service classes. "servicejars" subfolder "lib" contains all the dependencies which web service jars need.
At first I learnt from the web(Axis2 homepage, there was an instruction about axis2 and spring integration) for initializing Spring in Axis2 web service I need .aar archive and SpringInit service defined in services.xml. But this brought lots of problems since having old architecture built on jaxws and jaxb there was a huge need for refactoring the web services layer. Axis2 tolerated jaxws annotations only with "servicejars" solution. Initing Spring with SpringInit class meant that it initializes Spring beans according to the application context. This now runs web service bean(absence bean in previous post) as a separate web service and occupied 8080 port, when time came for the web service creation according to WSDL I got an error "JVM bind address already in use". So after that I figured I should create the service according to the absence Spring bean and let axis2server generate the WSDL, but axis2server didn't like jaxws annotation and even without them it didn't like my jaxb DTOs.
Therefore, I decided to drop .aar architecture and went back to the "servicejars" architecture. Unfortunately in there I didn't have services.xml support, to define the potential SpringInit service.
Since jaxws web services are the only entrypoints then I decided do the following (initialize Spring beans in the web service layer):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
private static AbsenceFactory absenceFactory;
private static DataManagerFactory dataManagerFactory;
private static DataSetFactory dataSetFactory;
static {
try {
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}, false);
appCtx.refresh();
absenceFactory = (AbsenceFactory) appCtx.getBean("absenceFactory", AbsenceFactory.class);
dataManagerFactory = (DataManagerFactory) appCtx.getBean("dataManagerFactory", DataManagerFactory.class);
dataSetFactory = (DataSetFactory) appCtx.getBean("datasetFactory", DataSetFactory.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
...
}
As you can see when this class is being called out, it will initialize applicationcontext and since it is static, all the spring beans will stay in the memory until the end(when service is closed). In other classes autowiring works perfectly, no need to get these beans wired manually.
In the end, I didn't find the possiblity to initialize Spring in the matter as I hoped through .aar architecture, but I found a work around with the guidance of a senior programmer. Huge thanks to him! And now the possible solution is visible for all StackOverFlow users.
EDIT:
In applicationContext.xml I had:
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"/>
Tries to create web services with Absence.class(absence bean). Removed it since I can in local machine as well use pre-generated WSDL with Jetty (originally was used for creating web service in the local machine, like I said before, I have local development environment and it should be also compatible with CICS, now it is solved).
I am new to Spring and Hessian and never used them before.
I want to write a small Hello World Program which clearly shows how this service works.
I am using Maven for list project details and dependencies.
The resources for hessian available online are not complete step-by-step guide.
would appreciate if I get help form someone who has worked writing hessian services
The steps for implementing a Hessian-callable service are:
Create a Java interface defining methods to be called by clients.
Write a Java class implementing this interface.
Configure a servlet to handle HTTP Hessian service requests.
Configure a HessianServiceExporter to handle Hessian service requests from the servlet by delegating service calls to the Java class implementing this interface.
Let's go through an example. Create a Java interface:
public interface EchoService {
String echoString(String value);
}
Write a Java class implementing this interface:
public class EchoServiceImpl implements EchoService {
public String echoString(String value) {
return value;
}
}
In the web.xml file, configure a servlet:
<servlet>
<servlet-name>/EchoService</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>/EchoService</servlet-name>
<url-pattern>/remoting/EchoService</url-pattern>
</servlet-mapping>
Configure an instance of the service class in the Spring application context:
<bean id="echoService" class="com.example.echo.EchoServiceImpl"/>
Configure the exporter in the Spring application context. The bean name must match the servlet name.
<bean
name="/EchoService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="echoService"/>
<property name="serviceInterface" value="com.example.echo.EchoService"/>
</bean>
The client has to create a proxy of the remote interface. You could simply write a JUnit-Test:
HessianProxyFactory proxyFactory = new HessianProxyFactory();
proxyFactory.setHessian2Reply(false);
proxyFactory.setHessian2Request(false);
com.example.echo.EchoService service = proxyFactory.create(
com.example.echo.EchoService, "http://localhost:8080/<optional-context/>remoting/EchoService");
Assert.equals(service.echoString("test"), "test");
I'm implementing a SOLR server in our application.
We use the CommonsHttpSolrServer in the SolrJ package to connect to our solr server which uses the commons-httpclient.
We also use Spring.
Now our sysadmin secured the solr server (with good reason) and used Basic Auth.
How can I instantiate a HttpClient with Basic Auth to be injected in the SolrJ?
e.g.
<bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.CommonsHttpSolrServer">
<constructor-arg value="${solrserver_path}" />
<constructor-arg ref="solrHttpClient" />
</bean>
Thanks!
Unfortunately, you have to use a factory that creates the client. There is no bean property for credentials in the classes involved in authentication, namely
HttpState.setCredentials(AuthScope, Credentials) which isn't a bean property.
I uploaded my HttpClientFactory to github. Se also the snippet for the spring context.