How can I user persistency in my REST application?
I want to use #Inject and #PersistenceUnit annotation to instantiate my needed PersistencyManager object,
by when I call the persistency functionality by REST service I get an error:
[2014-03-15 05:05:45,472] Artifact CubieboardGPIO:war: Error during artifact deployment. See server log for details.
[2014-03-15 05:05:45,473] Artifact CubieboardGPIO:war: javax.ejb.EJBException: The bean encountered a non-application exception; nested exception is:
org.apache.openejb.OpenEJBRuntimeException: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/]]
This is my Rest:
#Inject
private PersistenceManager persistenceManager;
#GET
#Path("/activate")
public String activate(#QueryParam("pin") int pin) {
persistenceManager = new PersistenceManager();
// URI : /cubieboard/gpio/activate?pin=67
String[] messages = _activate(pin);
StringBuilder sb = new StringBuilder();
sb.append(ConfigurationManager.getConfiguration("ACTIVATE_MESSAGE")+"\n");
sb.append("Persistence:\t"); sb.append(messages[0]); sb.append("\n");
sb.append("Terminal Response:\t"); sb.append(messages[1]); sb.append("\n");
return sb.toString();
}
This is PersisteneManager:
#Stateless
public class PersistenceManager {
#PersistenceUnit(name = "cubieDB")
private static EntityManagerFactory factory;
private EntityManager em;
public PersistenceManager(){
// factory = Persistence.createEntityManagerFactory(ConfigurationManager.getConfiguration("PERSISTENCE_UNIT_NAME"));
// factory = Persistence.createEntityManagerFactory("cubieDB");
em = factory.createEntityManager();
}
public List<Operation> getAllOperations() {
Query q = em.createQuery("SELECT op FROM Operation op");
List<Operation> ops = q.getResultList();
return ops;
}
public void persist(Operation operation) {
em.getTransaction().begin();
em.persist(operation);
em.getTransaction().commit();
}
public void deleteAll(){
em.getTransaction().begin();
Query q = em.createNativeQuery("DELETE FROM Operation");
q.executeUpdate();
em.getTransaction().commit();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
em.close();
}
}
And this is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="cubieDB" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.sakhoshdel.cubieboard.gpio.persistence.Operation</class>
<properties>
<!--<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>-->
<property name="eclipselink.ddl-generation" value="create-tables"/>
<!--<property name="javax.persistence.schema-generation-action" value="drop-and-create"/>-->
<!--<property name="javax.persistence.schema-generation-target" value="database-and-scripts"/>-->
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:cubieDB;create=true" />
</properties>
</persistence-unit>
</persistence>
Also when I call the persistence functionality from a normal class it runs. but when I want to deploy it I get error. I am using TomEE for application server.
Thank you
Well ejb constructor shouldnt be used (shouldnt even be called in last versions). Injection of static field is not recommanded neither.
Finally maybe just use a jta persistence unit and remove the em.getTransaction calls.
Side note: tomee comes with openjpa so you need to provide eclipselink if you want it
Related
I've been digging around and I can't seem to find the answer to what I'm looking for at all.
I need to call an external web service when an order is placed in magento 2. I also need to use the order information in the call. I simply dont know what the right path is. Has anyone done this before?
I know the answer is late, but here is the solution that works for me, I have written observer for event checkout_submit_all_after.
Create file at path [CompanyName]/[ModuleName]/etc/events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="checkout_submit_all_after">
<observer name="push_orders_to_purchaser" instance="RLTSquare\Quote\Observer\PushOrdersToPurchaserApi" />
</event>
</config>
Now in observer ([CompanyName]/[ModuleName]/observer/PushOrdersToPurchaserApi.php)
<?php
namespace RLTSquare\Quote\Observer;
use \Magento\Framework\Event\Observer;
use \Magento\Framework\Event\ObserverInterface;
use Magento\Framework\HTTP\Adapter\Curl;
class PushOrdersToPurchaserApi implements ObserverInterface
{
const MOCK_API = 'https://yourwebsite.com/insertorders';
protected $_request;
protected $_webApiRequest;
protected $_serviceOutputProcessor;
protected $_zendClientFactory;
public function __construct
(
\Magento\Framework\App\RequestInterface $request,
\Magento\Framework\Webapi\Rest\Request $webApiRequest,
\Magento\Framework\Webapi\ServiceOutputProcessor $serviceOutputProcessor,
\Magento\Framework\HTTP\ZendClientFactory $zendClientFactory
)
{
$this->_request = $request;
$this->_webApiRequest = $webApiRequest;
$this->_serviceOutputProcessor = $serviceOutputProcessor;
$this->_zendClientFactory = $zendClientFactory;
}
public function execute(Observer $observer)
{
/**
* #var \Magento\Sales\Model\Order[] $orders
*/
$orders = $observer->getOrders();
$encodedData = null;
if ($orders) {
$data = $this->_serviceOutputProcessor->convertValue($orders, '\Magento\Sales\Api\Data\OrderInterface[]');
$payload = \Zend_Json::encode($data, true);
$client = $this->_zendClientFactory->create();
$client->setUri(self::MOCK_API);
$client->setConfig(['maxredirects' => 0, 'timeout' => 30]);
$client->setRawData($payload);
$response = $client->request(\Zend_Http_Client::POST)->getBody();
//play with response here...
}
}
}
I looked at this link : How to write a unit test for a Spring Boot Controller endpoint
I am planning to unit test my Spring Boot Controller. I have pasted a method from my controller below. When I use the approach mentioned in the link above , will the call that I have to service.verifyAccount(request) not be made? Are we just testing whether the controller accepts the request in format specified and returns response in format specfied apart from testing the HTTP status codes?
#RequestMapping(value ="verifyAccount", method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<VerifyAccountResponse> verifyAccount(#RequestBody VerifyAccountRequest request) {
VerifyAccountResponse response = service.verifyAccount(request);
return new ResponseEntity<VerifyAccountResponse>(response, HttpStatus.OK);
}
You can write unit test case
using
#RunWith(SpringJUnit4ClassRunner.class)
// Your spring configuration class containing the
#EnableAutoConfiguration
// annotation
#SpringApplicationConfiguration(classes = Application.class)
// Makes sure the application starts at a random free port, caches it throughout
// all unit tests, and closes it again at the end.
#IntegrationTest("server.port:0")
#WebAppConfiguration
make sure you configure all your server configuration like port/url
#Value("${local.server.port}")
private int port;
private String getBaseUrl() {
return "http://localhost:" + port + "/";
}
Then use code mentioned below
protected <T> ResponseEntity<T> getResponseEntity(final String
requestMappingUrl, final Class<T> serviceReturnTypeClass, final Map<String, ?>
parametersInOrderOfAppearance) {
// Make a rest template do do the service call
final TestRestTemplate restTemplate = new TestRestTemplate();
// Add correct headers, none for this example
final HttpEntity<String> requestEntity = new HttpEntity<String>(new
HttpHeaders());
// Do a call the the url
final ResponseEntity<T> entity = restTemplate.exchange(getBaseUrl() +
requestMappingUrl, HttpMethod.GET, requestEntity, serviceReturnTypeClass,
parametersInOrderOfAppearance);
// Return result
return entity;
}
#Test
public void getWelcomePage() {
Map<String, Object> urlVariables = new HashMap<String, Object>();
ResponseEntity<String> response = getResponseEntity("/index",
String.class,urlVariables);
assertTrue(response.getStatusCode().equals(HttpStatus.OK));
}
Can anyone tell me where the spring integration ws:inbound-gateway sets its SOAP Exception Resolver?
The outbound gateway has an attribute that I can set but the inbound does not.
I ant to set the Soap Fault Details before returning the SOAPFault back to the caller.
I have looked through the AbstractSoapFaultDefinitionExceptionResolver and tried to trace it back to somewhere where I could set it but I seem to be failing.
Any chance some one could point me in the right direction.
***********UPDATE**********
just as an FYI this was my final solution based on Artem's suggestion:
<bean id="exceptionResolver"
class="com.cloud.utils.CloudSoapFaultDefinitionResolver">
<property name="defaultFault" value="SERVER" />
</bean>
public class CloudMessagingSoapFaultDefinitionResolver extends SoapFaultAnnotationExceptionResolver {
private Logger log = LoggerFactory.getLogger(getClass());
private static final int THREE = 3;
/* (non-Javadoc)
* #see org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver#customizeFault(java.lang.Object, java.lang.Exception, org.springframework.ws.soap.SoapFault)
*/
#Override
protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
SoapFaultDetail details = fault.addFaultDetail();
Method[] methods = ex.getClass().getDeclaredMethods();
if (ex instanceof MonitiseCloudServicesException) {
AbstractRuntimeException mcse = (AbstractRuntimeException) ex;
methods = mcse.getClass().getDeclaredMethods();
}
for(Method m:methods){
addDetailsElement(ex, details, m);
}
}
/**
* #param ex
* #param details
* #param m
*/
private void addDetailsElement(Exception ex, SoapFaultDetail details, Method m) {
if(m.getName().startsWith("get")){
SoapFaultDetailElement element = details.addFaultDetailElement(new QName(m.getName().substring(THREE)));
try {
element.addText((String) m.invoke(ex, new Object[]{}));
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
log.error("An error occured processing the SOAPFault detail node {}.",m.getName().substring(THREE));
}
}
}
}
Actually don't mix inbound and outbound parts. They are server and client respectivally, from Spring WS perspective. They have just a different nature for configuration.
So, on server part you can do that like this:
<bean id="exceptionResolver"
class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<value>
org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
</value>
</property>
</bean>
That's because any Spring Integration <ws:inbound-gateway> is a part of standard Spring WS MessageDispatcherServlet configuration:
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping"
p:defaultEndpoint-ref="ws-inbound-gateway"/>
And all Faul Resolving work is done by Spring WS.
How can I modify the namespace of the response like this:
old response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:GetAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</ns2:GetAmountResponse>
</soap:Body>
</soap:Envelope>
new response wanted :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</GetAmountResponse>
</soap:Body>
</soap:Envelope>
I want to remove the ns2 namespce prefix.
In the first case, the GetAmountResponse is in namespace http://ws.dsi.otn.com/dab while etat and montant are in a default (empty) namespace.
In the new message you want, GetAmountResponse, etat and montant are all in namespace http://ws.dsi.otn.com/dab.
The namespaces can be controlled from the namespaces of your classes. Use the same namespace in all and you will have them in the same namespace, leave classes with defaults and they default to empty namespace.
For example, if you were to have something like this in your web service class:
#WebMethod
public
#WebResult(name = "getAmountResponse", targetNamespace = "http://ws.dsi.otn.com/dab")
AmountResponse getAmount(
#WebParam(name = "getAmountRequest", targetNamespace = "http://ws.dsi.otn.com/dab") AmountRequest request) {
AmountResponse response = new AmountResponse();
response.setEtat(0);
response.setMontant(500.0);
return response;
}
with a response class like this:
#XmlRootElement
public class AmountResponse {
private int etat;
private double montant;
// getter and setters omitted
}
you will end up with the first type of soap message.
But if you change the response class to look like this instead:
#XmlRootElement(namespace = "http://ws.dsi.otn.com/dab")
#XmlAccessorType(XmlAccessType.NONE)
public class AmountResponse {
#XmlElement(namespace = "http://ws.dsi.otn.com/dab")
private int etat;
#XmlElement(namespace = "http://ws.dsi.otn.com/dab")
private double montant;
// getters and setter omitted
}
you will bring all tags in the same namespace and you get something equivalent to the new type of message you want. I said equivalent because I don't think you will get exactly this:
<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</GetAmountResponse>
It's more likely to get something like this instead:
<ns2:getAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
<ns2:etat>0</ns2:etat>
<ns2:montant>500.0</ns2:montant>
</ns2:getAmountResponse>
It's the same "XML meaning" for both messages although they don't look the same.
If you absolutely want it to look like that, I think you will have to go "low level" and use something like a SOAP handler to intercept the response and modify it. But be aware that it won't be a trivial task to change the message before it goes on the wire.
logical handler are enough to transform to the message as expected :
package com.ouertani.slim;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.LogicalMessage;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
/**
*
* #author ouertani
*/
public class MyLogicalHandler implements LogicalHandler<LogicalMessageContext> {
#Override
public boolean handleMessage(LogicalMessageContext messageContext) {
/// extract state and amount
int state = 0;
double amount = 200.0;
transform(messageContext, state, amount);
return false;
}
public boolean handleFault(LogicalMessageContext messageContext) {
return true;
}
public void close(MessageContext context) {
}
private void transform( LogicalMessageContext messageContext, int etat, double montant){
LogicalMessage msg = messageContext.getMessage();
String htom = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+
"<soap:Body>"+
"<GetAmountResponse xmlns=\"http://ws.dsi.otn.com/dab\">"+
"<etat>"+etat+"</etat>"+
"<montant>"+montant+"</montant>"+
"</GetAmountResponse>"+
"</soap:Body>"+
"</soap:Envelope>";
InputStream is = new ByteArrayInputStream(htom.getBytes());
Source ht = new StreamSource(is);
msg.setPayload(ht);
}
}
This is a very old question, still it is yet to be effectively answered. This week I faced a very similar problem. My application is invoking a Soap web-service provided by a legacy system whose XML is response syntactically wrong with some empty characters (line break, or tabs or white spaces) before XML declaration. In my scenario I could not change the legacy system to fix its response so changing the response before parsing was the only alternative I was left with.
Here is my solution:
I have added the following maven dependencies to my application:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.0</version>
</dependency>
Then I have registered a Java SPI custom implementation of “com.oracle.webservices.impl.internalspi.encoding.StreamDecoder”. This class is invoked immediately before the XML parse with the corresponding response InputStream, so at this point you can read the response InputStream or wrap/proxy it and make any change to jax-ws response before parsing. In my case I just remove some invisible characters before first visible character.
My StreamDecoder SPI implementation:
package sample.streamdecoder;
import com.oracle.webservices.impl.encoding.StreamDecoderImpl;
import com.oracle.webservices.impl.internalspi.encoding.StreamDecoder;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.Message;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
public class MyStreamDecoder implements StreamDecoder {
//JAX-WS default implementation
private static final StreamDecoderImpl streamDecoder = new StreamDecoderImpl();
#Override
public Message decode(InputStream inputStream, String charset, AttachmentSet attachmentSet, SOAPVersion soapVersion) throws IOException {
//Wrapping inputStream
InputStream wrapped = wrapInputStreamStrippingBlankCharactersBeforeXML(inputStream, charset);
//Delegating further processing to default StreamDecoder
return streamDecoder.decode(wrapped, charset, attachmentSet, soapVersion);
}
private InputStream wrapInputStreamStrippingBlankCharactersBeforeXML(InputStream inputStream, String charset) throws IOException {
int WHITESPACE = (int) Charset.forName(charset).encode(" ").get();
int LINE_BREAK = (int) Charset.forName(charset).encode("\n").get();
int TAB = (int) Charset.forName(charset).encode("\t").get();
return new InputStream() {
private boolean xmlBegin = true;
#Override
public int read() throws IOException {
int read = inputStream.read();
if (!xmlBegin) {
return read;
} else {
while (WHITESPACE == read
|| LINE_BREAK == read
|| TAB == read) {
read = inputStream.read();
}
xmlBegin = false;
}
return read;
}
};
}
}
In order to register it, just create a file “META-INF/services/ com.oracle.webservices.impl.internalspi.encoding.StreamDecoder” named “” and write the fully qualified name of your SPI implementation on the first line like that:
Content of file META-INF/services/ com.oracle.webservices.impl.internalspi.encoding.StreamDecoder :
sample.streamdecoder.MyStreamDecoder
Now every response will be passed to you implementation before parse.
I have a webservice created with jax-ws and netbeans 7's wizard (this is my first time) .
to use java.util.Date instead of XmlGregorianCalendar, I have modified the client's webservice with this xml :
<?xml version="1.0" encoding="UTF-8"?>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings>
<jaxb:serializable/>
<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"/>
</jaxb:globalBindings>
</jaxws:bindings>
Date is now used instead of XmlGregorianCalendar and an Adapter1 is generated :
public class Adapter1
extends XmlAdapter<String, Date>
{
public Date unmarshal(String value) {
return new Date(value);
}
public String marshal(Date value) {
if (value == null) {
return null;
}
return value.toString();
}
}
When i add a system.out.println in the adapter i see that the Date is received/sent to the server but if i use ws's methods i get always null on Date field/parameters .
Thanks .
The XmlAdapter that is generated is not going to perform the desired conversions. The default XmlAdapter expects the following to work:
Foo foo1 = new Foo(foo2.toString());
Which is not valid in this case:
Date date1 = new Date(date2.toString());
You will need to write some conversion code and reference it from an external bindings file:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:bindings schemaLocation="format.xsd">
<jxb:bindings node="//xs:element[#name='my-date']">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="java.util.Date"
parseMethod="org.example.DateFormatter.parseInt"
printMethod="org.example.DateFormatter.printInt" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
For More Information
http://blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html