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

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

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.listSubjectsWithProperty(RICO.type, Service.DIGITAL_OBJECT_TYPE).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
127
128
    fun getMimeType(uri: String): String {
        val mimeTypes = model.getResource(uri).listProperties(EBUCORE.hasMimeType).mapWith {
            it.`object`.asLiteral().string
129
        }.toList()
130
131
132
133
134
        if (mimeTypes.size == 1) {
            return mimeTypes[0]
        } else {
            throw MissingMimeTypeException("No MimeType found for resource $uri")
        }
135
    }
Thomas Bernhart's avatar
Thomas Bernhart committed
136
}