我编写了一个 Spring MVC(Spring 框架 4.1.1)java 1.8 应用程序,它使用 sapjco3.jar 驱动程序成功连接到 SAP,我使用 CustomDestinationDataProvider 技术完成了这项工作。然后我使用这个驱动器在我的 SAP R/3 系统中调用 RFC。Java 代码通过 AngularJS 前端应用程序的 api 调用执行。
我发现大约 5% 的 SAP 调用发生的时间是发生以下错误:
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()
我的猜测是多个 api 调用同时发生,一旦第一个查询注册了目标数据提供者,随后的查询,也尝试注册目标数据提供者,失败,因为它们使用相同的值 'destName ' 在 executeAvailabilityCall 方法中。
乍一看,在我看来,我应该为 destName 变量使用动态值,而不是只对所有查询使用“ABAP_AS”。换句话说,我应该更改以下行:
String destName = "ABAP_AS";
像这样:
String destName = "ABAP_AS_" + LocalDateTime.now();
这将保证 destName 变量的唯一值,从而保证唯一的目标提供程序名称。
关于尝试这个的智慧有什么想法吗?如果这不是一个好主意,还有什么其他解决方案值得探索?