We have an application which needs to consume an external web service. To do this we have generated the set of Java artifacts from the WSDL via Maven using the wsdl2java goal provided by the cxf-codegen-plugin plugin.
We have written an integration test as part of our test suite which calls the real web service and everything works fine.
The code to integrate with the actual web service is then packaged into a set of JARs and used inside the front end application which needs to use the web service.
We are having an issue when the FE application uses the integration code. Exactly the same code is being executed by the FE application as is being used in our working integration test but the SOAP message which is ultimately generated is different between the two and the message generated by the actual application is incorrect.
The working SOAP request produced by our integration tests is:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns12:ProcessUIRequest xmlns:ns10="http://zzz/yyyentityview/validation/"
xmlns:ns11="http://zzz/yyyview/search/list/"
xmlns:ns12="http://zzz/yyywebservice/v5/types/"
xmlns:ns2="http://zzz/yyyentityview/app/"
xmlns:ns3="http://zzz/yyyentityview/client/"
xmlns:ns4="http://zzz/yyyview/search/postcode/"
xmlns:ns5="http://zzz/yyyview/app/"
xmlns:ns6="http://zzz/yyyview/search/app/"
xmlns:ns7="http://zzz/yyyview/search/bank/"
xmlns:ns8="http://zzz/yyyview/uw/"
xmlns:ns9="http://zzz/yyybase/">
<ns12:ProcessUIRequest CallType="Submit" DisplayError="false"
IsAnonymous="false" IsCompactRequest="false" IsError="false">
<ns9:ModelData>
<ns9:TransactionData ApplicationReference="20000003CR3.00000003"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns5:QuoteLoadTxnDataVO" />
</ns9:ModelData>
<ns9:Activity ActionCode="QuoteLoad" ActionMode="Default"
ActivityCode="QuoteApplicationFull" ActivityMode="Default"
ActivityReference="" ActivityStatus="Inital"
ActivityTransaction="StartNewActivityAndLogOffUser"
CanProceedWithValidationsOutstanding="true">
<ns9:BusinessKeys>
<item>
<key>
<string>ADVREF</string>
</key>
<value>
<BusinessKeyVO KeyName="ADVREF" KeyValue="AVAGT01">
<BusinessKey KeyName="ADVREF" KeyType="Unknown"
KeyValue="AVAGT01" />
</BusinessKeyVO>
</value>
</item>
</ns9:BusinessKeys>
</ns9:Activity>
</ns12:ProcessUIRequest>
</ns12:ProcessUIRequest>
</S:Body>
</S:Envelope>
The POJO which is marshalled into that SOAP request is:
<tcp.ssgbase.BaseVO>
<modelData>
<transactionData class="tcp.ssgview.app.QuoteLoadTxnDataVO">
<applicationReference>20000003CR3.00000003</applicationReference>
</transactionData>
</modelData>
<activity>
<businessKeys>
<item>
<tcp.serializable__dictionary.BusinessKeyItem>
<key>
<string>ADVREF</string>
</key>
<value>
<businessKeyVO>
<businessKey>
<keyName>ADVREF</keyName>
<keyValue>AVAGT01</keyValue>
<keyType>Unknown</keyType>
</businessKey>
<keyName>ADVREF</keyName>
<keyValue>AVAGT01</keyValue>
</businessKeyVO>
</value>
</tcp.serializable__dictionary.BusinessKeyItem>
</item>
</businessKeys>
<actionMode>DEFAULT</actionMode>
<activityMode>DEFAULT</activityMode>
<activityTransaction>START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
<actionCode>QuoteLoad</actionCode>
<activityReference></activityReference>
<activityStatus>INITAL</activityStatus>
<activityCode>QuoteApplicationFull</activityCode>
<canProceedWithValidationsOutstanding>true</canProceedWithValidationsOutstanding>
</activity>
<displayError>false</displayError>
<isAnonymous>false</isAnonymous>
<isError>false</isError>
<isCompactRequest>false</isCompactRequest>
<callType>SUBMIT</callType>
</tcp.ssgbase.BaseVO>
The SOAP request generated by the actual FE application is:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<ns2:ProcessUIRequest xmlns:ns2="http://zzz/yyywebservice/v5/types/">
<processUIRequest>
<activity>
<actionCode>QuoteLoad</actionCode>
<actionMode>DEFAULT</actionMode>
<activityCode>QuoteApplicationFull</activityCode>
<activityMode>DEFAULT</activityMode>
<activityReference />
<activityStatus>INITAL</activityStatus>
<activityTransaction>
START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
<businessKeys />
<canProceedWithValidationsOutstanding>
true</canProceedWithValidationsOutstanding>
</activity>
<callType>SUBMIT</callType>
<displayError>false</displayError>
<isAnonymous>false</isAnonymous>
<isCompactRequest>false</isCompactRequest>
<isError>false</isError>
<modelData>
<transactionData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns2:quoteLoadTxnDataVO">
<applicationReference>
20000003ESF.00000018</applicationReference>
</transactionData>
</modelData>
</processUIRequest>
</ns2:ProcessUIRequest>
</soapenv:Body>
</soapenv:Envelope>
The POJO which is marshalled into that SOAP request is:
<tcp.ssgbase.BaseVO>
<modelData>
<transactionData class="tcp.ssgview.app.QuoteLoadTxnDataVO">
<applicationReference>20000003ESF.00000018</applicationReference>
</transactionData>
</modelData>
<activity>
<businessKeys>
<item>
<tcp.serializable__dictionary.BusinessKeyItem>
<key>
<string>ADVREF</string>
</key>
<value>
<businessKeyVO>
<businessKey>
<keyName>ADVREF</keyName>
<keyValue>AVAGT01</keyValue>
<keyType>Unknown</keyType>
</businessKey>
<keyName>ADVREF</keyName>
<keyValue>AVAGT01</keyValue>
</businessKeyVO>
</value>
</tcp.serializable__dictionary.BusinessKeyItem>
</item>
</businessKeys>
<actionMode>DEFAULT</actionMode>
<activityMode>DEFAULT</activityMode>
<activityTransaction>START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
<actionCode>QuoteLoad</actionCode>
<activityReference></activityReference>
<activityStatus>INITAL</activityStatus>
<activityCode>QuoteApplicationFull</activityCode>
<canProceedWithValidationsOutstanding>true</canProceedWithValidationsOutstanding>
</activity>
<displayError>false</displayError>
<isAnonymous>false</isAnonymous>
<isError>false</isError>
<isCompactRequest>false</isCompactRequest>
<callType>SUBMIT</callType>
</tcp.ssgbase.BaseVO>
You can see that the structure of the two requests are different even though the code being executed in our integration JARs is exactly the same and the structure of the POJOs used to create the SOAP message is the same (barring one value). From the request, it looks to be like the request generated in the FE application is not picking up the correct WSDL and associated XSDs.
Our code to generate the correct service endpoint interface implementation is:
private <T> T createServiceObject(final Class<T> p_seiClass) throws ApplicationException {
try {
final Service serviceFactory = Service.create(new URL(wsdlLocation), new QName(targetNamespace, serviceName));
final SoapHandlerResolver handlerResolver = new SoapHandlerResolver();
handlerResolver.addHandler(new SoapMessageLoggingHandler());
serviceFactory.setHandlerResolver(handlerResolver);
final T service = serviceFactory.getPort(p_seiClass);
((BindingProvider) service).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"endpoint");
return service;
} catch (MalformedURLException e) {
throw new ApplicationException(ApplicationErrorCode.COMM_ERR_UNEXPECTED_ERROR, e);
}
}
After doing some debugging, I have noticed that the instance of the serviceFactory is different in the integration test and when we are running within the FE application.
In the integration test, the instance of the class (taken from the Eclipse debugger where we run the integration test using jUnit) is: 'JAX-WS RI 2.1.6 in JDK 6: Stub for ' and it appears to be of type 'SEIStub'.
When running within the FE application, the instance of the class is org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler. The FE application is hosted and executed on WebSphere Application Server.
So, my question is what could be happening when running in the actual FE application to cause the incorrect WSDL and XSD definitions to be picked up when marshalling the POJO into the SOAP request? I have spent a long time trying to debug this but to no avail.
The two soap request are different because, as you already said, the two serviceFactory is different and using different specifications 1.1 and 1.2.
My suggestion is that you configure your maven project to import the right jars on your test enviroment or update the jar on the container (the jar that create the serviceFactory). As I'm not familiarized with cxf-codegen-plugin I can't suggest more than that.
This suggestion was originally posted as a comment. The OP ask to put it as an answer.
I had this experienced when I was trying to write a client application and deploy it in Web Logic Server. You need to use exact version of java which is used by the server while creating the classes.
Soap request is created internally by JVM. If JVM is different while creating the classes and testing them and while consuming it on real time, SOAP will or may be different.
Related
I'm using SSIS 2012 to create a package which will retrieve data from a web service and load a database. I've already successfully created a number of web service tasks in this package calling a number of other methods on this web service, but something is going wrong with one of them.
The GetDeviceInfo method accepts the following parameters:
certificate - Received after calling the WS login method
accountId - Account which the device exists in
cmuId - The serial number of a specific device
When calling the method using an arbitrary cmuId which I know does not exist (1234567 in this example), the XML response, which says that no records were found, is correctly returned as follows:
<?xml version="1.0" encoding="utf-16"?>
<ResponseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message xsi:nil="true" xmlns="http://schemas.datacontract.org/2004/07/CellocatorPlusModels" />
<state xmlns="http://schemas.datacontract.org/2004/07/CellocatorPlusModels">valueNotFound</state>
<timestamp xmlns="http://schemas.datacontract.org/2004/07/CellocatorPlusModels">6.36186059963802E+17</timestamp>
</ResponseModel>
As soon as a valid value for cmuId is entered, however, SSIS throws an error:
SSIS package "<redacted>\getData.dtsx" starting.
Error: 0xC002F304 at Web Service Task, Web Service Task: An error occurred with the following error message: "Microsoft.SqlServer.Dts.Tasks.WebServiceTask.WebserviceTaskException: Could not execute the Web method. The error is: There was an error generating the XML document..
at Microsoft.SqlServer.Dts.Tasks.WebServiceTask.WebMethodInvokerProxy.InvokeMethod(DTSWebMethodInfo methodInfo, String serviceName, Object connection)
at Microsoft.SqlServer.Dts.Tasks.WebServiceTask.WebServiceTaskUtil.Invoke(DTSWebMethodInfo methodInfo, String serviceName, Object connection, VariableDispenser taskVariableDispenser)
at Microsoft.SqlServer.Dts.Tasks.WebServiceTask.WebServiceTask.executeThread()".
Task failed: Web Service Task
SSIS package "<redacted>\getData.dtsx" finished: Success.
The web service task fails and the response is not written to the output file.
Calling the web service from a browser, using the same parameters, returns the following, which is exactly what I'm expecting:
<ResponseModel xmlns="http://schemas.datacontract.org/2004/07/CellocatorPlusModels" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<message i:type="ExtendedUnitInfoModel">
<Account><..></Account>
<AccountId i:nil="true"/>
<AssemblyDate>05/13/2015</AssemblyDate>
<CMUID>1169817</CMUID>
<CurrentFWVersion>331</CurrentFWVersion>
<FWStatus>On Wait</FWStatus>
<FirstFWVersion i:nil="true"/>
<FirstPLVersion i:nil="true"/>
<FirstStatusDate>05/13/2015</FirstStatusDate>
<GroupID>22493</GroupID>
<GroupName>CR300B</GroupName>
<Modem>CR300B GE864</Modem>
<PLName i:nil="true"/>
<ProgStatus>Normal Operation</ProgStatus>
<Prov></Prov>
<ProviderId>5186</ProviderId>
<PurchaseOrder>SO28906.4</PurchaseOrder>
<SIMNumber/>
<SerialId/>
<ShipmentDate>06/07/2015</ShipmentDate>
<ShipmentTrackingNumber>8577</ShipmentTrackingNumber>
<TesterName>Arcam3</TesterName>
<TestingDate>05/14/2015</TestingDate>
<WarrantyExpDate>06/08/2016</WarrantyExpDate>
</message>
<state>success</state>
<timestamp>6.3618603925336154E+17</timestamp>
</ResponseModel>
I've tried creating a standalone package containing only this web service task for troubleshooting, with the same results.
Since I can call other methods on this WS perfectly OK, the task runs properly when I specify a non-existent device and I can correctly write to the output file under these circumstances I can only conclude that something is malformed in this response or I'm missing something very silly.
Any ideas? Thanks in advance.
Coming back to this question after several years, I have concluded that this issue was due to some idiosyncrasy in SSIS processing complex XML using the web service task component.
The solution that ultimately worked for me was implementing the operation in an execute code component using C#. Here's the basic template (only parsing a single field for demonstration).
public void PreExecute()
{
// Load the XML response into an XDocument object
XDocument doc = XDocument.Parse(Dts.Variables["User::XmlResponse"].Value.ToString());
// Select the message element
XElement messageElement = doc.Root.Element("message");
// Select the CMUID element
XElement cmuidElement = messageElement.Element("CMUID");
// Extract the value of the CMUID element
string cmuid = cmuidElement.Value;
// Store the CMUID value in a variable
Dts.Variables["User::CmuId"].Value = cmuid;
}
Perhaps this will help someone else struggling with a similar issue.
I'm currently developing a REST service to replace an existing solution. I'm using plain Payara/JEE7/JAX-RS. I am not using Spring and I do not intent to.
The problem I'm facing is that we want to reuse as much of the original configuration as possible (deployment on multiple nodes in a cluster with puppet controlling the configuration files).
Usually in Glassfish/Payara, you'd have a domain.xml file that has some content like this:
<jdbc-connection-pool driver-classname="" pool-resize-quantity="10" datasource-classname="org.postgresql.ds.PGSimpleDataSource" max-pool-size="20" res-type="javax.sql.DataSource" steady-pool-size="10" description="" name="pgsqlPool">
<property name="User" value="some_user"/>
<property name="DatabaseName" value="myDatabase"/>
<property name="LogLevel" value="0"/>
<property name="Password" value="some_password"/>
<!-- bla --->
</jdbc-connection-pool>
<jdbc-resource pool-name="pgsqlPool" description="" jndi-name="jdbc/pgsql"/>
Additionally you'd have a persistence.xml file in your archive like this:
<persistence-unit name="myDatabase">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/pgsql</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<!-- bla -->
</properties>
</persistence-unit>
I need to replace both of these configuration files by a programmatic solution so I can read from the existing legacy configuration files and (if needed) create the connection pools and persistence units on the server's startup.
Do you have any idea how to accomplish that?
Actually you do not need to edit each domain.xml by hands. Just create glassfish-resources.xml file like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool driver-classname="" pool-resize-quantity="10" datasource-classname="org.postgresql.ds.PGSimpleDataSource" max-pool-size="20" res-type="javax.sql.DataSource" steady-pool-size="10" description="" name="pgsqlPool">
<property name="User" value="some_user"/>
<property name="DatabaseName" value="myDatabase"/>
<property name="LogLevel" value="0"/>
<property name="Password" value="some_password"/>
<!-- bla --->
</jdbc-connection-pool>
<jdbc-resource pool-name="pgsqlPool" description="" jndi-name="jdbc/pgsql"/>
</resources>
Then either use
$PAYARA_HOME/bin/asadmin add-resources glassfish-resources.xml
on each node once or put it under WEB-INF/ of your war (note, in this case jndi-name SHOULD be java:app/jdbc/pgsql because you do not have access to global: scope at this context).
Note that your persistence.xml should be under META-INF/ of any jar in your classpath.
If you do not like this, you may use
#PersistenceUnit(unitName = "MyDatabase")
EmtityManagerFactory emf;
to create EntityManager on fly:
createEntityManager(java.util.Map properties).
By the way, using Payara you can share configuration with JCache across you cluster.
Since the goal is to have a dockerized server that runs a single application, I can very well use an embedded server.
Using an embedded sever, the solution to my problem looks roughly like this:
For the server project, create a Maven dependency:
<dependencies>
<dependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-embedded-all</artifactId>
<version>4.1.1.163.0.1</version>
</dependency>
</dependencies>
Start your server like this:
final BootstrapProperties bootstrapProperties = new BootstrapProperties();
final GlassFishRuntime runtime = GlassFishRuntime.bootstrap();
final GlassFishProperties glassfishProperties = new GlassFishProperties();
final GlassFish glassfish = runtime.newGlassFish(glassfishProperties);
glassfish.start();
Add your connection pools to the started instance:
final CommandResult createPoolCommandResult = commandRunner.run("create-jdbc-connection-pool",
"--datasourceclassname=org.postgresql.ds.PGConnectionPoolDataSource", "--restype=javax.sql.ConnectionPoolDataSource", //
"--property=DatabaseName=mydb"//
+ ":ServerName=127.0.0.1"//
+ ":PortNumber=5432"//
+ ":User=myUser"//
+ ":Password=myPassword"//
//other properties
, "Mydb"); //the pool name
Add a corresponding jdbc resource:
final CommandResult createResourceCommandResult = commandRunner.run("create-jdbc-resource", "--connectionpoolid=Mydb", "jdbc__Mydb");
(In the real world you would get the data from some external configuration file)
Now deploy your application:
glassfish.getDeployer().deploy(new File(pathToWarFile));
(Usually you would read your applications from some deployment directory)
In the application itself you can just refer to the configured pools like this:
#PersistenceContext(unitName = "mydb")
EntityManager mydbEm;
Done.
A glassfish-resources.xml would have been possible too, but with a catch: My configuration file is external, shared by some applications (so the file format is not mine) and created by external tools on deployment. I would need to XSLT the file to a glassfish-resources.xml file and run a script that does the "asadmin" calls.
Running an embedded server is an all-java solution that I can easily build on a CI server and my application's test suite could spin up the same embedded server build to run some integration tests.
Running Netbeans 6.5.1 with OpenESB (Glassfish-full-installer-windows2.1).
I'm using this tutorial (http://www.youtube.com/watch?v=a76RxkzB4Bg) as reference to orchestrate web services by calling a local WSDL that invokes an external WSDL (http://www.webservicex.net/CreditCard.asmx?WSDL). I have my BPEL ready
and my Composite Application created, it automatically binds a SOAP call from my local WSDL to the BPEL (Consumer to Producer), I had to drag and drop another SOAP object and configure it with the same interface as my local WSDL to receive the output from the invoke action (is that correct?).
When I run my test case selecting the operation from my local WSDL, I get the following SoapResponse:
<SOAP-ENV:Fault>
<faultcode xmlns="">SOAP-ENV:Server</faultcode>
<faultstring xmlns="">BPCOR-6135: A fault was not handled in the process scope; Fault Name is {http://www.sun.com/wsbpel/2.0/process/executable/SUNExtension/ErrorHandling}systemFault; Fault Data is &a....Sending errors for the pending requests in the process scope before terminating the process instance</faultstring>
<faultactor xmlns="">sun-bpel-engine</faultactor>
<detail xmlns="">
<detailText>BPCOR-6135: A fault was not handled in the process scope; Fault Name is {http://www.sun.com/wsbpel/2.0/process/executable/SUNExtension/ErrorHandling}systemFault; Fault Data is &a... Sending errors for the pending requests in the process scope before terminating the process instance
Caused by: BPCOR-6131: An Error status was received while doing an invoke (partnerLink=externalBPELImplementation, portType={http://www.webservicex.net}CCCheckerSoap, operation=ValidateCardNumber)
BPCOR-6129: Line Number is 37
BPCOR-6130: Activity Name is Invoke1
Caused by: HTTP Status-Code 404: Not Found - Not Found</detailText>
</detail>
I've created a separated project to test the external WSDL and it is validating credit card numbers as expected, there's something wrong with my BPEL or my Composite Application.
If I create another test case and select the local port that is created when I drag and drop the Soap object into the Comp. App. Design interface, I get a different error:
Dec 24, 2012 12:54:11 AM com.sun.xml.messaging.saaj.client.p2p.HttpSOAPConnection call
SEVERE: SAAJ0006: Bad URL (endPoint instance of String)
java.net.MalformedURLException: no protocol:
any ideas?
Your process seams to be correct (at the first look).
It looks like your process can't find the service you ask:
BPCOR-6130: Activity Name is Invoke1 - Caused by: HTTP Status-Code 404: Not Found - Not Found
Is your "soap adress" in the wsdl you imported correct ?
Have you try to overload the url in the bpel mapping ? (Properties -> SOAP HTTP BC -> Outbound -> UR)
There is also something strnage in your CASA: If you are trying to consume "localCreditCard_WSDLPort" and expose in OpenESB "casaPort1", the SOAP Binding are inversed. The arrow should start from casaPort1 and finish at localCreditCard_WSDLPort.
I hope this could help you,
Simon
According to #brasseld from www.open-esb.net
In fact, you've made two mistake :
The first one, for your unit test, you have to use the good WSDL which come from the BPEL because you've created a concrete SOAP WSDL
(CreditCard_WSDL.wsdl).
Then, when you create a new port in your composite application for your plnk externalServiceCard_WSDL, you have to set the soap address
location by right-click > properties. By default, this one is set to
localhost:${HttpDefaultPort}/compositeapp/casaportX?wsdl that's why
you encounter your errors (404 or bad url error).
Based on his suggestions, I've decided to document the development process step-by-step, here's the result:
http://www.youtube.com/watch?v=-1W1xR3-iJQ
i am creating a web service using 3rd party wsdl that helps me in getting a kind of notification. now i have to save that notification in DB and perform several other operations related to DataBase.
in My persistence.xml there are two persistence units as following:
<persistence-unit name="PU1" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/vsDS</jta-data-source>
<class>com.Response</class>
<class>com.Request</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
<persistence-unit name="PU2" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/vdDS</jta-data-source>
<class>com.LogRequest</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
till yet i have made a class named Service.java that have all functions i need to perform on DB as following:
public class Service {
private static Logger logger = Logger.getLogger(Service.class);
private EntityManagerFactory PU1;
private EntityManagerFactory PU2;
public Service(){
System.out.println("in service's constructer");
PU1=Persistence.createEntityManagerFactory("PU1");
PU2=Persistence.createEntityManagerFactory("PU2");
}
public void logSubRequest(String msg){
EntityManager em= PU1.createEntityManager();
try{
em.getTransaction().begin();
Request req=new Request();
req.setMessage(msg);
req.setStatus("Y");
em.persist(req);
em.getTransaction().commit();
}catch(Exception e){
logger.error("In logSubRequest="+e.getMessage());
e.printStackTrace();
}finally{
if(em.isOpen()){
em.close();
}
}
}
// there are several other methods of such kind that either persist entities or executeUpdate
}
My Question is: Am i going with standard approach to implement JPA with webservice or should i go with some other technology/method. kindly suggest and guide if i am doing any thing out of standard.
The combination of a Web services and JPA is often used, I see no reason to choose some other persistence mechanism. I'd recommend sticking with your current design until your requirements get more complex.
Larger applications where the equivalent of your Request object is more complex and the resulting business logic more challenging will add more layers of objects in order to control the structure and enable reuse.
I tend to think like this: The Web service interface is just one possible "way in" to the my business logic. So I might also have a RESTful service, or a JMS interface. Hence I tend to put my business logic inside an EJB, in simple cases a "No Interface" EJB. I focus on the EJB as a reusable piece of business logic that I can test in isolation. It will do all the JPA work. Then my Web service just uses that EJB to do its work. The EJB looks after the transactions so I don't need to write the transaction control code you have.
I have JPA mapping to HSQLDB and persistence.xml reads as below:
<persistence-unit name="HMC">
<jta-data-source>java:hmc</jta-data-source>
<class>org.hmc.jpa.models.BloodGroup</class>
<class>org.hmc.jpa.models.ContactInfo</class>
<properties>
<property
name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
</properties>
</persistence-unit>
But whenever application is deployed, it JBoss throws RuntimeException saying:
Specification violation [EJB3 JPA 6.2.1.2] - You have not defined a non-jta-data-source for a RESOURCE_LOCAL enabled persistence context named: ABC
I also have datasource defined in JBoss. Is there anything that I am missing in the configuration?
Regards,
Satya
if the transaction type of the persistence unit is JTA, the
jta-datasource element is used to declare the JNDI name of the JTA
data source that will be used to obtain connections. This is the
common case.
if the transaction type of the persistence unit is resource-local,
the non-jta-data-source should be used to declare the JNDI name of a
non-JTA data source.
hat is happening is that JBoss automatically scans and validates files named persistence.xml, since you are using spring to manage your beans, I guess you are not using EJB3.
What needs to be understood is if you want JBoss to control JTA transactions for you and if you want to use JBoss Transaction Manager, or if you just want to do JPA transactions, without JTA transaction control.
If you want to just use the JPA transactions and skip JBoss TransactionManagener, you can just rename your persistence.xml file to spring-persistence.xml (or whatever you like), and in spring-context.xml file you can change your entityManagerFactory to this:
<!-- JPA primary EntityManagerFactory -->
<bean id="entityManagerFactory" lazy-init="true"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistenceUnitName="ExamplePU"
p:persistenceXmlLocation="classpath:/META-INF/spring-persistence.xml"
p:jpaVendorAdapter-ref="jpaVendorAdapter"
p:jpaDialect-ref="jpaDialect"
p:dataSource-ref="dataSource"/>
What happens is that by renaming the file JBoss won't validate it, since you are working outside of the EJB spec and not using any EJB beans, JBoss shouldn't be scanning this file anyways. And since you renamed it, you need to tell spring where it is and under what name.
I got it working by removing transaction-type="RESOURCE_LOCAL" and changing java:hmc to java:/hmc. But now my application has another problem whenever I try to persist.
It throws : java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
Can anybody tell me how to get a connection and start transaction in JTA mode?
Regards,
Satya