Soap Spring+JAXB DataStoreProvider

0

Hej

Próbuję za pośrednictwem soap'a pobrać dane z usługi DataStoreProvider (pobieranie danych z CEIDG) do której mam wygenerowany klucz api w aplikacji opartej o spring boota.

WSDL usługi umieszczony w katalogu resources:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="DataStoreProvider201901" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
	<wsp:Policy wsu:Id="BasicHttpBinding_IDataStoreProvider2019011_policy">
		<wsp:ExactlyOne>
			<wsp:All>
				<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
					<wsp:Policy>
						<sp:TransportToken>
							<wsp:Policy>
								<sp:HttpsToken RequireClientCertificate="false"/>
							</wsp:Policy>
						</sp:TransportToken>
						<sp:AlgorithmSuite>
							<wsp:Policy>
								<sp:Basic256/>
							</wsp:Policy>
						</sp:AlgorithmSuite>
						<sp:Layout>
							<wsp:Policy>
								<sp:Strict/>
							</wsp:Policy>
						</sp:Layout>
					</wsp:Policy>
				</sp:TransportBinding>
			</wsp:All>
		</wsp:ExactlyOne>
	</wsp:Policy>
	<wsdl:types>
		<xsd:schema targetNamespace="http://tempuri.org/Imports">
			<xsd:import schemaLocation="https://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc?xsd=xsd0" namespace="http://tempuri.org/"/>
			<xsd:import schemaLocation="https://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
			<xsd:import schemaLocation="https://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc?xsd=xsd2" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="IDataStoreProvider201901_GetID_InputMessage">
		<wsdl:part name="parameters" element="tns:GetID"/>
	</wsdl:message>
	<wsdl:message name="IDataStoreProvider201901_GetID_OutputMessage">
		<wsdl:part name="parameters" element="tns:GetIDResponse"/>
	</wsdl:message>
	<wsdl:message name="IDataStoreProvider201901_GetMigrationData201901_InputMessage">
		<wsdl:part name="parameters" element="tns:GetMigrationData201901"/>
	</wsdl:message>
	<wsdl:message name="IDataStoreProvider201901_GetMigrationData201901_OutputMessage">
		<wsdl:part name="parameters" element="tns:GetMigrationData201901Response"/>
	</wsdl:message>
	<wsdl:portType name="IDataStoreProvider201901">
		<wsdl:operation name="GetID">
			<wsdl:input wsaw:Action="http://tempuri.org/IDataStoreProvider201901/GetID" message="tns:IDataStoreProvider201901_GetID_InputMessage"/>
			<wsdl:output wsaw:Action="http://tempuri.org/IDataStoreProvider201901/GetIDResponse" message="tns:IDataStoreProvider201901_GetID_OutputMessage"/>
		</wsdl:operation>
		<wsdl:operation name="GetMigrationData201901">
			<wsdl:input wsaw:Action="http://tempuri.org/IDataStoreProvider201901/GetMigrationData201901" message="tns:IDataStoreProvider201901_GetMigrationData201901_InputMessage"/>
			<wsdl:output wsaw:Action="http://tempuri.org/IDataStoreProvider201901/GetMigrationData201901Response" message="tns:IDataStoreProvider201901_GetMigrationData201901_OutputMessage"/>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="BasicHttpBinding_IDataStoreProvider201901" type="tns:IDataStoreProvider201901">
		<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
		<wsdl:operation name="GetID">
			<soap:operation soapAction="http://tempuri.org/IDataStoreProvider201901/GetID" style="document"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
		<wsdl:operation name="GetMigrationData201901">
			<soap:operation soapAction="http://tempuri.org/IDataStoreProvider201901/GetMigrationData201901" style="document"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:binding name="BasicHttpBinding_IDataStoreProvider2019011" type="tns:IDataStoreProvider201901">
		<wsp:PolicyReference URI="#BasicHttpBinding_IDataStoreProvider2019011_policy"/>
		<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
		<wsdl:operation name="GetID">
			<soap:operation soapAction="http://tempuri.org/IDataStoreProvider201901/GetID" style="document"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
		<wsdl:operation name="GetMigrationData201901">
			<soap:operation soapAction="http://tempuri.org/IDataStoreProvider201901/GetMigrationData201901" style="document"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="DataStoreProvider201901">
		<wsdl:port name="BasicHttpBinding_IDataStoreProvider201901" binding="tns:BasicHttpBinding_IDataStoreProvider201901">
			<soap:address location="http://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc"/>
		</wsdl:port>
		<wsdl:port name="BasicHttpBinding_IDataStoreProvider2019011" binding="tns:BasicHttpBinding_IDataStoreProvider2019011">
			<soap:address location="https://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc"/>
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

POM uzupełniony o plugin, struktura klas na podstawie WSDL także wygenerowana.

Beany skonfigurowane:

@Configuration
public class BeanConfig {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("me.plich.cashregistersystem.generated");
        return marshaller;
    }
    @Bean
    public DataStoreProviderServiceAdapter soapConnector(Jaxb2Marshaller marshaller) {
        DataStoreProviderServiceAdapter client = new DataStoreProviderServiceAdapter();
        client.setDefaultUri("https://datastore.ceidg.gov.pl/CEIDG.DataStore/services/DataStoreProvider201901.svc");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }
}

Klasa rozszerzająca WebServiceGatewaySupport również(nip na potrzeby posta wzięty z generatora, do usługi strzelam rzeczywistym, w miejscu myApiKey oczywiście doklejam swój klucz do api):

public class DataStoreProviderServiceAdapter extends WebServiceGatewaySupport {

    public GetMigrationData201901Response getCompanyData(){
        GetMigrationData201901 request = new GetMigrationData201901();
        ObjectFactory factory = new ObjectFactory();

        JAXBElement<String> key = factory.createGetMigrationData201901AuthToken("myApiKey");
        ArrayOfstring check = new ArrayOfstring();
        check.getString().add(0,"1075310455");
        JAXBElement<ArrayOfstring> nip = factory.createGetMigrationData201901NIP(check);
        System.out.println("NIP: "+nip.getValue().getString().toString());
        System.out.println("key: "+key.getValue());
        request.setNIP(nip);
        request.setCity(factory.createGetMigrationData201901City(null));
        request.setREGON(factory.createGetMigrationData201901REGON(null));
        request.setNIPSC(factory.createGetMigrationData201901NIPSC(null));
        request.setREGONSC(factory.createGetMigrationData201901REGONSC(null));
        request.setName(factory.createGetMigrationData201901Name(null));
        request.setProvince(factory.createGetMigrationData201901Province(null));
        request.setCounty(factory.createGetMigrationData201901County(null));
        request.setCommune(factory.createGetMigrationData201901Commune(null));
        request.setStreet(factory.createGetMigrationData201901Street(null));
        request.setPostcode(factory.createGetMigrationData201901Postcode(null));
        request.setDateFrom(factory.createGetMigrationData201901DateFrom(null));
        request.setDateTo(factory.createGetMigrationData201901MigrationDateTo(null));
        request.setPKD(factory.createGetMigrationData201901PKD(null));
        request.setStatus(factory.createGetMigrationData201901Status(null));
        request.setUniqueId(factory.createGetMigrationData201901UniqueId(null));
        request.setMigrationDateFrom(factory.createGetMigrationData201901DateFrom(null));
        request.setMigrationDateTo(factory.createGetMigrationData201901MigrationDateTo(null));
        request.setAuthToken(key);
        GetMigrationData201901Response response = (GetMigrationData201901Response) getWebServiceTemplate().marshalSendAndReceive(request);

        return response;
    }
}

Po uzupełnieniu klucza do api oraz numeru nip.
Klasa startowa:

public class CashregistersystemApplication {

    @PostConstruct
    void init() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }

    public static void main(String[] args) {
        SpringApplication.run(CashregistersystemApplication.class, args);
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        DataStoreProviderServiceAdapter ds = context.getBean(DataStoreProviderServiceAdapter.class);
        GetMigrationData201901Response response = ds.getCompanyData();
        System.out.println("Wynik pobierania ="+response.toString());
    }

    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}

W logach w terminalu dostaję komunikat:

Exception in thread "main" org.springframework.ws.soap.client.SoapFaultClientException: Komunikat o parametrze Action „” nie może zostać przetworzony w punkcie odbioru z powodu niezgodności parametru ContractFilter w EndpointDispatcher. Może to być spowodowane niezgodnością kontraktu (niezgodność czynności między nadawcą i odbiorcą) lub niezgodnością powiązania/zabezpieczeń między nadawcą i odbiorcą. Sprawdź, czy nadawca i odbiorca mają te same kontrakty i powiązania (w tym wymagania zabezpieczeń, np.: Message, Transport, None).
	at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:38)
	at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:830)
	at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:624)
	at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
	at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
	at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383)
	at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373)
	at aa.xyz.cashregistersystem.config.DataStoreProviderServiceAdapter.getCompanyData(DataStoreProviderServiceAdapter.java:45)
	at aa.xyz.cashregistersystem.CashregistersystemApplication.main(CashregistersystemApplication.java:33)

Coś zrobiłem źle, tylko na podstawie samego WSDL'a nie jestem w stanie wywnioskować co (może czegoś nie przekazuję w requeście).
To moje pierwsze zetknięcie z soap'em także będę wdzięczny za poradę / wskazówkę :)

Update:
Zauważyłem, że mój request różni się od przykładowego z dokumentacji tagami ns.

Mój request:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
	<SOAP-ENV:Header/>
	<SOAP-ENV:Body>
		<ns2:GetMigrationData201901 xmlns:ns2="http://tempuri.org/" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/">
			<ns2:AuthToken>5WQKywVlcEBgbqzOmojzGFA+hKY9PfWZeW32Emel4O+BMcMbCZtfc7CbGTX+bIhP</ns2:AuthToken>
			<ns2:Province xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
		</ns2:GetMigrationData201901>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Przykładowy request z dokumentacji:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
	<soapenv:Header/>
	<soapenv:Body>
		<tem: GetMigrationData201901>
			<tem:AuthToken> Klucz dostępu użytkownika </tem:AuthToken>
			<tem:Province>
				<arr:string>podlaskie</arr:string>
			</tem:Province>
			<tem:MigrationDateFrom>2017-01-05</tem:MigrationDateFrom>
			<tem:MigrationDateTo>2017-01-05</tem:MigrationDateTo>
		</tem: GetMigrationData201901>
	</soapenv:Body>
</soapenv:Envelope>  

AKTUALIZACJA:
Udało się rozwiązać problem.
Brakowało nagłówka soapAction:

GetMigrationData201901Response response =
                (GetMigrationData201901Response) getWebServiceTemplate().marshalSendAndReceive(request,
                        new SoapActionCallback("http://tempuri.org/IDataStoreProvider201901/GetMigrationData201901"));

Kolejny problem to fakt, że api nie zwraca xml'a jako takiego a długiego stringa w postaci:

<WynikWyszukiwania>
	<InformacjaOWpisie>
		<IdentyfikatorWpisu>9069a104dd12345d987c0cc36a2a614</IdentyfikatorWpisu>
		<DanePodstawowe>
			<Imie>Kamil</Imie>
			<Nazwisko>Nowak</Nazwisko>
			<NIP>5210342338</NIP>
			<REGON>010456779</REGON>
			<Firma>Kamil Nowak Nazwa Firmy</Firma>
		</DanePodstawowe>
		<DaneKontaktowe>
			<AdresPocztyElektronicznej>[email protected]</AdresPocztyElektronicznej>
			<AdresStronyInternetowej/>
			<Telefon/>
			<Faks/>
		</DaneKontaktowe>
	</InformacjaOWpisie>
</WynikWyszukiwania>

Ale to już (domyślam się) kwestia opracowania odpowiedniego parsera :)

0

Podpowie ktoś w jaki sposób powinno się przekształcić stringa (finalną odpowiedź z usługi):

<WynikWyszukiwania>
	<InformacjaOWpisie>
		<IdentyfikatorWpisu>9069a104dd6feb21d987c0cc36a2a614</IdentyfikatorWpisu>
		<DanePodstawowe>
			<Imie>Jan</Imie>
			<Nazwisko>Kowalski</Nazwisko>
			<NIP>12345678900</NIP>
			<REGON>123456789</REGON>
			<Firma>Jan Kowalski Broń Masowej Zagłady LTD</Firma>
		</DanePodstawowe>
	</InformacjaOWpisie>
</WynikWyszukiwania>

W obiekt, by wygodnie móc wyciągać z niego wszelkie dane?

1

Powinieneś użyć XSD do tego aby wygenerować klasy Javove, tu masz przykład jak to zrobić w Springu: https://github.com/asciborek/countries-ws

0

Doszukałem się pliku xsd dopiero po zalogowaniu na https://datastore.ceidg.gov.pl/.
W intellij (nie wiem czy w wersji community to jest), po otwarciu pliku xsd po wybraniu tools -> JAXB -> Generate Java code from XML Schema using JAXB... można sobie wygenerować klasy reprezentujące obiekt.

Fragment kodu, może komuś się przyda:

        GetMigrationData201901Response response = dataStoreProviderService.getCompanyData();
        StringReader reader = new StringReader(response.getGetMigrationData201901Result().getValue());
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(WynikWyszukiwania.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            WynikWyszukiwania searchResult = (WynikWyszukiwania) jaxbUnmarshaller.unmarshal(reader);

            System.out.println(searchResult.getInformacjaOWpisie().get(0).getDaneAdresowe().getAdresGlownegoMiejscaWykonywaniaDzialalnosci().getKodPocztowy());
        } catch (JAXBException e) {
            e.printStackTrace();
        }

1 użytkowników online, w tym zalogowanych: 0, gości: 1