简体   繁体   English

使用sapjco连接到SAP BAPI的两个Web应用程序

[英]Two web applications connecting to SAP BAPI using sapjco

I have two web applications deployed on WebSphere Application Server 8.5 for RHEL6 (x64). 我在用于RHEL6(x64)的WebSphere Application Server 8.5上部署了两个Web应用程序。 Both web applications use SAPJCO library to connect to BAPI deployed in SAP ECC6. 这两个Web应用程序都使用SAPJCO库连接到SAP ECC6中部署的BAPI。 Both of the application need to access the same BAPI in order to create Purchase Requests. 这两个应用程序都需要访问相同的BAPI才能创建购买请求。 So, we use the same code modified from SAP's CustomDestinationDataProvider to connect. 因此,我们使用从SAP的CustomDestinationDataProvider修改的相同代码进行连接。 To ensure that application register it only once, we use Spring to make it a singleton. 为了确保应用程序仅注册一次,我们使用Spring使其成为单例。

However, when applications started, one application (which we guess it is loaded after the first) encounters "java.lang.IllegalStateException: DestinationDataProvider already registered" when "com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider)" is executed. 但是,当应用程序启动时,一个应用程序(我们猜测它是在第一个应用程序之后加载的)在"com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider)"时遇到"java.lang.IllegalStateException: DestinationDataProvider already registered" "com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider)"被执行。

The CustomDestinationDataProvider is as follow: CustomDestinationDataProvider如下:


    public class CustomDestinationDataProvider {
    public CustomDestinationDataProvider () {
    }

public static BapiConfigBean bapiConfigBean;

//The custom destination data provider implements DestinationDataProvider and
//provides an implementation for at least getDestinationProperties(String).
//Whenever possible the implementation should support events and notify the JCo runtime
//if a destination is being created, changed, or deleted. Otherwise JCo runtime
//will check regularly if a cached destination configuration is still valid which incurs
//a performance penalty.
public static class MyDestinationDataProvider implements DestinationDataProvider
{
    private DestinationDataEventListener eL;
    private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();

    public MyDestinationDataProvider () {

    }
    public Properties getDestinationProperties(String destinationName)
    {
        try
        {
            //read the destination from DB
            Properties p = secureDBStorage.get(destinationName);

            if(p!=null)
            {
                //check if all is correct, for example
                if(p.isEmpty())
                    throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, 
                            "destination configuration is incorrect", null);
                return p;
            }

            return null;
        }
        catch(RuntimeException re)
        {
            throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
        }
    }

    //An implementation supporting events has to retain the eventListener instance provided
    //by the JCo runtime. This listener instance shall be used to notify the JCo runtime
    //about all changes in destination configurations.
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener)
    {
        this.eL = eventListener;
    }

    public boolean supportsEvents()
    {
        return true;
    }

    //implementation that saves the properties in a very secure way
    void changeProperties(String destName, Properties properties)
    {
        synchronized(secureDBStorage)
        {
            if(properties==null)
            {
                if(secureDBStorage.remove(destName)!=null)
                    eL.deleted(destName);
            }
            else 
            {
                secureDBStorage.put(destName, properties);
                eL.updated(destName); // create or updated
            }
        }
    }

    public void removeDestination(String destName) {
        // TODO Auto-generated method stub

    }
    public void addDestination(String destName,
            MyDestinationDataProvider myProvider) {
        // TODO Auto-generated method stub

    }

} // end of MyDestinationDataProvider


//business logic
void executeCalls(String destName)
{
    JCoDestination dest;
    try
    {
        dest = JCoDestinationManager.getDestination(destName);
        dest.ping();
        System.out.println("Destination " + destName + " works");
    }
    catch(JCoException e)
    {
        e.printStackTrace();
        System.out.println("Execution on destination " + destName+ " failed");
    }
}

static Properties getDestinationPropertiesFromUI()
{
    //adapt parameters in order to configure a valid destination
    Properties connectProperties = new Properties();
    connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, getBapiConfigBean().getServerIp());
    connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR,  getBapiConfigBean().getSystemNumber());
    connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, getBapiConfigBean().getClientId());
    connectProperties.setProperty(DestinationDataProvider.JCO_USER,   getBapiConfigBean().getUserName());
    connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, getBapiConfigBean().getUserPassword());
    connectProperties.setProperty(DestinationDataProvider.JCO_LANG,   getBapiConfigBean().getClientLang());
    return connectProperties;
}

static MyDestinationDataProvider myProvider = null; //2014-06-30 00:30 

public static void initProvider(BapiConfigBean bapiConfigBean) {
    CustomDestinationDataProvider.destroy();
    setBapiConfigBean(bapiConfigBean);
    myProvider = new MyDestinationDataProvider();
    String destName = getBapiConfigBean().getSapDestname();

    try
    {

        com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
        CustomDestinationDataProvider test = new CustomDestinationDataProvider();
        myProvider.changeProperties(destName, getDestinationPropertiesFromUI());
        test.executeCalls(destName);

    }
    catch(IllegalStateException providerAlreadyRegisteredException)
    {
        try {
            JCoDestination jcodest = JCoDestinationManager.getDestination(getBapiConfigBean().getSapDestname());
        } catch (JCoException exJCo) {
            //TODO: Add exception handling and send friendly message to ui
        }
    }   
}

public static BapiConfigBean getBapiConfigBean() {
    return bapiConfigBean;
}

public static void setBapiConfigBean(BapiConfigBean bapiConfigBean) {
    CustomDestinationDataProvider.bapiConfigBean = bapiConfigBean;
}

public static void destroy() {
    try {
        Environment.unregisterDestinationDataProvider(myProvider);  
        System.out.println("Unregistered connection to SAP");
    } catch (IllegalStateException e) {  
    System.out.println("Failed to unregister connection to SAP: "+ e);
    }
}
}
</code></pre>

And the error from SystemOut.log in WebSphere is as follow: [6/30/14 22:29:15:198 ICT] 00000043 webapp E com.ibm.ws.webcontainer.webapp.WebApp notifyServletContextCreated SRVE0283E: Exception caught while initializing context: {0} org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdoConnector' defined in ServletContext resource [/WEB-INF/applicationContext-BAPI.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.sps.tmps.bean.bapi.JCOConnector]: Constructor threw exception; nested exception is java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider already registered [com.sps.tmps.bean.bapi.CustomDestinationDataProvider$MyDestinationDataProvider] Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.sps.tmps.bean.bapi.JCOConnector]: Constructor threw exception; nested exception is java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider already registered [com.sps.tmps.bean.bapi.CustomDestinationDataProvider$MyDestinationDataProvider] Caused by: java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider already registered [com.sps.tmps.bean.bapi.CustomDestinationDataProvider$MyDestinationDataProvider] at com.sps.tmps.bean.bapi.CustomDestinationDataProvider.initProvider(CustomDestinationDataProvider.java:174) at com.sps.tmps.bean.bapi.JCOConnector.(JCOConnector.java:41) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:56) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:39) at java.lang.reflect.Constructor.newInstance(Constructor.java:527) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:85) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:186) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:800) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:720) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:387) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352) at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:244) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:187) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49) at com.ibm.ws.webcontainer.webapp.WebApp.notifyServletContextCreated(WebApp.java:1678) at com.ibm.ws.webcontainer.webapp.WebAppImpl.initialize(WebAppImpl.java:414) at com.ibm.ws.webcontainer.webapp.WebGroupImpl.addWebApplication(WebGroupImpl.java:88) at com.ibm.ws.webcontainer.VirtualHostImpl.addWebApplication(VirtualHostImpl.java:169) at com.ibm.ws.webcontainer.WSWebContainer.addWebApp(WSWebContainer.java:749) at com.ibm.ws.webcontainer.WSWebContainer.addWebApplication(WSWebContainer.java:634) at com.ibm.ws.webcontainer.component.WebContainerImpl.install(WebContainerImpl.java:426) at com.ibm.ws.webcontainer.component.WebContainerImpl.start(WebContainerImpl.java:718) at com.ibm.ws.runtime.component.ApplicationMgrImpl.start(ApplicationMgrImpl.java:1175) at com.ibm.ws.runtime.component.DeployedApplicationImpl.fireDeployedObjectStart(DeployedApplicationImpl.java:1370) at com.ibm.ws.runtime.component.DeployedModuleImpl.start(DeployedModuleImpl.java:639) at com.ibm.ws.runtime.component.DeployedApplicationImpl.start(DeployedApplicationImpl.java:968) at com.ibm.ws.runtime.component.ApplicationMgrImpl.startApplication(ApplicationMgrImpl.java:774) at com.ibm.ws.runtime.component.ApplicationMgrImpl.start(ApplicationMgrImpl.java:2182) at com.ibm.ws.runtime.component.CompositionUnitMgrImpl.start(CompositionUnitMgrImpl.java:445) at com.ibm.ws.runtime.component.CompositionUnitImpl.start(CompositionUnitImpl.java:123) at com.ibm.ws.runtime.component.CompositionUnitMgrImpl.start(CompositionUnitMgrImpl.java:388) at com.ibm.ws.runtime.component.CompositionUnitMgrImpl.access$500(CompositionUnitMgrImpl.java:116) at com.ibm.ws.runtime.component.CompositionUnitMgrImpl$CUInitializer.run(CompositionUnitMgrImpl.java:994) at com.ibm.wsspi.runtime.component.WsComponentImpl$_AsynchInitializer.run(WsComponentImpl.java:502) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862) Caused by: java.lang.IllegalStateException: DestinationDataProvider already registered [com.sps.tmps.bean.bapi.CustomDestinationDataProvider$MyDestinationDataProvider] at com.sap.conn.jco.rt.RuntimeEnvironment.setDestinationDataProvider(RuntimeEnvironment.java:134) at com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(Environment.java:259) at com.sps.tmps.bean.bapi.CustomDestinationDataProvider.initProvider(CustomDestinationDataProvider.java:156) ... 41 more

My questions are: 我的问题是:
1) How to make two application able to use the same CustomDestinationDataProvider? 1)如何使两个应用程序能够使用相同的CustomDestinationDataProvider?
2) If 2 application cannot use the same provider, How can I access the same BAPI using the same server/user/client number? 2)如果2个应用程序不能使用相同的提供程序,如何使用相同的服务器/用户/客户端号访问相同的BAPI?
Constraints in this case are that (1) We should use sapjco and (2) we have only on BAPI function. 这种情况下的约束是(1)我们应该使用sapjco,而(2)我们仅使用BAPI函数。 customDestinationDataProvider can be discarded if you think it is a problem. 如果您认为有问题,可以将customDestinationDataProvider丢弃。 By the way, I apologized for the long code and terrible formatting. 顺便说一句,我为冗长的代码和糟糕的格式表示歉意。
thank you. 谢谢。

A simple solution for your problem is to use different destination Names for your two applications (though they are same in your case). 一个简单的解决方案是为两个应用程序使用不同的目标名称(尽管在您的情况下它们是相同的)。 Use two different destination names, one for each application. 使用两个不同的目的地名称,每个应用程序使用一个。 eg PROD_APP1, PROD_APP2 例如PROD_APP1,PROD_APP2

All other things can remain same, i believe. 我相信所有其他事情都可以保持不变。

In an ideal situation, i would prefer a more robust solution. 在理想情况下,我希望使用更可靠的解决方案。 May be i think in the lines of a custom class loader, etc 可能是我认为是在自定义类加载器等方面

Good Luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM