I can't get the SOAP server working in Zend Framework 2 module. I am not completely sure, but I believe that the problem is the WSDL file. I try to create the WSDL file via Autodiscover, which is provided by the Zend Framework. Here is the error.log:
[Fri Apr 19 20:39:29 2013] [error] [client 172.23.31.109] PHP Warning: SoapServer::SoapServer(): I/O warning : failed to load external entity "http-LINK/services?wsdl" in /PATH/public_html/vendor/zendframework/zendframework/library/Zend/Soap/Server.php on line 749
[Fri Apr 19 20:39:29 2013] [error] [client 172.23.31.109] PHP Fatal error: SOAP-ERROR: Parsing WSDL: Couldn't load from 'http-LINK/services?wsdl' : failed to load external entity "http-LINK/services?wsdl"\n in /PATH/public_html/vendor/zendframework/zendframework/library/Zend/Soap/Server.php on line 749
I added an own module for this services test, this is the structure, module is called "Services":
-Services
--config
---module.config.php
--src
---Services
----API
-----1.0
------servicesAPI.php
---Controller
----ServicesController.php
--view
---services
----serivces
-Module.php
-autoload_classmap.php
This is my file "servicesAPI.php"
class servicesAPI {
/**
* This method takes a value and gives back the md5 hash of the value
*
* #param String $value
* #return String
*/
public function md5Value($value) {
return md5($value);
}
}
And this is ServicesController.php:
namespace Services\Controller;
ini_set("soap.wsdl_cache_enabled", 0);
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Soap\AutoDiscover;
use Zend\Soap\Server;
require_once __DIR__ . '/../API/1.0/servicesAPI.php';
class ServicesController extends AbstractActionController {
private $_options;
private $_URI = "http-LINK/services";
private $_WSDL_URI = "http-LINK/services?wsdl";
public function indexAction() {
if (isset($_GET['wsdl'])) {
$this->handleWSDL();
} else {
$this->handleSOAP();
}
}
private function handleWSDL() {
$autodiscover = new AutoDiscover();
$autodiscover->setClass('servicesAPI')
->setUri($this->_URI);
$autodiscover->handle();
}
private function handleSOAP() {
$soap = new Server($this->_WSDL_URI);
$soap->setClass('servicesAPI');
$soap->handle();
}
}
So when I deploy this and open http-LINK/services in the browser, it gives me the following:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>
SOAP-ERROR: Parsing WSDL: Couldn't load from 'http-LINK/services?wsdl' : failed to load external entity "http-LINK/services?wsdl"
</faultstring>
<detail/>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
On this call also the PHP error output is written!
If I try to open the services?wsdl in browser, it shows me this (chrome and safari):
This page contains the following errors:
error on line 3 at column 1: Extra content at the end of the document
Below is a rendering of the page up to the first error.
This method takes a value and gives back the md5 hash of the value
But if I inspect the element, it looks completely ok:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http-LINK/services" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="servicesAPI" targetNamespace="http-LINK/services"><types><xsd:schema targetNamespace="http-LINK/services"/></types><portType name="servicesAPIPort"><operation name="md5Value"><documentation>This method takes a value and gives back the md5 hash of the value</documentation><input message="tns:md5ValueIn"/><output message="tns:md5ValueOut"/></operation></portType><binding name="servicesAPIBinding" type="tns:servicesAPIPort"><soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><operation name="md5Value"><soap:operation soapAction="http-LINK/services#md5Value"/><input><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http-LINK/services"/></input><output><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http-LINK/services"/></output></operation></binding><service name="servicesAPIService"><port name="servicesAPIPort" binding="tns:servicesAPIBinding"><soap:address location="http-LINK/services"/></port></service><message name="md5ValueIn"><part name="value" type="xsd:string"/></message><message name="md5ValueOut"><part name="return" type="xsd:string"/></message></definitions>
I can validate this xml with any xml validator, it seems to be valid.
I read all the posts concerning this on stackoverflow, searched google, but none of the solutions helped me. Here a short list of what else I tried:
According to this: https://bugs.php.net/bug.php?id=48216 I tried to save the wsdl xml to a file and open it from this file when starting the soap server, fail
I tried to run the autodiscover and soapserver statements with try/catch to catch any exceptions, nothing appears
I tried with echo-ing through toXML() and other outputs, fail
Used XMLReader::open and isValid to make sure, that the xml is valid (it is)
Some more information:
PHP Version 5.3.23
Ubuntu server 11.04
php-soap module is loaded
Zend Framework version 2.1.4
Any help or hints are appreciated. Thanks in advance.
Try instantiate the Soap Server class this way:
...
private function handleSOAP() {
$soap = new Server(
null, array(,
'wsdl' => http-LINK/services?wsdl,
)
);
$soap->setClass('servicesAPI');
$soap->handle();
}
....
Also you should add this line to the end of your indexAction()
return $this->getResponse();
.. it disables the layout.
Related
I'm working with an existing database and EJB 2.x application.
My task is to migrate the app from WebSphere 8 over to JBOSS EAP 6.4
After many days of fighting with this thing, everything seemed to be working until we started trying to use some of the beans. There are beans that end with "Mgr". For example, there is a SiteMgr bean and a Site bean. Right now, all of the Mgr beans work, but not the rest.
If you couldn't tell already, I'm not an EJB 2 Guru. Here is code that errors out:
/**
* getSessionContext
*/
public SiteVO getSite(int siteId) {
SiteLocal siteLocal;
try {
siteLocal = getSiteHome().findByPrimaryKey(new SiteKey(siteId));
} catch (FinderException e) {
throw new EJBException(e);
}
return siteLocal.getSiteVO();
}
So, when I try to findByPrimaryKey I get javax.ejb.FinderException, with the following cause:
java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
Drilling into that a bit more, here is the cause:
Error : 942, Position : 27, Sql = SELECT t0_Site.siteId FROM SITE t0_Site WHERE t0_Site.siteId=:1 , OriginalSql = SELECT t0_Site.siteId FROM SITE t0_Site WHERE t0_Site.siteId=?, Error Msg = ORA-00942: table or view does not exist
The database contains a table named APP_SITES and the WebSphere app probably figures that out using some files that appear to be specific to WebSphere.
There is appdb70.dbm and Map.mapxmi
These files are very long. I will provide some example text that is specific to the above example.
ejb-jar.xml
<entity id="Site">
<ejb-name>Site</ejb-name>
<local-home>com.app.site.entity.SiteLocalHome</local-home>
<local>com.app.site.entity.SiteLocal</local>
<ejb-class>com.app.site.entity.SiteBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>com.app.site.entity.SiteKey</prim-key-class>
<reentrant>false</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Site</abstract-schema-name>
<cmp-field id="CMPAttribute_1087249279390">
<field-name>siteId</field-name>
</cmp-field>
<cmp-field id="CMPAttribute_1087249281781">
<field-name>siteName</field-name>
</cmp-field>
...
Map.mapxmi
<ejbrdbmapping:EjbRdbDocumentRoot xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:OracleModel="http:///com/ibm/db/models/oracle/oracle.ecore"
xmlns:SQLConstraints="http:///org/eclipse/datatools/modelbase/sql/constraints.ecore"
xmlns:SQLTables="http:///org/eclipse/datatools/modelbase/sql/tables.ecore" xmlns:ejb="ejb.xmi"
xmlns:ejbrdbmapping="ejbrdbmapping.xmi" xmlns:Mapping="Mapping.xmi" xmi:id="EjbRdbDocumentRoot_1289312938455" topToBottom="true" commandStack="">
<helper xmi:type="ejbrdbmapping:RdbSchemaProperies" xmi:id="RdbSchemaProperies_1289312938455" primitivesDocument="ORACLE_V11"/>
<nested xmi:type="ejbrdbmapping:RDBEjbMapper" xmi:id="RDBEjbMapper_1289313262395">
<helper xmi:type="ejbrdbmapping:PrimaryTableStrategy" xmi:id="PrimaryTableStrategy_1289313262395">
<table xmi:type="OracleModel:OracleTable" href="META-INF/backends/ORACLE_V11_3/acapdb70.dbm#_q0x58OwNEd-LtOpsZa3J5w"/>
</helper>
<nested xmi:type="ejbrdbmapping:RDBEjbFieldMapper" xmi:id="RDBEjbFieldMapper_1289315290408">
<inputs xmi:type="ejb:CMPAttribute" href="META-INF/ejb-jar.xml#CMPAttribute_1087249279390"/>
<outputs xmi:type="SQLTables:Column" href="META-INF/backends/ORACLE_V11_3/acapdb70.dbm#_q0x58ewNEd-LtOpsZa3J5w"/>
<typeMapping xmi:type="ejbrdbmapping:RDBEjbFieldMapper" href="JavatoORACLE_V11TypeMaps.V7.xmi#int-NUMBER"/>
</nested>
<nested xmi:type="ejbrdbmapping:RDBEjbFieldMapper" xmi:id="RDBEjbFieldMapper_1289315290409">
<inputs xmi:type="ejb:CMPAttribute" href="META-INF/ejb-jar.xml#CMPAttribute_1087249285656"/>
<outputs xmi:type="SQLTables:Column" href="META-INF/backends/ORACLE_V11_3/acapdb70.dbm#_q0x5-ewNEd-LtOpsZa3J5w"/>
<typeMapping xmi:type="ejbrdbmapping:RDBEjbFieldMapper" href="JavatoORACLE_V11TypeMaps.V7.xmi#String-VARCHAR"/>
</nested>
appdb70.dbm (contains WAY too much data to post...)
<?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<xmi:XMI xmlns:datamodelversion="http://www.ibm.com/com.ibm.datatools.core/model/7.5.1.1" xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:OracleModel="http:///com/ibm/db/models/oracle/oracle.ecore" xmlns:SQLConstraints="http:///org/eclipse/datatools/modelbase/sql/constraints.ecore" xmlns:SQLDataTypes="http:///org/eclipse/datatools/modelbase/sql/datatypes.ecore" xmlns:SQLExpressions="http:///org/eclipse/datatools/modelbase/sql/expressions.ecore" xmlns:SQLSchema="http:///org/eclipse/datatools/modelbase/sql/schema.ecore" xmlns:SQLStatements="http:///org/eclipse/datatools/modelbase/sql/statements.ecore" xmlns:SQLTables="http:///org/eclipse/datatools/modelbase/sql/tables.ecore">
<OracleModel:OracleDatabase xmi:id="_WPDywewNEd-LtOpsZa3J5w" name="APPdb70" vendor="Oracle" version="11" schemas="_WQG7oOwNEd-LtOpsZa3J5w"/>
<SQLSchema:Schema xmi:id="_WQG7oOwNEd-LtOpsZa3J5w" name="APPWDB" triggers="_q0VNoOwNEd-LtOpsZa3J5w ..." database="_WPDywewNEd-LtOpsZa3J5w"/>
<SQLTables:Trigger xmi:id="_q0VNoOwNEd-LtOpsZa3J5w" name="APP_APPOINTMENT_D_TRG" schema="_WQG7oOwNEd-LtOpsZa3J5w" subjectTable="_q0VNpuwNEd-LtOpsZa3J5w" ...>
<dependencies xmi:id="_q0VNoewNEd-LtOpsZa3J5w" targetEnd="_q07ry-wNEd-LtOpsZa3J5w"/>
<dependencies xmi:id="_q0VNouwNEd-LtOpsZa3J5w" targetEnd="_q0e_b-wNEd-LtOpsZa3J5w"/>
<dependencies xmi:id="_q0VNo-wNEd-LtOpsZa3J5w" targetEnd="_q0VNpuwNEd-LtOpsZa3J5w"/>
<dependencies xmi:id="_q0VNpOwNEd-LtOpsZa3J5w" targetEnd="_q0VN_OwNEd-LtOpsZa3J5w"/>
<actionStatement xsi:type="SQLStatements:SQLStatementDefault" ..."/>
</SQLTables:Trigger>
<OracleModel:OracleTable xmi:id="_q0VNpuwNEd-LtOpsZa3J5w" name="APP_APPOINTMENT" schema="_WQG7oOwNEd-LtOpsZa3J5w" triggers="_q0VNoOwNEd-LtOpsZa3J5w ...>
<columns xmi:id="_q0VNp-wNEd-LtOpsZa3J5w" name="APPT_ID" nullable="false">
<containedType xsi:type="SQLDataTypes:FixedPrecisionDataType" xmi:id="_q0VNqOwNEd-LtOpsZa3J5w" name="NUMBER" primitiveType="NUMERIC"/>
</columns>
<columns xmi:id="_q0VNqewNEd-LtOpsZa3J5w" name="RMKS_TX">
<containedType xsi:type="SQLDataTypes:CharacterStringDataType" xmi:id="_q0VNquwNEd-LtOpsZa3J5w" name="VARCHAR2" primitiveType="CHARACTER_VARYING" length="200"/>
</columns>
Notice that you can find "CMPAttribute_1087249279390" in multiple files. JBOSS does not seem to make use of these extra files.
I'm not sure what to do at this point. I figured out everything else, but I can't seem to get around this. Any fix that gets the beans to work would be appreciated!
I have 2 stores English and Arabic. Default Store is Arabic and default currency is SAR. Currency symbol is showing fine on English Store but not showing anywhere on Arabic store. It only showing price like this 44 on product listing page and on single product page.
I fixed it.
Posting my answer may be it can help someone.
edit this file.
vendor\magento\zendframework1\library\Zend\Locale\Data\ar_SA.xml
and remove following code.
<numbers>
<currencyFormats numberSystem="latn">
<currencyFormatLength>
<currencyFormat type="standard">
<pattern>¤#0.00</pattern>
</currencyFormat>
</currencyFormatLength>
</currencyFormats>
</numbers>
UPDATED ANSWER ========
I got better solution instead editing core file you can do it with observer.
Vendor/Module/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="currency_display_options_forming">
<observer name="change_currency_position" instance="Vendor\Module\Model\Observer\ChangeCurrencyPosition" />
</event>
</config>
and observer File.
use Magento\Framework\Event\ObserverInterface;
class ChangeCurrencyPosition implements ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$currencyOptions = $observer->getEvent()->getCurrencyOptions();
$currencyOptions->setData('position', \Magento\Framework\Currency::RIGHT);
return $this;
}
}
Need to change the 'position' to RIGHT.
Its a bug in 2.4.3:
src\vendor\magento\module-directory\Model\Currency.php
Comment out these lines:
if ($this->canUseNumberFormatter($options)) {
return $this->formatCurrency($price, $options);
}
Then:
php -dmemory_limit=6G bin/magento setup:upgrade
php -dmemory_limit=6G bin/magento setup:di:compile
php -dmemory_limit=6G bin/magento setup:static-content:deploy -f
php -dmemory_limit=6G bin/magento cache:flush
Editing core is bad, we can create preference.
If #Ask4Tec's solution is not working
Try this
Copy the currency and numbers block from en.xml file and paste it into the ar_SA.xml file
Clean and flush cache
Check after hard refresh
Update ar_SA.xml like below:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd">
<!-- Copyright © 1991-2013 Unicode, Inc.
CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
For terms of use, see http://www.unicode.org/copyright.html
-->
<ldml>
<identity>
<version number="$Revision: 9287 $"/>
<generation date="$Date: 2013-08-28 21:32:04 -0500 (Wed, 28 Aug 2013) $"/>
<language type="ar"/>
<territory type="SA"/>
</identity>
<dates>
<calendars>
<calendar type="islamic">
<dateTimeFormats>
<availableFormats>
<dateFormatItem id="Md" draft="contributed">M/d</dateFormatItem>
<dateFormatItem id="MEd" draft="contributed">E, M/d</dateFormatItem>
<dateFormatItem id="MMMd" draft="contributed">MMM d</dateFormatItem>
<dateFormatItem id="MMMEd" draft="contributed">E, MMM d</dateFormatItem>
</availableFormats>
</dateTimeFormats>
</calendar>
</calendars>
</dates>
<numbers>
<symbols numberSystem="latn">
<decimal>.</decimal>
<group>,</group>
<list>;</list>
<percentSign>%</percentSign>
<plusSign>+</plusSign>
<minusSign>-</minusSign>
<exponential>E</exponential>
<superscriptingExponent>×</superscriptingExponent>
<perMille>‰</perMille>
<infinity>∞</infinity>
<nan>NaN</nan>
</symbols>
<decimalFormats numberSystem="latn">
<decimalFormatLength>
<decimalFormat>
<pattern>#,##0.###</pattern>
</decimalFormat>
</decimalFormatLength>
</decimalFormats>
<currencyFormats numberSystem="latn">
<currencyFormatLength>
<currencyFormat type="standard">
<pattern>¤#,##0.00</pattern>
</currencyFormat>
<currencyFormat type="accounting">
<pattern>¤#,##0.00;(¤#,##0.00)</pattern>
</currencyFormat>
</currencyFormatLength>
<unitPattern count="one">{0} {1}</unitPattern>
<unitPattern count="other">{0} {1}</unitPattern>
</currencyFormats>
<currencies>
<currency type="USD">
<displayName>US Dollar</displayName>
<displayName count="one">US dollar</displayName>
<displayName count="other">US dollars</displayName>
<symbol>$</symbol>
</currency>
</currencies>
</numbers>
</ldml>
I am trying to send a SOAP request using Spring Integration like
<int:chain input-channel="wsOutChannel" output-channel="stdoutChannel">
<int-ws:header-enricher>
<int-ws:soap-action value="..."/>
</int-ws:header-enricher>
<int-ws:outbound-gateway
uri="..."/>
</int:chain>
but you can only add the SOAP body, and Spring Integration adds the envelope, header, and body tags like
<SOAP-ENV:Envelope>
<SOAP-ENV:Header>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
<SOAP-ENV:Header>
</SOAP-ENV:Envelope>
I need to customize the envelope and header tags with specific attributes, for example:
<soapenv:Envelope attribute1="value1" attribute2="value2">
and child elements, for example:
<soapenv:Header>
<child>...<child>
<soapenv:Header>
Is this possible with Spring Integration Web Services, or should I not use int-ws:outbound-gateway and take a different approach?
You can add a ClientInterceptor (via the interceptor attribute) which allows you to modify the request before it's sent out.
EDIT
#Artem's suggestion is simpler but the interceptor gives you access to the response too; but either way, the code is similar.
For the interceptor:
public class MyInterceptor extends ClientInterceptorAdapter {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
SoapMessage request = (SoapMessage) messageContext.getRequest();
SoapEnvelope envelope = request.getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
return super.handleRequest(messageContext);
}
}
For the callback version:
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
SoapEnvelope envelope = ((SoapMessage) message).getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
}
I thing you can inject WebServiceMessageCallback:
<xsd:attribute name="request-callback" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Reference to a Spring Web Services WebServiceMessageCallback. This enables changing
the Web Service request message after the payload has been written to it but prior
to invocation of the actual Web Service.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.ws.client.core.WebServiceMessageCallback"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
and cast the message to the SoapMessage and use its getEnvelope() to customize a desired way.
I'm following http://www.java2blog.com/2015/09/spring-restful-web-services-json-example.html and as it's suggested in the article when I deploy my application to tomcat I get the warning:
WARNING: [SetContextPropertiesRule]{Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:restordering' did not find a matching property.
(restordering is my application context)
And when I try to access my application I get this warning:
WARNING: No mapping found for HTTP request with URI [/restordering] in DispatcherServlet with name 'restordering'
and I see a 404 error page!
I've tested this on tomcat 7 and 8. I've created the war and deployed outside of eclipse and followed all suggested solution including change in server definition (publish module context to separate XML files) and removing and adding and doing all the tricks it's described in the above article and on stackoverflow but nothing has worked so far.
Before I get "this is a warning and ..." yes it is a warning but also I get 404 error and can't access my services.
And yes I have the correct package name in my restordering-servlet.xml ( context:component-scan base-package="com.obp.restordering.controller" ).
As requested here is my web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>restordering</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restordering</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
and restordering-servlet.xml is:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.obp.restordering.controller" />
</beans>
and my controller file is this:
package com.obp.restordering.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.obp.restordering.bean.Country;
#RestController
public class CountryController {
#RequestMapping(value = "/countries", method = RequestMethod.GET, headers = "Accept=application/json")
public List<Country> getCountries() {
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries = createCountryList();
return listOfCountries;
}
#RequestMapping(value = "/country/{id}", method = RequestMethod.GET, headers = "Accept=application/json")
public Country getCountryById(#PathVariable int id) {
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries = createCountryList();
for (Country country : listOfCountries) {
if (country.getId() == id)
return country;
}
return null;
}
// Utiliy method to create country list.
public List<Country> createCountryList() {
Country indiaCountry = new Country(1, "India");
Country chinaCountry = new Country(4, "China");
Country nepalCountry = new Country(3, "Nepal");
Country bhutanCountry = new Country(2, "Bhutan");
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries.add(indiaCountry);
listOfCountries.add(chinaCountry);
listOfCountries.add(nepalCountry);
listOfCountries.add(bhutanCountry);
return listOfCountries;
}
}
Any idea?
This is embarrassing but I need to come clean and admit and provide an answer so if others have the same issue they don't circle around days as I did.
Arpit the author of the mentioned tutorial responded to my request for help and after checking my code confirmed all works as expected!
The issue was in how I was trying to access my service! If I go to /restordering/countries I get the 404 error. To access the service I need to go to /restordering/restordering/countries! As simple as that.
The warnings I still get and I can't resolve them at this time but at least the service is working and this seems more of a deployment/setting issue than actual spring development issue.
Anyways, I thought this may help some others.
Cheers
Here below is the step-by-step attempt to developp a Web Service client in an application developped in Borland C++ Builder 6.
Help is welcome to correct this code or to suggest any other solution (though I now try to use a dll developped in C++ Builder XE3).
Here is my attempt to use Soap in Borland 6 C++ Builder. Untill now I conclude that I cannot succeed because Borland 6 does not manage SOAP header (absent of InvokeRegistry.hpp) and the SOAP server to whom we send requests needs cookies to be passed after the login of this interface :
__interface INTERFACE_UUID("{B0F412ED-AC6A-42C3-8730-DD0D9680F16D}") AuthenticationSoap : public IInvokable
{
public:
virtual LoginResult* Login(const AnsiString username, const AnsiString password) = 0;
virtual AuthenticationMode Mode() = 0;
};
typedef DelphiInterface<AuthenticationSoap> _di_AuthenticationSoap;
this login first sends a :
500 Server Internal Error
then is ok if I add this call :
InvRegistry()->RegisterInvokeOptions(__interfaceTypeinfo(AuthenticationSoap), ioDocument);
then I pass the User Name to a HTTPRIO :
MyHTTPRIO->HTTPWebNode->UserName = AnsiString("xxx...");
And this HTTPRIO is passed to the second interface :
__interface INTERFACE_UUID("{1E5B3820-A40E-FD40-326D-95A9F6B7A5F0}") OrganizerWS_1_1Soap : public IInvokable
{
public:
...
virtual void findHorse(const ArrayOfString FEIIDs, const AnsiString Name, const AnsiString SexCode, const bool IsPony, const AnsiString AthleteFEIID, ArrayOfHorseOC& findHorseResult, ArrayOfMessage& Messages) = 0;
...
};
typedef DelphiInterface<OrganizerWS_1_1Soap> _di_OrganizerWS_1_1Soap;
_di_OrganizerWS_1_1Soap GetOrganizerWS_1_1Soap(bool useWSDL=false, AnsiString addr="", Soaphttpclient::THTTPRIO* HTTPRIO=0);
But we get an error "AuthHeader is missing" because we have used Borland 6's WSDL importer which does not generates code for Headers and headers are not defined in Invokeregistry.hpp.
So in the "BeforeExecute" of our HTTPRIO we have this request :
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<findHorse xmlns="http://fei.org/">
<FEIIDs/>
<Name></Name>
<SexCode></SexCode>
<IsPony>false</IsPony>
<AthleteFEIID>10002254</AthleteFEIID>
<findHorseResult/>
<Messages/>
</findHorse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
whereas Borland XE3 generates this request which is ok and brings the expected response from the server :
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<NS1:AuthHeader xmlns:NS1="http://fei.org/">
<UserName xmlns="http://fei.org/">xxx...</UserName>
<Language xmlns="http://fei.org/">en</Language>
</NS1:AuthHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<findHorse xmlns="http://fei.org/">
<IsPony>false</IsPony>
<AthleteFEIID>10002254</AthleteFEIID>
</findHorse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
So I first replaced
<SOAP-ENV:Body>
by
<SOAP-ENV:Header><NS1:AuthHeader xmlns:NS1="http://fei.org/"><UserName xmlns="http://fei.org/">xxx...</UserName><Language xmlns="http://fei.org/">en</Language></NS1:AuthHeader></SOAP-ENV:Header><SOAP-ENV:Body>
then added options as for example "<< xoHolderClass << xoInlineArrays" :
RemClassRegistry()->RegisterSerializeOptions(__classid(findHorse), (TSerializationOptions() << xoHolderClass << xoInlineArrays));
here I obtain the same request but the answer of the server is a NULL array whereas there are three items in the answer to a test written in borland xe3.
Or with other manipulations (without xo... options) I get access violation in delphi interfaces destructor :
__fastcall ~DelphiInterface<T>()
{
if (intf != 0)
{
intf->Release();
intf = 0;
}
}
I explored other solutions (such as using indySOAP which is available only in Delphi sources (no C++ sources), thought about creating the XML and sending with Indy components (but expect I would encounter a same authentication header issue ?), using CAPICOM, or windows SDK ? ...) but without success until now and as said before I now try to use a dll developped in C++ Builder XE3 :
https://stackoverflow.com/questions/15485276/embarcadero-c-xe3-dll-imported-in-c-xe3-project-library-loads-but-access-v