Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/silk-framework/silk into…
Browse files Browse the repository at this point in the history
… develop
  • Loading branch information
robertisele committed Nov 18, 2021
2 parents f5026cd + a983f5a commit 77ef295
Show file tree
Hide file tree
Showing 108 changed files with 529 additions and 365 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.silkframework.config

import org.silkframework.util.Identifier

/**
* Inherited by classes that provide an identifier and metadata.
*/
trait HasMetaData {

/**
* The unique identifier for this object.
*/
def id: Identifier

/**
* The metadata for this object.
*/
def metaData: MetaData

/**
* Returns a label for this object.
* Per default, it will fall back to generating a label from the identifier, if no label is defined.
* Subclasses may override this behaviour.
* Truncates the label to maxLength characters.
*
* @param maxLength the max length in characters
*/
def label(maxLength: Int = MetaData.DEFAULT_LABEL_MAX_LENGTH)(implicit prefixes: Prefixes = Prefixes.empty): String = {
metaData.formattedLabel(MetaData.labelFromId(id), maxLength)
}

/**
* Returns a label for this object with no length restriction.
*/
def fullLabel(implicit prefixes: Prefixes = Prefixes.empty): String = label(Int.MaxValue)

}
17 changes: 9 additions & 8 deletions silk-core/src/main/scala/org/silkframework/config/MetaData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scala.xml._
/**
* Holds meta data about a task.
*/
case class MetaData(label: String,
case class MetaData(label: Option[String],
description: Option[String] = None,
modified: Option[Instant] = None,
created: Option[Instant] = None,
Expand All @@ -26,10 +26,11 @@ case class MetaData(label: String,
*/
def formattedLabel(defaultLabel: String, maxLength: Int = MetaData.DEFAULT_LABEL_MAX_LENGTH): String = {
assert(maxLength > 5, "maxLength for task label must be at least 5 chars long")
val trimmedLabel = if(label.trim != "") {
label.trim
} else {
defaultLabel
val trimmedLabel = label match {
case Some(l) if l.trim != "" =>
l.trim
case _ =>
defaultLabel
}
if(trimmedLabel.length > maxLength) {
val sideLength = (maxLength - 2) / 2
Expand Down Expand Up @@ -72,7 +73,7 @@ object MetaData {

val DEFAULT_LABEL_MAX_LENGTH = 50

def empty: MetaData = MetaData("", None, None, None, None, None)
def empty: MetaData = MetaData(None, None, None, None, None, None)

/**
* Generates a nice label from an identifier.
Expand Down Expand Up @@ -114,7 +115,7 @@ object MetaData {
*/
def read(node: Node)(implicit readContext: ReadContext): MetaData = {
MetaData(
label = (node \ "Label").text,
label = Some((node \ "Label").text).filter(_.nonEmpty),
description = Some((node \ "Description").text).filter(_.nonEmpty),
modified = (node \ "Modified").headOption.map(node => Instant.parse(node.text)),
created = (node \ "Created").headOption.map(node => Instant.parse(node.text)),
Expand All @@ -129,7 +130,7 @@ object MetaData {
def write(data: MetaData)(implicit writeContext: WriteContext[Node]): Node = {
val descriptionPCData = PCData(data.description.getOrElse(""))
<MetaData>
<Label>{data.label}</Label>
<Label>{data.label.getOrElse("")}</Label>
<Description xml:space="preserve">{descriptionPCData}</Description>
{ data.modified.map(instant => <Modified>{instant.toString}</Modified>).toSeq }
{ data.created.map(instant => <Created>{instant.toString}</Created>).toSeq }
Expand Down
12 changes: 1 addition & 11 deletions silk-core/src/main/scala/org/silkframework/config/Task.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import scala.xml._
*
* @tparam TaskType The type of this task, e.g., TransformSpec.
*/
trait Task[+TaskType <: TaskSpec] {
trait Task[+TaskType <: TaskSpec] extends HasMetaData {
/** The id of this task. */
def id: Identifier

Expand Down Expand Up @@ -46,16 +46,6 @@ trait Task[+TaskType <: TaskSpec] {
/** Find tasks that are either input or output to this task. */
def findRelatedTasksInsideWorkflows()(implicit userContext: UserContext): Set[Identifier] = Set.empty

/**
* Returns the label if defined or the task ID. Truncates the label to maxLength characters.
* @param maxLength the max length in characters
*/
def taskLabel(maxLength: Int = MetaData.DEFAULT_LABEL_MAX_LENGTH): String = {
metaData.formattedLabel(id, maxLength)
}

def fullTaskLabel: String = taskLabel(Int.MaxValue)

override def equals(obj: scala.Any): Boolean = obj match {
case task: Task[_] =>
id == task.id &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ trait ExecutionReport {
/**
* A user-friendly label for this report, usually just the task label.
*/
def label: String = task.taskLabel()
def label: String = task.label()

/**
* Short label for the executed operation, e.g., read or write (optional).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,22 @@ private class ActivityExecution[T](activity: Activity[T],
}

override def cancel()(implicit user: UserContext): Unit = {
var cancelling = false
StatusLock.synchronized {
if (status().isRunning && !status().isInstanceOf[Status.Canceling]) {
cancelling = true
this.cancelledByUser = user
this.cancelTimestamp = Some(Instant.now)
status.update(Status.Canceling(status().progress))
children().foreach(_.cancel())
ThreadLock.synchronized {
activity.cancelExecution()
runningThread foreach { thread =>
thread.interrupt() // To interrupt an activity that might be blocking on something else, e.g. slow network connection
}
}
}
if(cancelling) {
// cancel children outside of lock to not run into dead locks
children().foreach(_.cancel())
activity.cancelExecution()
ThreadLock.synchronized {
runningThread foreach { thread =>
thread.interrupt() // To interrupt an activity that might be blocking on something else, e.g. slow network connection
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
package org.silkframework.workspace

import java.util.logging.Logger

import com.typesafe.config.ConfigException

import javax.inject.Inject
import org.silkframework.config.{Config, DefaultConfig, MetaData, Prefixes}
import org.silkframework.config.{Config, DefaultConfig, HasMetaData, MetaData, Prefixes}
import org.silkframework.util.Identifier

/**
Expand All @@ -32,7 +32,8 @@ import org.silkframework.util.Identifier
case class ProjectConfig(id: Identifier = Identifier.random,
prefixes: Prefixes = Prefixes.default,
projectResourceUriOpt: Option[String] = None,
metaData: MetaData = MetaData.empty) {
metaData: MetaData = MetaData.empty) extends HasMetaData {

def withMetaData(metaData: MetaData): ProjectConfig = this.copy(metaData = metaData)

def generateDefaultUri: String = {
Expand All @@ -43,6 +44,10 @@ case class ProjectConfig(id: Identifier = Identifier.random,
def resourceUriOrElseDefaultUri: String = {
projectResourceUriOpt.getOrElse(generateDefaultUri)
}

override def label(maxLength: Int)(implicit prefixes: Prefixes): String = {
metaData.formattedLabel(id, maxLength)
}
}

object ProjectConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ case class DatasetTaskReferenceAutoCompletionProvider() extends PluginParameterA
workspace: WorkspaceReadTrait)
(implicit userContext: UserContext): Traversable[AutoCompletionResult] = {
val taskProject = dependOnParameterValues.headOption.getOrElse(projectId)
val allDatasets = workspace.project(taskProject).tasks[GenericDatasetSpec].map(spec => AutoCompletionResult(spec.id, Some(spec.metaData.label)))
val allDatasets = workspace.project(taskProject).tasks[GenericDatasetSpec].map(spec => AutoCompletionResult(spec.id, spec.metaData.label))
filterResults(searchQuery, allDatasets)
}

Expand All @@ -29,6 +29,6 @@ case class DatasetTaskReferenceAutoCompletionProvider() extends PluginParameterA
workspace: WorkspaceReadTrait)
(implicit userContext: UserContext): Option[String] = {
val taskProject = dependOnParameterValues.headOption.getOrElse(projectId)
workspace.project(taskProject).taskOption[GenericDatasetSpec](value).map(_.metaData.label)
workspace.project(taskProject).taskOption[GenericDatasetSpec](value).flatMap(_.metaData.label)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package org.silkframework.plugins.dataset.rdf.endpoint

import java.io._
import java.util.logging.Logger

import org.apache.jena.query.{Dataset, Query, QueryExecution, QueryExecutionFactory}
import org.apache.jena.rdf.model.{Model, ModelFactory}
import org.apache.jena.riot.{Lang, RDFLanguages}
import org.apache.jena.update.{UpdateExecutionFactory, UpdateFactory, UpdateProcessor}
import org.silkframework.dataset.rdf.{GraphStoreTrait, SparqlEndpoint, SparqlParams}
import org.silkframework.runtime.activity.UserContext

import scala.util.control.NonFatal

/**
* A SPARQL endpoint which executes all queries on a Jena Dataset.
*/
Expand All @@ -20,7 +21,13 @@ class JenaDatasetEndpoint(dataset: Dataset, val sparqlParams: SparqlParams = Spa
}

override def createUpdateExecution(query: String): UpdateProcessor = {
UpdateExecutionFactory.create(UpdateFactory.create(query), dataset)
try {
UpdateExecutionFactory.create(UpdateFactory.create(query), dataset)
}
catch {
case NonFatal(ex) =>
throw ex
}
}

override def graphStoreEndpoint(graph: String): String = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import scala.util.matching.Regex
object PagingSparqlTraversable {

val graphPatternRegex: Regex = """[Gg][Rr][Aa][Pp][Hh]\s+<""".r
private val xmlFactory = XMLInputFactory.newInstance()

private val logger = Logger.getLogger(getClass.getName)

Expand Down Expand Up @@ -47,12 +46,12 @@ object PagingSparqlTraversable {
override def foreach[U](f: SortedMap[String, RdfNode] => U): Unit = {
val parsedQuery = QueryFactory.create(query)
// Don't set graph if the query is already containing a GRAPH pattern (not easily possible to check with parsed query)
if(graphPatternRegex.findFirstIn(query).isEmpty) {
if(graphPatternRegex.findFirstIn(query).isEmpty && parsedQuery.getGraphURIs.size() == 0) {
params.graph foreach { graphURI =>
parsedQuery.addGraphURI(graphURI)
}
}

// FIXME: Also inject FROM NAMED when GRAPH pattern exists and no FROM NAMED was defined in the original query (breaking change).
if (parsedQuery.hasLimit || parsedQuery.hasOffset) {
val inputStream = executeQuery(parsedQuery.serialize(Syntax.syntaxSPARQL_11))
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ case class SparqlEndpointDatasetAutoCompletionProvider() extends PluginParameter
(implicit userContext: UserContext): Traversable[AutoCompletionResult] = {
val allResults = workspace.project(projectId).tasks[GenericDatasetSpec]
.filter(datasetSpec => datasetSpec.data.plugin.isInstanceOf[RdfDataset])
.map(datasetSpec => AutoCompletionResult(datasetSpec.id, Some(datasetSpec.metaData.label)))
.map(datasetSpec => AutoCompletionResult(datasetSpec.id, datasetSpec.metaData.label))
filterResults(searchQuery, allResults)
}

override def valueToLabel(projectId: String, value: String, dependOnParameterValues: Seq[String], workspace: WorkspaceReadTrait)
(implicit userContext: UserContext): Option[String] = {
workspace.project(projectId).taskOption[GenericDatasetSpec](value).map(_.metaData.label)
workspace.project(projectId).taskOption[GenericDatasetSpec](value).flatMap(_.metaData.label)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import scala.collection.JavaConverters._
@Plugin(
id = "sparqlSelectOperator",
label = "SPARQL Select query",
description = "A task that executes a SPARQL Select query on a SPARQL enabled data source and outputs the SPARQL result."
description = "A task that executes a SPARQL Select query on a SPARQL enabled data source and outputs the SPARQL result. If the SPARQL source is defined on a specific graph, " +
"a FROM clause will be added to the query at execution time, except when there already exists a GRAPH or FROM clause in the query. FROM NAMED clauses are not injected."
)
case class SparqlSelectCustomTask(@Param(label = "Select query", value = "A SPARQL 1.1 select query", example = "select * where { ?s ?p ?o }")
selectQuery: MultilineStringParameter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.silkframework.runtime.plugin.MultilineStringParameter
label = "SPARQL Update query",
description =
"""A task that outputs SPARQL Update queries for every entity from the input based on a SPARQL Update template.
The output of this operator should be connected to the SPARQL datasets to which the results should be written."""
The output of this operator should be connected to the SPARQL datasets to which the results should be written. In contrast to the SPARQL select operator, no FROM clause gets injected into the query."""
)
case class SparqlUpdateCustomTask(@Param(label = "SPARQL update query", value = SparqlUpdateCustomTask.sparqlUpdateTemplateDescription,
example = "DELETE DATA { ${<PROP_FROM_ENTITY_SCHEMA1>} rdf:label ${\"PROP_FROM_ENTITY_SCHEMA2\"} }")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ object ExecutionReportSerializers {

def serializeBasicValues(value: ExecutionReport)(implicit writeContext: WriteContext[JsValue]): JsObject = {
Json.obj(
LABEL -> value.task.taskLabel(),
LABEL -> value.task.label(),
OPERATION -> value.operation,
OPERATION_DESC -> value.operationDesc,
TASK -> GenericTaskJsonFormat.write(value.task),
Expand Down Expand Up @@ -96,7 +96,8 @@ object ExecutionReportSerializers {
entityCount = numberValue(value, ENTITY_COUNTER).intValue,
entityErrorCount = numberValue(value, ENTITY_ERROR_COUNTER).intValue,
ruleResults = readRuleResults(objectValue(value, RULE_RESULTS)),
globalErrors = arrayValue(value, GLOBAL_ERRORS).value.map(_.as[String])
globalErrors = arrayValue(value, GLOBAL_ERRORS).value.map(_.as[String]),
error = stringValueOption(value, ERROR)
)
}

Expand Down
Loading

0 comments on commit 77ef295

Please sign in to comment.