Skip to content

Commit 0a83207

Browse files
committed
Add StyleRepositories for files and databases.
1 parent a48f765 commit 0a83207

7 files changed

Lines changed: 668 additions & 0 deletions
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package geoscript.style
2+
3+
import groovy.sql.GroovyRowResult
4+
import groovy.sql.Sql
5+
6+
/**
7+
* A StyleRepository that stores styles in a database table called layer_styles.
8+
* H2, Postgres and SQLite are supported.
9+
* @author Jared Erickson
10+
*/
11+
class DatabaseStyleRepository implements StyleRepository {
12+
13+
private final Sql sql
14+
15+
private final Dialect dialect = Dialect.H2
16+
17+
private enum Dialect {
18+
H2, POSTGRES, SQLITE
19+
}
20+
21+
private DatabaseStyleRepository(Dialect dialect, Sql sql) {
22+
this.dialect = dialect
23+
this.sql = sql
24+
this.createTable()
25+
}
26+
27+
static DatabaseStyleRepository forPostgres(Sql sql) {
28+
new DatabaseStyleRepository(Dialect.POSTGRES, sql)
29+
}
30+
31+
static DatabaseStyleRepository forH2(Sql sql) {
32+
new DatabaseStyleRepository(Dialect.H2, sql)
33+
}
34+
35+
static DatabaseStyleRepository forSqlite(Sql sql) {
36+
new DatabaseStyleRepository(Dialect.SQLITE, sql)
37+
}
38+
39+
@Override
40+
String getDefaultForLayer(String layerName) {
41+
getForLayer(layerName, layerName)
42+
}
43+
44+
@Override
45+
String getForLayer(String layerName, String styleName) {
46+
List results = sql.rows(
47+
"SELECT stylesld FROM layer_styles WHERE f_table_name = :name AND styleName = :styleName",
48+
[name: layerName, styleName: styleName]
49+
)
50+
if (results) {
51+
getText(results[0].stylesld)
52+
} else {
53+
null
54+
}
55+
}
56+
57+
@Override
58+
List<Map<String, String>> getForLayer(String layerName) {
59+
sql.rows(
60+
"""SELECT
61+
id,
62+
f_table_catalog,
63+
f_table_schema,
64+
f_table_name,
65+
f_geometry_column,
66+
styleName,
67+
styleQML,
68+
styleSLD,
69+
useAsDefault,
70+
description,
71+
owner,
72+
ui,
73+
update_time
74+
FROM layer_styles WHERE f_table_name = :name""",
75+
[name: layerName]
76+
).collect { GroovyRowResult result ->
77+
mapRow(result)
78+
}
79+
}
80+
81+
@Override
82+
List<Map<String, String>> getAll() {
83+
sql.rows(
84+
"""SELECT
85+
id,
86+
f_table_catalog,
87+
f_table_schema,
88+
f_table_name,
89+
f_geometry_column,
90+
styleName,
91+
styleQML,
92+
styleSLD,
93+
useAsDefault,
94+
description,
95+
owner,
96+
ui,
97+
update_time
98+
FROM layer_styles"""
99+
).collect { GroovyRowResult result ->
100+
mapRow(result)
101+
}
102+
}
103+
104+
@Override
105+
void save(String layerName, String styleName, String style, Map options = [:]) {
106+
sql.execute("""INSERT INTO layer_styles (
107+
f_table_catalog,
108+
f_table_schema,
109+
f_table_name,
110+
f_geometry_column,
111+
styleName,
112+
styleSLD,
113+
styleQML,
114+
useAsDefault,
115+
description,
116+
owner,
117+
ui
118+
) VALUES (:catalog, :schema, :table, :geometryColumn, :styleName, :sld, :qml, :default, :description, :owner, :ui)""", [
119+
catalog: options.get("catalog", "") as String,
120+
schema: options.get("schema", "public") as String,
121+
table: options.get("table", layerName) as String,
122+
geometryColumn: options.get("geometryColumn", "") as String,
123+
styleName: options.get("stylename", styleName) as String,
124+
sld: options.get("sld", style),
125+
qml: options.get("qml", options.get("qml","")),
126+
default: options.get("useAsDefault", layerName.equalsIgnoreCase(styleName)),
127+
description: options.get("description", "Style ${styleName} for Layer ${layerName}") as String,
128+
owner: options.get("owner", System.getProperty("user.name")) as String,
129+
ui: options.get("ui", options.get("ui","")),
130+
])
131+
}
132+
133+
@Override
134+
void delete(String layerName, String styleName) {
135+
sql.execute(
136+
"delete from layer_styles where f_table_name = :layerName AND stylename = :styleName",
137+
[layerName: layerName, styleName: styleName]
138+
)
139+
}
140+
141+
private void createTable() {
142+
sql.execute('''CREATE TABLE IF NOT EXISTS layer_styles (
143+
id ''' + getPrimaryKey() + ''',
144+
f_table_catalog VARCHAR(256),
145+
f_table_schema VARCHAR(256),
146+
f_table_name VARCHAR(256),
147+
f_geometry_column VARCHAR(256),
148+
styleName VARCHAR(30),
149+
styleQML TEXT,
150+
styleSLD TEXT,
151+
useAsDefault BOOLEAN,
152+
description VARCHAR,
153+
owner VARCHAR(30),
154+
ui VARCHAR(30),
155+
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
156+
)''')
157+
}
158+
159+
private Map mapRow(GroovyRowResult result) {
160+
[
161+
layerName: result.f_table_name,
162+
styleName: result.stylename,
163+
style: getText(result.stylesld),
164+
id: result.id,
165+
f_table_catalog: result.f_table_catalog,
166+
f_table_schema: result.f_table_schema,
167+
f_table_name: result.f_table_name,
168+
f_geometry_column: result.f_geometry_column,
169+
styleQML: getText(result.styleQML),
170+
styleSLD: getText(result.styleSLD),
171+
useAsDefault: result.useAsDefault,
172+
description: result.description,
173+
owner: result.owner,
174+
ui: result.ui,
175+
update_time: result.update_time
176+
]
177+
}
178+
179+
private String getPrimaryKey() {
180+
if (dialect == Dialect.H2) {
181+
"INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL"
182+
} else if (dialect == Dialect.POSTGRES) {
183+
"SERIAL PRIMARY KEY"
184+
} else if (dialect == Dialect.SQLITE) {
185+
"INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"
186+
} else {
187+
"INTEGER PRIMARY KEY AUTO INCREMENT NOT NULL"
188+
}
189+
}
190+
191+
private String getText(Object result) {
192+
if (dialect == Dialect.H2) {
193+
result.characterStream.text
194+
} else if (dialect == Dialect.POSTGRES) {
195+
result
196+
} else if (dialect == Dialect.SQLITE) {
197+
result.toString()
198+
} else {
199+
null
200+
}
201+
}
202+
203+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package geoscript.style
2+
3+
import org.apache.commons.io.FilenameUtils
4+
5+
/**
6+
* A StyleRepository that uses a flat directory structure.
7+
* Each file in the given directory is the default style for the layer.
8+
* @author Jared Erickson
9+
*/
10+
class DirectoryStyleRepository implements StyleRepository {
11+
12+
private final File directory
13+
14+
DirectoryStyleRepository(File directory) {
15+
this.directory = directory
16+
}
17+
18+
@Override
19+
String getDefaultForLayer(String layerName) {
20+
getForLayer(layerName, layerName)
21+
}
22+
23+
@Override
24+
String getForLayer(String layerName, String styleName) {
25+
["sld","css"].findResult { String ext ->
26+
File file = new File(this.directory,"${styleName}.${ext}")
27+
if (file.exists()) {
28+
return file.text
29+
}
30+
}
31+
}
32+
33+
@Override
34+
List<Map<String, String>> getForLayer(String layerName) {
35+
String defaultStyle = getDefaultForLayer(layerName)
36+
if (defaultStyle) {
37+
[
38+
[
39+
layerName: layerName,
40+
styleName: layerName,
41+
style: defaultStyle
42+
]
43+
]
44+
} else {
45+
[]
46+
}
47+
}
48+
49+
@Override
50+
List<Map<String, String>> getAll() {
51+
this.directory.listFiles(new StyleFileNameFilter()).collect { File file ->
52+
[
53+
layerName: FilenameUtils.getBaseName(file.name),
54+
styleName: FilenameUtils.getBaseName(file.name),
55+
style: file.text
56+
]
57+
}
58+
}
59+
60+
@Override
61+
void save(String layerName, String styleName, String style, Map options = [:]) {
62+
File file = new File(directory, "${styleName}.${options.get('type','sld')}")
63+
file.text = style
64+
}
65+
66+
@Override
67+
void delete(String layerName, String styleName) {
68+
["sld","css"].each { String ext ->
69+
File file = new File(directory, "${styleName}.${ext}")
70+
if (file.exists()) {
71+
file.delete()
72+
}
73+
}
74+
}
75+
76+
private static class StyleFileNameFilter implements FilenameFilter {
77+
@Override
78+
boolean accept(File dir, String name) {
79+
name.endsWith(".sld") || name.endsWith(".css")
80+
}
81+
}
82+
83+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package geoscript.style
2+
3+
import org.apache.commons.io.FilenameUtils
4+
5+
/**
6+
* A StyleRepository that uses a nested directory structure. There
7+
* is a directory for each layer which contains a file for each style.
8+
* @author Jared Erickson
9+
*/
10+
class NestedDirectoryStyleRepository implements StyleRepository {
11+
12+
private final File directory
13+
14+
NestedDirectoryStyleRepository(File directory) {
15+
this.directory = directory
16+
}
17+
18+
@Override
19+
String getDefaultForLayer(String layerName) {
20+
getForLayer(layerName, layerName)
21+
}
22+
23+
@Override
24+
String getForLayer(String layerName, String styleName) {
25+
File layerDirectory = new File(directory, layerName)
26+
if (layerDirectory.exists()) {
27+
["sld", "css"].findResult { String ext ->
28+
File file = new File(layerDirectory, "${styleName}.${ext}")
29+
if (file.exists()) {
30+
return file.text
31+
}
32+
}
33+
} else {
34+
""
35+
}
36+
}
37+
38+
@Override
39+
List<Map<String, String>> getForLayer(String layerName) {
40+
File layerDirectory = new File(directory, layerName)
41+
if (layerDirectory.exists()) {
42+
layerDirectory.listFiles(new StyleFileNameFilter()).collect { File file ->
43+
[
44+
layerName: FilenameUtils.getBaseName(file.name),
45+
styleName: FilenameUtils.getBaseName(file.name),
46+
style : file.text
47+
]
48+
}
49+
} else {
50+
[]
51+
}
52+
}
53+
54+
@Override
55+
List<Map<String, String>> getAll() {
56+
List styles = []
57+
this.directory.listFiles(new DirectoryFileFilter()).each { File dir ->
58+
dir.listFiles(new StyleFileNameFilter()).each { File file ->
59+
styles.add([
60+
layerName: FilenameUtils.getBaseName(file.name),
61+
styleName: FilenameUtils.getBaseName(file.name),
62+
style : file.text
63+
])
64+
}
65+
}
66+
styles
67+
}
68+
69+
@Override
70+
void save(String layerName, String styleName, String style, Map options = [:]) {
71+
File layerDirectory = new File(directory, layerName)
72+
layerDirectory.mkdir()
73+
File file = new File(layerDirectory, "${styleName}.${options.get('type','sld')}")
74+
file.text = style
75+
}
76+
77+
@Override
78+
void delete(String layerName, String styleName) {
79+
File layerDirectory = new File(directory, layerName)
80+
if (layerDirectory.exists()) {
81+
["sld", "css"].each { String ext ->
82+
File file = new File(layerDirectory, "${styleName}.${ext}")
83+
if (file.exists()) {
84+
file.delete()
85+
}
86+
}
87+
}
88+
}
89+
90+
private static class StyleFileNameFilter implements FilenameFilter {
91+
@Override
92+
boolean accept(File dir, String name) {
93+
name.endsWith(".sld") || name.endsWith(".css")
94+
}
95+
}
96+
97+
private static class DirectoryFileFilter implements FileFilter {
98+
@Override
99+
boolean accept(File pathname) {
100+
pathname.isDirectory()
101+
}
102+
}
103+
104+
}

0 commit comments

Comments
 (0)