Skip to content

Commit 02e0484

Browse files
authored
Merge pull request #5 from herminiogg/enhancement-#4
Enhancement #4
2 parents 6616f38 + 18e205e commit 02e0484

File tree

10 files changed

+478
-8
lines changed

10 files changed

+478
-8
lines changed

.github/workflows/scala.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Scala CI
2+
3+
on: push
4+
5+
jobs:
6+
build:
7+
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- uses: actions/checkout@v2
12+
- name: Set up JDK 8
13+
uses: actions/setup-java@v2
14+
with:
15+
java-version: '8'
16+
distribution: 'adopt'
17+
- name: Run tests
18+
run: sbt test

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ project/plugins/project/
1515
# Scala-IDE specific
1616
.scala_dependencies
1717
.worksheet
18-
.idea
18+
.idea
19+
20+
# Testing
21+
tmp

build.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ libraryDependencies += "info.picocli" % "picocli" % "4.0.4"
2020

2121
libraryDependencies += "be.ugent.rml" % "rmlmapper" % "4.9.0"
2222

23+
libraryDependencies += "org.scalatest" % "scalatest_2.12" % "3.2.11" % "test"
24+
2325
// Allows to avoid the conflicts between ShExML and RML jena versions
2426
dependencyOverrides += "org.apache.jena" % "apache-jena-libs" % "3.8.0"
2527

src/main/resources/javaDataAccessSingleton.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
public class DataAccessSingleton {
66

77
private static DataAccess dataAccess;
8-
private static String dataFile = "$pathToData/data.ttl";
8+
private static String dataFile = "$pathToData";
99
private static String mappingRules;
1010
private static String mappingLanguage;
1111
private static Long reloadMinutes;

src/main/scala/com/herminiogarcia/dmaog/codeGeneration/CodeGenerator.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ class CodeGenerator(mappingRules: String, mappingLanguage: String, pathToGenerat
2929

3030
private def generateData(): String = {
3131
val rdfResult = generateDataByMappingLanguage(mappingRules, mappingLanguage, username, password, drivers)
32-
val finalPath = pathToGenerate + "/" + "data.ttl"
3332
val result = Await.result(rdfResult, Duration.Inf)
34-
writeFile(finalPath, result)
35-
finalPath
33+
writeFile("data.ttl", result)
34+
pathToGenerate + "/" + "data.ttl"
3635
}
3736

3837
private def getTypes(model: Model): List[String] = {
@@ -105,7 +104,8 @@ class CodeGenerator(mappingRules: String, mappingLanguage: String, pathToGenerat
105104

106105
private def generateClasses(attributesByType: Map[String, List[DataTypedPredicate]]): Unit = {
107106
val rdfsType = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
108-
val model = loadModel(pathToGenerate + "/data.ttl", None, None, None, username, password, drivers)
107+
val finalPath = if(pathToGenerate.endsWith("/")) pathToGenerate + "data.ttl" else pathToGenerate + "/" + "data.ttl"
108+
val model = loadModel(finalPath, None, None, None, username, password, drivers)
109109
val prefixes = model.getNsPrefixMap.asScala.toMap
110110
val convertPrefixedNameFunction = convertPrefixedName(prefixes)_
111111
attributesByType.keys.foreach(t => {
@@ -134,7 +134,7 @@ class CodeGenerator(mappingRules: String, mappingLanguage: String, pathToGenerat
134134
val singletonCode = loadFromResources("javaDataAccessSingleton.java")
135135
.replaceFirst("\\$package", packageName)
136136
.replaceFirst("\\$drivers", drivers.getOrElse(""))
137-
.replaceFirst("\\$pathToData", pathToGenerate)
137+
.replaceFirst("\\$pathToData", finalPath)
138138
writeFile("DataAccessSingleton.java", singletonCode)
139139

140140
}
@@ -152,7 +152,7 @@ class CodeGenerator(mappingRules: String, mappingLanguage: String, pathToGenerat
152152
}
153153

154154
private def writeFile(filename: String, content: String): Unit = {
155-
val file = new PrintWriter(new File(filename))
155+
val file = new PrintWriter(new File(pathToGenerate + "/" + filename))
156156
file.write(content)
157157
file.close()
158158
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.herminiogarcia.dmaog
2+
3+
import com.herminiogarcia.dmaog.codeGeneration.CodeGenerator
4+
5+
import java.io.File
6+
7+
trait ClassGenerator {
8+
9+
val rules: String
10+
11+
def generateClasses(): Unit = {
12+
new File("./tmp").mkdir() //create temp directory for tests
13+
new CodeGenerator(rules, "shexml", "./tmp/", "com.example",
14+
None, None, None).generate()
15+
}
16+
17+
def loadClass(entityName: String): String = {
18+
val buffer = scala.io.Source.fromFile("./tmp/"+ entityName + ".java")
19+
val result = buffer.mkString
20+
buffer.close()
21+
result
22+
}
23+
24+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.herminiogarcia.dmaog
2+
3+
import org.scalatest.BeforeAndAfter
4+
import org.scalatest.funsuite.AnyFunSuite
5+
6+
class DataAccessSingletonTest extends AnyFunSuite with BeforeAndAfter with ClassGenerator {
7+
8+
val rules =
9+
"""
10+
|PREFIX : <http://example.com/>
11+
|PREFIX dbr: <http://dbpedia.org/resource/>
12+
|PREFIX schema: <http://schema.org/>
13+
|PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
14+
|SOURCE films_xml_file <http://shexml.herminiogarcia.com/files/films.xml>
15+
|SOURCE films_json_file <http://shexml.herminiogarcia.com/files/films.json>
16+
|ITERATOR film_xml <xpath: //film> {
17+
| FIELD id <@id>
18+
| FIELD name <name>
19+
| FIELD year <year>
20+
| FIELD country <country>
21+
| FIELD directors <crew/directors/director>
22+
| FIELD screenwritters <crew//screenwritter>
23+
| FIELD music <crew/music>
24+
| FIELD photography <crew/photography>
25+
|}
26+
|ITERATOR film_json <jsonpath: $.films[*]> {
27+
| PUSHED_FIELD id <id>
28+
| FIELD name <name>
29+
| FIELD year <year>
30+
| FIELD country <country>
31+
| FIELD directors <crew.director>
32+
| FIELD screenwritters <crew.screenwritter>
33+
| FIELD music <crew.music>
34+
| FIELD photography <crew.cinematography>
35+
|}
36+
|EXPRESSION films <films_xml_file.film_xml UNION films_json_file.film_json>
37+
|
38+
|:Films :[films.id] {
39+
| a :Film ;
40+
| schema:name [films.name] ;
41+
| :year [films.year] xsd:integer ;
42+
| schema:countryOfOrigin dbr:[films.country] ;
43+
| schema:director dbr:[films.directors] ;
44+
| :screenwritter dbr:[films.screenwritters] ;
45+
| schema:musicBy dbr:[films.music] ;
46+
| :cinematographer dbr:[films.photography] ;
47+
|}
48+
|""".stripMargin
49+
50+
before {
51+
generateClasses()
52+
}
53+
54+
test("Class name and package are correctly generated") {
55+
val content = loadClass("DataAccessSingleton")
56+
assert(content.contains("public class DataAccessSingleton"))
57+
assert(content.contains("package com.example;"))
58+
}
59+
60+
test("Attributes are correctly generated") {
61+
val content = loadClass("DataAccessSingleton")
62+
63+
assert(content.contains("private static DataAccess dataAccess;"))
64+
assert(content.contains("private static String dataFile = \"./tmp/data.ttl\";"))
65+
assert(content.contains("private static String mappingRules;"))
66+
assert(content.contains("private static String mappingLanguage;"))
67+
assert(content.contains("private static Long reloadMinutes;"))
68+
assert(content.contains("private static String username;"))
69+
assert(content.contains("private static String password;"))
70+
assert(content.contains("private static String drivers = \"\";"))
71+
}
72+
73+
test("getInstance is correctly generated") {
74+
val content = loadClass("DataAccessSingleton")
75+
val getInstance = ("public static DataAccess getInstance[(][)][ \r\n]*[{][ \r\n]*if[(]dataAccess == null[)]" +
76+
"[ \r\n]*[{][ \r\n]*dataAccess = new DataAccess[(]dataFile, mappingRules, mappingLanguage, reloadMinutes, username, password, drivers[)];" +
77+
"[ \r\n]*[}][ \r\n]*return dataAccess;[ \r\n]*[}]").r
78+
79+
assert(getInstance.findFirstIn(content).isDefined)
80+
}
81+
82+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package com.herminiogarcia.dmaog
2+
3+
class FilmAndActorCodeGenerationTest extends FilmCodeGenerationTest {
4+
5+
override val rules =
6+
"""
7+
|PREFIX : <http://example.com/>
8+
|PREFIX dbr: <http://dbpedia.org/resource/>
9+
|PREFIX schema: <http://schema.org/>
10+
|PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
11+
|SOURCE films_xml_file <http://shexml.herminiogarcia.com/files/films.xml>
12+
|SOURCE films_json_file <http://shexml.herminiogarcia.com/files/films.json>
13+
|ITERATOR film_xml <xpath: //film> {
14+
| FIELD id <@id>
15+
| FIELD name <name>
16+
| FIELD year <year>
17+
| FIELD country <country>
18+
| FIELD directors <crew/directors/director>
19+
| FIELD screenwritters <crew//screenwritter>
20+
| FIELD music <crew/music>
21+
| FIELD photography <crew/photography>
22+
| ITERATOR actors <cast/actor> {
23+
| FIELD name <name>
24+
| FIELD role <role>
25+
| FIELD film <../../@id>
26+
| }
27+
| ITERATOR actresses <cast/actress> {
28+
| FIELD name <name>
29+
| FIELD role <role>
30+
| FIELD film <../../@id>
31+
| }
32+
|}
33+
|ITERATOR film_json <jsonpath: $.films[*]> {
34+
| PUSHED_FIELD id <id>
35+
| FIELD name <name>
36+
| FIELD year <year>
37+
| FIELD country <country>
38+
| FIELD directors <crew.director>
39+
| FIELD screenwritters <crew.screenwritter>
40+
| FIELD music <crew.music>
41+
| FIELD photography <crew.cinematography>
42+
| ITERATOR actors <cast[*]> {
43+
| FIELD name <name>
44+
| FIELD role <role>
45+
| POPPED_FIELD film <id>
46+
| }
47+
|}
48+
|EXPRESSION films <films_xml_file.film_xml UNION films_json_file.film_json>
49+
|
50+
|:Films :[films.id] {
51+
| a :Film ;
52+
| schema:name [films.name] ;
53+
| :year [films.year] xsd:integer ;
54+
| schema:countryOfOrigin dbr:[films.country] ;
55+
| schema:director dbr:[films.directors] ;
56+
| :screenwritter dbr:[films.screenwritters] ;
57+
| schema:musicBy dbr:[films.music] ;
58+
| :cinematographer dbr:[films.photography] ;
59+
| schema:actor @:Actor ;
60+
| schema:actor @:Actress ;
61+
|}
62+
|
63+
|:Actor dbr:[films.actors.name] {
64+
| a :Actor ;
65+
| :name [films.actors.name] ;
66+
| :appear_on :[films.actors.film] ;
67+
|}
68+
|
69+
|:Actress dbr:[films.actresses.name] {
70+
| a :Actor ;
71+
| :name [films.actresses.name] ;
72+
| :appear_on :[films.actresses.film] ;
73+
|}
74+
|""".stripMargin
75+
76+
test("Actor class name and package are correctly generated") {
77+
val content = loadClass("Actor")
78+
assert(content.contains("public class Actor"))
79+
assert(content.contains("package com.example;"))
80+
}
81+
82+
test("Film to Actor relation is correctly generated") {
83+
val content = loadClass("Film")
84+
85+
assert(content.contains("private List<IRIValue> schemaActor;"))
86+
87+
val setSchemaActor = "public Film setSchemaActor\\(List<IRIValue> schemaActor\\)[ \r\n]*[{][ \r\n]*this.schemaActor = schemaActor;[ \r\n]*return this;[ \r\n]*[}]".r
88+
assert(setSchemaActor.findFirstIn(content).isDefined)
89+
90+
val getSchemaActor = "public List<IRIValue> getSchemaActor\\(\\)[ \r\n]*[{][ \r\n]*return this.schemaActor;[ \r\n]*[}]".r
91+
assert(getSchemaActor.findFirstIn(content).isDefined)
92+
}
93+
94+
test("Actor attributes are correctly generated") {
95+
val content = loadClass("Actor")
96+
97+
assert(content.contains("public final static String rdfType = \"http://example.com/Actor\";"))
98+
assert(content.contains("public final static String subjectPrefix = \"http://dbpedia.org/resource/\";"))
99+
100+
assert(content.contains("private String name;"))
101+
assert(content.contains("private IRIValue appear_on;"))
102+
assert(content.contains("private IRIValue id;"))
103+
}
104+
105+
test("Actor constructor is correctly generated") {
106+
val content = loadClass("Actor")
107+
108+
assert("public Actor\\(\\)[ \r\n]*[{][ \r\n]*[}]".r.findFirstIn(content).isDefined)
109+
}
110+
111+
test("Actor setters are correctly generated") {
112+
val content = loadClass("Actor")
113+
val setName = "public Actor setName\\(String name\\)[ \r\n]*[{][ \r\n]*this.name = name;[ \r\n]*return this;[ \r\n]*[}]".r
114+
val setAppear_on = "public Actor setAppear_on\\(IRIValue appear_on\\)[ \r\n]*[{][ \r\n]*this.appear_on = appear_on;[ \r\n]*return this;[ \r\n]*[}]".r
115+
val setId = "public Actor setId\\(IRIValue id\\)[ \r\n]*[{][ \r\n]*this.id = id;[ \r\n]*return this;[ \r\n]*[}]".r
116+
117+
assert(setName.findFirstIn(content).isDefined)
118+
assert(setAppear_on.findFirstIn(content).isDefined)
119+
assert(setId.findFirstIn(content).isDefined)
120+
}
121+
122+
test("Actor getters are correctly generated") {
123+
val content = loadClass("Actor")
124+
val getName = "public String getName\\(\\)[ \r\n]*[{][ \r\n]*return this.name;[ \r\n]*[}]".r
125+
val getAppear_on = "public IRIValue getAppear_on\\(\\)[ \r\n]*[{][ \r\n]*return this.appear_on;[ \r\n]*[}]".r
126+
val getId = "public IRIValue getId\\(\\)[ \r\n]*[{][ \r\n]*return this.id;[ \r\n]*[}]".r
127+
128+
assert(getName.findFirstIn(content).isDefined)
129+
assert(getAppear_on.findFirstIn(content).isDefined)
130+
assert(getId.findFirstIn(content).isDefined)
131+
}
132+
133+
}

0 commit comments

Comments
 (0)