001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2024-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.rdf.io; 019 020import dev.enola.common.io.resource.WritableResource; 021 022import org.eclipse.rdf4j.model.Statement; 023import org.eclipse.rdf4j.rio.*; 024import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; 025 026import java.io.Closeable; 027import java.io.IOException; 028import java.io.Writer; 029import java.net.URISyntaxException; 030import java.util.Optional; 031 032public class WritableResourceRDFHandler implements RDFHandler, Closeable { 033 034 public static Optional<WritableResourceRDFHandler> create(WritableResource resource) 035 throws IOException { 036 try { 037 String baseURI = resource.uri().toString(); 038 var mediaType = resource.mediaType().withoutParameters().toString(); 039 var writerFormat = Rio.getWriterFormatForMIMEType(mediaType); 040 // TODO See https://github.com/eclipse-rdf4j/rdf4j/issues/5272: 041 if (mediaType.equals("text/plain") 042 && writerFormat.isPresent() 043 && writerFormat.get().equals(RDFFormat.NTRIPLES)) 044 writerFormat = Optional.empty(); 045 if (writerFormat.isEmpty()) writerFormat = Rio.getWriterFormatForFileName(baseURI); 046 if (writerFormat.isEmpty()) return Optional.empty(); 047 048 var ioWriter = resource.charSink().openBufferedStream(); 049 var rdfWriter = Rio.createWriter(writerFormat.get(), ioWriter, baseURI); 050 var writerConfig = new WriterConfig(); 051 writerConfig.set(BasicWriterSettings.BASE_DIRECTIVE, false); 052 writerConfig.set(BasicWriterSettings.INLINE_BLANK_NODES, true); 053 rdfWriter.setWriterConfig(writerConfig); 054 055 var it = new WritableResourceRDFHandler(rdfWriter, ioWriter); 056 rdfWriter.startRDF(); 057 return Optional.of(it); 058 059 } catch (URISyntaxException e) { 060 throw new IOException("URISyntaxException: " + resource, e); 061 } 062 } 063 064 private final RDFWriter /* IS-A RDFHandler */ rdfWriter; 065 private final Writer ioWriter; 066 067 private WritableResourceRDFHandler(RDFWriter rdfWriter, Writer ioWriter) 068 throws IOException, URISyntaxException { 069 this.rdfWriter = rdfWriter; 070 this.ioWriter = ioWriter; 071 } 072 073 @Override 074 public void close() throws IOException { 075 rdfWriter.endRDF(); 076 ioWriter.close(); 077 } 078 079 @Override 080 public void startRDF() throws RDFHandlerException { 081 // SUPPRESS rdfWriter.startRDF(); 082 } 083 084 @Override 085 public void endRDF() throws RDFHandlerException { 086 // SUPPRESS rdfWriter.endRDF(); 087 } 088 089 @Override 090 public void handleNamespace(String prefix, String uri) throws RDFHandlerException { 091 rdfWriter.handleNamespace(prefix, uri); 092 } 093 094 @Override 095 public void handleStatement(Statement st) throws RDFHandlerException { 096 rdfWriter.handleStatement(st); 097 } 098 099 @Override 100 public void handleComment(String comment) throws RDFHandlerException { 101 rdfWriter.handleComment(comment); 102 } 103}