, , ,

Как получить доступ к 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;
/

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

,

Результат Select’а в виде одной строки и одна строка в виде набора строк

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

Часто бывает необходимо получить результат выборки в виде одной строки, разделенных каким-нибудь разделителем. Обычно всегда пишем для этого свои агрегирующие функции. Но бывает, что так, что запрещено создавать свои типы и пакеты, и результат необходимо получить чистым select’ом с использованием стандартных функций.

Вот пару способов это сделать. Примеры выполнены в схеме SCOTT.

SQL> select ltrim(max(sys_connect_by_path(ename, ',')), ',')
2 from (
3 select emp.ename,
4 row_number() over (order by emp.ename) as rn
5 from emp
6 where emp.job = 'SALESMAN'
7 )
8 start with rn = 1
9 connect by prior rn = rn-1;

LTRIM(MAX(SYS_CONNECT_BY_PATH(
--------------------------------------------------------------------------------
ALLEN,MARTIN,TURNER,WARD

SQL>

Еще один способ.

SQL> select rtrim(extract(xmlagg(xmlelement(x, ename||',') order by emp.ename),'//X/text()').getstringval(), ',')
2 from emp
3 where emp.job = 'SALESMAN';

RTRIM(EXTRACT(XMLAGG(XMLELEMEN
--------------------------------------------------------------------------------
ALLEN,MARTIN,TURNER,WARD

SQL>

Еще пару раз приходилось делать наоборот, есть строка, со значениями, и их надо превратить в набор строк со значениями. Ниже несколько способов, как это сделать.


SQL> select emp.empno, emp.ename
2 from emp
3 where emp.ename in
4 (
5 with t as (
6 select ltrim('ALLEN,MARTIN,TURNER,WARD'/*:p_list*/, ',') || ',' as s,
7 rownum as rn
8 from emp /* или all_objects, здесь можно emp*/
9 )
10 select substr(t.s,
11 lag(instr(t.s, ',', 1, rn), 1, 0) over (order by instr(t.s, ',', 1, rn)) + 1,
12 instr(t.s, ',', 1, rn) - lag(instr(t.s, ',', 1, rn), 1, 0) over (order by instr(t.s, ',', 1, rn)) - 1
13 ) as str
14 from t
15 where instr(t.s, ',', 1, rn) != 0
16 );

EMPNO ENAME
----- ----------
7499 ALLEN
7521 WARD
7654 MARTIN
7844 TURNER

SQL>

Еще один способ.


SQL> select emp.empno, emp.ename
2 from emp
3 where emp.ename in
4 (
5 with t as (
6 select '' || replace('ALLEN,MARTIN,TURNER,WARD', ',', '') || '' s
7 from dual
8 )
9 select extractvalue(value(row_data), '/X')
10 from t,
11 table(xmlsequence(extract(xmltype(t.s), '/Y/X'))) row_data
12 );

EMPNO ENAME
----- ----------
7499 ALLEN
7654 MARTIN
7844 TURNER
7521 WARD

SQL>

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