java访问华为网管软件iMaster NCE的北向接口

时间:2024-11-04 18:08:50


最近做的一个项目,需要读取华为一个叫iMaster NCE的网管软件的北向接口。这个iMaster NCE(以下简称NCE)用于管理项目的整个网络,尤其是光网络。业主要求我们访问该软件提供的对外接口,读取一些网络信息,比如网元、故障告警、性能等。

NCE的接口提供了多种协议的版本,给过来的资料是基于SOAP的WebService,据说目前最常用的http版本要收费。

基于SOAP的WebService,我以前用.NET的时候搞过。首先要在项目里访问WebService的WSDL,生成一个客户端(代理),然后本地通过此代理对接口进行访问。Java项目也是类似的套路。以下是d调用XML接口的开发步骤介绍,并附上一个读取NCE上告警信息数量的实例。

一、开发前准备

1、选择SOAP中间件

在开始开发之前,需要选择适当的SOAP中间件来实现WebService的客户端。
开源SOAP中间件主要包括:

Apache CXF
Apache AXIS

商业SOAP中间件主要包括:

IBM Websphere
BEA Weblogic

理论上可以*选择任意符合SOAP规范的中间件以进行客户端的开发。华为选择Apache CXF作为服务端中间件,同时建议客户端也采用Apache CXF,以获得最大的兼容性。不过Apache CXF只支持使用JAVA作为编程语言。我们用的正是java,很自然就选用Apache CXF。

2、获取WSDL文件

接入XML接口,首先需要获取WSDL文件。获取WSDL的方式有两种,分别是使用发布文档中打包的WSDL文件,以及直接访问每一个XML接口所在服务地址来获取。可以通过北向XML接口服务地址获取WSDL,比如http://10.71.226.29:9997/ManagedElementRetrieval?wsdl

这种方式一次只能获取一种服务的WSDL。由于厂家直接给了所有WSDL,所以这一步就省了。

3、生成Stub代码

1)生成代码

获取到WSDL文件后,需要通过Apache CXF附带的wsdl2java工具将其转换成JAVA代码。wsdl2java可以到Apache CXF官网下载。需要注意的是,新的版本不支持JDK8,如果还是JDK8,最后的版本是apache-cxf-3.5.9。

生成语句示例:
apache-cxf不需安装,解压即用。

cd D:\soft\develop\wsdl\apache-cxf-3.5.9\bin

wsdl2java -client -xjc-npa -d q:\test2 Q:\wsdl\ManageResourceInventory\IIS\wsdl\TopoViewRetrieval\TopoViewRetrievalHttp.wsdl

生成了一堆代码:

java访问华为网管软件iMaster NCE的北向接口_iMaster NCE

2)创建Stub代码项目

将生成的代码搭建一个项目,比如叫mtop项目。则可以将它生成一个jar包,比如叫mtop.jar。

java访问华为网管软件iMaster NCE的北向接口_SOAP_02

3)应用Stub代码

然后将它放到我们读取NCE的项目中:

java访问华为网管软件iMaster NCE的北向接口_XML接口_03


java访问华为网管软件iMaster NCE的北向接口_SOAP_04

4、后面加入新的接口

上面只是生成了一个wsdl的Stub代码。如果后面需要加入新的wsdl,则如法炮制,先用wsdl2java生成Stub代码,然后将整个代码文件拷贝到Stub项目,遇到同名的忽略,不要覆盖,相当于只拷贝了新增的文件。然后重新生成jar包。

二、示例

以下是一个读取NCE告警数量的示例。

1、基本工具

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.landtool.jbh.entity.Otn;
import com.landtool.jbh.service.OtnService;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import org.tmforum.mtop.fmw.xsd.hdr.v1.CommunicationPatternType;
import org.tmforum.mtop.fmw.xsd.hdr.v1.CommunicationStyleType;
import org.tmforum.mtop.fmw.xsd.hdr.v1.Header;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.xml.ws.Holder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * otn的地址及账号信息,既定义于配置文件,也保存于数据库
 * 从代码可看出,优先级上,数据库 > 配置文件
 */
@Component
public class WebServiceUtil {
    // the type of communication pattern
    private static CommunicationPatternType patternType = CommunicationPatternType.SIMPLE_RESPONSE;
    // the type of communication style
    private static CommunicationStyleType styleType = CommunicationStyleType.RPC;

    // the Web Service URL
    private static String strURL = "http://10.0.2.18:9997/";
    public void setStrUrl(String value) {
        WebServiceUtil.strURL = value;
    }

    // userName
    private static String strUser = "BXuser";
    public void setStrUser(String value) {
        WebServiceUtil.strUser = value;
    }

    // password
    private static String strPassword = "Changeme_147";
    public void setStrPassword(String value) {
        WebServiceUtil.strPassword = value;
    }

    // MD
    private static String strMD = "Huawei/NCE";
    @Value("${data-oc.md}")
    public void setStrMD(String value) {
        WebServiceUtil.strMD = value;
    }
    public static String getStrMD() {
        return WebServiceUtil.strMD;
    }

    @Resource
    private OtnService otnService;

    @PostConstruct
    public void init() {
        Otn otn = new Otn();
        List<Otn> list = this.otnService.queryByPage(otn, PageRequest.of(0, 1000)).getContent();
        if (list.size() > 0) {
            otn = list.get(0);
            setStrPassword(otn.getPassword());
            setStrUser(otn.getAccount());
            setStrUrl(String.format("http://%s:%s/", otn.getIp(), otn.getPort()));
            setStrMD(otn.getNote());
        }
    }

    public static <T> T getWebService(String action, Class<T> clazz) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(clazz);
        Map<String, Object> properties = factory.getProperties();
        if (properties == null) {
            properties = new HashMap<String, Object>();
            factory.setProperties(properties);
        }
        properties.put("set-jaxb-validation-event-handler", Boolean.FALSE);
        factory.setAddress(strURL + action);
        T webservice = (T) factory.create();
        try {
            //TrustHttpsConnection();
            //configureSSLClient(webservice);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return webservice;
    }

    public static Holder<Header> getHeader() {
        Header header = new Header();

        header.setCommunicationPattern(patternType.value());
        header.setCommunicationStyle(styleType.value());
        header.setBatchSequenceNumber(1L);
        header.setRequestedBatchSize(1000L);
        header.setSecurity(strUser + ":" + strPassword);
        return (new Holder<Header>(header));
    }
}

2、应用示例

从下面密密麻麻的import可以看出,大部分都是引用Stub代码的。

import org.springframework.stereotype.Component;
import org.tmforum.mtop.fmw.xsd.gen.v1.NameAndAnyValueType;
import org.tmforum.mtop.fmw.xsd.gen.v1.ObjectEnumType;
import org.tmforum.mtop.fmw.xsd.nam.v1.NamingAttributeType;
import org.tmforum.mtop.fmw.xsd.nam.v1.RelativeDistinguishNameType;
import org.tmforum.mtop.mri.wsdl.mer.v1_0.ManagedElementRetrieval_RPC;
import org.tmforum.mtop.mri.wsdl.tlr.v1_0.GetAllTopLevelTopologicalLinksException;
import org.tmforum.mtop.mri.wsdl.tlr.v1_0.TopologicalLinkRetrievalRPC;
import org.tmforum.mtop.mri.wsdl.tpr.v1_0.GetAllPhysicalTerminationPointsWithoutFtpsException;
import org.tmforum.mtop.mri.wsdl.tpr.v1_0.GetContainedPotentialConnectionTerminationPointsException;
import org.tmforum.mtop.mri.wsdl.tpr.v1_0.TerminationPointRetrievalRPC;
import org.tmforum.mtop.mri.wsdl.tvr.v1_0.GetAllTopoViewNodesInfoException;
import org.tmforum.mtop.mri.wsdl.tvr.v1_0.TopoViewRetrievalRPC;
import org.tmforum.mtop.mri.xsd.mer.v1.GetAllManagedElementsRequest;
import org.tmforum.mtop.mri.xsd.mer.v1.MultipleMeObjectsResponseType;
import org.tmforum.mtop.mri.xsd.tlr.v1.GetAllTopLevelTopologicalLinksRequest;
import org.tmforum.mtop.mri.xsd.tlr.v1.MultipleTlObjectsResponseType;
import org.tmforum.mtop.mri.xsd.tpr.v1.GetAllConnectionTerminationPointsType;
import org.tmforum.mtop.mri.xsd.tpr.v1.GetAllTerminationPointsType;
import org.tmforum.mtop.mri.xsd.tpr.v1.MultipleTerminationPointObjectsResponseType;
import org.tmforum.mtop.mri.xsd.tvr.v1.GetAllTopoViewNodesInfoRequest;
import org.tmforum.mtop.mri.xsd.tvr.v1.GetAllTopoViewNodesInfoResponse;
import org.tmforum.mtop.nra.xsd.alm.v1.AlarmListType;
import org.tmforum.mtop.nra.xsd.alm.v1.AlarmType;
import org.tmforum.mtop.nra.xsd.pm.v1.PerformanceMonitoringParameterNameListType;
import org.tmforum.mtop.nra.xsd.pmdata.v1.PerformanceMonitoringDataType;
import org.tmforum.mtop.nra.xsd.pmmsrt.v1.PerformanceMonitoringMeasurementType;
import org.tmforum.mtop.nra.xsd.pmtgt.v1.ObjectFactory;
import org.tmforum.mtop.nra.xsd.pmtgt.v1.PerformanceMonitoringObjectSelectListType;
import org.tmforum.mtop.nra.xsd.pmtgt.v1.PerformanceMonitoringObjectSelectType;
import org.tmforum.mtop.nrf.xsd.me.v1.ManagedElementType;
import org.tmforum.mtop.nrf.xsd.tl.v1.TopologicalLinkType;
import org.tmforum.mtop.nrf.xsd.topo.v1.NodeType;
import org.tmforum.mtop.nrf.xsd.tp.v1.TerminationPointType;
import org.tmforum.mtop.rpm.wsdl.pmr.v1_0.GetAllCurrentPerformanceMonitoringDataException;
import org.tmforum.mtop.rpm.wsdl.pmr.v1_0.PerformanceManagementRetrieval;
import org.tmforum.mtop.rpm.xsd.pmr.v1.GetAllCurrentPerformanceMonitoringDataRequest;
import org.tmforum.mtop.rpm.xsd.pmr.v1.MultiplePerformanceMonitoringDataObjectsResponseType;
import org.tmforum.mtop.rtm.wsdl.ar.v1_0.AlarmRetrieval;
import org.tmforum.mtop.rtm.wsdl.ar.v1_0.GetActiveAlarmsCountException;
import org.tmforum.mtop.rtm.wsdl.ar.v1_0.GetActiveAlarmsException;
import org.tmforum.mtop.rtm.xsd.ar.v1.GetActiveAlarmsCountRequest;
import org.tmforum.mtop.rtm.xsd.ar.v1.GetActiveAlarmsCountResponse;
import org.tmforum.mtop.rtm.xsd.ar.v1.GetActiveAlarmsRequest;
import org.w3c.dom.Element;

import javax.xml.bind.JAXBElement;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

。。。

 /**
  * 故障告警信息数量
  */
 public long getActiveAlarmsCount() {
     long count = 0L;

     try {
         AlarmRetrieval alarmRetrieval = WebServiceUtil.getWebService("AlarmRetrieval", AlarmRetrieval.class);
         GetActiveAlarmsCountRequest request = new GetActiveAlarmsCountRequest();
         GetActiveAlarmsCountResponse response = alarmRetrieval.getActiveAlarmsCount(WebServiceUtil.getHeader(), request);
         count = response.getActiveAlarmCount();
     } catch (GetActiveAlarmsCountException e) {
         e.printStackTrace();
         System.err.println("failed getActiveAlarmsCount");
     } catch (Exception ex) {
         System.err.println(String.valueOf(ex.getCause()));
     }

     return count;
 }

对应的NCE XML接口说明

java访问华为网管软件iMaster NCE的北向接口_OTN_05

java访问华为网管软件iMaster NCE的北向接口_SOAP_06

三、总结

NCE的XML接口感觉就是异常繁琐,数据类型非常多,传参、返回值都非常复杂。如果是http接口的话,参数全部是json,结构简单明了。而且,利用XML传数据,少量数据还好,大批量数据就不行,XML相比json,实在笨重,传输量太大了。

华为这个nce软件,叫网管软件,它接管了整个局域网,然后在上面做各种逻辑划分和管理。不过,它加载需要一段时间。比如我们项目,设备通电以后,20分钟后网络才能访问。再上面做一些更改,比如用户解锁,要约2个小时才生效。之前遇到明明用户已经解锁了,还是不能登录,正疑惑的时候,忽然就可以了。这时已经过去了2个小时。