2017-05-26 27 views
2

sapjco3.jarドライバを使用してSAPに正常に接続するSpring MVC(Spring framework 4.1.1)Java 1.8アプリケーションを作成しました。これをCustomDestinationDataProviderテクニックを使用して実行しました。私はこのドライブを使用して、SAP R/3システムのRFCを呼び出します。 Javaコードは、AngularJSフロントエンドアプリケーションからのAPI呼び出しによって実行されます。ここでsapjco3ドライバの問題

NestedServletException: Handler processing failed; nested exception is 
java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider 
already registered 

私CustomDestinationDataProvider.javaファイルの内容です:

public class CustomDestinationDataProvider { 

public class MyDestinationDataProvider implements DestinationDataProvider { 
    private DestinationDataEventListener eL; 
    private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>(); 
    public Properties getDestinationProperties(String destinationName) { 
     try { 
      Properties p = secureDBStorage.get(destinationName); 
      if(p!=null) { 
       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); 
     } 
    } 
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener) { 
     this.eL = eventListener; 
    } 
    public boolean supportsEvents() { 
     return true; 
    } 
    public 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 ArrayList<MaterialBean> executeAvailabilityCall(Properties connectProperties, String searchString) { 
    String destName = "ABAP_AS"; 
    SAPDAO sapDAO = new SAPDAO(); 
    ArrayList<MaterialBean> searchResults = new ArrayList<MaterialBean>(); 
    MyDestinationDataProvider myProvider = new MyDestinationDataProvider(); 
    JCoDestination dest; 
    try { 
     com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider); 
    } catch(IllegalStateException providerAlreadyRegisteredException) { 
    } 
    myProvider.changeProperties(destName, connectProperties); 
    try { 
     dest = JCoDestinationManager.getDestination(destName); 
     searchResults = sapDAO.searchAvailability(dest, searchString); 
    } catch(JCoException e) { 
     e.printStackTrace(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    myProvider.changeProperties(destName, null); 
    try { 
     com.sap.conn.jco.ext.Environment.unregisterDestinationDataProvider(myProvider); 
    } catch(IllegalStateException providerAlreadyRegisteredException) { 
     throw new Error(providerAlreadyRegisteredException); 
    } 
    return searchResults; 
} // end method executeAvailabilityCall() 
} // end class CustomDestinationProvider() 
を私はSAPへの呼び出しが発生した時間の約5%をoccuring発見した

何かが次のエラーが発生しています

複数のAPIコールが同時に発生していて、最初のクエリで宛先データプロバイダが登録されると、宛先データプロバイダを登録しようとする後続のクエリも同じ値を使用しているため失敗しますために ' executeAvailabilityCallメソッドの「destName」。

最初のグレースでは、すべてのクエリに「ABAP_AS」を使用するのではなく、destName変数に動的値を使用する必要があるようです。このような何かに

String destName = "ABAP_AS"; 

::他の言葉で、私は次の行を変更する必要があり

String destName = "ABAP_AS_" + LocalDateTime.now(); 

これは、このようにユニーク先プロバイダ名をdestName変数に一意の値を保証します。

これを試すことの知恵について考えてみましょうか?これが良い考えではない場合は、他にどのような解決策を検討する価値がありますか?

答えて

0

はい、さまざまなログオンプロパティー構成セットに複数の一意の宛先名を使用する必要があります。あなたのクラスMyDestinationDataProviderは既にそのように実装されています。しかし、目的地の名前にタイムスタンプを入れるのはなぜですか? 「TargetSystem_ <SID> _ with_ <username>」のような宛先名スキーマを使用するだけではどうですか?

例外については、MyDestinationDataProviderを1回登録するだけで、永続的に登録および登録解除しないでください。これは、JCoがこれを実装する方法を示しているわけではありません。 JCo JavaDocからの引用:com.sap.conn.jco.ext.DestinationDataProvider

DestinationDataProviderの実装は1つしか登録できません。 別の実装を登録するために、インフラストラクチャは最初に に登録されている実装の登録を解除します。 DestinationDataProvider の登録を恒久的に交換することは推奨されていません。 1つの登録済みインスタンスは、インフラストラクチャ環境全体のすべての宛先設定をグローバルに管理する必要があります。

+0

'MyDestinationDataProvider'を一度登録することについては、シングルトンスタイルのクラスで行うべきか、データプロバイダがまだ登録されていない場合にのみ実行される 'registerDestinationDataProvider'ラインの周りに条件付きロジックを使用する必要がありますか? – Stephen

+0

「DestinationDataProvider」の登録は、一度しか呼び出されない初期化ルーチン内で行うことをお勧めします。'DestinationDataProvider'がすでに登録されているかどうかを繰り返しチェックすることは、私の意見では効率的なコーディングスタイルではありません。 – Trixx

+0

それは良いアイデアのように思えます。あなたのご意見をありがとうございました! :) – Stephen

関連する問題