Здравствуйте. Данная тема очень слабо раскрыта в Сети поскольку представляет интерес лишь в узких кругах. Чтобы немного восполнить этот пробел, данное место мне видится наиболее подходящим.
Интерфейс CORBA AlarmIRP присутствует во всех системах управления производителей оборудования с которыми мне пришлось столкнуться, поскольку предписан стандартом 3GPP 3G TS 32.106-2. Рассмотрим на примере OSS-RC Ericsson, в чьей документации процесс хоть как-то описан. Для NetAct Nokia и M-2000 Huawei код будет примерно такой же, с отличиями в нюансах реализации одного стандарта. Я постараюсь максимально понятно описать процесс создания приложения для чтения списка аварийных сообщений, но, поскольку, ранее я никогда не писал ничего на Java и не работал с CORBA некоторые детали позволю себе оставить за рамками данной статьи.
Всё приложении можно разбить на 3 части:
Итак, согласно документации IOR хранится в двух местах: в файле
Если быть точным, то метод выше нам вернёт не IOR, а ссылку на NameService (терминология CORBA), которую мы могли бы получить из IOR-файла на web-сервере. Если проще: результат мы будем использовать для инициализации подключения.
Второй этап инициализация объекта подключения ORB:
Теперь у нас есть ссылка на объект к которому мы можем обращаться вызывая его методы. В частности метод get_alarm_list и возвращает нужный нам список. Вот его поисание из 3GPP:
Данный метод получает итератор содержащий список аварий в виде объектов типа StructuredEvent которые затем выводит в консоль alarmPrint(alarm). Запись StructuredEvent содержит заголовок header и, собственно, данные filterable_data. Данные это тоже запись имеющая имя name и значение value. Описание полей тоже есть в стандарте:
Теперь всё это соберём вместе и выведем для примера instance и specific_problem:
Наконец полный код полученного черновика:
Запуск производится командой:
Что в итоге: кроме «фана» я других применений пока не использую. В перспективе есть ещё NotificationIRP — получение событий сразу после их появления, BulkCmIRP — конфигурирование из внешней системы и т.д. Технология аналогичная, но при необходимости можно написать отдельную статью. По этой теме, пожалуй, всё. На вопросы могу ответить в комментариях. Спасибо!
Интерфейс CORBA AlarmIRP присутствует во всех системах управления производителей оборудования с которыми мне пришлось столкнуться, поскольку предписан стандартом 3GPP 3G TS 32.106-2. Рассмотрим на примере OSS-RC Ericsson, в чьей документации процесс хоть как-то описан. Для NetAct Nokia и M-2000 Huawei код будет примерно такой же, с отличиями в нюансах реализации одного стандарта. Я постараюсь максимально понятно описать процесс создания приложения для чтения списка аварийных сообщений, но, поскольку, ранее я никогда не писал ничего на Java и не работал с CORBA некоторые детали позволю себе оставить за рамками данной статьи.
Всё приложении можно разбить на 3 части:
- получение IOR интерфейса
- создание объекта ссылающегося на интерфейс
- вызов методов интерфейса
Итак, согласно документации IOR хранится в двух местах: в файле
/var/opt/ericsson/blkcm/data/bulkcm.nameserviceи на web-сервере
http://«masterhost ip»:80/ior/ExternalNameService.iorВоспользуемся первым способом:
private String readIOR() {
String mastersvc = "/var/opt/ericsson/blkcm/data/bulkcm.nameservice";
File f = new File(mastersvc);
BufferedReader br;
String iorContents = null;
try {
br = new BufferedReader(new FileReader(f));
iorContents = br.readLine();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return iorContents;
}
Если быть точным, то метод выше нам вернёт не IOR, а ссылку на NameService (терминология CORBA), которую мы могли бы получить из IOR-файла на web-сервере. Если проще: результат мы будем использовать для инициализации подключения.
Второй этап инициализация объекта подключения ORB:
public void createAlarmObj(){
org.omg.CORBA.Object rootObj = null;
NamingContextExt rootNameCon = null;
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitRef", "NameService=" + readIOR());
org.omg.CORBA.ORB orb = ORB.init(new String[0], props);
// Resolve the CORBA Naming Service
try {
rootObj = orb.resolve_initial_references("NameService");
rootNameCon = NamingContextExtHelper.narrow(rootObj);
String s = "com/ericsson/nms/fm_cirpagent/AlarmIRP";
//Locate Alarm IRP
rootObj = rootNameCon.resolve(rootNameCon.to_name(s));
_alarmIrp = com.ericsson.irp.AlarmIRPSystem._AlarmIRPOperationsHelper.narrow(rootObj);
} catch (InvalidName | NotFound | CannotProceed | org.omg.CosNaming.NamingContextPackage.InvalidName e) {
e.printStackTrace();
}
}
Теперь у нас есть ссылка на объект к которому мы можем обращаться вызывая его методы. В частности метод get_alarm_list и возвращает нужный нам список. Вот его поисание из 3GPP:
This method returns Alarm Informations. If flag is
TRUE, all returned Alarm Informations shall be in AlarmInformationSeq
that contains 0,1 or more Alarm Informations. Output parameter iter
shall be useless. If flag is FALSE, no Alarm Information shall be
in AlarmInformationSeq. IRPAgent needs to use iter to retrieve them.
public void getActiveAlarms(){
BooleanHolder flag = new BooleanHolder(false); // false for iteration
com.ericsson.irp.AlarmIRPSystem.AlarmInformationIteratorHolder iter = new com.ericsson.irp.AlarmIRPSystem.AlarmInformationIteratorHolder();
try {
_alarmIrp.get_alarm_list(alarmFilter, flag, iter);
EventBatchHolder alarmInformation = new EventBatchHolder();
short alarmSize = 100;
List<StructuredEvent> alarms = new ArrayList<StructuredEvent>();
boolean haveMoreAlarms = false;
do{
if (iter.value != null) {
haveMoreAlarms = iter.value.next_alarmInformations(alarmSize, alarmInformation);
alarms.addAll(Arrays.asList(alarmInformation.value));
}
}while (haveMoreAlarms);
for (StructuredEvent alarm: alarms) {
alarmPrint(alarm);
}
}
} catch (GetAlarmList | ParameterNotSupported | InvalidParameter | NextAlarmInformations e) {
e.printStackTrace();
}
}
Данный метод получает итератор содержащий список аварий в виде объектов типа StructuredEvent которые затем выводит в консоль alarmPrint(alarm). Запись StructuredEvent содержит заголовок header и, собственно, данные filterable_data. Данные это тоже запись имеющая имя name и значение value. Описание полей тоже есть в стандарте:
const string NV_NOTIFICATION_ID =«a»;
const string NV_CORRELATED_NOTIFICATIONS = «b»;
const string NV_EVENT_TIME = «c»;
const string NV_SYSTEM_DN = «d»;
const string NV_MANAGED_OBJECT_CLASS = «e»;
const string NV_MANAGED_OBJECT_INSTANCE= «f»;
const string NV_SPECIFIC_PROBLEM = «i»;
…
Теперь всё это соберём вместе и выведем для примера instance и specific_problem:
private void alarmPrint(StructuredEvent alarm){
String result = ""
if (alarm.filterable_data != null) {
for (Property filterableData: alarm.filterable_data) {
String fieldName = filterableData.name;
switch (fieldName){
case "f":
result = result + filterableData.value.extract_string() + ";";
break;
case "i":
result = result + filterableData.value.extract_string();
break;
}
}
}
System.out.println(result);
}
Наконец полный код полученного черновика:
Полный код
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.omg.CORBA.*;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.CosNotification.EventBatchHolder;
import org.omg.CosNotification.Property;
import org.omg.CosNotification.StructuredEvent;
import com.ericsson.irp.AlarmIRPSystem.GetAlarmList;
import com.ericsson.irp.AlarmIRPSystem.InvalidParameter;
import com.ericsson.irp.AlarmIRPSystem.NextAlarmInformations;
import com.ericsson.irp.AlarmIRPSystem.ParameterNotSupported;
public class AlarmClient {
private com.ericsson.irp.AlarmIRPSystem._AlarmIRPOperations _alarmIrp = null;
public static void main(String[] args) {
AlarmClient ac = new AlarmClient();
ac.createAlarmObj();
ac.getActiveAlarms();
}
private String readIOR() {
File f = new File("/var/opt/ericsson/blkcm/data/bulkcm.nameservice");
BufferedReader br;
String iorContents = null;
try {
br = new BufferedReader(new FileReader(f));
iorContents = br.readLine();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return iorContents;
}
public void createAlarmObj(){
org.omg.CORBA.Object rootObj = null;
NamingContextExt rootNameCon = null;
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitRef", "NameService=" + readIOR());
org.omg.CORBA.ORB orb = ORB.init(new String[0], props);
// Resolve the CORBA Naming Service
try {
rootObj = orb.resolve_initial_references("NameService");
rootNameCon = NamingContextExtHelper.narrow(rootObj);
String s = "com/ericsson/nms/fm_cirpagent/AlarmIRP";
//Locate Alarm IRP
rootObj = rootNameCon.resolve(rootNameCon.to_name(s));
_alarmIrp = com.ericsson.irp.AlarmIRPSystem._AlarmIRPOperationsHelper.narrow(rootObj);
//System.out.println(_alarmIrp);
} catch (InvalidName | NotFound | CannotProceed | org.omg.CosNaming.NamingContextPackage.InvalidName e) {
e.printStackTrace();
}
}
public void getActiveAlarms(){
BooleanHolder flag = new BooleanHolder(false); // false for iteration
com.ericsson.irp.AlarmIRPSystem.AlarmInformationIteratorHolder iter = new com.ericsson.irp.AlarmIRPSystem.AlarmInformationIteratorHolder();
try {
_alarmIrp.get_alarm_list("", flag, iter);
EventBatchHolder alarmInformation = new EventBatchHolder();
short alarmSize = 100;
List<StructuredEvent> alarms = new ArrayList<StructuredEvent>();
boolean haveMoreAlarms = false;
do{
if (iter.value != null) {
haveMoreAlarms = iter.value.next_alarmInformations(alarmSize, alarmInformation);
alarms.addAll(Arrays.asList(alarmInformation.value));
}
}while (haveMoreAlarms);
if (iter.value != null) {
for (StructuredEvent alarm: alarms) {
alarmPrint(alarm);
}
}
} catch (GetAlarmList | ParameterNotSupported | InvalidParameter | NextAlarmInformations e) {
e.printStackTrace();
}
}
private void alarmPrint(StructuredEvent alarm){
String result = "";
if (alarm.filterable_data != null) {
for (Property filterableData: alarm.filterable_data) {
String fieldName = filterableData.name;
switch (fieldName){
case "f":
result = result + filterableData.value.extract_string() + ";";
break;
case "i":
result = result + filterableData.value.extract_string();
break;
}
}
}
System.out.println(result);
}
}
Запуск производится командой:
java -cp .:/opt/ericsson/fm_core/classes/alarmirp.jar AlarmClient
Что в итоге: кроме «фана» я других применений пока не использую. В перспективе есть ещё NotificationIRP — получение событий сразу после их появления, BulkCmIRP — конфигурирование из внешней системы и т.д. Технология аналогичная, но при необходимости можно написать отдельную статью. По этой теме, пожалуй, всё. На вопросы могу ответить в комментариях. Спасибо!
sensem
Спасибо за статью. Как человек, бившийся с CORBA почти год, узнал во многом себя.
Жаль, Вы не добрались до вывода NV_EVENT_TIME: в этом поле зашит сюрприз в виде огромного целого числа, эквивалентного сотням наносекунд(!), прошедших с 15 октября 1582 года. Пришлось пилить метод для преобразования этого числа в нормальную дату:
Есть очень много интересных вещей, связанных с CORBA у Ericsson, Huawei и Nokia (особенно те, что касаются NotificationIRP).
Tinkz Автор
Спасибо за отзыв, дату я выводил:
NotificationIRP в итоге тоже победил, но да, пришлось повозиться.