Java-клиент JAX-WS, функциональная совместимость службы WCF: «400: неверный запрос» - PullRequest
5 голосов
/ 24 февраля 2012

Я также задавал этот вопрос на форуме Mirth .

В настоящее время мы пытаемся подключиться к службе WCF с помощью механизма интеграции здравоохранения с открытым исходным кодом Mirth.Mirth основан на Java, использует Mule для внутреннего использования, который использует JAX-WS.Сервер WCF возвращает код состояния HTTP «400: неверный запрос».У нас нет легкого доступа к серверу WCF.

Связь с клиентом хорошо работает в C #.В Visual Studio добавьте ссылку на службу, а затем в main ():

PatientRegistryQueryFulfiller.GetDemographicsClient svc = new PatientRegistryQueryFulfiller.GetDemographicsClient();
doc.Load(@"C:\MirthTesting\PRPA_EX201307NO_10_PatientReg_GetDemographics.xml");
PatientRegistryQueryFulfiller.PRPA_IN201307NO patientRegistryRequest = (PatientRegistryQueryFulfiller.PRPA_IN201307NO)ObjectSerializer.DeserializeObject(doc, typeof(PatientRegistryQueryFulfiller.PRPA_IN201307NO));
PatientRegistryQueryFulfiller.PRPA_IN201307NOResponse patientRegistryResponse = svc.GetDemographics(patientRegistryRequest);
doc = ObjectSerializer.SerializeObject(patientRegistryResponse.Item);

У автоматически сгенерированного клиента WCF (из WSDL) есть файл app.config с конечной точкой и эта привязка:

<bindings>
    <basicHttpBinding>
        <binding name="PatientRegistryQueryFulfiller_Binding" closeTimeout="00:01:00"
         openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
         allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
         maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
         messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
         useDefaultWebProxy="true">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="655360"
           maxBytesPerRead="4096" maxNameTableCharCount="655360" />
        <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"
             realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

Единственное, что делается по-другому в WCF-решении, - это расширение maxNameTableCharCount и maxArrayLength в теге readerQuotas для рассматриваемой привязки, остальное остается со значениями по умолчанию.Однако я не нашел способа установить их в Mirth, если это действительно является причиной ошибки.

Мы запускаем Mirth v 2.2.1 (самая последняя проверка), а Mirth Channel -установите для чтения и отправки документа HL7v3.Проблема возникает только при попытке связаться с WCF-сервисом.Назначением является отправитель веб-службы, и служба, и порт считываются из WSDL.Нет аутентификации, и конверт генерируется из единственной доступной операции.Мы не используем MTOM.

Мы совершенно уверены, что это связано с совместимостью JAX-WS и WCF.Есть общие советы?

Мы пробовали устанавливать свойства для соединения JAX-WS.В недрах веселья мы попытались установить размер куска http: dispatch.getRequestContext (). Put (JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192) (строка 140 WebServiceMessageDispatcher.Java):

ERROR-410: Web Service Connector error
ERROR MESSAGE: Error connecting to web service.
com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 400: Bad Request
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.checkStatusCode(Unknown Source)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(Unknown Source)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(Unknown Source)
at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Unknown Source)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Unknown Source)
at com.sun.xml.internal.ws.client.Stub.process(Unknown Source)
at com.sun.xml.internal.ws.client.dispatch.DispatchImpl.doInvoke(Unknown Source)
at com.sun.xml.internal.ws.client.dispatch.DispatchImpl.invoke(Unknown Source)
at com.mirth.connect.connectors.ws.WebServiceMessageDispatcher.processMessage(WebServiceMessageDispatcher.java:176)
at com.mirth.connect.connectors.ws.WebServiceMessageDispatcher.doDispatch(WebServiceMessageDispatcher.java:106)
at com.mirth.connect.connectors.ws.WebServiceMessageDispatcher.doSend(WebServiceMessageDispatcher.java:204)
at org.mule.providers.AbstractMessageDispatcher.send(AbstractMessageDispatcher.java:164)
at org.mule.impl.MuleSession.sendEvent(MuleSession.java:191)
at org.mule.impl.MuleSession.sendEvent(MuleSession.java:130)
at org.mule.routing.outbound.AbstractOutboundRouter.send(AbstractOutboundRouter.java:85)
at org.mule.routing.outbound.FilteringMulticastingRouter.route(FilteringMulticastingRouter.java:54)
at org.mule.routing.outbound.OutboundMessageRouter$1.doInTransaction(OutboundMessageRouter.java:78)
at org.mule.transaction.TransactionTemplate.execute(TransactionTemplate.java:48)
at org.mule.routing.outbound.OutboundMessageRouter.route(OutboundMessageRouter.java:82)
at org.mule.impl.model.DefaultMuleProxy.onCall(DefaultMuleProxy.java:247)
at org.mule.impl.model.seda.SedaComponent.doSend(SedaComponent.java:209)
at org.mule.impl.model.AbstractComponent.sendEvent(AbstractComponent.java:277)
at org.mule.impl.MuleSession.sendEvent(MuleSession.java:201)
at org.mule.routing.inbound.InboundMessageRouter.send(InboundMessageRouter.java:176)
at org.mule.routing.inbound.InboundMessageRouter.route(InboundMessageRouter.java:143)
at org.mule.providers.AbstractMessageReceiver$DefaultInternalMessageListener.onMessage(AbstractMessageReceiver.java:487)
at org.mule.providers.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:266)
at org.mule.providers.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:225)
at com.mirth.connect.connectors.vm.VMMessageReceiver.getMessages(VMMessageReceiver.java:223)
at org.mule.providers.TransactedPollingMessageReceiver.poll(TransactedPollingMessageReceiver.java:108)
at org.mule.providers.PollingMessageReceiver.run(PollingMessageReceiver.java:97)
at org.mule.impl.work.WorkerContext.run(WorkerContext.java:290)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:575)
at java.lang.Thread.run(Unknown Source)

1 Ответ

3 голосов
/ 06 марта 2012

Мы нашли решение. Длинное описание решения на форуме Мирт .

Проблема заключалась в том, что веб-службы выдавали нам «400: плохой запрос», когда мы пытались отправить ему запрос, который, по нашему мнению, имел смысл. «400 неверных запросов» - это очень общая и не очень информативная ошибка.

Решение для тестирования

Это решение создает отладочный жгут для тестирования на основе файлов, который можно использовать, чтобы понять, что делает Mirth. Это не качественное решение. YMMV.

  • Установить Мирт
  • Загрузите файлы WSDL веб-службы (например, EncounterManager) и поместите их под Миртом Server \ public_html \ EncounterManager, чтобы Mirth могла их разместить.
  • В указанном выше локальном файле WSDL измените его и убедитесь, что Действие SOAP в конце указывает на фактический веб-сервис:

мыло: адрес Местонахождение = "http://your -server / HL7Connector / GetDemographicsService30 /" /

  • Перезапустите Mirth, если он уже запущен.
  • В Mirth Connect создайте новый канал, например Отправитель
  • Только для тестирования, сделайте Source этого канала средством чтения файлов который читает что-то в (например, идентификатор пациента из текста файл). Например, сделайте опрос C: \ MirthTesting \ unread . Скажи Мирту переместить файл после его завершения в C: \ MirthTesting \ read
  • На сводной странице нового преобразователя нажмите «Задать типы данных».
  • Установить типы данных для входящего соединителя источника = Текст с разделителями , Исходящий соединитель источника = HL7 , Исходящий пункт 1 = Текст с разделителями . Это только для тестирования, позже вы можете сделать что-то необычное в HL7.
  • В источнике нажмите Изменить трансформатор .
  • Нажмите «Добавить новый шаг», введите имя новой переменной «Patient IdWanted» и введите для сопоставления « messageObject.getRawData () ». Это заставляет Мирта прочитать содержимое любого текстового файла, который вы поместили в каталог «Непрочитанные» и поместили в переменную, которую вы сможете использовать позже (в карту каналов)
  • Превратите пункт назначения вашего нового канала в отправителя веб-службы . Введите URL-адрес локального WSDL (например, http://localhost:8080/EncounterManager/EncounterManagerQueryFulfiller.wsdl)
  • Нажмите «Получить операции», затем «Создать конверт».
  • SOAP-конверт очень большой и полон бессмысленного HL7 (для меня). Замените его на простой пример, который работает, и удалите все ненужные лжи HL7. Ваш провайдер должен дать вам рабочий пример.
  • Теперь вам нужно поместить переменные, которые вы прочитали на этапе чтения файлов, в конверт SOAP. Ваш конверт SOAP должен содержать «полезную нагрузку», например, идентификатор пациента где-то. Для запроса GetDemographics это выглядело так (часть его). Обратите внимание, что $ {PatientIdWanted} - это место, где Mirth заменяет значение в шаблоне из того, что мы поместили в карту каналов из текстового файла выше.
  • Теперь сохраните этот канал.
  • Создайте новый канал, чтобы получать то, что вам отправил веб-сервис на предыдущем шаге. Назовите это Приемник
  • В новом канале установите для всех типов данных значение «Текст с разделителями». Опять же, просто для тестирования.
  • Установите источник канала "Receiver" на "Channel reader"
  • Установите назначение нового канала на File writer . Введите каталог и имя файла, например, C: \ MirthTesting \ чтения \ WebService-response.txt . В шаблоне введите $ {message.rawData} , чтобы увидеть все, что есть у Mirth.
  • Вернитесь на канал Отправитель , выберите пункт назначения, введите канал Получатель в качестве пункта назначения ответа.
  • Сохранение изменений, проверка разъема, повторное развертывание всех каналов.
  • Теперь создайте текстовый файл с идентификатором пациента и поместите его в C: \ MirthTesting \ unread
  • Mirth прочитает этот файл (затем переместит его в каталог «read»). Ваш первый канал получит текстовый файл, переместит содержимое в карту каналов $ {PatientIdWanted} . Ваш веб-сервис получит конверт SOAP с этим идентификатором пациента. Ответ будет отправлен на канал Receiver и выведен в виде простого текста.

Материал, который был полезен

  • Понимая, что Мирт - это ядерная субмарина: мощная и таинственная. Нет руководства!
  • Будучи несколько опытным в C # и Java
  • Имея примеры сообщений HL7, которые имеют смысл
  • Использование Visual Studio для генерации чистого клиента C # для проверки того, что мы можем читать из веб-службы с простым C #. (Мы использовали Mirth для размещения файлов WSDL, но вы могли использовать IIS)
  • Использование Eclipse для генерации Java-клиента, чтобы убедиться, что мы можем читать из веб-сервиса с Java. Мы использовали SOAPUI (так же, как использует Mirth) с Eclipse Indigo EE edition (из командной строки, использующей wsimport.bat)
  • Загрузка Mirth из исходного кода и запуск его из Eclipse.
  • Включение дампа HTTP (в Eclipse). Введите в разделе «Run config» аргументы VM. Это позволяет вам точно увидеть, что Mirth (или ваш Java-клиент) отправляет в веб-сервис: -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump = истина

  • Добавьте сценарий предварительной обработки в канал отправителя, чтобы увидеть, что на самом деле делает Mirth:

    FileUtil.write('C:/MirthTesting/read/sender_preprocessmessage_in.txt', false, message);return message;
    
  • Добавьте скрипт постобработки в канал отправителя, чтобы увидеть, что делает Mirth:

    FileUtil.write('C:/MirthTesting/read/dipssender_postprocessmessage.txt', false, message);
    return;
    

Одно изменение кода

Чтобы на самом деле сделать это, мы должны были сделать одно изменение в исходном коде Mirth. С JDK1.7, который мы использовали, Мирт фактически не отправлял действие SOAP. В строке 137 Server /.../ WebServiceMessageDispatcher.Java нам пришлось добавить:

    dispatch.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, true);

(взято из этого блога )

...