Механизм хранения файлов в сибеле на примере файлов прикладываемых к шаблону письма

Загруженные в сибель файлы хранятся в сжатом виде. Чтобы их получить программным способом необходимо сначала распаковать нужный файл во временный каталог, считать его и так далее, потом удалить. Хорошая статья на эту тему: http://it.toolbox.com/blogs/siebel-answers/reading-an-attachment-file-using-siebel-escript-getfile-method-26360

тут описывается ручное прикрепление файла к отправляемому письму http://siebel.ittoolbox.com/groups/technical-functional/siebel-dev-l/outbound-mail-with-attachment-3893707

Если коротко, то используется БС.InvokeMethod("GetFile", "CommFileName") где параметр это имя поля где хранится имя файла (на рисунке ниже данное поле называется "Атачмент Нэйм")

Применительно к файлам прикладываемым к шаблону письма (навигатор \ Administration - Communications > All Templates):

Вот пример кода:

var boCommPackage:BusObject=TheApplication().GetBusObject("Comm Package");
var bcCommPackageItem:BusComp=boCommPackage.GetBusComp("Comm Package Item");

bcCommPackageItem.ClearToQuery();
bcCommPackageItem.SetViewMode(AllView);
// bcCommPackageItem.ActivateField("Subject Text");
bcCommPackageItem.SetSearchSpec("Id","1-AJSYRY")
bcCommPackageItem.ExecuteQuery();

var sGetFileReturn = "";
var sAbsoluteFileName = "";
var sStatus = "";
var oFile;

sGetFileReturn = bcCommPackageItem.InvokeMethod("GetFile", "CommFileName");

//TheApplication().RaiseErrorText(sGetFileReturn);
sStatus = sGetFileReturn.substring(0, sGetFileReturn.indexOf(","));

if (sStatus == "Success")//if GetFile was successful...
{
sAbsoluteFileName = sGetFileReturn.substring(sGetFileReturn.indexOf(",") + 1);
//open the file for reading
oFile = Clib.fopen(sAbsoluteFileName,"rt");
if ( oFile == null )
TheApplication().RaiseErrorText("Error opening file for reading. ");

//throw contents of the file to error message
var buff:Buffer = new Buffer(100 , false , true);
var a=Clib.fread(buff, 115, oFile);
TheApplication().RaiseErrorText(buff.toString());
var Result = Clib.remove(sAbsoluteFileName) ;//del tmp file. Clib.system("rm " + sAbsoluteFileName);
Clib.fclose(oFile);
oFile = null;

buff=null;
}
bcCommPackageItem=null;
boCommPackage=null;

Дополнение "работа с файлами":

var oFile = Clib.fopen("C:\\myfile.txt","r");//Clib.fopen("filename.txt", "rwu"). Use this mode for both ASCII and non-ASCII characters.
if (oFile==null)
TheApplication().RaiseErrorText("oFile is null");

var msg=Clib.fgets(oFile);
TheApplication().RaiseErrorText(msg);

var buff:Buffer = new Buffer(100 , false , true);
//http://docs.oracle.com/cd/B31104_02/books/eScript/eScript_JSReference19.html
Clib.fread(buff, 115, oFile);
TheApplication().RaiseErrorText(buff.toString());

var i;
Clib.fread(i, SWORD8, oFile)
TheApplication().RaiseErrorText(i);

var bl:Blob;
//http://docs.oracle.com/cd/B40099_02/books/eScript/eScript_JSReference16.html#wp1003708
Clib.fread(bl, 10, oFile);
TheApplication().RaiseErrorText(Blob.get(bl,0,1000));

Clib.fclose(oFile);

Вызов JAVA-кода из Siebel

Вызов JAVA-кода из Siebel

всё неплохо расписано в: http://docs.oracle.com/cd/E14004_01/books/EAI3/EAI3_EAIJBS.html ( EAI Java Business Service)

Если коротко, то пишем джава код и компилируем обычный (не Runable) джарник. При этом надо помнить, что наш класс должен наследоваться от "extends com.siebel.eai.SiebelBusinessService", а исключение поднимать только как "throw new SiebelBusinessServiceException("NOT_INT", "Noninteger passed");".

Весь наш код должен располагаться в метода doInvokeMethod (там есть ещё деструктор Destroy - см документацию. Джава-класс создаётся сибелем при загрузке и всё время существует в памяти)

Пример простейшего джава кода

package ru;

import com.siebel.data.SiebelPropertySet;
import com.siebel.eai.SiebelBusinessServiceException;

public class AddBusinessService extends com.siebel.eai.SiebelBusinessService {

public void doInvokeMethod(String methodName, SiebelPropertySet input,
SiebelPropertySet output) throws SiebelBusinessServiceException {
String X = input.getProperty("X");
String Y = input.getProperty("Y");
if (X == null || X.equals("") || (Y == null) || Y.equals(""))
throw new SiebelBusinessServiceException("NO_PAR", "Missing param");

if (!methodName.equals ("Add"))
throw new SiebelBusinessServiceException("NO_SUCH_METHOD", "No such method");
else {
int x = 0;
int y = 0;
try {
x = Integer.parseInt(X);
y = Integer.parseInt(Y);
}
catch (NumberFormatException e) {
throw new SiebelBusinessServiceException("NOT_INT", "Noninteger passed");
}

int z = x + y;
output.setProperty("Z", new Integer(z).toString());
}
}
}

Далее мы настраиваем сибель

Мобильный клиент (в cfg-файле):

[JAVA]
DLL = C:\Program Files\Java\jre6\bin\client\jvm.dll
CLASSPATH = "C:\SiebelJars\SimpleJava.jar;C:\SiebelJars\SiebelJI_enu.jar;C:\SiebelJars\Siebel.jar;."
VMOPTIONS = -Xrs -Djava.compiler=NONE

Большой клиент:

Сибель не был бы сибелем если бы в нём всё было сделано нормально. Вышеприведённый аплет не вмещает строку ClassPath до конца (максимальный размер 1024 символа). То есть если вы скопируете её и потом вставите обратно, то получите болт(так строчки classpath по факту будут отличаться). Настоящую строчку classpath можно увидеть в файле (внимание он обновляется после каждого перезапуска сибеля. Это информационный файл)  /u02/siebel/gtwysrvr/sys/siebns.dat. Обязательно сохраните эту строчку перед изменением, чтобы потом вы могли вернуться.

Пример строчки с нашего боя /u01/siebel/siebsrvr/classes/Siebel.jar:/u01/siebel/siebsrvr/classes/SiebelJI_enu.jar:/u01/siebel/siebsrvr/classes/sqljdbc_1.2/enu/sqljdbc.jar:/u01/siebel/siebsrvr/classes/CROC/IntegraBusServ.jar:/u01/siebel/siebsrvr/classes/CROC/sbj/SiebelSmsInform.jar:/u01/siebel/siebsrvr/classes/CROC/sbj/SmsInformDownloadFromCisco.jar

То есть на конце строчки ничего нет. Это для aix-системы

Далее мы создаём БС оборачивающий наш класс. Для этого надо создать копию с БС "EAI Java Business Service"

пример вызова самописной БС оборачивающей самописный класс (см пример джава-кода выше)

var inpPS: PropertySet = TheApplication().NewPropertySet();
var outPS: PropertySet = TheApplication().NewPropertySet();
var bs:Service = TheApplication().GetService("TAlexJavaBS");
inpPS.SetProperty("X","1");
inpPS.SetProperty("Y","2");
bs.InvokeMethod("Add", inpPS, outPS);
TheApplication().RaiseErrorText(outPS.GetProperty("Z"));
outPS=null; inpPS=null;bs=null;

Несколько замечаний по смене templates из apllet escript

Из серверных и браузерных скриптов аплета можно переключаться между его шаблонами вызывая стандартные методы


  • this.InvokeMethod("CloseApplet");   закрыть popup applet из кода

  • this.InvokeMethod("ExecuteQuery"); - выполнить поиск

  • WriteRecord, NewQuery, NewRecord и так далее.

Задача: в query-шаблоне поиска есть какое-то поле, не имеющееся на БК. Распарсив которое можно выполнить корректный запрос.

Решение:

0)Кнопка "найти" вызывает метод MyExecuteQuery

1)В браузерном скрипте аплета мы передаём значение этого поля в серверный скрипт

function Applet_PreInvokeMethod (name, inputPropSet)
{
if ((name=="MyExecuteQuery")||(name == "ExecuteQuery")){
theApplication().SetProfileAttr("QFIO", this.FindControl("QFIO").GetValue());
}
return ("ContinueOperation");
}

2)В серверном скрипте аплета мы вытаскиваем сохранённое значение. Так как поиск должен запускаться и по нажатию кнопки и по нажатию энтера из поля, то мы должны отлавливать два метода (стандартный ExecuteQuery и мой MyExecuteQuery).

function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
{

if ((MethodName == "MyExecuteQuery")||(MethodName == "ExecuteQuery"))
{
CanInvoke = "TRUE";
return CancelOperation;
}

return (ContinueOperation);
}

function WebApplet_PreInvokeMethod (MethodName)

{
if ((MethodName == "MyExecuteQuery")||(MethodName == "ExecuteQuery")){
var QFIO=TheApplication().GetProfileAttr("QFIO");
/*парсим поле QFIO и на основе него формируем запрос (
this.BusComp().ClearToQuery(); this.BusComp().ActivateField("...");
var se="([Id] is not null)";
if (ln!="") se=se+"and [Last Name] like '"+ln+"*'";
if (QInegrationId!="") se=se+"and [Integration Id]='"+QInegrationId+"'";
this.BusComp().SetSearchExpr(se);
*/
if (MethodName=="MyExecuteQuery"){
this.InvokeMethod("ExecuteQuery");
return (CancelOperation);
}
if (MethodName=="ExecuteQuery"){
return (ContinueOperation);
}
}
return (ContinueOperation);
}

Браузерные скрипты. Заметки

Общение с пользователем из браузерного скрипта (и передача данных в серверный скрипт)
function Applet_PreInvokeMethod (name, inputPropSet)
{
if (name=="SetDateContact"){
//TheApplication().SWEAlert("11111");
var today = new Date();
var curDate = today.getDate()+ "." + (today.getMonth()+1) + "." +
today.getYear() + " " + today.getHours() + ":" + today.getMinutes() + ":" +
today.getSeconds();
var name = prompt("Введите дату/время контакта с клиентом в формате дд.мм.гггг чч:мм:сс:",curDate);
// Проверка введенного пользователем значения
if(name != null && name.length>0)
{
TheApplication().SetProfileAttr("DatContact", name);
}
else
{
// Пользователь нажал отмену, ничего не делаем
TheApplication().SetProfileAttr("DatContact", "no");
}
}
Общение с пользователем из браузерного скрипта
var name = prompt("Введите ваше имя:","имя");   // Отобразить диалоговое окно с блоком ввода и сохранить введенное в переменную. if(confirm("Вас зовут "+name+"?!")) // Окно с подтверждением ввода
Передача данных между браузерным и серверным скриптом
В браузерном скрипте TheApplication().SetProfileAttr("DatContact", name);
В серверном var DatContact=TheApplication().GetProfileAttr("DatContact");
Пример работы с контролами на аплете в браузерном скрипте
Пример браузерного скрипта на аплете меняющего свойства (цвет и шрифт) контрола.
Описание: на аплете есть два контрола "Bank Information Source" и "Bank Information Source Alter". Нужно в зависимости от значения одного из них (первого) установить цвет и свойства "только для чтения" второго контрола
function Applet_ChangeFieldValue (field, value)
{
if (field == "Bank Information Source"){
var oCtrlAnother = this.FindControl("Bank Information Source Alter"); //получаем контрол с аплета для работы
if (value == "Другое"){
oCtrlAnother.SetLabelProperty("FontColor", "#ff0000");
oCtrlAnother.SetLabelProperty("FontWeight", "bold");
oCtrlAnother.SetProperty("ReadOnly","false");
}
else{
oCtrlAnother.SetLabelProperty("FontColor", "#000000");
oCtrlAnother.SetLabelProperty("FontWeight", "normal");
oCtrlAnother.SetProperty("ReadOnly","true");
oCtrlAnother.SetValue("");
}
}
Необходимо помнить следующие вещи:
1) Если в бразуерном скрипте ошибка синтаксиса, то никаких сообщений не будет. Просто бразуерный скрипт не запустится (сразу запустится серверный, если он есть).
2) Тулсы выгружают бразуерные скрипты по пути описанному в View\Options\Scripting
3) На большом сервере браузерные скрипты должны лежать в:
/u02/siebel/siebsrvr/webmaster/enu
/u02/siebel/siebsrvr/webmaster/rus
/u02/siebel/sweapp/public/enu
/u02/siebel/sweapp/public/rus

Создание иконок для лист-аплета

Сначала создаём "Bitmap Category"

"Alt Text" - текст, который будет заменяться на соответствующую картинку. Только английский текст. Файлики можно брать с различным расширением. Если формат файла bmp, то его можно импортировать через правую кнопку мыши по строчке. Файлы других форматов должны лежать там, где лежит сибель-сервер в папке .../public/код языка/images

2)Создаём "Icon Map"

3)так как у нас поле которое я хочу показывать в виде иконок содержит русский текст, то придётся создать на БК калькулируемое поле на основ нужного нам поля и на аплете выводить уже его. Выражение для калькуруемого поля будет следующим: IIF([TAlexStatus]='завершено','0',IIF([TAlexStatus]='актуально','1',IIF([TAlexStatus]='не актуально','2',2)))

4)Создаём поле на аплете

Обратите внимание: здесь указывается "icon map", а не "bitmap category".

5)И вот как это всё выглядит:

ссылки:

Создаём кнопку для запуска сначала браузерного, а потом серверного скрипта на аплете

Основополагающий серверный скрипт разрешающий нажатие на кнопку вызывающую метод указанный в МетодНайм

function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
{
if ((MethodName=="RunENU")||(MethodName=="RunRUS")){
CanInvoke = "TRUE";
return CancelOperation;
}
return (ContinueOperation);
}

Дополнительный серверный скрипт выполняющий какие-то действия (получает инф из бразуерного скрипта и выводит на экран)

function WebApplet_PreInvokeMethod (MethodName)
{
var WorkFlowNameForStart="no workflow name";
if ((MethodName=="RunENU")||(MethodName=="RunRUS")){
var WorkFlowNameForStart = TheApplication().GetProfileAttr("WorkFlowNameForStart");
//TheApplication().RaiseErrorText(WorkFlowNameForStart);
}
if (MethodName=="RunENU"){
return (CancelOperation);
}
if (MethodName=="RunRUS"){
return (CancelOperation);
}
return (ContinueOperation);
}

браузерный скрипт передающий инф из поля ввода в серверный скрипт путём помещения её в атрибут профиля пользователя

function Applet_PreInvokeMethod (name, inputPropSet)
{
if ((name=="RunENU")||(name=="RunRUS")){
var WfName = this.FindControl("WfName").GetValue();
//TheApplication().SWEAlert(WfName);
theApplication().SetProfileAttr("WorkFlowNameForStart", WfName);
}
return ("ContinueOperation");
}

свойства кнопки на аплете

Создание двух БК в пределах одного БО связанных отношением master-detail

Создаём два БК: SettingsMainTableBC и SettingsSlaveTableBC. Каждый из них имеет поле Pul Numberпо которому и будет осуществляться связь. Оба эти бк добавлены в объект SettingsMainSlaveBO (главным бк для него установлен SettingsMainTableBC).

Также создана связь(Link). Так как у нас отношение один ко многим (а не многие ко многим) то промежуточная таблица (inner table) не используется.

Содержимое БО у нас следующее:

теперь если мы создаём по лист-аплету настроенному на каждый из БК и представление, настроенное на БО, то у нас автоматом получится связь вида master-detail.

Работа в коде с бк связанными отношениями мастре-детайл аналогичными указанным выше

связь идёт по полю id_dpt. Оно должно быть активировано, чтобы в дочернем БК полученном черезтот же БО можно было получить записи относящиеся к главному БК

var bo:BusObject=TheApplication().GetBusObject("BO Kos");
var bcKos:BusComp =bo.GetBusComp("BC Kos");
bcKos.ClearToQuery();
bcKos.SetViewMode(AllView);
bcKos.ActivateField("id_dpt");//активируем поле, по которому идет линк между БК
bcKos.SetSearchSpec("Id", Inputs.GetProperty("id"));//ставим на текущую в главном
bcKos.ExecuteQuery();

var childBC:BusComp =bo.GetBusComp("BC Kos Child");
childBC.ActivateField("Name");
childBC.SetSearchSpec("Name","*");//задаем диапазон
childBC.ExecuteQuery();

Работа в коде с БК связанными в пределах одного БО

БО Comm Package имеет главный БС Comm Package и ещё один БС Comm Package Item

Два простых правила:


  • Активируем поля в БК до поиска(ExecuteQuery), если хотим получить(GetFieldValue) их значения после поиска. Активируем поля БК после поиска если хотим установить(SetFieldValue / WriteRecord) их значения в коде.

  • Если в коде создать два (имеющих связь) БК в пределах одного БО, а потом сделать поиск по одному БК, то второй автоматом получит требуемый набор записей. Но это только если объявлять БК до поиска.

var boCommPackage:BusObject=TheApplication().GetBusObject("Comm Package");
var bcCommPackage:BusComp=boCommPackage.GetBusComp("Comm Package");
var bcCommPackageItem:BusComp=boCommPackage.GetBusComp("Comm Package Item");  <===========объявлять БК до поиска
bcCommPackageItem.ActivateField("CommFileSrcPath");
bcCommPackageItem.ActivateField("Name");

bcCommPackage.ClearToQuery();
bcCommPackage.SetViewMode(AllView);
bcCommPackage.ActivateField("Subject Text");
bcCommPackage.ActivateField("Template Text");
bcCommPackage.SetSearchSpec("Name","TAlexTestTemplate")
bcCommPackage.ExecuteQuery(); <=======================поиск по главному БК
var SubjectText=bcCommPackage.GetFieldValue("Subject Text");
var TemplateText=bcCommPackage.GetFieldValue("Template Text");

bcCommPackageItem.NextRecord(); <======================в другом БК уже получен набор записей
bcCommPackage=null;bcCommPackageItem=null;
boCommPackage=null;

Пример создания БК, БО на стороне Siebel CRM и outbound-адаптера на стороне IBM WebSphere MB

В тулсах на стороне сибеля

Создаём таблицу в бд сибеля с двумя пользовательскими полями (D - числовое и Str - строковое). Не забывайте сначала заставить тулсы создать таблицу в базе (кнопка apply/ddl) и активировать её (вторая кнопка)

на основе этой таблицы создаём БК. Причём культурно создаём, через контекстное меню, визард и так далее

Создаём новый БО. Добавляем в него созданный на предыдущем шаге БК и делаем его главным для данного БО (ибо он там единственный)

Все созданные объекты надо добавить в репозиторий и подложить на сервер сибеля под русскую и английскую (это самое важное) версии

В тулките на стороне шины

Создаём поток используя ноду сибелёвского адаптера

далее выбираем проект подключения к сибелёвскому серверу (или создаём проект подключения если  у нас раньше его не было).

Примечание: для создания нового проекта подключения вам понадобятся файлы Siebel.jar и SiebelJI_enu.jar (взять с сервера сибеля)

Далее надо будет выбрать (или создать, там кнопочка "new...") мессаджсет (message set) для адаптера, который необходимо диплоить вместе с ним, при любом изменении набора полей выбираемых адаптером из БК на стороне сибеля.

Примеры работы с адаптером

Вот такой у нас мессаджсет получился

ESQL-код в компуте-ноде

declare myns namespace 'http://www.ibm.com/xmlns/prod/wbi/j2ca/siebel/BOTestObjBCTestComp1';

CREATE COMPUTE MODULE flow1_Compute
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
CREATE FIELD OutputRoot.DataObject.myns:BOTestObjBCTestComp1;
DECLARE custref REFERENCE TO OutputRoot.DataObject.myns:BOTestObjBCTestComp1;
set custref.Str='ppoott';
set custref.D=6666;
RETURN TRUE;
END;
END MODULE;

вот так выглядит группа выполнения с нашим потоком:

1)Создание новой записи

до входа в адаптер:

на выходе из адаптера:

Как видно появилось ай-ди новосозданной записи

2)Поиск записей

set custref.Str='*';

на входе в адаптер(говорим, что искать все записи имеющие не пустое поле Str):

Также можно подавать "pon*" или "*on*" и так далее и любой набор полей. Все поданные поля будут участвовать в поиске

на выходе из адаптера мы получаем все найденные записи:

работать с ними можно с помощью следующей конструкции (взято из другого проекта).

InputRoot.DataObject.phoneContainer:BOAlternatePhoneBCAlternatePhoneContainer[<].BOAlternatePhoneBCAlternatePhone[I].Address;

Общие сведения об интеграции Siebel CRM с шиной(IBM WebSphere MB) с помощью outbound-адаптеров на ст

Совсем уж общие сведения

В сибеле есть бизнес-компоненты(БК) основывающиеся на одной или нескольких таблиц физически хранящих информацию в БД. Бизнес-объекты(БО) представляют собой объединение нескольких БК, чтобы между ними можно было устанавливать связи вида "родитель-ребёнок", "один к одному", "многие ко многим" и другие.

Существует множество способов интегрировать сибель с чем-то другим (в том числе и с шиной). Далее пойдёт речь только об интеграции с помощью адаптеров на стороне шины выбирающие/обновляющие/создающие/удаляющие записи (экземпляры объектов в терминах ооп) в отдельных БК принадлежащих разным БО.

Настройка шины(IBM WebSphere MB 6.x/7.x) чтобы она могла использовать адаптеры

Чтобы шина могла общаться с сибелем надо сделать следующее:


  1. На сибель-сервере найти файлы Siebel.jar и SiebelJI_enu.jar (возможно лежащие в /siebel/siebsrvr/classes)

  2. Перенести указанные файлы на сервер шины и положить их, например, в /var/mqsi/siebel

  3. После чего на сервере шины выполнить следующие команды "mqsichangeproperties MB_DEV.NSK.MDM.BR -c EISProviders -o Siebel -n jarsURL -v /var/mqsi/siebel/" и  "mqsichangeproperties MB_DEV.NSK.MDM.BR -c EISProviders -o Siebel -n nativeLibs -v /var/mqsi/siebel/"(может быть нужно ещё перезапустить брокер)

  4. Теперь мы можем в среде разработки под шину (WebSphere Message Broker Toolkit - Message Broker) использовать в своих потоках сибелёвские адаптеры

Адаптеры бывают двух типов

  • Inbound (то есть срабатывающие когда на стороне сибеля произошло какое-то событие. Например создали новую запись)

  • Outbound (когда инициатором создания/удаления/обновления/выборки записей является поток на стороне шины). В принципе мы можем использовать только Outbound-адаптеры так как они умеют в том числе и выбирать записи из БК по некоторым условиям.

Этапы создания нового outbound-адаптера в картинках

Создаём в потоке на стороне шины новую ноду , которая будет выглядеть так:

Выбрав ноду (или можно создать адаптер в окошке проектов (слева-сверху по умолчанию) выбрав New \ Adapter Connection).

Обратите внимание на галочку (по умолчанию она не установлена) позволяющую видеть(выбирать) какие поля из БК будут доступны в адаптере. И на "тип объектов сибеля для поиска". Вы можете работать с данными с помощью БО\БК, а можете вызывать бизнес-сервисы.

Обратите внимание на число означающее максимальное число записей выбираемых по операции retriveall (выбрать все удовлетворяющие входным условиям). Вы можете установить этот параметр в -1 (выбирать все, сколько ни есть) или, например, в 999999. Но! Теперь ограничение числа выбирающихся записей устанавливает сам сибель. По умолчанию у него стоит 10 тысяч.

Необходимо понимать, что адаптерам требуется мессаджсет (message set) - один на всех или каждому свой. Мессаджсет, если коротко, это такая штука которая указывает как преобразовывать сообщение перед тем как подать его на вход. В принципе для создания адаптеров вам и не надо знать, что это такое. Просто создайте его (там будет кнопочка "new...")

Примеры использования адаптеров

1)Используем адаптер для выборки данных (для создания/удаления/изменения в целом тоже самое)

следующий код генерирует то, что подаётся на вход адаптеру:

DECLARE CampmemContainerSMS NAMESPACE 'http://www.ibm.com/xmlns/prod/wbi/j2ca/siebel/bocampaignmemberssmsbccampaignmemberssmscontainer';

SET OutputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMS.CampaignId=Environment.CampaignId;
SET OutputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMS.MobilePhone='*';
SET OutputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMS.TreatmentId='*';

на вход адаптера подаётся:

на выходе из адаптера имеем(было выбрано несколько записей удовлетворяющих поданных на вход условиям):

работать с выходными данными можно, например, так

SET J=CARDINALITY(InputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMSContainer.BOCampaignMembersSMSBCCampaignMembersSMS[]);

set Environment.CompMem[II].MobilePhone=REPLACE(InputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMSContainer[<].BOCampaignMembersSMSBCCampaignMembersSMS[II].MobilePhone,'+','');

set Environment.CompMem[II].Id=InputRoot.DataObject.CampmemContainerSMS:BOCampaignMembersSMSBCCampaignMembersSMSContainer[<].BOCampaignMembersSMSBCCampaignMembersSMS[II].Id;

2)небольшое объяснение на примере

Итак, у нас в сибеле есть бк Campaign Members SMS (см картинки из примера 1). Имеющее поле First Name, которое видится на шине под отладкой как . Где же связь между First Name и FirstName? Она в мессаджсете!

открываем файлик (автоматом создаваемый при создании нового адаптера) лежащий по пути C:\Documents and Settings\brkuser\IBM\wmbt70\workspace_zanzara\CollectionMsgSet\CollectionMsgSet\com\ibm\www\xmlns\prod\wbi\j2ca\siebel\bocampaignmemberssmsbccampaignmemberssms\BOCampaignMembersSMSBCCampaignMembersSMS.mxsd  (в данном примере имя БО и его главного БК совпадают. Так получилось просто). И в этом файлике мы видим:

собственно это ещё одна прокладка позволяющая сделать так, чтобы в сибеле поле называлось одним образом, а шина называла его по другому. Также из этого файла можно узнать какие поля из БК видит шина (наверное можно было бы и писать сюда руками если в сибеле на бк добавилось поле, а пересоздавать адаптер на шине не хочется. Правда я этого не пробовал).

Важные замечания на понимание которых у меня ушло немало времени (а вам нужно только прочитать и суметь понять)


  1. Если вы изменили БК, то нужно пересоздать(пункт Interactive Discoverty в контекстном меню если нажать на адптер в окне проектов тулкита) или создать заново адаптер. Задиплоить его в группу выполнения на брокере. И, обязательно, задиплоить мессаджсет ибо именно в нём хранится информация для шины о том какие поля есть на бк и как они называются! В противном случае вы будете использовать старый мессаджсет и долго недоумевать почему он у вас не видит новые поля.

  2. По уму диплоить нужно в таком порядке: мессаджсет, адаптеры, потоки.

  3. Для создания на стороне шины адаптера НЕ НУЖНО создавать интеграционный объект на стороне сибеля (это совсем другое, хотя тоже служит для интеграции, но без шины).

  4. Двойной щелчок по ноде с адаптером открывает окошко где прописываются параметры подключения к серверу сибеля Так вот, если вы захотите их изменить, то надо будет после введения новых перейти в другое поле (или на другую вкладку), потом вернуться и сохранить. Если сохраните сразу, то они не сохранятся. Такой вот суперстранный косяк.

Краткая памятка по созданию join-ов в БК

Существуют Link () для создания связей между БК-ами в отношении один к одному, один ко многим и многие ко многим (через промежуточную таблицу). Но сейчас речь не об этом (smile)

Если нужно в один БК добавить ссылочные поля из другой таблицы (обратите внимание, здесь мы не устанавливаем связи между двумя БК, а устанавливаем связь один к одному между одним БК и какой-то другой таблицей(на основе которой может быть создан другой бк или другие бк или вообще не быть создано ни одного бк. Не имеет значения)).

Пример:

У нас есть БК "Campaign Members SMS". У него есть какие-то свои поля и два важных для нас поля (обратите внимание, что колонка джойн пуста, то есть эти поля физически располагаются на таблице на которой основан наш БК).

По этим полям мы сейчас сделаем связь(один к одному, если надо что-то другое то см Link) БК "Campaign Members SMS" с двумя другими таблицами

                         

В Join Constration можно создать условия чтобы не выбирать из таблиц какие-то записи, но сейчас это не требуется. Мы заходим в Join Specification и создаём там связь

для таблицы S_CONTACT

для таблицы S_PRSP_CONTACT

Теперь мы в нашем БК можем использовать поля из другой таблицы:

Заодно мы создали вычислимое(то есть физически не располагающееся в базе, а вычисляющееся на основе других полей БК) поле заполняющееся или из таблицы S_CONTACT или из таблицы S_PRSP_CONTACT  в зависимости от того где лежат наши данные. Вот вычислимое выражение для поля First Name: IIf ([Contact Id] IS NOT NULL, [Contact First Name], [Prospect First Name])

Подробнее см