comparison pkg/geoserver/boot.go @ 876:8b9bd9ccdd93 geo-style

Upload style during boot. TODO: Connect with layer.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sun, 30 Sep 2018 19:42:16 +0200
parents 371c756f0370
children 254cd247826d
comparison
equal deleted inserted replaced
875:371c756f0370 876:8b9bd9ccdd93
1 package geoserver 1 package geoserver
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
5 "encoding/json" 5 "encoding/json"
6 "encoding/xml"
6 "fmt" 7 "fmt"
8 "io"
7 "log" 9 "log"
8 "net" 10 "net"
9 "net/http" 11 "net/http"
10 "net/url" 12 "net/url"
11 "strings" 13 "strings"
35 37
36 func asJSON(req *http.Request) { 38 func asJSON(req *http.Request) {
37 req.Header.Set("Content-Type", "application/json") 39 req.Header.Set("Content-Type", "application/json")
38 } 40 }
39 41
42 func asContentType(req *http.Request, contentType string) {
43 req.Header.Set("Content-Type", contentType)
44 }
45
40 func ensureWorkspace() error { 46 func ensureWorkspace() error {
41 var ( 47 var (
42 url = config.GeoServerURL() 48 geoURL = config.GeoServerURL()
43 user = config.GeoServerUser() 49 user = config.GeoServerUser()
44 password = config.GeoServerPassword() 50 password = config.GeoServerPassword()
45 auth = basicAuth(user, password) 51 auth = basicAuth(user, password)
46 ) 52 )
47 53
48 // Probe workspace. 54 // Probe workspace.
49 req, err := http.NewRequest( 55 req, err := http.NewRequest(
50 http.MethodGet, 56 http.MethodGet,
51 url+"/rest/workspaces/"+workspaceName+".json", 57 geoURL+"/rest/workspaces/"+workspaceName+".json",
52 nil) 58 nil)
53 if err != nil { 59 if err != nil {
54 return err 60 return err
55 } 61 }
56 auth(req) 62 auth(req)
70 76
71 const createJSON = `{"workspace":{"name":"` + workspaceName + `"}}` 77 const createJSON = `{"workspace":{"name":"` + workspaceName + `"}}`
72 78
73 req, err = http.NewRequest( 79 req, err = http.NewRequest(
74 http.MethodPost, 80 http.MethodPost,
75 url+"/rest/workspaces", 81 geoURL+"/rest/workspaces",
76 strings.NewReader(createJSON)) 82 strings.NewReader(createJSON))
77 if err != nil { 83 if err != nil {
78 return err 84 return err
79 } 85 }
80 auth(req) 86 auth(req)
92 return err 98 return err
93 } 99 }
94 100
95 func ensureDataStore() error { 101 func ensureDataStore() error {
96 var ( 102 var (
97 url = config.GeoServerURL() 103 geoURL = config.GeoServerURL()
98 user = config.GeoServerUser() 104 user = config.GeoServerUser()
99 password = config.GeoServerPassword() 105 password = config.GeoServerPassword()
100 auth = basicAuth(user, password) 106 auth = basicAuth(user, password)
101 ) 107 )
102 108
103 // Probe datastore. 109 // Probe datastore.
104 req, err := http.NewRequest( 110 req, err := http.NewRequest(
105 http.MethodGet, 111 http.MethodGet,
106 url+"/rest/workspaces/"+workspaceName+"/datastores/"+datastoreName+".json", 112 geoURL+"/rest/workspaces/"+workspaceName+"/datastores/"+datastoreName+".json",
107 nil) 113 nil)
108 if err != nil { 114 if err != nil {
109 return err 115 return err
110 } 116 }
111 auth(req) 117 auth(req)
152 return err 158 return err
153 } 159 }
154 160
155 req, err = http.NewRequest( 161 req, err = http.NewRequest(
156 http.MethodPost, 162 http.MethodPost,
157 url+"/rest/workspaces/"+workspaceName+"/datastores", 163 geoURL+"/rest/workspaces/"+workspaceName+"/datastores",
158 bytes.NewReader(out.Bytes())) 164 bytes.NewReader(out.Bytes()))
159 if err != nil { 165 if err != nil {
160 return err 166 return err
161 } 167 }
162 auth(req) 168 auth(req)
175 return err 181 return err
176 } 182 }
177 183
178 func ensureFeatures() error { 184 func ensureFeatures() error {
179 var ( 185 var (
180 url = config.GeoServerURL() 186 geoURL = config.GeoServerURL()
181 user = config.GeoServerUser() 187 user = config.GeoServerUser()
182 password = config.GeoServerPassword() 188 password = config.GeoServerPassword()
183 auth = basicAuth(user, password) 189 auth = basicAuth(user, password)
184 ) 190 )
185 191
209 } 215 }
210 216
211 // Fetch all featuretypes. 217 // Fetch all featuretypes.
212 req, err := http.NewRequest( 218 req, err := http.NewRequest(
213 http.MethodGet, 219 http.MethodGet,
214 url+"/rest/workspaces/"+workspaceName+ 220 geoURL+"/rest/workspaces/"+workspaceName+
215 "/datastores/"+datastoreName+ 221 "/datastores/"+datastoreName+
216 "/featuretypes.json", 222 "/featuretypes.json",
217 nil) 223 nil)
218 if err != nil { 224 if err != nil {
219 return err 225 return err
261 return err 267 return err
262 } 268 }
263 269
264 req, err := http.NewRequest( 270 req, err := http.NewRequest(
265 http.MethodPost, 271 http.MethodPost,
266 url+"/rest/workspaces/"+workspaceName+ 272 geoURL+"/rest/workspaces/"+workspaceName+
267 "/datastores/"+datastoreName+ 273 "/datastores/"+datastoreName+
268 "/featuretypes", 274 "/featuretypes",
269 bytes.NewReader(out.Bytes())) 275 bytes.NewReader(out.Bytes()))
270 if err != nil { 276 if err != nil {
271 return err 277 return err
294 return nil 300 return nil
295 } 301 }
296 302
297 log.Println("info: delete workspace " + workspaceName) 303 log.Println("info: delete workspace " + workspaceName)
298 var ( 304 var (
299 url = config.GeoServerURL() 305 geoURL = config.GeoServerURL()
300 user = config.GeoServerUser() 306 user = config.GeoServerUser()
301 password = config.GeoServerPassword() 307 password = config.GeoServerPassword()
302 auth = basicAuth(user, password) 308 auth = basicAuth(user, password)
303 ) 309 )
304 310
305 req, err := http.NewRequest( 311 req, err := http.NewRequest(
306 http.MethodDelete, 312 http.MethodDelete,
307 url+"/rest/workspaces/"+workspaceName+"?recurse=true", 313 geoURL+"/rest/workspaces/"+workspaceName+"?recurse=true",
308 nil) 314 nil)
309 if err != nil { 315 if err != nil {
310 return err 316 return err
311 } 317 }
312 auth(req) 318 auth(req)
315 } 321 }
316 322
317 func ensureStyles() error { 323 func ensureStyles() error {
318 log.Println("info: creating styles") 324 log.Println("info: creating styles")
319 325
320 // TODO: Implement me! 326 var (
327 geoURL = config.GeoServerURL()
328 user = config.GeoServerUser()
329 password = config.GeoServerPassword()
330 auth = basicAuth(user, password)
331 )
332
333 type styles struct {
334 Styles struct {
335 Style []struct {
336 Name string `json:"name"`
337 } `json:"style"`
338 } `json:"styles"`
339 }
340
341 var stls styles
342
343 hasStyle := func(name string) bool {
344 for i := range stls.Styles.Style {
345 if stls.Styles.Style[i].Name == name {
346 return true
347 }
348 }
349 return false
350 }
351
352 req, err := http.NewRequest(
353 http.MethodGet,
354 geoURL+"/rest/workspaces/"+workspaceName+"/styles.json",
355 nil)
356 if err != nil {
357 return err
358 }
359 auth(req)
360 resp, err := http.DefaultClient.Do(req)
361 if err != nil {
362 return err
363 }
364
365 // Fetch all styles
366 if err := json.NewDecoder(resp.Body).Decode(&stls); err != nil {
367 // XXX: Same quirk as with featuretypes.
368 }
369 resp.Body.Close()
370
371 entries := models.InternalServices.Filter(
372 models.IntAnd(models.IntWMS, models.IntWithStyle))
373
374 for i := range entries {
375 if hasStyle(entries[i].Name) {
376 log.Printf("already has style for %s\n", entries[i].Name)
377 continue
378 }
379
380 log.Printf("creating style %s\n", entries[i].Name)
381
382 req, err := http.NewRequest(
383 http.MethodPost,
384 geoURL+"/rest/workspaces/"+workspaceName+"/styles?name="+
385 url.QueryEscape(entries[i].Name),
386 strings.NewReader(entries[i].Style.String))
387 if err != nil {
388 return err
389 }
390 auth(req)
391 if isSymbologyEncoding(entries[i].Style.String) {
392 asContentType(req, "application/vnd.ogc.se+xml")
393 } else {
394 asContentType(req, "application/vnd.ogc.sld+xml")
395 }
396 resp, err := http.DefaultClient.Do(req)
397 if err != nil {
398 return err
399 }
400
401 if resp.StatusCode != http.StatusCreated {
402 return fmt.Errorf("cannot create style %s (%s)",
403 entries[i].Name, http.StatusText(resp.StatusCode))
404 }
405
406 // TODO: Connect with feature.
407 }
321 408
322 return nil 409 return nil
410 }
411
412 // isSymbologyEncoding tries to figure out if its plain SLD or SE.
413 func isSymbologyEncoding(data string) bool {
414 decoder := xml.NewDecoder(strings.NewReader(data))
415 for {
416 tok, err := decoder.Token()
417 switch {
418 case tok == nil && err == io.EOF:
419 return false
420 case err != nil:
421 log.Printf("warn: invalid XML: %v\n", err)
422 return false
423 }
424 if t, ok := tok.(xml.StartElement); ok &&
425 t.Name.Space == "http://www.opengis.net/se" {
426 return true
427 }
428 }
323 } 429 }
324 430
325 func prepareGeoServer() error { 431 func prepareGeoServer() error {
326 432
327 if config.DBUser() == "" { 433 if config.DBUser() == "" {