Проблема с драйвером 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__with_"?

Что касается вашего исключения, просто зарегистрируйте MyDestinationDataProvider только один раз и не регистрируйте его постоянно и не отменяйте регистрацию. Это не то, как JCo ожидает, что это будет реализовано. Цитата из JCo JavaDoc на com.sap.conn.jco.ext.DestinationDataProvider:

Только одна реализация DestinationDataProvider может быть зарегистрирована. Для регистрации другой реализации инфраструктура должна сначала отменить регистрацию реализации, которая в данный момент зарегистрирована. Не рекомендуется постоянно обмениваться регистрациями DestinationDataProvider. Один зарегистрированный экземпляр должен глобально управлять всеми конфигурациями назначения для всей среды инфраструктуры.

Другие вопросы по тегам