Показаны сообщения с ярлыком Oracle SOA. Показать все сообщения
Показаны сообщения с ярлыком Oracle SOA. Показать все сообщения
, , ,

Как получить доступ к Oracle SOA Suite Worklist’у с помощью удаленного Java-клиента (Часть 2)

пятница, 20 ноября 2009 г. 1 коммент.

В первой части я рассмотрел способ соединения SOAP_CLIENT, теперь рассмотрим способ соединения REMOTE_CLIENT. Собственно все тоже, за исключением некоторых особенностей. В файле wf_client_config.xml необходимо, чтобы содержимое секции ejb было корректным. Почему нужно проверить секцию ejb можно прочитать в Oracle® BPEL Process Manager Developer's Guide, в главе 16.6 Building Clients for Workflow Services.

Следует убедиться, что содержимое элемента serverurl корректное. Правильное значение можно найти в элементе jndi.url в файле:

SOA_Oracle_Home\bpel\utilities\ant-orabpel.properties

Подробнее об этом можно почитать здесь. Секция ejb в файле должна иметь такой вид:

  opmn:ormi://soahost:6006:oc4j_soa/hw_services
oc4jadmin
welcome1
oracle.j2ee.rmi.RMIInitialContextFactory

Также следует изменить способ подключения.
// ...
IWorkflowServiceClient wfSvcClient = WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT);
// ...

На этом все изменения закончены, можно пользоватся новым подключением.
Читать полностью

, , ,

Как получить доступ к Oracle SOA Suite Worklist’у с помощью удаленного Java-клиента (Часть 1)

пятница, 9 октября 2009 г. 0 коммент.

Сначала показалось, что это простая задача: есть примеры в интернете, в руководстве Oracle, на блогах технических специалистов. Но, оказалось, что количество препонов настолько велико, что наскока решить эту задачу не удалось.

Итак существует несколько способов соединения:

  • JAVA_CLIENT – доступ к Workflow сервису напрямую с помощью Java (устаревший способ для версии 11.1.1);
  • LOCAL_CLEINT – доступ к Workflow сервису напрямую с помощью EJB;
  • REMOTE_CLIENT – доступ к Workflow сервису удаленно с помощью EJB;
  • SOAP_CLIENT – доступ к Workflow сервису удаленно с помощью SOAP;
  • WSIF_CLIENT – доступ к Workflow сервису удаленно с помощью WSIF (устаревший способ для версии 11.1.1);

Рассмотрим подробно способ соединения SOAP_CLIENT.

Для проекта мне понадобились библиотеки (вроде бы порядок важен):

  • bpm-infra.jar
  • orabpel-common.jar
  • orabpel-thirdparty.jar
  • orabpel.jar
  • oc4jclient.jar
  • jazncore.jar
  • xml.jar
  • xmlparserv2.jar
  • orasaaj.jar
  • soap.jar
  • orabpel-boot.jar
  • bpm-services.jar
  • wsclient_extended.jar (это файл надо взять с OTN)

Кроме библиотек понадобиться файл wf_client_config.xml. Данный файл необходимо включить в class-path вашего приложения. Файл можно скопировать с сервера, где установлен BPEL по следующему пути:

SOA_Oracle_Home\bpel\system\services\config\wf_client_config.xml

Следует убедиться, что содержимое элемента taskService корректное, указанный url доступен, и открывается форма для вызова веб-сервиса:

SOA_Oracle_Home\bpel\utilities\ant-orabpel.properties

Подробнее об этом можно почитать здесь. Секция taskService в файле должна иметь такой вид:



http://soahost:7777/integration/services/TaskService/TaskServicePort

Одного файла wf_client_config.xml достаточно для запуска приложения, но при этом будут выдаваться предупреждения:

<::> ORABPEL-30028
<::>
<::> Invalid configuration file wf_config.xml
<::> The configuration file wf_config.xml not be read.
<::> Make sure that the configuration file wf_config.xml is available and is a valid XML document. Contact oracle support if error is not fixable.

Чтобы избежать не нужных предупреждений необходимо в приложение добавить следующие файлы, и включить их в class-path:

  • SOA_Oracle_Home\bpel\system\services\config\wf_config.xml
  • SOA_Oracle_Home\bpel\system\services\schema\wf_config.xsd

При соединение к сервису workflow необходимо правильно указать параметры аутентификации. В моем случае это:

  • Логин: bpeladmin
  • Пароль: welcome1
  • Рилм(Realm): myrealm

Правильно значение realm можно подсмотреть в атрибуте realmName элемента configuration секции ISConfigaration\configurations файле:

SOA_Oracle_Home\bpel\system\services\config\is_config.xml

При запуске программы можно получить ошибку:

java.lang.SecurityException: class "com.collaxa.cube.LoggerException"'s signer information does not match signer information of other classes in the same package

или

java.lang.SecurityException: class "com.collaxa.cube.ExceptionIndex"'s signer information does not match signer information of other classes in the same package

или похожую.

Все дело в версии Java. Ошибка возникает только в версии 1.5 и связано с багом, возникающим, когда классы в одном пакете подписаны по разному или не подписаны вообще. Для запуска необходимо использовать версию 1.4 или 1.6.

Ну вот наконец-то добрались до самого кода:

package wl_test;

import java.util.ArrayList;
import java.util.List;

import oracle.bpel.services.workflow.client.IWorkflowServiceClient;
import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;
import oracle.bpel.services.workflow.query.ITaskQueryService;
import oracle.bpel.services.workflow.task.model.Task;

import java.util.Iterator;

import oracle.bpel.services.workflow.repos.Ordering;
import oracle.bpel.services.workflow.repos.Column;
import oracle.bpel.services.workflow.repos.Predicate;
import oracle.bpel.services.workflow.repos.TableConstants;
import oracle.bpel.services.workflow.repos.table.WFTaskConstants;
import oracle.bpel.services.workflow.task.ITaskService;

import oracle.bpel.services.workflow.task.model.IdentityType;
import oracle.bpel.services.workflow.verification.IWorkflowContext;

public class app {

private static final String WF_MANAGER = "bpeladmin";
private static final String WF_PASSWORD = "welcome1";
private static final String WF_REALM = "myrealm";

public static void main(String[] args) {

try {
System.out.println("Пытаемся создать WorkflowServiceClient");
IWorkflowServiceClient wfSvcClient = WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.SOAP_CLIENT);
System.out.println("Создали WorkflowServiceClient");

System.out.println("Получаем TaskQueryService");
ITaskQueryService querySvc = wfSvcClient.getTaskQueryService();
System.out.println("Получили TaskQueryService");

System.out.println("Пытаеся пройти аутенсификацию");
IWorkflowContext ctx = querySvc.authenticate
(WF_MANAGER, // администратор
WF_PASSWORD,// пароль
WF_REALM, // realm, ldap каталог
null); // Работать из под другого пользователя

//Задаем колонки для выборки
List displayColumnsList = new ArrayList();
displayColumnsList.add("TASKNUMBER");
displayColumnsList.add("TITLE");
displayColumnsList.add("PRIORITY");
displayColumnsList.add("STATE");
displayColumnsList.add("OUTCOME");
displayColumnsList.add("EXPIRATIONDATE");
displayColumnsList.add("UPDATEDDATE");
displayColumnsList.add("UPDATEDBY");
displayColumnsList.add("CREATEDDATE");
displayColumnsList.add("CREATOR");
displayColumnsList.add("ASSIGNEEUSERS");
displayColumnsList.add("ASSIGNEEGROUPS");
displayColumnsList.add("ACQUIREDBY");
displayColumnsList.add("IDENTIFICATIONKEY");
displayColumnsList.add("PROCESSNAME");


//Сериализуем предикаты
Predicate.enableXMLSerialization(true);
// Добавляем условия
// 1. Ищем по названию процесса
Predicate filterPredicate = new Predicate(
TableConstants.WFTASK_PROCESSNAME_COLUMN,
Predicate.OP_EQ,
"test_wf");
// 2. Ищем по номеру задачи
filterPredicate.addClause(
Predicate.AND,
TableConstants.WFTASK_TASKNUMBER_COLUMN,
Predicate.OP_EQ,
"10431");

// Добавляем условия для сортировки
Column sortFieldColumn = Column.getColumn(WFTaskConstants.TEXTATTRIBUTE2_COLUMN);
boolean isAscending = false;
// Nulls в конец...
boolean isNullFirst = false;
Ordering taskOrdering = new Ordering(sortFieldColumn,isAscending,isNullFirst);

// Запрашиваем задачи
List tasks = querySvc.queryTasks
(ctx, // workflow context
displayColumnsList, // колонки для выборки
null, // Не запрашивать доп. информацию
ITaskQueryService.ASSIGNMENT_FILTER_ADMIN,
null, // Нет ключевого слова
filterPredicate, // Условия для выборки
taskOrdering, // Условие сортировки
0, // Не задаем сколько записей хотим получить
0 // Не задаем сколько записей хотим получить
);

// Получить доступ к сервису задач
ITaskService taskSvc = wfSvcClient.getTaskService();

// Посмотрим сколько у нас записей
System.out.println("tasks.size()=" + tasks.size() + "=");
for (int i=0;i<tasks.size();i++)
{
Task thisTask = (Task) tasks.get(i);
List assigneeUsers = thisTask.getSystemAttributes().getAssigneeUsers();
Iterator valueUsers = (assigneeUsers).iterator();

// Перезапросим задачу, чтобы получить полную информацию о задаче
thisTask = querySvc.getTaskDetailsById(ctx, thisTask.getSystemAttributes().getTaskId());

// Посмотрим результат
System.out.println("getSystemAttributes().getOutcome()="+
thisTask.getSystemAttributes().getOutcome() + "=" );
// Посмотрим состояние
System.out.println("getSystemAttributes().getState()="+
thisTask.getSystemAttributes().getState() + "=" );
// Посмотрим ID задачи
System.out.println("getSystemAttributes().getTaskId()="+
thisTask.getSystemAttributes().getTaskId() + "=" );
// Посмотрим номер задачи
System.out.println("getSystemAttributes().getTaskNumber()="+
thisTask.getSystemAttributes().getTaskNumber() + "=" );
// Посмотри название процесса
System.out.println("getProcessName()="+
thisTask.getProcessInfo().getProcessName()+ "=" );

// Посмотрим пользователей, которые участвуют в этой задаче
while (valueUsers.hasNext())
{
String listItem = ((IdentityType) valueUsers.next()).getId();
System.out.println("User=" + listItem);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

За дополнительной информацией можно обратиться сюда:


Читать полностью

, , ,

Удаление BPEL Instance’ов и Human Task’ов.

четверг, 8 октября 2009 г. 0 коммент.

Иногда надо почистить BPEL инстансы и очень хочется, чтобы это происходило автоматически. Для ручного удаления можно воспользоваться BPEL консолью, но там есть большой недостаток – не возможно удалить все дерево связанных процессов. Чтобы это можно было сделать я написал небольшой пакетик. Одна процедура удаляет Human Task’и, другая связанные BPEL инстансы и Human Task’и.


create or replace package bpel_enhancement is

procedure delete_ci( p_cikey in cube_instance.cikey%type
,p_ignore_root in boolean default false
);

procedure delete_wt(p_taskid in wftask.taskid%type
);

end bpel_enhancement;
/
create or replace package body bpel_enhancement is

procedure delete_ci( p_cikey in cube_instance.cikey%type
,p_ignore_root in boolean default false
)
is
vi pls_integer;
begin

-- Проверим сначала, что инстанс не имеет родителей
select count(1)
into vi
from cube_instance
start with cube_instance.cikey = p_cikey
connect by to_char(cube_instance.cikey) = prior to_char(cube_instance.parent_id);

if (vi = 0) then
raise_application_error(-20000, 'Не найден инстанс "' || p_cikey || '"');
elsif (vi > 1) then
if not p_ignore_root then
raise_application_error(-20000, 'Найдены родительские процессы для инстанса "' || p_cikey || '"');
end if;
end if;

-- начинаем удалять иерархически в обратном порядке
for vCur in (
select cube_instance.*
from cube_instance
start with cube_instance.cikey = p_cikey
connect by prior to_char(cube_instance.cikey) = to_char(cube_instance.parent_id)
order by level desc
) loop
-- Удаляем инстанс
dbms_output.put_line('Удаление истанса: "' || vCur.Cikey || '" -- "' || vCur.Title || '"');
collaxa.delete_ci(p_cikey => vCur.cikey);

-- Ищем связанные задачи
for vCurTask in (
select *
from wftask
where wftask.instanceid = vCur.cikey
) loop

dbms_output.put_line('Удаление задачи: "' || vCurTask.Taskid || '" -- "' || vCurTask.Tasknumber || '"');
delete_wt(vCurTask.Taskid);
end loop;
end loop;

end delete_ci;

procedure delete_wt(p_taskid in wftask.taskid%type
)
is
begin
delete from wftaskhistory where taskid = p_taskid;
delete from wfassignee where taskid = p_taskid;
delete from wfattachment where taskid = p_taskid;
delete from wfcomments where taskid = p_taskid;
delete from wfmessageattribute where taskid = p_taskid;
delete from wfnotification where taskid = p_taskid;
delete from wfnotificationmessages where taskid = p_taskid;
delete from wfroutingslip where taskid = p_taskid;
delete from wftasktimer where taskid = p_taskid;

delete from wftask where taskid = p_taskid;
end delete_wt;

end bpel_enhancement;
/

Читать полностью

, , , ,

Таймаут при вызове bpel-процесса

среда, 18 марта 2009 г. 0 коммент.

При вызове сервиса в Oracle BPEL cтолкнулся с такой ошибкой "java.lang.IllegalStateException: Cannot call setRollbackOnly() current thread is NOT associated with a transaction".

Ошибку также можно найти в логе по следующему пути:
"SOA_Oracle_Home\opmn\logs\".
Смотрим файл лога для контейнера в котором крутиться BPEL.

Поиск по документации привел к следующему решению.
A.1.1 Setting Properties for BPEL Processes to Successfully Complete and Catch Exception Errors

Следует обратить внимание не следующие особенности:
1. Параметр transaction-timeout в файле "SOA_Oracle_Home\j2ee\home\config\transaction-manager.xml".
1.1. На самом деле необходимо изменять файл, который повлияет на контейнер в котором крутиться bpel, т.е. правильный путь будет "SOA_Oracle_Home\j2ee\КОНТЕЙНЕР_ГДЕ_КРУТИТЬСЯ_BPEL\config\transaction-manager.xml"
1.2. Для исталяции одинокого Oracle BPEL Process Manager файл надо искать здесь "SOA_Oracle_Home\bpel\system\appserver\oc4j\j2ee\home\config".
2. Параметр transaction-timeout в файле "SOA_Oracle_Home\j2ee\home\application-deployments\orabpel\ejb_ob_engine\orion-ejb-jar.xml".
2.1. Также надо искать по другому пути.
"SOA_Oracle_Home\j2ee\КОНТЕЙНЕР_ГДЕ_КРУТИТЬСЯ_BPEL\application-deployments\orabpel\ejb_ob_engine\orion-ejb-jar.xml".
2.2. Обязательно поменять параметр во всем файле, он встречается несколько раз, для каждого бина.
3. Параметр syncMaxWaitTime в "SOA_Oracle_Home\bpel\domains\domain_name\config\domain.xml"
3.1. Не забываем поменять параметр для каждого домена.

Перестартовываем Application Server.

Иногда при длительном ожидании ответа от bpel-процесса, можно поймать ошибку "500 Server Error". В данном случае ругается Apache.
Что бы увеличить таймаут ожидания, находим параметр Timeout в файле "SOA_Oracle_Home\Apache\Apache\conf\httpd.conf" и увеличиваем значение. Перестартовываем Apache. Читать полностью

, , ,

Как получить userName из WS-Security soap-заголовка, способ 2

вторник, 17 февраля 2009 г. 0 коммент.

Я уже писал тут, как можно получить userName из soap-заголовка.
Теперь это можно сделать еще одним способом, зарегистрировав свой custom step в wsm.
Для этого в wsm идем по этой дорожке "Policy Management > Manage Policies > Steps", нажимаем "Add New Step" и указываем путь к конфигурационному xml-файлу своего custom step'а.

В файле указываем название шага, java-пакет, который реализует наш шаг, идентификатор, и одно свойство "Enabled" - разрешен или запрещен шаг.


<csw:StepTemplate
xmlns:csw="http://schemas.confluentsw.com/ws/2004/07/policy"
name="owsmcustomstep"
package="test_owsmcustomstep"
timestamp="Oct 15, 2007 05:00:00 PM"
version="1"
id="200902051">

<csw:Description>Custom step test</csw:Description>

<csw:Implementation>test_owsmcustomstep.CustomTestStep</csw:Implementation>

<csw:PropertyDefinitions>
<csw:PropertyDefinitionSet name="Basic Properties">
<csw:PropertyDefinition name="Enabled" type="boolean">
<csw:Description>If set to true, this step is enabled</csw:Description>
<csw:DefaultValue>
<csw:Absolute>true</csw:Absolute>
</csw:DefaultValue>
</csw:PropertyDefinition>
</csw:PropertyDefinitionSet>
</csw:PropertyDefinitions>
</csw:StepTemplate>

Ниже представлен класс, который реализует custom step.
Сначала получаем сообщение, возвращаем его в виде XML-документа. Находим имя пользователя и элемент, куда запишем это имя. После этого создаем новое сообщение на основе измененного XML-документа и возвращаем его.

package test_owsmcustomstep;

import com.cfluent.policysteps.sdk.AbstractStep;
import com.cfluent.policysteps.sdk.IMessageContext;
import com.cfluent.policysteps.sdk.IResult;
import com.cfluent.policysteps.sdk.Result;
import com.cfluent.policysteps.sdk.Fault;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

import org.apache.axis.message.SOAPEnvelope;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class CustomTestStep extends AbstractStep {
private PrintWriter out = null;

public CustomTestStep() {
}

public void init() throws IllegalStateException {
try {
out = new PrintWriter(new BufferedWriter(new FileWriter("log/CustomTestStep.log", true)));
}
catch (Exception e) {
String errMsg = "Error in creating log file for custom step:" + e.getMessage();
System.err.println(errMsg);
e.printStackTrace();
throw new IllegalStateException(errMsg);
}
}

/**
* Used for cleaning up any resources created in the init() method
* It is called during server shutdown or when the policy is updated.
*/
public void destroy() {
out.close();
}

private void log(String str) {
try {
Date d = new Date();
DateFormat df = new SimpleDateFormat("HH:mm:ss yyyy/MM/dd");

out.println(df.format(d) + ":1158: " +str);
out.flush();
} catch (Exception ex) {
System.err.println("Exception encountered when writing to file");
ex.printStackTrace();
}
}

private void logSOAPMessage(SOAPMessage soapMsg) {
String msg = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
soapMsg.writeTo(baos);
msg = baos.toString();
log("CustomTestStep: Request SOAP message is " + msg);
} catch (Exception ex) {
System.err.println("Exception encountered while converting SOAP message to a String");
ex.printStackTrace();
}
}

public IResult execute(IMessageContext messageContext) throws Fault {
log("CustomTestStep: Entering");

IResult resultStatus = new Result();
resultStatus.setStatus(IResult.FAILED);

try {
//Getting the SOAPMessage object from the context
SOAPMessage soapMessage = messageContext.getRequestMessage();
// loging request
logSOAPMessage(soapMessage);

SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = (SOAPEnvelope)soapPart.getEnvelope();

String namespaceURI_soap = "http://schemas.xmlsoap.org/soap/envelope/";
String namespaceURI_wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

// get XML-Document
Document document = soapEnvelope.getAsDocument();
Element rootElement = document.getDocumentElement();
// element, where put username
Element elementInput = null;
String username = null;

// search username
if(rootElement != null) {
Element header = getToken(rootElement, "Header", namespaceURI_soap);
if(header != null) {
Element securityHeader = getToken(header, "Security", namespaceURI_wsse);
if(securityHeader != null) {
Element usernameTokenElement = getToken(securityHeader, "UsernameToken", namespaceURI_wsse);
if(usernameTokenElement != null) {
Element usernameElement = getToken(usernameTokenElement, "Username", namespaceURI_wsse);
if(usernameElement != null) {
username = usernameElement.getTextContent();
}
}
}
}
}

// search element
if(rootElement != null) {
String namespaceURI_ns1 = "http://xmlns.oracle.com/test_soap";
Element body = getToken(rootElement, "Body", namespaceURI_soap);
if(body != null) {
elementInput = getToken(body, "input", namespaceURI_ns1);
}
}

if (username != null && elementInput != null) {
elementInput.setTextContent(username);
}

//Convert the Document object to a String Object
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
DOMSource domSource = new DOMSource(document);
StringWriter strWriter = new StringWriter();
StreamResult streamResult = new StreamResult(strWriter);
transformer.transform(domSource, streamResult);
String xmlString = strWriter.toString();

//Convert this string object to a SOAPMessage object
MessageFactory messageFactory = MessageFactory.newInstance();
MimeHeaders mimeheaders = new MimeHeaders();
mimeheaders.addHeader("Content-Type", "text/xml");

// IMPORTANT : The following is very important especially if your
// SOAP message would contain UTF-8 data like European characters etc.
ByteArrayInputStream soapByteArrayInputStream = new ByteArrayInputStream(xmlString.getBytes("UTF-8"));
SOAPMessage newSoapMessage = messageFactory.createMessage(mimeheaders, soapByteArrayInputStream);

//Set the SOAP Request back into the context
messageContext.setRequestMessage(newSoapMessage);

// logging new request
logSOAPMessage(messageContext.getRequestMessage());
log("CustomTestStep: Exiting");
resultStatus.setStatus(IResult.SUCCEEDED);

} catch (Exception ex) {
String errMsg = ex.getMessage();
log("CustomTestStep: Error:" + errMsg);
generateFault(errMsg);
}

return resultStatus;
}

private Element getToken(Element parentElement, String tokenName, String tokenNameSpaceURI)
{
Element token = null;
NodeList nodeList = parentElement.getElementsByTagNameNS(tokenNameSpaceURI, tokenName);
if (nodeList != null) {
token = (Element)nodeList.item(0);
}
return token;
}

}

Примеры для создания custom step в WSM можно найти на metalink:How To read a SOAP Message into an XML Document & back into a SOAP Message?

Читать полностью

, , ,

Соответсвие WSDL рекомендациям WS-I версии 1.1

понедельник, 26 января 2009 г. 0 коммент.

Обычная ситуация: делаешь сервисы, они хорошо работают.
Но тут приходит время использование сервисов внешними системами и оказывается, что сделанные сервисы не соответсвуют рекомендациям WS-I и хоть это и рекомендации, но внешние системы все эти рекомендации соблюдают, а твои сервисы нет. :(

Рассмотрим один случай. Есть WSDL.


<?xml version="1.0" encoding="UTF-8"?>
<definitions
name="test_wsdl"
targetNamespace="http://xmlns.oracle.com/test_wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns1="http://xmlns.oracle.com/test_scheme"
xmlns:client="http://xmlns.oracle.com/test_wsdl">
<!--> start cut
...
end cut </!-->
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://xmlns.oracle.com/test_scheme"
schemaLocation="test_scheme.xsd"/>
</xsd:schema>
<!--> start cut
...
end cut </!-->
</types>
<message name="test_wsdl_getdata1RequestMessage">
<part name="payload" element="ns1:Request"/>
</message>
<message name="test_wsdl_getdata1ResponseMessage">
<part name="payload" element="ns1:Response"/>
</message>
<message name="test_wsdl_getdata2RequestMessage">
<part name="payload" element="ns1:Request"/>
</message>
<message name="test_wsdl_getdata2ResponseMessage">
<part name="payload" element="ns1:Response"/>
</message>
<!--> start cut
...
end cut </!-->
<portType name="test_wsdl">
<operation name="getdata1">
<input message="tns:test_wsdl_getdata1RequestMessage"/>
<output message="tns:test_wsdl_getdata2ResponseMessage"/>
</operation>
<operation name="getdata2">
<input message="tns:test_wsdl_getdata2RequestMessage"/>
<output message="tns:test_wsdl_getdata2ResponseMessage"/>
</operation>
<!--> start cut
...
end cut </!-->
</portType>
<binding name="test_wsdlBinding" type="tns:test_wsdl">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getdata1">
<soap:operation style="document" soapAction="subscribe"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="getdata2">
<soap:operation style="document" soapAction="getdata"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<!--> start cut
...
end cut </!-->
</binding>
<service name="test_wsdl">
<port name="test_wsdlPort" binding="tns:test_wsdlBinding">
<soap:address
location="http://myhost:80/orabpel/domain_test/test_wsdl/1.0"/>
</port>
</service>
<plnk:partnerLinkType name="test_wsdl">
<plnk:role name="test_wsdlProvider">
<plnk:portType name="tns:test_wsdl"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>

Проверяем wsdl программкой взятой с родного сайта: Interoperability Testing Tools 1.1

Assertion: BP2120
Failure Detail Message
getdata1,
getdata2
Element Location: lineNumber=96

В логе видим, что пункт "BP2120" не выполнен. Ошибка вот в этой строке:

<binding name="test_wsdlBinding" type="tns:test_wsdl">

Читаем про это: Test Assertion: BP2120
Хм, в байдинге не уникальные операции. Читаем дальше требования:
R2710

4.7.6 Operation Signatures

Definition: operation signature

The profile defines the "operation signature" to be the fully qualified name of the child element of SOAP body of the SOAP input message described by an operation in a WSDL binding.

In the case of rpc-literal binding, the operation name is used as a wrapper for the part accessors. In the document-literal case, since a wrapper with the operation name is not present, the message signatures must be correctly designed so that they meet this requirement.

An endpoint that supports multiple operations must unambiguously identify the operation being invoked based on the input message that it receives. This is only possible if all the operations specified in the wsdl:binding associated with an endpoint have a unique operation signature.

R2710The operations in a wsdl:binding in a DESCRIPTION MUST result in operation signatures that are different from one another.


Оказывается все просто. Точка входа (вызова) должна быть однозначно определена, в нашем случае part и element одинаковые для операций getdata1 и getdata2.

<message name="test_wsdl_getdata1RequestMessage">
<part name="payload" element="ns1:Request"/>
</message>

<message name="test_wsdl_getdata2RequestMessage">
<part name="payload" element="ns1:Request"/>
</message>

Изменеяем схему, добавляем новый элемент Request2, копию Request1 и используем его.

<message name="test_wsdl_getdata1RequestMessage">
<part name="payload" element="ns1:Request"/>
</message>
<message name="test_wsdl_getdata2RequestMessage">
<part name="payload" element="ns1:Request2"/>
</message>
Читать полностью

, , ,

Как получить userName из WS-Security soap-заголовка

четверг, 22 января 2009 г. 0 коммент.

Иногда в BPEL-процессе необходимо знать, какой пользователь вызвал этот web-сервис. Хорошо, когда имя пользователя передается в структуре сообщения, но когда имя пользователя необходимо получить из заголовка soap-сообщенини, то возникают небольшие трудности. Дело осложняется, если сервис защищен, например OWSM, с авторизацией в каком-нибудь LDAP-каталоге. Посмотрим как их можно решить.

Посмотрим на рисунок.



В этом "PipeLine" выполняются шаги по извлечению информации для авторизации "Extract Credentials", аутентификации "Ldap Authenticate" и авторизации "Ldap Authorize".
После выполнения шага "Extract Credentials" из сообщения удаляется информация о пользователе и пароле, поэтому чтобы получить необходимую информацию, добавим шаг "XML Transform", где укажем свою xsl-трансформацию.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:ns1="http://xmlns.oracle.com/test_soap"
version="1.0" >
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns1:input">
<xsl:element name="{name()}">
<xsl:value-of select="/soap:Envelope/soap:Header/wsse:Security/wsse:UsernameToken/wsse:Username"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Трансформация копирует сообщение один в один за исключением одного элемента "ns1:input", в этом элемент мы копируем имя пользователя. Читать полностью