4

GlassFish と SAP JCo コネクタ (sapjco3.jar) に問題があります。

J2EE アプリケーション (jwm.ear) の起動時にロードし、SAP への接続が初めて必要になったときにシングルトンにラップして初期化します。

問題は、この jar がメモリ内で常に初期化されたままになることです。単一のパラメーターを変更する必要がある場合は、初期化された接続をアンロードするために Glassfish を再起動する必要があります。アプリを停止またはアンデプロイしても sapjco.jar がアンロードされず、アプリをさらに再デプロイしても新しい接続パラメーターが取得されず、GlassFish が再起動するまで最初の初期化が残ります。

このライブラリをアンロードまたは再初期化する方法を知っている人はいますか? できればアプリを再デプロイしなくても、最初にアプリがアクティブ化されたときに jcoProvider への参照があり、次のアクティブ化では jcoProvider への null 参照が取得されますが、jcoProvider は初期値でメモリ内でインスタンス化され続けます。

よろしく!

注: GlassFish は Windows 2008 サーバーのバージョン 2.1、jdk は 1.6.0.14 です。

SAP 接続を取得するためのシングルトン:

パッケージ es.grupotec.ejb.SAP;

com.sap.conn.jco.JCoDestination をインポートします。
com.sap.conn.jco.JCoDestinationManager をインポートします。
インポート com.sap.conn.jco.JCoException;
com.sap.conn.jco.ext.DestinationDataProvider をインポートします。
com.sap.conn.jco.ext.Environment をインポートします。
es.grupotec.ejb.util.ConexionSAPException をインポートします。
java.util.Properties をインポートします。

公開最終クラス SAP {

    private static String SAP_SERVER = "JWM";
    プライベート静的 SAP インスタンス = null;
    プライベート静的 JCOProvider jcoProvider = null;

    プライベート SAP() {
      // インスタンス化を無効にするためだけに存在します。
    }

    // SAP 接続を取得
    public static synchronized JCoDestination getDestination() は ConexionSAPException をスローします {

        JCoDestination jcoDestination = null;

            if (Environment.isDestinationDataProviderRegistered()) {
                試す {

                    jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
                    jcoDestination を返します。

                } catch (JCoException ex) {

                    新しい ConexionSAPException(ex.getMessage()) をスローします。

                }
            }

        // 新しい接続を作成します
        if(jcoProvider == null) init();

        // 接続を取得
        試す {

            jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
            jcoDestination を返します。

        } catch (JCoException ex) {

            新しい ConexionSAPException(ex.getMessage()) をスローします。

        }

    }

    // SAP への接続を初期化します
    public static synchronized void init() throws ConexionSAPException {

        SAPVO sap = 新しい SAPVO();
        プロパティ プロパティ = 新しいプロパティ();

        if(jcoProvider == null) {


            // データベースから SAP 構成を取得します
            試す {
                樹液 = SAPDAO.getSAPConfig();
            } catch (例外例) {
                新しい ConexionSAPException(ex.getMessage()) をスローします。
            }

             // 接続オブジェクトを作成
            jcoProvider = 新しい JCOProvider();

        }

        properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());

        試す {

            jcoProvider.changePropertiesForABAP_AS(プロパティ);

        キャッチ(例外e){

            新しい ConexionSAPException(e.getMessage()) をスローします。

        }

    }

    public static synchronized void change(SAPVO sap) throws ConexionSAPException {

        プロパティ プロパティ = 新しいプロパティ();

        // 接続が null の場合、新しい接続を作成します
        if(jcoProvider == null) jcoProvider = new JCOProvider();

        properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());

        試す {

            jcoProvider.changePropertiesForABAP_AS(プロパティ);

        キャッチ(例外e){

            新しい ConexionSAPException(e.getMessage()) をスローします。

        }


    }

    // クローンによるインスタンス化を防ぐ
    @オーバーライド
    public Object clone() は CloneNotSupportedException をスローします {

        新しい CloneNotSupportedException() をスローします。

    }

}

JCo プロバイダーの実装:

パッケージ es.grupotec.ejb.SAP;

import com.sap.conn.jco.ext.DestinationDataEventListener;
com.sap.conn.jco.ext.DestinationDataProvider をインポートします。
com.sap.conn.jco.ext.Environment をインポートします。
es.grupotec.ejb.util.ConexionSAPException をインポートします。
java.util.Properties をインポートします。

public class JCOProvider は DestinationDataProvider を実装します {

    private String SAP_SERVER = "JWM";
    プライベート DestinationDataEventListener eventListener;
    プライベート プロパティ ABAP_AS_properties;

    public JCOProvider(){

    }

    public JCOProvider(SAPVO sap){

        ABAP_AS_properties = 新しいプロパティ();
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, sap.getJCO_POOL_CAPACITY());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, sap.getJCO_PEAK_LIMIT());

        試す {
            if (!Environment.isDestinationDataProviderRegistered())
                Environment.registerDestinationDataProvider(これ);
            そうでなければchangePropertiesForABAP_AS(ABAP_AS_properties);
        } catch (例外例) {
            文字列 msg = ex.getMessage();
        }

    }

    @オーバーライド
    パブリック プロパティ getDestinationProperties(文字列名) {

        if (name.equals(SAP_SERVER) && ABAP_AS_properties!=null) return ABAP_AS_properties;
        それ以外の場合は null を返します。

    }

    @オーバーライド
    public boolean supportsEvents() {
        true を返します。
    }

    @オーバーライド
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
        this.eventListener = eventListener;
    }

 public void changePropertiesForABAP_AS(プロパティ プロパティ) は ConexionSAPException をスローします {

        試す {

            if (!Environment.isDestinationDataProviderRegistered()) {

                if (ABAP_AS_properties == null) ABAP_AS_properties = プロパティ;
                Environment.registerDestinationDataProvider(これ);

            }

            if (プロパティ == null) {

                if (eventListener != null) eventListener.deleted(SAP_SERVER);
                ABAP_AS_properties = null;

            } そうしないと {

                ABAP_AS_properties = プロパティ;
                if (eventListener != null) eventListener.updated(SAP_SERVER);

            }

        } catch (例外例) {

            新しい ConexionSAPException(ex.getMessage()) をスローします。

        }

 }

}

4

2 に答える 2

3

あなたの問題はおそらく、ここにいくつかのネイティブコードが含まれているという事実に関連しています。これはJCo3にも当てはまります。JCo3はネイティブRFCライブラリを使用しなくなりましたが、CPIC層と通信するにはJNIが必要です。

JVMにネイティブライブラリをアンロードさせることは、最大のフラストレーションの練習です。JNI仕様では、実装を提供するクラスに関連付けられたClassLoaderがアンロードされると、ネイティブライブラリがアンロードされると規定されていますが、JVM内でClassLoaderを強制的にアンロードしようとすることは事実上不可能です。

EARファイルにsapjco3.jarが含まれている場合、コードがリロードされるたびにリロードされます。ネイティブライブラリは複数回ロードできず、ネイティブコードをアンロードする方法が実質的にないため、これにより例外が発生する可能性が非常に高くなります。したがって、sapjco3.jarをJ2EEコンテナの外に配置し、J2EEエンジンに、何度もリロードされるEARにライブラリを配置するのではなく、開始時に1回そのライブラリをロードさせることを検討してください。

于 2009-12-21T19:15:09.660 に答える
0

どのリリースの SAP に接続する予定ですか? Java コネクタにはいくつかの問題がありました。実際にはスレッドセーフではなく、EJB アプリケーションに適切に埋め込むことができませんでした。シングル サインオン用の SAP の seculib でも同じ問題が発生しました。それもうまくいきませんでした。唯一の解決策は、J2EE エンジンの外部にロードすることでした。

JCO を Web サービスに置き換えることを考えたことはありますか? もちろん、データが ICF を通過する必要があるため、少し遅くなりますが、より堅牢です。すべての統合をこのソリューションに切り替えました。

于 2009-12-24T00:01:58.370 に答える