Проблема с драйвером sapjco3
Я написал java 1.8 приложение Spring MVC (Spring framework 4.1.1), которое успешно подключается к SAP с помощью драйвера sapjco3.jar, и я выполнил это с помощью метода CustomDestinationDataProvider. Затем я использую этот диск для вызова RFC в моей системе SAP R/3. Java-код выполняется через вызов API из клиентского приложения AngularJS.
В 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, то есть уникальное имя провайдера назначения.
Есть мысли о целесообразности попытки этого? Если это не очень хорошая идея, какое другое решение стоило бы изучить?
1 ответ
Да, вы должны использовать несколько уникальных имен назначения для различных наборов конфигурации свойств входа в систему. Ваш класс MyDestinationDataProvider уже реализован таким образом. Но зачем указывать временную метку в имени пункта назначения? Почему бы просто не использовать схему имени получателя, например "TargetSystem_
Что касается вашего исключения, просто зарегистрируйте MyDestinationDataProvider только один раз и не регистрируйте его постоянно и не отменяйте регистрацию. Это не то, как JCo ожидает, что это будет реализовано. Цитата из JCo JavaDoc на com.sap.conn.jco.ext.DestinationDataProvider
:
Только одна реализация DestinationDataProvider может быть зарегистрирована. Для регистрации другой реализации инфраструктура должна сначала отменить регистрацию реализации, которая в данный момент зарегистрирована. Не рекомендуется постоянно обмениваться регистрациями DestinationDataProvider. Один зарегистрированный экземпляр должен глобально управлять всеми конфигурациями назначения для всей среды инфраструктуры.