如何使用JCO3.0同时访问多个SAP系统

遇到问题

前两天遇到一个SAP JCO 3.0 开发的问题,分享给大家解决方法。共享系统连接两个(多个)SAP代理商系统,其中SAP所在服务器、函数、字段全部不一样,这是两个完全不一样的SAP系统。最终出现,最多只能连接成功其中任意一个SAP系统。

知识前提

为了完成这个事情的探索,还需要一些基本的应用积累。

接口文件

  1. 在Windows环境下将dll文件放到windows的system32文件中;
  2. 在Linux环境下将so文件放入指定的路径里,并指定启动参数中包含这个路径。
  3. 将jar文件放到java程序中使用。

这里写图片描述

连接方式

目前市面上常见两种方式。

简单连接

对象初始化时,装载properties以及自定义destnationName,然后将properties保存到java web跟目录。因为SAP在这种情况下,是默认读取java web根目录的配置文件,然后进行连接的。

public class JcoTest {
    static String DESTINATIONNAME = "ABAP_AS_WITHOUT_POOL";
    static String DESTINATION_NAME2 = "ABAP_AS_WITH_POOL";

    // 配置连接
    static {
        Properties connectProperties = new Properties();
        connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "192.168.6.66");// IP
        connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00");// 系统编号
        connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "100");// 客户端编号
        connectProperties.setProperty(DestinationDataProvider.JCO_USER, "sscrfc");// 用户名
        connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "abc123");// 密码
        connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "zh");// 语言
        connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "30");// 最大空闲连接数
        connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "150");// 最大活动连接数
        createDestinationDataFile(DESTINATION_NAME1, connectProperties);
    }

    /**
     * 
     * 保存配置文件  <br>
     *
     * @param destinationName
     * @param connectProperties  void
     */
    static void createDestinationDataFile(String destinationName, 
        Properties connectProperties) {
        File destCfg = new File(destinationName + ".jcoDestination");
        try {
            FileOutputStream fos = new FileOutputStream(destCfg, false);
            connectProperties.store(fos, "For tests only !");
            fos.close();
        } catch (Exception e) {
            throw new RuntimeException("Unable to create the destination files", e);
        }
    }

    /**
     * 
     * 测试连接  <br>
     *
     * @return
     * @throws JCoException  JCoDestination
     */
    public static JCoDestination getSAPDestination() 
        throws JCoException {
        JCoDestination destination = JCoDestinationManager.getDestination(DESTINATIONNAME);
        destination.ping();
        return destination;
    }
}
使用DestinationDataProvider连接
public class JcoProviderImpl implements DestinationDataProvider {

    private Map<String, Properties> proMap = new HashMap<String, Properties>();

    @Override
    public Properties getDestinationProperties(String destName) {
        return proMap.get(destName);
    }

    @Override
    public void setDestinationDataEventListener(DestinationDataEventListener arg0) {

    }

    @Override
    public boolean supportsEvents() {
        return false;
    }

    /**
     * 
     * 填充连接参数 <br>
     *
     * @param destName
     * @param p
     *            void
     */
    public void addProperty(String destName, Properties p) {
        proMap.put(destName, p);
    }
}

上面是注册provider,接下来是使用它进行连接,定义一个管理类。

public class RfcManage {

    private JcoProviderImpl provider;

    public RfcManage(JcoProviderImpl provider) {
        this.provider = provider;
    }

    /**
     * 
     * 注册Provider <br>
     * void
     */
    public void registProvider() {
        try {
            Environment.registerDestinationDataProvider(provider);
        } catch (Exception e) {
            throw new InfomationException("注册Provider异常", e);
        }
    }

    /**
     * 
     * 取消注册 <br>
     * void
     */
    public void unRegistProvider() {
        try {
            Environment.unregisterDestinationDataProvider(provider);
        } catch (Exception e) {
            throw new InfomationException("取消注册Provider异常", e);
        }
    }

    /**
     * 
     * 获取连接实例 <br>
     *
     * @param destinationName
     * @return JCoDestination
     */
    public JCoDestination creataDestination(String destinationName) {
        try {
            JCoDestination destination = JCoDestinationManager.getDestination(destinationName);
            destination.ping();
            return destination;
        } catch (Exception e) {
            unRegistProvider();
            throw new ExtRuntimeException("获取JCoDestination异常", e);
        }
    }
}

接下来是测试类。

JcoProviderImpl provider = new JcoProviderImpl();
provider.addProperty(DESTINATION_NAME1, getP());
RfcManage manage = new RfcManage(provider);
// 注册连接
manage.registProvider();
// 获取连接
JCoDestination dest = manage.creataDestination(DESTINATION_NAME1);
// 调用函数
JCoFunction function = dest.getRepository().getFunction("ZSSC_MD_VENDOR");
System.out.println(function);

核心思想是,在调用sap接口前需要重写DestinationDataProvider 中的 getDestinationProperties方法,将我们自定义的连接名称和连接配置设置上去。然后使用Environment.registerDestinationDataProvider(provider);进行注册。最后就可以获取Destination对象,进行调用函数的使用了。

解决问题

现在回到问题。共享中心连接两个(多个)完全不同SAP代理商,根据jco3.0中官方说明。Environment.registerDestinationDataProvider 只能在注册一次

SAP官方解释如下:

Only one implementation of DestinationDataProvider can be registered. For registering another implementation the infrastructure has first to unregister the implementation that is currently registered. It is not recommended to permanently exchange DestinationDataProvider registrations. The one registered instance should globally manage all destination configurations for the whole infrastructure environment.

译文:

只有一个DestinationDataProvider实现可以被注册。 为了注册另一个实现,基础架构首先注销当前注册的实现。 不建议永久交换DestinationDataProvider注册。 一个注册实例应全局管理整个基础架构环境的所有目标配置。

最终方式

查阅了很多资料,试过了很多方法,直到看到上面这个解释的时候,才明白问题的根本。根据官方的解释,那么我们之前在代码定义的unregisterDestinationDataProvider终于有了用武之地。所以最终的方法是:

JcoProviderImpl provider = new JcoProviderImpl();
provider.addProperty(DESTINATION_NAME1, getP());
RfcManage manage = new RfcManage(provider);
manage.registProvider();
JCoDestination dest = manage.creataDestination(DESTINATION_NAME1);
JCoFunction function = dest.getRepository().getFunction("ZSSC_MD_VENDOR");
System.out.println(function);
manage.unRegistProvider();

总结

调用unregisterDestinationDataProvider方法。举个例子,连接SAP-1后,如果想再连接SAP-2那么必须先取消provider的注册。从官方说明上来看,其实是不建议这样做的,但目前没有找到更好的解决办法。因为每次注册都会消耗一定的资源,如果只有一个SAP系统,只需要第一次使用时注册,后续调用函数时无需也无法再此注册。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值