RdfHandler.kt 5.81 KB
Newer Older
Jonas Waeber's avatar
Jonas Waeber committed
1
2
package org.memobase

3
4
5
import ch.memobase.rdf.EBUCORE
import ch.memobase.rdf.RDF
import ch.memobase.rdf.RICO
6
import java.io.ByteArrayInputStream
Jonas Waeber's avatar
Jonas Waeber committed
7
8
import org.apache.jena.rdf.model.Model
import org.apache.jena.rdf.model.ModelFactory
9
10
11
import org.apache.jena.rdf.model.Statement
import org.apache.jena.rdf.model.impl.SelectorImpl
import org.apache.jena.rdf.model.impl.StatementImpl
12
13
import org.apache.jena.riot.Lang
import org.apache.jena.riot.RDFDataMgr
14
import org.apache.log4j.LogManager
15
import org.memobase.exceptions.MissingMimeTypeException
Jonas Waeber's avatar
Jonas Waeber committed
16

17
18
class RdfHandler(data: String, private val externalBaseUrl: String) {
    private val log = LogManager.getLogger("IngestRdfHandler")
Jonas Waeber's avatar
Jonas Waeber committed
19
20
21
    private val model = ModelFactory.createDefaultModel()

    init {
22
        RDFDataMgr.read(model, ByteArrayInputStream(data.toByteArray()), Lang.NTRIPLES)
Jonas Waeber's avatar
Jonas Waeber committed
23
24
    }

25
    fun getRecord(): Pair<String, Model> {
Jonas Waeber's avatar
Jonas Waeber committed
26
        val resultModel = ModelFactory.createDefaultModel()
27
        var uri = ""
Jonas Waeber's avatar
Jonas Waeber committed
28
29
30
31
32
33
34
35
36
37
        model.listSubjectsWithProperty(RDF.type, RICO.Record).forEach { resource ->
            resource.listProperties().forEach { statement ->
                if (statement.`object`.isAnon) {
                    val blankNode = statement.`object`.asResource()
                    if (blankNode.hasProperty(RDF.type, RICO.CreationRelation)) {
                        blankNode.listProperties(RICO.creationRelationHasTarget).forEach { targetStatement ->
                            // Adding agent statements connected to creation relations
                            resultModel.add(targetStatement.`object`.asResource().listProperties())
                        }
                    }
38
39
40
41
42
43
44
45
46
47
48
49
50
                    // Adding statements connected via Activity / Mechanism.
                    if (blankNode.hasProperty(RICO.resultsFrom)) {
                        blankNode.listProperties(RICO.resultsFrom).forEach { targetStatement ->
                            val values = targetStatement.`object`.asResource().listProperties()
                            values.forEach { activityStatement ->
                                if (activityStatement.predicate == RICO.performedBy) {
                                    val mechanism = activityStatement.`object`.asResource()
                                    resultModel.add(mechanism.listProperties())
                                }
                                resultModel.add(activityStatement)
                            }
                        }
                    }
Jonas Waeber's avatar
Jonas Waeber committed
51
52
53
54
55
56
                    // Adding blank node statements connected to record
                    resultModel.add(blankNode.listProperties())
                }
                // Adding record statements
                resultModel.add(statement)
            }
57
            uri = resource.uri
Jonas Waeber's avatar
Jonas Waeber committed
58
        }
59
        return Pair(uri, resultModel)
Jonas Waeber's avatar
Jonas Waeber committed
60
61
    }

62
    private fun isInternalNonBinaryResource(uri: String): Boolean {
63
        return uri.startsWith(externalBaseUrl) && !uri.endsWith("/${Service.BINARY_FILE_URI_PATH}")
64
65
66
67
68
69
70
71
72
    }

    fun getReferencedNonBinaryResources(): List<String> {
        return model.listStatements().filterKeep { statement ->
            statement.getObject().isURIResource
        }.mapWith { statement ->
            statement.getObject().asResource().uri
        }.filterKeep { uri ->
            isInternalNonBinaryResource(uri)
73
        }.toList().distinct().sorted()
74
75
    }

76
    fun getInstantiations(): List<Pair<String, Model>> {
Jonas Waeber's avatar
Jonas Waeber committed
77
78
79
80
81
82
83
84
85
86
        return model.listSubjectsWithProperty(RDF.type, RICO.Instantiation).mapWith { resource ->
            val model = ModelFactory.createDefaultModel()
            resource.listProperties().forEach { statement ->
                if (statement.`object`.isAnon) {
                    val blankNode = statement.`object`.asResource()
                    // Adding blank node statements connected to record
                    model.add(blankNode.listProperties())
                }
                model.add(statement)
            }
87
88
89
            if (resource.hasProperty(EBUCORE.locator)) {
                replaceSftpLocator(resource.uri, model)
            }
90
            Pair(resource.uri, model)
Jonas Waeber's avatar
Jonas Waeber committed
91
92
        }.toList()
    }
Jonas Waeber's avatar
Jonas Waeber committed
93

94
95
96
    private fun replaceSftpLocator(uri: String, model: Model) {
        var newStatement: Statement? = null
        val string: String? = null
97
        val replacementLocator = "$uri/${Service.BINARY_FILE_URI_PATH}"
98
        val removedStatement = model.listStatements(SelectorImpl(null, EBUCORE.locator, string)).mapWith {
99
100
            if (it.`object`.asLiteral().string.startsWith(Service.SFTP_PREFIX)) {
                newStatement = StatementImpl(it.subject, it.predicate, model.createLiteral(replacementLocator))
101
102
103
104
105
106
107
108
109
            }
            it
        }.nextOptional()
        removedStatement.let {
            if (it.isPresent && newStatement != null) {
                model.remove(it.get())
                model.add(newStatement)
            }
        }
110
        log.info("Replaced sftp locator with fedora url: $replacementLocator.")
111
112
    }

Jonas Waeber's avatar
Jonas Waeber committed
113
    fun getSftpLocators(): List<Pair<String, String?>> {
114
        return model.listResourcesWithProperty(RDF.type, RICO.Instantiation).filterKeep {
Jonas Waeber's avatar
Jonas Waeber committed
115
116
117
            it.hasProperty(EBUCORE.locator)
        }.mapWith {
            val url = it.getProperty(EBUCORE.locator).`object`.asLiteral().string
118
119
            if (url.startsWith(Service.SFTP_PREFIX)) {
                Pair(it.uri, url.replace(Service.SFTP_PREFIX, ""))
Jonas Waeber's avatar
Jonas Waeber committed
120
121
122
123
124
            } else {
                Pair(it.uri, null)
            }
        }.toList()
    }
125

126
    @Throws(MissingMimeTypeException::class)
127
128
129
    fun getMimeType(uri: String): String {
        val mimeTypes = model.getResource(uri).listProperties(EBUCORE.hasMimeType).mapWith {
            it.`object`.asLiteral().string
130
        }.toList()
131
132
133
134
135
        if (mimeTypes.size == 1) {
            return mimeTypes[0]
        } else {
            throw MissingMimeTypeException("No MimeType found for resource $uri")
        }
136
    }
Thomas Bernhart's avatar
Thomas Bernhart committed
137
}