RDF4J RIO UnsupportedRDFormatException при добавлении данных в HTTPRepository с помощью автономного приложения

У меня есть HTTPRepository, инициализированный URL-адресом репозитория. Я использую RepositoryConnection для извлечения и добавления данных (погоды) в репозиторий. Данные извлекаются из веб-службы, затем преобразуются в операторы RDF и добавляются в репозиторий. Это периодически выполняется отдельным приложением.

Когда я запускаю это приложение в IntelliJ, все работает нормально.

Чтобы запустить это приложение на сервере, я создал файл jar (содержащий все зависимости). Приложение запускается должным образом и может извлекать данные из репозитория.

Однако, когда приложение пытается записать данные в репозиторий, я получаю UnsupportedRDFormatException:

org.eclipse.rdf4j.rio.UnsupportedRDFormatException: Did not recognise RDF format object BinaryRDF (mimeTypes=application/x-binary-rdf; ext=brf)
    at org.eclipse.rdf4j.rio.Rio.lambda$unsupportedFormat$0(Rio.java:568) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at java.util.Optional.orElseThrow(Optional.java:290) ~[na:1.8.0_111]
    at org.eclipse.rdf4j.rio.Rio.createWriter(Rio.java:134) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.rio.Rio.write(Rio.java:371) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.rio.Rio.write(Rio.java:324) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.addModel(HTTPRepositoryConnection.java:588) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.flushTransactionState(HTTPRepositoryConnection.java:662) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.http.HTTPRepositoryConnection.commit(HTTPRepositoryConnection.java:326) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.base.AbstractRepositoryConnection.conditionalCommit(AbstractRepositoryConnection.java:366) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at org.eclipse.rdf4j.repository.base.AbstractRepositoryConnection.add(AbstractRepositoryConnection.java:431) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at nl.wur.fbr.data.weather.WeatherApp.retrieveData(WeatherApp.java:122) ~[weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at nl.wur.fbr.data.weather.WeatherData$WeatherTask.run(WeatherData.java:105) [weatherData-1.0-SNAPSHOT-jar-with-dependencies.jar:na]
    at java.util.TimerThread.mainLoop(Timer.java:555) [na:1.8.0_111]
    at java.util.TimerThread.run(Timer.java:505) [na:1.8.0_111]

Исходный код, в котором возникает ошибка:

    public void retrieveData(){
        logger.info("Retrieving data for weather for app: "+ID+" ");
        RepositoryConnection connection = null;
        ValueFactory vf = SimpleValueFactory.getInstance();
        try {
            connection = repository.getConnection();

            // Retrieving the locations from the repository (no problem here).
            List<Location> locations = this.retrieveLocations(connection);
            List<Statement> statements = new ArrayList<>();

            // Retrieving weather data from each location and transforming it to statements.
            for(Location location : locations){
                List<Weather> retrievedWeather = weatherService.retrieveWeatherData(location.name,location.latitude,location.longitude);
                for(Weather weather : retrievedWeather){
                    BNode phenomenon = vf.createBNode();
                    statements.add(vf.createStatement(location.ID,WEATHER.HAS_WEATHER,phenomenon,rdfStoreGraph));
                    statements.addAll(weather.getStatements(phenomenon,vf,rdfStoreGraph));
                    statements = this.correctOMIRIs(statements,vf);
                }
            }

            // Adding data retrieved from the weather API
            // This is where the exception happens.
            connection.add(statements,rdfStoreGraph);

        } catch (Exception e) {
            logger.error("Could not retrievedata for weather app: '"+ID+"' because no monitor locations could be found.",e);
        } finally {
            if(connection != null){
                connection.close();
            }
        }
    }

HTTPRespository инициализируется так:

        repository = new HTTPRepository(rdfStore.toString());
        ((HTTPRepository)repository).setPreferredRDFFormat(RDFFormat.BINARY);
        ((HTTPRepository)repository).setPreferredTupleQueryResultFormat(TupleQueryResultFormat.BINARY);

Я попытался изменить форматы на TURTLE. Но это не имеет значения.

Можете ли вы сказать мне, как это решить?

NB. И сервер RDF4J, и библиотека имеют версию 2.0.1 (rdf4j).


person Dieudonné    schedule 01.12.2016    source источник


Ответы (2)


Чтобы запустить это приложение на сервере, я создал файл jar (содержащий все зависимости).

Вот ваша проблема: вы создали «толстую банку» и, вероятно, неправильно объединили файлы реестра SPI.

Парсеры RDF4J Rio (а также несколько других модулей) используют для регистрации механизм Java Service Provider Interface (SPI). Этот механизм основан на текстовом файле в META-INF\services файла jar, содержащем полное имя каждой реализации парсера.

Проблема возникает, когда вы объединяете jar-файлы: в каждом jar-парсере Rio есть файл реестра с одинаковым именем, но разным содержимым. Если вы используете что-то вроде плагина сборки maven для создания толстой банки, каждый файл реестра перезаписывается следующим. В результате RDF4J может найти только один анализатор — тот, чей файл реестра был добавлен в толстую банку последним.

Решение состоит в том, чтобы либо вообще не создавать толстую банку, либо, если необходимо, использовать другую технику для ее создания, которая объединяет файлы реестра, а не перезаписывает их. У плагина maven Shade есть хороший вариант конфигурации для этого: ServicesResourceTransformer.

person Jeen Broekstra    schedule 01.12.2016
comment
Я решил пойти другим путем и создал «бережливую» банку и вывел зависимости в отдельный каталог lib. Путь к классам, содержащий все зависимости, включен в манифест (как в этот вопрос). Спасибо! - person Dieudonné; 05.12.2016

Я повторно публикую этот пост, потому что я застрял с этим на несколько часов. Наконец, я мог создать исполняемый файл jar, используя плагин maven shadow со следующей конфигурацией:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <configuration>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </filter>
        </filters>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>${fully.qualified.main.class}</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

Я использовал затененный плагин с ManifestResourceTransformer для создания исполняемого jar-файла, указывающего основной класс моего проекта, и с ServicesResourceTransformer для работы с именами пакетов RDF4J, чтобы избежать того, что один синтаксический анализатор переопределяет предыдущий. Кроме того, мне пришлось включить раздел фильтра, чтобы избежать ошибок JNI, возникающих из-за подписей пакетов.

Я надеюсь, что это полезно для кого-то.

Привет.

person fabad    schedule 26.03.2021