1
2
3
4
5
6 package org.tailormap.api.configuration.dev;
7
8 import static org.tailormap.api.persistence.Configuration.HOME_PAGE;
9 import static org.tailormap.api.persistence.Configuration.PORTAL_MENU;
10 import static org.tailormap.api.persistence.json.GeoServiceProtocol.QUANTIZEDMESH;
11 import static org.tailormap.api.persistence.json.GeoServiceProtocol.TILES3D;
12 import static org.tailormap.api.persistence.json.GeoServiceProtocol.WMS;
13 import static org.tailormap.api.persistence.json.GeoServiceProtocol.WMTS;
14 import static org.tailormap.api.persistence.json.GeoServiceProtocol.XYZ;
15 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.ATTRIBUTE_LIST;
16 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.EXPORT;
17 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.FEATURE_INFO;
18 import static org.tailormap.api.security.AuthorizationService.ACCESS_TYPE_READ;
19
20 import com.fasterxml.jackson.core.JsonProcessingException;
21 import com.fasterxml.jackson.databind.ObjectMapper;
22 import java.io.IOException;
23 import java.lang.invoke.MethodHandles;
24 import java.time.OffsetDateTime;
25 import java.time.ZoneId;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.NoSuchElementException;
31 import java.util.Optional;
32 import java.util.Set;
33 import java.util.UUID;
34 import org.apache.solr.client.solrj.SolrServerException;
35 import org.quartz.SchedulerException;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.springframework.beans.factory.annotation.Value;
39 import org.springframework.boot.SpringApplication;
40 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
41 import org.springframework.boot.context.event.ApplicationReadyEvent;
42 import org.springframework.context.ApplicationContext;
43 import org.springframework.context.event.EventListener;
44 import org.springframework.core.io.ClassPathResource;
45 import org.springframework.jdbc.core.simple.JdbcClient;
46 import org.springframework.transaction.annotation.Transactional;
47 import org.tailormap.api.admin.model.TaskSchedule;
48 import org.tailormap.api.geotools.featuresources.FeatureSourceFactoryHelper;
49 import org.tailormap.api.geotools.featuresources.JDBCFeatureSourceHelper;
50 import org.tailormap.api.geotools.featuresources.WFSFeatureSourceHelper;
51 import org.tailormap.api.persistence.Application;
52 import org.tailormap.api.persistence.Catalog;
53 import org.tailormap.api.persistence.Configuration;
54 import org.tailormap.api.persistence.GeoService;
55 import org.tailormap.api.persistence.Group;
56 import org.tailormap.api.persistence.Page;
57 import org.tailormap.api.persistence.SearchIndex;
58 import org.tailormap.api.persistence.TMFeatureSource;
59 import org.tailormap.api.persistence.TMFeatureType;
60 import org.tailormap.api.persistence.Upload;
61 import org.tailormap.api.persistence.User;
62 import org.tailormap.api.persistence.helper.GeoServiceHelper;
63 import org.tailormap.api.persistence.json.AppContent;
64 import org.tailormap.api.persistence.json.AppLayerSettings;
65 import org.tailormap.api.persistence.json.AppSettings;
66 import org.tailormap.api.persistence.json.AppTreeLayerNode;
67 import org.tailormap.api.persistence.json.AppTreeLevelNode;
68 import org.tailormap.api.persistence.json.AppTreeNode;
69 import org.tailormap.api.persistence.json.AppUiSettings;
70 import org.tailormap.api.persistence.json.AttributeSettings;
71 import org.tailormap.api.persistence.json.AuthorizationRule;
72 import org.tailormap.api.persistence.json.AuthorizationRuleDecision;
73 import org.tailormap.api.persistence.json.Bounds;
74 import org.tailormap.api.persistence.json.CatalogNode;
75 import org.tailormap.api.persistence.json.FeatureTypeRef;
76 import org.tailormap.api.persistence.json.FeatureTypeTemplate;
77 import org.tailormap.api.persistence.json.GeoServiceDefaultLayerSettings;
78 import org.tailormap.api.persistence.json.GeoServiceLayerSettings;
79 import org.tailormap.api.persistence.json.GeoServiceSettings;
80 import org.tailormap.api.persistence.json.JDBCConnectionProperties;
81 import org.tailormap.api.persistence.json.MenuItem;
82 import org.tailormap.api.persistence.json.PageTile;
83 import org.tailormap.api.persistence.json.ServiceAuthentication;
84 import org.tailormap.api.persistence.json.TailormapObjectRef;
85 import org.tailormap.api.persistence.json.TileLayerHiDpiMode;
86 import org.tailormap.api.repository.ApplicationRepository;
87 import org.tailormap.api.repository.CatalogRepository;
88 import org.tailormap.api.repository.ConfigurationRepository;
89 import org.tailormap.api.repository.FeatureSourceRepository;
90 import org.tailormap.api.repository.GeoServiceRepository;
91 import org.tailormap.api.repository.GroupRepository;
92 import org.tailormap.api.repository.PageRepository;
93 import org.tailormap.api.repository.SearchIndexRepository;
94 import org.tailormap.api.repository.UploadRepository;
95 import org.tailormap.api.repository.UserRepository;
96 import org.tailormap.api.scheduling.FailingPocTask;
97 import org.tailormap.api.scheduling.IndexTask;
98 import org.tailormap.api.scheduling.InterruptablePocTask;
99 import org.tailormap.api.scheduling.PocTask;
100 import org.tailormap.api.scheduling.TMJobDataMap;
101 import org.tailormap.api.scheduling.Task;
102 import org.tailormap.api.scheduling.TaskManagerService;
103 import org.tailormap.api.scheduling.TaskType;
104 import org.tailormap.api.security.InternalAdminAuthentication;
105 import org.tailormap.api.solr.SolrHelper;
106 import org.tailormap.api.solr.SolrService;
107 import org.tailormap.api.viewer.model.AppStyling;
108 import org.tailormap.api.viewer.model.Component;
109 import org.tailormap.api.viewer.model.ComponentConfig;
110
111
112
113
114
115 @org.springframework.context.annotation.Configuration
116 @ConditionalOnProperty(name = "tailormap-api.database.populate-testdata", havingValue = "true")
117 public class PopulateTestData {
118
119 private static final Logger logger =
120 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
121 private final ApplicationContext appContext;
122 private final UserRepository userRepository;
123 private final GroupRepository groupRepository;
124 private final CatalogRepository catalogRepository;
125 private final GeoServiceRepository geoServiceRepository;
126 private final GeoServiceHelper geoServiceHelper;
127 private final SolrService solrService;
128 private final TaskManagerService taskManagerService;
129 private final FeatureSourceRepository featureSourceRepository;
130 private final ApplicationRepository applicationRepository;
131 private final ConfigurationRepository configurationRepository;
132 private final SearchIndexRepository searchIndexRepository;
133 private final FeatureSourceFactoryHelper featureSourceFactoryHelper;
134 private final UploadRepository uploadRepository;
135 private final PageRepository pageRepository;
136 private final JdbcClient jdbcClient;
137
138 @Value("${spatial.dbs.connect:false}")
139 private boolean connectToSpatialDbs;
140
141 @Value("#{'${tailormap-api.database.populate-testdata.categories}'.split(',')}")
142 private Set<String> categories;
143
144 @Value("${spatial.dbs.localhost:true}")
145 private boolean connectToSpatialDbsAtLocalhost;
146
147 @Value("${tailormap-api.database.populate-testdata.admin-hashed-password}")
148 private String adminHashedPassword;
149
150 @Value("${tailormap-api.database.populate-testdata.exit:false}")
151 private boolean exit;
152
153 @Value("${MAP5_URL:#{null}}")
154 private String map5url;
155
156 private final String tiles3dProxyUsername = "b3p";
157
158
159 private final String tiles3dProxyPassword = "cOxPlJFWmtndFk0eVg5VdL";
160
161 @Value("${tailormap-api.solr-batch-size:1000}")
162 private int solrBatchSize;
163
164 @Value("${tailormap-api.solr-geometry-validation-rule:repairBuffer0}")
165 private String solrGeometryValidationRule;
166
167 public PopulateTestData(
168 ApplicationContext appContext,
169 UserRepository userRepository,
170 GroupRepository groupRepository,
171 CatalogRepository catalogRepository,
172 GeoServiceRepository geoServiceRepository,
173 GeoServiceHelper geoServiceHelper,
174 SolrService solrService,
175 TaskManagerService taskManagerService,
176 FeatureSourceRepository featureSourceRepository,
177 ApplicationRepository applicationRepository,
178 ConfigurationRepository configurationRepository,
179 FeatureSourceFactoryHelper featureSourceFactoryHelper,
180 SearchIndexRepository searchIndexRepository,
181 UploadRepository uploadRepository,
182 PageRepository pageRepository,
183 JdbcClient jdbcClient) {
184 this.appContext = appContext;
185 this.userRepository = userRepository;
186 this.groupRepository = groupRepository;
187 this.catalogRepository = catalogRepository;
188 this.geoServiceRepository = geoServiceRepository;
189 this.geoServiceHelper = geoServiceHelper;
190 this.solrService = solrService;
191 this.taskManagerService = taskManagerService;
192 this.featureSourceRepository = featureSourceRepository;
193 this.applicationRepository = applicationRepository;
194 this.configurationRepository = configurationRepository;
195 this.featureSourceFactoryHelper = featureSourceFactoryHelper;
196 this.searchIndexRepository = searchIndexRepository;
197 this.uploadRepository = uploadRepository;
198 this.pageRepository = pageRepository;
199 this.jdbcClient = jdbcClient;
200 }
201
202 @EventListener(ApplicationReadyEvent.class)
203 @Transactional
204 public void populate() throws Exception {
205 InternalAdminAuthentication.setInSecurityContext();
206 try {
207
208
209 createTestUsersAndGroups();
210 createConfigurationTestData();
211 if (categories.contains("catalog")) {
212 createCatalogTestData();
213 }
214 if (categories.contains("apps")) {
215 createAppTestData();
216 }
217 if (categories.contains("search-index")) {
218 try {
219 createSolrIndex();
220 } catch (Exception e) {
221 logger.error("Exception creating Solr Index for testdata (continuing)", e);
222 }
223 }
224 if (categories.contains("tasks")) {
225 createScheduledTasks();
226 }
227 if (categories.contains("pages")) {
228 createPages();
229 }
230 logger.info("Test entities created");
231 if (categories.contains("drawing")) {
232 insertTestDrawing();
233 logger.info("Test drawing created");
234 }
235 } finally {
236 InternalAdminAuthentication.clearSecurityContextAuthentication();
237 }
238 if (exit) {
239
240
241 new Thread(() -> {
242 try {
243 logger.info("Exiting in 10 seconds");
244 Thread.sleep(10000);
245 } catch (InterruptedException ignored) {
246
247 }
248 SpringApplication.exit(appContext, () -> 0);
249 System.exit(0);
250 })
251 .start();
252 }
253 }
254
255 public void createTestUsersAndGroups() throws NoSuchElementException {
256 Group groupFoo = new Group().setName("test-foo").setDescription("Used for integration tests.");
257 groupRepository.save(groupFoo);
258
259 Group groupBar = new Group().setName("test-bar").setDescription("Used for integration tests.");
260 groupBar.addOrUpdateAdminProperty("group-property", true, true);
261 groupBar.addOrUpdateAdminProperty("group-private-property", 999.9, false);
262 groupRepository.save(groupBar);
263
264 Group groupBaz = new Group().setName("test-baz").setDescription("Used for integration tests.");
265 groupRepository.save(groupBaz);
266
267
268 User u = new User().setUsername("user").setPassword("{noop}user").setEmail("user@example.com");
269 u.getGroups().addAll(List.of(groupFoo, groupBar, groupBaz));
270 userRepository.save(u);
271
272
273 u = new User().setUsername("tm-admin").setPassword(adminHashedPassword);
274 u.addOrUpdateAdminProperty("some-property", "some-value", true);
275 u.addOrUpdateAdminProperty("admin-property", "private-value", false);
276 u.getGroups().add(groupRepository.findById(Group.ADMIN).orElseThrow());
277 u.getGroups().add(groupBar);
278 userRepository.save(u);
279 }
280
281 private final List<AuthorizationRule> ruleAnonymousRead = List.of(new AuthorizationRule()
282 .groupName(Group.ANONYMOUS)
283 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)));
284
285 private final List<AuthorizationRule> ruleLoggedIn = List.of(new AuthorizationRule()
286 .groupName(Group.AUTHENTICATED)
287 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)));
288
289 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
290 private void createCatalogTestData() throws Exception {
291 Catalog catalog = catalogRepository.findById(Catalog.MAIN).orElseThrow();
292 CatalogNode rootCatalogNode = catalog.getNodes().get(0);
293 CatalogNode catalogNode = new CatalogNode().id("test").title("Test services");
294 rootCatalogNode.addChildrenItem(catalogNode.getId());
295 catalog.getNodes().add(catalogNode);
296
297 String osmAttribution = "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors";
298
299 Bounds rdTileGridExtent =
300 new Bounds().minx(-285401.92).maxx(595401.92).miny(22598.08).maxy(903401.92);
301
302 Upload legend = new Upload()
303 .setCategory(Upload.CATEGORY_LEGEND)
304 .setFilename("gemeentegebied-legend.png")
305 .setMimeType("image/png")
306 .setContent(new ClassPathResource("test/gemeentegebied-legend.png").getContentAsByteArray())
307 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
308 uploadRepository.save(legend);
309
310 Collection<GeoService> services = List.of(
311 new GeoService()
312 .setId("demo")
313 .setProtocol(WMS)
314 .setTitle("Demo")
315 .setPublished(true)
316 .setAuthorizationRules(ruleAnonymousRead)
317 .setUrl("https://demo.tailormap.com/geoserver/geodata/ows?SERVICE=WMS"),
318 new GeoService()
319 .setId("osm")
320 .setProtocol(XYZ)
321 .setTitle("OSM")
322 .setUrl("https://tile.openstreetmap.org/{z}/{x}/{y}.png")
323 .setAuthorizationRules(ruleAnonymousRead)
324 .setSettings(new GeoServiceSettings()
325 .xyzCrs("EPSG:3857")
326 .layerSettings(Map.of(
327 "xyz",
328 new GeoServiceLayerSettings()
329 .attribution(osmAttribution)
330 .maxZoom(19)))),
331
332 new GeoService()
333 .setId("snapshot-geoserver")
334 .setProtocol(WMS)
335 .setTitle("Test GeoServer")
336 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
337 .setAuthorizationRules(ruleAnonymousRead)
338 .setPublished(true),
339 new GeoService()
340 .setId("filtered-snapshot-geoserver")
341 .setProtocol(WMS)
342 .setTitle("Test GeoServer (with authorization rules)")
343 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
344 .setAuthorizationRules(List.of(
345 new AuthorizationRule()
346 .groupName("test-foo")
347 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)),
348 new AuthorizationRule()
349 .groupName("test-baz")
350 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))
351 .setSettings(new GeoServiceSettings()
352 .layerSettings(Map.of(
353 "BGT",
354 new GeoServiceLayerSettings()
355 .addAuthorizationRulesItem(new AuthorizationRule()
356 .groupName("test-foo")
357 .decisions(Map.of(
358 ACCESS_TYPE_READ, AuthorizationRuleDecision.DENY)))
359 .addAuthorizationRulesItem(new AuthorizationRule()
360 .groupName("test-baz")
361 .decisions(Map.of(
362 ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))))
363 .setPublished(true),
364 new GeoService()
365 .setId("snapshot-geoserver-proxied")
366 .setProtocol(WMS)
367 .setTitle("Test GeoServer (proxied)")
368 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
369 .setAuthorizationRules(ruleAnonymousRead)
370 .setSettings(new GeoServiceSettings().useProxy(true)),
371 new GeoService()
372 .setId("openbasiskaart")
373 .setProtocol(WMTS)
374 .setTitle("Openbasiskaart")
375 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
376 .setAuthorizationRules(ruleAnonymousRead)
377 .setSettings(new GeoServiceSettings()
378 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
379 .layerSettings(Map.of(
380 "osm",
381 new GeoServiceLayerSettings()
382 .title("Openbasiskaart")
383 .hiDpiDisabled(false)
384 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
385 .hiDpiSubstituteLayer("osm-hq")))),
386 new GeoService()
387 .setId("openbasiskaart-proxied")
388 .setProtocol(WMTS)
389 .setTitle("Openbasiskaart (proxied)")
390 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
391 .setAuthorizationRules(ruleAnonymousRead)
392
393
394 .setAuthentication(new ServiceAuthentication()
395 .method(ServiceAuthentication.MethodEnum.PASSWORD)
396 .username("test")
397 .password("test"))
398 .setSettings(new GeoServiceSettings()
399 .useProxy(true)
400 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
401 .layerSettings(Map.of(
402 "osm",
403 new GeoServiceLayerSettings()
404 .hiDpiDisabled(false)
405 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
406 .hiDpiSubstituteLayer("osm-hq")))),
407 new GeoService()
408 .setId("openbasiskaart-tms")
409 .setProtocol(XYZ)
410 .setTitle("Openbasiskaart (TMS)")
411 .setUrl("https://openbasiskaart.nl/mapcache/tms/1.0.0/osm@rd/{z}/{x}/{-y}.png")
412 .setAuthorizationRules(ruleAnonymousRead)
413 .setSettings(
414 new GeoServiceSettings()
415 .xyzCrs("EPSG:28992")
416 .defaultLayerSettings(
417 new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
418 .layerSettings(
419 Map.of(
420 "xyz",
421 new GeoServiceLayerSettings()
422 .maxZoom(15)
423 .tileGridExtent(rdTileGridExtent)
424 .hiDpiDisabled(false)
425 .hiDpiMode(
426 TileLayerHiDpiMode
427 .SUBSTITUTELAYERTILEPIXELRATIOONLY)
428 .hiDpiSubstituteLayer(
429 "https://openbasiskaart.nl/mapcache/tms/1.0.0/osm-hq@rd-hq/{z}/{x}/{-y}.png")))),
430 new GeoService()
431 .setId("pdok-hwh-luchtfotorgb")
432 .setProtocol(WMTS)
433 .setTitle("PDOK HWH luchtfoto")
434 .setUrl("https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0")
435 .setAuthorizationRules(ruleAnonymousRead)
436 .setPublished(true)
437 .setSettings(new GeoServiceSettings()
438 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
439 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
440 .hiDpiDisabled(false))
441 .putLayerSettingsItem(
442 "Actueel_orthoHR", new GeoServiceLayerSettings().title("Luchtfoto"))),
443 new GeoService()
444 .setId("b3p-mapproxy-luchtfoto")
445 .setProtocol(XYZ)
446 .setTitle("Luchtfoto (TMS)")
447 .setUrl("https://mapproxy.b3p.nl/tms/1.0.0/luchtfoto/EPSG28992/{z}/{x}/{-y}.jpeg")
448 .setAuthorizationRules(ruleAnonymousRead)
449 .setPublished(true)
450 .setSettings(new GeoServiceSettings()
451 .xyzCrs("EPSG:28992")
452 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
453 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
454 .hiDpiDisabled(false))
455 .layerSettings(Map.of(
456 "xyz",
457 new GeoServiceLayerSettings()
458 .maxZoom(14)
459 .tileGridExtent(rdTileGridExtent)
460 .hiDpiMode(TileLayerHiDpiMode.SHOWNEXTZOOMLEVEL)))),
461 new GeoService()
462 .setId("at-basemap")
463 .setProtocol(WMTS)
464 .setTitle("basemap.at")
465 .setUrl("https://mapsneu.wien.gv.at/basemapneu/1.0.0/WMTSCapabilities.xml")
466 .setAuthorizationRules(ruleAnonymousRead)
467 .setPublished(true)
468 .setSettings(new GeoServiceSettings()
469 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
470 .attribution("© [basemap.at](https://basemap.at)")
471 .hiDpiDisabled(true))
472 .layerSettings(Map.of(
473 "geolandbasemap",
474 new GeoServiceLayerSettings()
475 .title("Basemap")
476 .hiDpiDisabled(false)
477 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERTILEPIXELRATIOONLY)
478 .hiDpiSubstituteLayer("bmaphidpi"),
479 "bmaporthofoto30cm",
480 new GeoServiceLayerSettings()
481 .title("Orthophoto")
482 .hiDpiDisabled(false)))),
483 new GeoService()
484 .setId("pdok-kadaster-bestuurlijkegebieden")
485 .setProtocol(WMS)
486 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
487 .setAuthorizationRules(ruleAnonymousRead)
488 .setSettings(new GeoServiceSettings()
489 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
490 .description("This layer shows an administrative boundary."))
491
492 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
493 .useProxy(true)
494 .putLayerSettingsItem(
495 "Gemeentegebied",
496 new GeoServiceLayerSettings()
497 .legendImageId(legend.getId().toString())))
498 .setPublished(true)
499 .setTitle("PDOK Kadaster bestuurlijke gebieden"),
500 new GeoService()
501 .setId("bestuurlijkegebieden-proxied")
502 .setProtocol(WMS)
503 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
504 .setAuthorizationRules(ruleAnonymousRead)
505
506
507
508 .setAuthentication(new ServiceAuthentication()
509 .method(ServiceAuthentication.MethodEnum.PASSWORD)
510 .username("test")
511 .password("test"))
512 .setSettings(new GeoServiceSettings()
513
514 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
515 .useProxy(true))
516 .setPublished(true)
517 .setTitle("Bestuurlijke gebieden (proxied met auth)"),
518 new GeoService()
519 .setId("3dbag_utrecht")
520 .setProtocol(TILES3D)
521 .setUrl("https://3dtilesnederland.nl/tiles/1.0/implicit/nederland/344.json")
522 .setTitle("3D BAG Utrecht")
523 .setPublished(true)
524 .setAuthorizationRules(ruleAnonymousRead),
525 new GeoService()
526 .setId("ahn_terrain_model")
527 .setProtocol(QUANTIZEDMESH)
528 .setUrl(
529 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections/digitaalterreinmodel")
530 .setTitle("AHN Terrain Model")
531 .setPublished(true)
532 .setAuthorizationRules(ruleAnonymousRead),
533 new GeoService()
534 .setId("3d_basisvoorziening_gebouwen_proxy")
535 .setProtocol(TILES3D)
536 .setUrl(
537 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1_0/collections/gebouwen/3dtiles")
538 .setTitle("3D Basisvoorziening Gebouwen Proxy")
539 .setPublished(true)
540 .setAuthorizationRules(ruleAnonymousRead)
541 .setSettings(new GeoServiceSettings().useProxy(true)),
542 new GeoService()
543 .setId("3d_utrecht_proxied_auth")
544 .setProtocol(TILES3D)
545 .setUrl("https://snapshot.tailormap.nl/tiles3d-proxy/3dtiles")
546 .setTitle("3D Utrecht Proxied with Authorization")
547 .setPublished(true)
548 .setAuthorizationRules(ruleAnonymousRead)
549 .setAuthentication(new ServiceAuthentication()
550 .method(ServiceAuthentication.MethodEnum.PASSWORD)
551 .username(tiles3dProxyUsername)
552 .password(tiles3dProxyPassword))
553 .setSettings(new GeoServiceSettings().useProxy(true))
554
555 );
556
557 if (map5url != null) {
558 GeoServiceLayerSettings osmAttr = new GeoServiceLayerSettings().attribution(osmAttribution);
559 GeoServiceLayerSettings map5Attr = new GeoServiceLayerSettings()
560 .attribution("Kaarten: [Map5.nl](https://map5.nl), data: " + osmAttribution);
561 services = new ArrayList<>(services);
562 services.add(new GeoService()
563 .setId("map5")
564 .setProtocol(WMTS)
565 .setTitle("Map5")
566 .setUrl(map5url)
567 .setAuthorizationRules(ruleAnonymousRead)
568 .setSettings(new GeoServiceSettings()
569 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().hiDpiDisabled(true))
570 .layerSettings(Map.of(
571 "openlufo",
572 new GeoServiceLayerSettings()
573 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl), "
574 + osmAttribution),
575 "luforoadslabels",
576 osmAttr,
577 "map5topo",
578 new GeoServiceLayerSettings()
579 .attribution(map5Attr.getAttribution())
580 .hiDpiDisabled(false)
581 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
582 .hiDpiSubstituteLayer("map5topo_hq"),
583 "map5topo_gray",
584 map5Attr,
585 "map5topo_simple",
586 map5Attr,
587 "map5topo_simple_gray",
588 map5Attr,
589 "opensimpletopo",
590 osmAttr,
591 "opensimpletopo_gray",
592 osmAttr,
593 "opentopo",
594 osmAttr,
595 "opentopo_gray",
596 osmAttr))));
597 }
598
599 for (GeoService geoService : services) {
600 try {
601 geoServiceHelper.loadServiceCapabilities(geoService);
602 } catch (Exception e) {
603 logger.error(
604 "Error loading capabilities for {} service URL {}: {}, {}",
605 geoService.getProtocol().getValue(),
606 geoService.getUrl(),
607 e.getClass(),
608 e.getMessage());
609 }
610
611 geoServiceRepository.save(geoService);
612 catalogNode.addItemsItem(new TailormapObjectRef()
613 .kind(TailormapObjectRef.KindEnum.GEO_SERVICE)
614 .id(geoService.getId()));
615 }
616
617 CatalogNode wfsFeatureSourceCatalogNode =
618 new CatalogNode().id("wfs_feature_sources").title("WFS feature sources");
619 rootCatalogNode.addChildrenItem(wfsFeatureSourceCatalogNode.getId());
620 catalog.getNodes().add(wfsFeatureSourceCatalogNode);
621
622 services.stream().filter(s -> s.getProtocol() == WMS).forEach(s -> {
623 geoServiceHelper.findAndSaveRelatedWFS(s);
624 List<TMFeatureSource> linkedSources = featureSourceRepository.findByLinkedServiceId(s.getId());
625 for (TMFeatureSource linkedSource : linkedSources) {
626 wfsFeatureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
627 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
628 .id(linkedSource.getId().toString()));
629 }
630 });
631
632 String geodataPassword = "980f1c8A-25933b2";
633
634 Map<String, TMFeatureSource> featureSources = Map.of(
635 "postgis",
636 new TMFeatureSource()
637 .setProtocol(TMFeatureSource.Protocol.JDBC)
638 .setTitle("PostGIS")
639 .setJdbcConnection(new JDBCConnectionProperties()
640 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
641 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
642 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
643 .database("geodata")
644 .schema("public")
645 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
646 .setAuthentication(new ServiceAuthentication()
647 .method(ServiceAuthentication.MethodEnum.PASSWORD)
648 .username("geodata")
649 .password(geodataPassword)),
650 "postgis_osm",
651 new TMFeatureSource()
652 .setProtocol(TMFeatureSource.Protocol.JDBC)
653 .setTitle("PostGIS OSM")
654 .setJdbcConnection(new JDBCConnectionProperties()
655 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
656 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
657 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
658 .database("geodata")
659 .schema("osm")
660 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
661 .setAuthentication(new ServiceAuthentication()
662 .method(ServiceAuthentication.MethodEnum.PASSWORD)
663 .username("geodata")
664 .password(geodataPassword)),
665 "oracle",
666 new TMFeatureSource()
667 .setProtocol(TMFeatureSource.Protocol.JDBC)
668 .setTitle("Oracle")
669 .setJdbcConnection(new JDBCConnectionProperties()
670 .dbtype(JDBCConnectionProperties.DbtypeEnum.ORACLE)
671 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "oracle")
672 .database("/FREEPDB1")
673 .schema("GEODATA")
674 .additionalProperties(Map.of("connectionOptions", "?oracle.jdbc.J2EE13Compliant=true")))
675 .setAuthentication(new ServiceAuthentication()
676 .method(ServiceAuthentication.MethodEnum.PASSWORD)
677 .username("geodata")
678 .password(geodataPassword)),
679 "sqlserver",
680 new TMFeatureSource()
681 .setProtocol(TMFeatureSource.Protocol.JDBC)
682 .setTitle("MS SQL Server")
683 .setJdbcConnection(new JDBCConnectionProperties()
684 .dbtype(JDBCConnectionProperties.DbtypeEnum.SQLSERVER)
685 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "sqlserver")
686 .database("geodata")
687 .schema("dbo")
688 .additionalProperties(Map.of("connectionOptions", ";encrypt=false")))
689 .setAuthentication(new ServiceAuthentication()
690 .method(ServiceAuthentication.MethodEnum.PASSWORD)
691 .username("geodata")
692 .password(geodataPassword)),
693 "pdok-kadaster-bestuurlijkegebieden",
694 new TMFeatureSource()
695 .setProtocol(TMFeatureSource.Protocol.WFS)
696 .setUrl(
697 "https://service.pdok.nl/kadaster/bestuurlijkegebieden/wfs/v1_0?service=WFS&VERSION=2.0.0")
698 .setTitle("Bestuurlijke gebieden")
699 .setNotes(
700 "Overzicht van de bestuurlijke indeling van Nederland in gemeenten en provincies alsmede de rijksgrens. Gegevens zijn afgeleid uit de Basisregistratie Kadaster (BRK)."));
701 featureSourceRepository.saveAll(featureSources.values());
702
703 new WFSFeatureSourceHelper().loadCapabilities(featureSources.get("pdok-kadaster-bestuurlijkegebieden"));
704 geoServiceRepository.findById("pdok-kadaster-bestuurlijkegebieden").ifPresent(geoService -> {
705 geoService
706 .getSettings()
707 .getLayerSettings()
708 .put(
709 "Provinciegebied",
710 new GeoServiceLayerSettings()
711 .description("The administrative boundary of Dutch Provinces, connected to a WFS.")
712 .featureType(new FeatureTypeRef()
713 .featureSourceId(featureSources
714 .get("pdok-kadaster-bestuurlijkegebieden")
715 .getId())
716 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
717 .title("Provinciegebied (WFS)"));
718 geoServiceRepository.save(geoService);
719 });
720
721 geoServiceRepository.findById("bestuurlijkegebieden-proxied").ifPresent(geoService -> {
722 geoService
723 .getSettings()
724 .getLayerSettings()
725 .put(
726 "Provinciegebied",
727 new GeoServiceLayerSettings()
728 .featureType(new FeatureTypeRef()
729 .featureSourceId(featureSources
730 .get("pdok-kadaster-bestuurlijkegebieden")
731 .getId())
732 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
733 .title("Provinciegebied (WFS, proxied met auth)"));
734 geoServiceRepository.save(geoService);
735 });
736
737 CatalogNode featureSourceCatalogNode =
738 new CatalogNode().id("feature_sources").title("Test feature sources");
739 rootCatalogNode.addChildrenItem(featureSourceCatalogNode.getId());
740 catalog.getNodes().add(featureSourceCatalogNode);
741
742 for (TMFeatureSource featureSource : featureSources.values()) {
743 featureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
744 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
745 .id(featureSource.getId().toString()));
746 }
747 catalogRepository.save(catalog);
748
749 if (connectToSpatialDbs) {
750 featureSources.values().forEach(fs -> {
751 try {
752 if (fs.getProtocol() == TMFeatureSource.Protocol.JDBC) {
753 new JDBCFeatureSourceHelper().loadCapabilities(fs);
754 } else if (fs.getProtocol() == TMFeatureSource.Protocol.WFS) {
755 new WFSFeatureSourceHelper().loadCapabilities(fs);
756 }
757 } catch (Exception e) {
758 logger.error("Error loading capabilities for feature source {}", fs.getTitle(), e);
759 }
760 });
761
762 services.stream()
763
764
765 .filter(s -> s.getId().startsWith("snapshot-geoserver"))
766 .forEach(s -> s.getSettings()
767 .layerSettings(Map.of(
768 "postgis:begroeidterreindeel",
769 new GeoServiceLayerSettings()
770 .description(
771 """
772 This layer shows data from https:
773
774 https:
775 .featureType(new FeatureTypeRef()
776 .featureSourceId(featureSources
777 .get("postgis")
778 .getId())
779 .featureTypeName("begroeidterreindeel")),
780 "postgis:bak",
781 new GeoServiceLayerSettings()
782 .featureType(new FeatureTypeRef()
783 .featureSourceId(featureSources
784 .get("postgis")
785 .getId())
786 .featureTypeName("bak")),
787 "postgis:kadastraal_perceel",
788 new GeoServiceLayerSettings()
789 .description("cadastral parcel label points")
790 .featureType(new FeatureTypeRef()
791 .featureSourceId(featureSources
792 .get("postgis")
793 .getId())
794 .featureTypeName("kadastraal_perceel")),
795 "sqlserver:wegdeel",
796 new GeoServiceLayerSettings()
797 .attribution(
798 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)")
799 .description(
800 """
801 This layer shows data from [MS SQL Server](https:
802
803 https:
804 .featureType(new FeatureTypeRef()
805 .featureSourceId(featureSources
806 .get("sqlserver")
807 .getId())
808 .featureTypeName("wegdeel")),
809 "oracle:WATERDEEL",
810 new GeoServiceLayerSettings()
811 .description("This layer shows data from Oracle Spatial.")
812 .featureType(new FeatureTypeRef()
813 .featureSourceId(featureSources
814 .get("oracle")
815 .getId())
816 .featureTypeName("WATERDEEL")),
817 "postgis:osm_polygon",
818 new GeoServiceLayerSettings()
819 .description("This layer shows OSM data from postgis.")
820 .featureType(new FeatureTypeRef()
821 .featureSourceId(featureSources
822 .get("postgis_osm")
823 .getId())
824 .featureTypeName("osm_polygon")))));
825 }
826
827 featureSources.get("pdok-kadaster-bestuurlijkegebieden").getFeatureTypes().stream()
828 .filter(ft -> ft.getName().equals("bestuurlijkegebieden:Provinciegebied"))
829 .findFirst()
830 .ifPresent(ft -> {
831 ft.getSettings().addHideAttributesItem("identificatie");
832 ft.getSettings().addHideAttributesItem("ligtInLandCode");
833 ft.getSettings().addHideAttributesItem("fuuid");
834 ft.getSettings().putAttributeSettingsItem("naam", new AttributeSettings().title("Naam"));
835 ft.getSettings()
836 .setTemplate(
837 new FeatureTypeTemplate()
838 .templateLanguage("simple")
839 .markupLanguage("markdown")
840 .template(
841 """
842 ### Provincie
843 Deze provincie heet **{{naam}}** en ligt in _{{ligtInLandNaam}}_.
844
845 | Attribuut | Waarde |
846 | --------- | ------------------ |
847 | `code` | {{code}} |
848 | `naam` | {{naam}} |
849 | `ligt in` | {{ligtInLandNaam}} |"""));
850 });
851
852 featureSources.get("postgis").getFeatureTypes().stream()
853 .filter(ft -> ft.getName().equals("begroeidterreindeel"))
854 .findFirst()
855 .ifPresent(ft -> {
856 ft.getSettings().addHideAttributesItem("terminationdate");
857 ft.getSettings().addHideAttributesItem("geom_kruinlijn");
858 ft.getSettings().putAttributeSettingsItem("gmlid", new AttributeSettings().title("GML ID"));
859 ft.getSettings()
860 .putAttributeSettingsItem("identificatie", new AttributeSettings().title("Identificatie"));
861 ft.getSettings()
862 .putAttributeSettingsItem(
863 "tijdstipregistratie", new AttributeSettings().title("Registratie"));
864 ft.getSettings()
865 .putAttributeSettingsItem(
866 "eindregistratie", new AttributeSettings().title("Eind registratie"));
867 ft.getSettings().putAttributeSettingsItem("class", new AttributeSettings().title("Klasse"));
868 ft.getSettings()
869 .putAttributeSettingsItem("bronhouder", new AttributeSettings().title("Bronhouder"));
870 ft.getSettings()
871 .putAttributeSettingsItem("inonderzoek", new AttributeSettings().title("In onderzoek"));
872 ft.getSettings()
873 .putAttributeSettingsItem(
874 "relatievehoogteligging", new AttributeSettings().title("Relatieve hoogteligging"));
875 ft.getSettings()
876 .putAttributeSettingsItem("bgt_status", new AttributeSettings().title("BGT status"));
877 ft.getSettings()
878 .putAttributeSettingsItem("plus_status", new AttributeSettings().title("Plus-status"));
879 ft.getSettings()
880 .putAttributeSettingsItem(
881 "plus_fysiekvoorkomen", new AttributeSettings().title("Plus-fysiek voorkomen"));
882 ft.getSettings()
883 .putAttributeSettingsItem(
884 "begroeidterreindeeloptalud", new AttributeSettings().title("Op talud"));
885 ft.getSettings().addAttributeOrderItem("identificatie");
886 ft.getSettings().addAttributeOrderItem("bronhouder");
887 ft.getSettings().addAttributeOrderItem("class");
888 });
889
890 featureSources.get("postgis").getFeatureTypes().stream()
891 .filter(ft -> ft.getName().equals("bak"))
892 .findFirst()
893 .ifPresent(ft -> {
894 ft.getSettings().addHideAttributesItem("gmlid");
895 ft.getSettings().addHideAttributesItem("lv_publicatiedatum");
896 ft.getSettings().addHideAttributesItem("creationdate");
897 ft.getSettings().addHideAttributesItem("tijdstipregistratie");
898 ft.getSettings().addHideAttributesItem("eindregistratie");
899 ft.getSettings().addHideAttributesItem("terminationdate");
900 ft.getSettings().addHideAttributesItem("inonderzoek");
901 ft.getSettings().addHideAttributesItem("relatievehoogteligging");
902 ft.getSettings().addHideAttributesItem("bgt_status");
903 ft.getSettings().addHideAttributesItem("plus_status");
904 ft.getSettings().addHideAttributesItem("function_");
905 ft.getSettings().addHideAttributesItem("plus_type");
906 });
907
908 featureSources.get("postgis").getFeatureTypes().stream()
909 .filter(ft -> ft.getName().equals("kadastraal_perceel"))
910 .findFirst()
911 .ifPresent(ft -> ft.getSettings().addHideAttributesItem("gml_id"));
912 }
913
914 public void createAppTestData() throws Exception {
915 Upload logo = new Upload()
916 .setCategory(Upload.CATEGORY_APP_LOGO)
917 .setFilename("gradient.svg")
918 .setMimeType("image/svg+xml")
919 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
920 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
921 uploadRepository.save(logo);
922
923 List<AppTreeNode> baseNodes = List.of(
924 new AppTreeLayerNode()
925 .objectType("AppTreeLayerNode")
926 .id("lyr:openbasiskaart:osm")
927 .serviceId("openbasiskaart")
928 .layerName("osm")
929 .visible(true),
930 new AppTreeLayerNode()
931 .objectType("AppTreeLayerNode")
932 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
933 .serviceId("pdok-hwh-luchtfotorgb")
934 .layerName("Actueel_orthoHR")
935 .visible(false));
936
937 Application app = new Application()
938 .setName("default")
939 .setTitle("Tailormap demo")
940 .setCrs("EPSG:28992")
941 .setAuthorizationRules(ruleAnonymousRead)
942 .setComponents(List.of(
943 new Component()
944 .type("SIMPLE_SEARCH")
945 .config(new ComponentConfig()
946 .enabled(true)
947 .putAdditionalProperty("municipalities", List.of("0344"))),
948 new Component().type("EDIT").config(new ComponentConfig().enabled(true)),
949 new Component()
950 .type("COORDINATE_LINK_WINDOW")
951 .config(new ComponentConfig()
952 .enabled(true)
953 .putAdditionalProperty(
954 "urls",
955 List.of(
956 Map.of(
957 "id",
958 "google-maps",
959 "url",
960 "https://www.google.com/maps/@[lat],[lon],18z",
961 "alias",
962 "Google Maps",
963 "projection",
964 "EPSG:4326"),
965 Map.of(
966 "id",
967 "tm-demo",
968 "url",
969 "https://demo.tailormap.com/#@[X],[Y],18",
970 "alias",
971 "Tailormap demo",
972 "projection",
973 "EPSG:28992"))))))
974 .setContentRoot(new AppContent()
975 .addBaseLayerNodesItem(new AppTreeLevelNode()
976 .objectType("AppTreeLevelNode")
977 .id("root-base-layers")
978 .root(true)
979 .title("Base layers")
980 .childrenIds(List.of(
981 "lyr:openbasiskaart:osm",
982 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
983 "lyr:openbasiskaart-proxied:osm",
984 "lyr:openbasiskaart-tms:xyz",
985 "lyr:b3p-mapproxy-luchtfoto:xyz")))
986 .addBaseLayerNodesItem(
987
988
989 new AppTreeLayerNode()
990 .objectType("AppTreeLayerNode")
991 .id("lyr:openbasiskaart-proxied:osm")
992 .serviceId("openbasiskaart-proxied")
993 .layerName("osm")
994 .visible(false))
995 .addBaseLayerNodesItem(new AppTreeLayerNode()
996 .objectType("AppTreeLayerNode")
997 .id("lyr:openbasiskaart-tms:xyz")
998 .serviceId("openbasiskaart-tms")
999 .layerName("xyz")
1000 .visible(false))
1001 .addBaseLayerNodesItem(new AppTreeLayerNode()
1002 .objectType("AppTreeLayerNode")
1003 .id("lyr:b3p-mapproxy-luchtfoto:xyz")
1004 .serviceId("b3p-mapproxy-luchtfoto")
1005 .layerName("xyz")
1006 .visible(false))
1007 .addLayerNodesItem(new AppTreeLevelNode()
1008 .objectType("AppTreeLevelNode")
1009 .id("root")
1010 .root(true)
1011 .title("Layers")
1012 .childrenIds(List.of(
1013 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1014 "lyr:bestuurlijkegebieden-proxied:Provinciegebied",
1015 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1016 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1017 "lyr:snapshot-geoserver:postgis:bak",
1018 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1019 "lyr:snapshot-geoserver:sqlserver:wegdeel",
1020 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1021 "lyr:snapshot-geoserver:BGT",
1022 "lvl:proxied",
1023 "lvl:osm",
1024 "lvl:archeo")))
1025 .addLayerNodesItem(new AppTreeLayerNode()
1026 .objectType("AppTreeLayerNode")
1027 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1028 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1029 .layerName("Provinciegebied")
1030 .visible(true))
1031
1032
1033
1034 .addLayerNodesItem(new AppTreeLayerNode()
1035 .objectType("AppTreeLayerNode")
1036 .id("lyr:bestuurlijkegebieden-proxied:Provinciegebied")
1037 .serviceId("bestuurlijkegebieden-proxied")
1038 .layerName("Provinciegebied")
1039 .visible(false))
1040 .addLayerNodesItem(new AppTreeLayerNode()
1041 .objectType("AppTreeLayerNode")
1042 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1043 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1044 .layerName("Gemeentegebied")
1045 .visible(true))
1046 .addLayerNodesItem(new AppTreeLayerNode()
1047 .objectType("AppTreeLayerNode")
1048 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1049 .serviceId("snapshot-geoserver")
1050 .layerName("postgis:begroeidterreindeel")
1051 .visible(true))
1052 .addLayerNodesItem(new AppTreeLayerNode()
1053 .objectType("AppTreeLayerNode")
1054 .id("lyr:snapshot-geoserver:postgis:bak")
1055 .serviceId("snapshot-geoserver")
1056 .layerName("postgis:bak")
1057 .visible(false))
1058 .addLayerNodesItem(new AppTreeLayerNode()
1059 .objectType("AppTreeLayerNode")
1060 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
1061 .serviceId("snapshot-geoserver")
1062 .layerName("postgis:kadastraal_perceel")
1063 .visible(false))
1064 .addLayerNodesItem(new AppTreeLayerNode()
1065 .objectType("AppTreeLayerNode")
1066 .id("lyr:snapshot-geoserver:sqlserver:wegdeel")
1067 .serviceId("snapshot-geoserver")
1068 .layerName("sqlserver:wegdeel")
1069 .visible(true))
1070 .addLayerNodesItem(new AppTreeLayerNode()
1071 .objectType("AppTreeLayerNode")
1072 .id("lyr:snapshot-geoserver:oracle:WATERDEEL")
1073 .serviceId("snapshot-geoserver")
1074 .layerName("oracle:WATERDEEL")
1075 .visible(true))
1076 .addLayerNodesItem(new AppTreeLayerNode()
1077 .objectType("AppTreeLayerNode")
1078 .id("lyr:snapshot-geoserver:BGT")
1079 .serviceId("snapshot-geoserver")
1080 .layerName("BGT")
1081 .visible(false))
1082 .addLayerNodesItem(new AppTreeLevelNode()
1083 .objectType("AppTreeLevelNode")
1084 .id("lvl:proxied")
1085 .title("Proxied")
1086 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1087 .addLayerNodesItem(new AppTreeLayerNode()
1088 .objectType("AppTreeLayerNode")
1089 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1090 .serviceId("snapshot-geoserver-proxied")
1091 .layerName("postgis:begroeidterreindeel")
1092 .visible(false))
1093 .addLayerNodesItem(new AppTreeLevelNode()
1094 .objectType("AppTreeLevelNode")
1095 .id("lvl:osm")
1096 .title("OSM")
1097 .childrenIds(List.of("lyr:snapshot-geoserver:postgis:osm_polygon")))
1098 .addLayerNodesItem(new AppTreeLayerNode()
1099 .objectType("AppTreeLayerNode")
1100 .id("lyr:snapshot-geoserver:postgis:osm_polygon")
1101 .serviceId("snapshot-geoserver")
1102 .layerName("postgis:osm_polygon")
1103 .visible(false))
1104 .addLayerNodesItem(new AppTreeLevelNode()
1105 .objectType("AppTreeLevelNode")
1106 .id("lvl:archeo")
1107 .title("Archeology")
1108 .childrenIds(List.of("lyr:demo:geomorfologie")))
1109 .addLayerNodesItem(new AppTreeLayerNode()
1110 .objectType("AppTreeLayerNode")
1111 .id("lyr:demo:geomorfologie")
1112 .serviceId("demo")
1113 .layerName("geomorfologie")
1114 .visible(true)))
1115 .setStyling(new AppStyling().logo(logo.getId().toString()))
1116 .setSettings(new AppSettings()
1117 .putLayerSettingsItem("lyr:openbasiskaart:osm", new AppLayerSettings().title("Openbasiskaart"))
1118 .putLayerSettingsItem(
1119 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", new AppLayerSettings().title("Luchtfoto"))
1120 .putLayerSettingsItem(
1121 "lyr:openbasiskaart-proxied:osm",
1122 new AppLayerSettings().title("Openbasiskaart (proxied)"))
1123 .putLayerSettingsItem(
1124 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1125 new AppLayerSettings()
1126 .opacity(50)
1127 .title("Waterdeel overridden title")
1128 .editable(true)
1129 .description("This is the layer description from the app layer setting.")
1130 .attribution(
1131 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)"))
1132 .putLayerSettingsItem(
1133 "lyr:snapshot-geoserver:postgis:osm_polygon",
1134 new AppLayerSettings()
1135 .description("OpenStreetMap polygon data in EPSG:3857")
1136 .opacity(60)
1137 .editable(true)
1138 .title("OSM Polygon (EPSG:3857)")
1139 .attribution(
1140 "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors"))
1141 .putLayerSettingsItem(
1142 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1143 new AppLayerSettings()
1144 .editable(true)
1145 .addHideAttributesItem("begroeidterreindeeloptalud")
1146 .addReadOnlyAttributesItem("eindregistratie"))
1147 .putLayerSettingsItem(
1148 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1149 new AppLayerSettings().editable(true).addReadOnlyAttributesItem("aanduiding"))
1150 .putLayerSettingsItem(
1151 "lyr:snapshot-geoserver:sqlserver:wegdeel", new AppLayerSettings().editable(true))
1152 .putLayerSettingsItem(
1153 "lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel",
1154 new AppLayerSettings().editable(false))
1155 .putLayerSettingsItem(
1156 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1157 new AppLayerSettings()
1158 .hiddenFunctionality(Set.of(FEATURE_INFO, ATTRIBUTE_LIST, EXPORT))));
1159
1160 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1161 app.setInitialExtent(
1162 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d));
1163 app.setMaxExtent(new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d));
1164
1165 if (map5url != null) {
1166 AppTreeLevelNode root =
1167 (AppTreeLevelNode) app.getContentRoot().getBaseLayerNodes().get(0);
1168 List<String> childrenIds = new ArrayList<>(root.getChildrenIds());
1169 childrenIds.add("lyr:map5:map5topo");
1170 childrenIds.add("lyr:map5:map5topo_simple");
1171 childrenIds.add("lvl:luchtfoto-labels");
1172 root.setChildrenIds(childrenIds);
1173 app.getSettings()
1174 .putLayerSettingsItem("lyr:map5:map5topo", new AppLayerSettings().title("Map5"))
1175 .putLayerSettingsItem("lyr:map5:map5topo_simple", new AppLayerSettings().title("Map5 simple"));
1176 app.getContentRoot()
1177 .addBaseLayerNodesItem(new AppTreeLayerNode()
1178 .objectType("AppTreeLayerNode")
1179 .id("lyr:map5:map5topo")
1180 .serviceId("map5")
1181 .layerName("map5topo")
1182 .visible(false))
1183 .addBaseLayerNodesItem(new AppTreeLayerNode()
1184 .objectType("AppTreeLayerNode")
1185 .id("lyr:map5:map5topo_simple")
1186 .serviceId("map5")
1187 .layerName("map5topo_simple")
1188 .visible(false))
1189 .addBaseLayerNodesItem(new AppTreeLevelNode()
1190 .objectType("AppTreeLevelNode")
1191 .id("lvl:luchtfoto-labels")
1192 .title("Luchtfoto met labels")
1193 .addChildrenIdsItem("lyr:map5:luforoadslabels")
1194 .addChildrenIdsItem("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2"))
1195 .addBaseLayerNodesItem(new AppTreeLayerNode()
1196 .objectType("AppTreeLayerNode")
1197 .id("lyr:map5:luforoadslabels")
1198 .serviceId("map5")
1199 .layerName("luforoadslabels")
1200 .visible(false))
1201 .addBaseLayerNodesItem(new AppTreeLayerNode()
1202 .objectType("AppTreeLayerNode")
1203 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2")
1204 .serviceId("pdok-hwh-luchtfotorgb")
1205 .layerName("Actueel_orthoHR")
1206 .visible(false));
1207 }
1208
1209 applicationRepository.save(app);
1210
1211 app = new Application()
1212 .setName("base")
1213 .setTitle("Service base app")
1214 .setCrs("EPSG:28992")
1215 .setAuthorizationRules(ruleAnonymousRead)
1216 .setContentRoot(new AppContent()
1217 .addBaseLayerNodesItem(new AppTreeLevelNode()
1218 .objectType("AppTreeLevelNode")
1219 .id("root-base-layers")
1220 .root(true)
1221 .title("Base layers")
1222 .childrenIds(List.of(
1223 "lyr:openbasiskaart:osm", "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR"))));
1224 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1225 applicationRepository.save(app);
1226
1227 app = new Application()
1228 .setName("secured")
1229 .setTitle("secured app")
1230 .setCrs("EPSG:28992")
1231 .setAuthorizationRules(ruleLoggedIn)
1232 .setContentRoot(new AppContent()
1233 .addBaseLayerNodesItem(new AppTreeLevelNode()
1234 .objectType("AppTreeLevelNode")
1235 .id("root-base-layers")
1236 .root(true)
1237 .title("Base layers")
1238 .childrenIds(List.of(
1239 "lyr:openbasiskaart:osm",
1240 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1241 "lyr:openbasiskaart-proxied:osm")))
1242 .addBaseLayerNodesItem(new AppTreeLayerNode()
1243 .objectType("AppTreeLayerNode")
1244 .id("lyr:openbasiskaart-proxied:osm")
1245 .serviceId("openbasiskaart-proxied")
1246 .layerName("osm")
1247 .visible(false))
1248 .addLayerNodesItem(new AppTreeLevelNode()
1249 .objectType("AppTreeLevelNode")
1250 .id("root")
1251 .root(true)
1252 .title("Layers")
1253 .childrenIds(List.of(
1254 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1255 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1256 "lvl:proxied")))
1257 .addLayerNodesItem(new AppTreeLayerNode()
1258 .objectType("AppTreeLayerNode")
1259 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1260 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1261 .layerName("Gemeentegebied")
1262 .visible(true))
1263 .addLayerNodesItem(new AppTreeLayerNode()
1264 .objectType("AppTreeLayerNode")
1265 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1266 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1267 .layerName("Provinciegebied")
1268 .visible(false))
1269 .addLayerNodesItem(new AppTreeLevelNode()
1270 .objectType("AppTreeLevelNode")
1271 .id("lvl:proxied")
1272 .title("Proxied")
1273 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1274 .addLayerNodesItem(new AppTreeLayerNode()
1275 .objectType("AppTreeLayerNode")
1276 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1277 .serviceId("snapshot-geoserver-proxied")
1278 .layerName("postgis:begroeidterreindeel")
1279 .visible(false)))
1280 .setSettings(new AppSettings()
1281 .putLayerSettingsItem(
1282 "lyr:openbasiskaart-proxied:osm",
1283 new AppLayerSettings().title("Openbasiskaart (proxied)")));
1284
1285 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1286 applicationRepository.save(app);
1287
1288 app = new Application()
1289 .setName("secured-auth")
1290 .setTitle("secured (with authorizations)")
1291 .setCrs("EPSG:28992")
1292 .setAuthorizationRules(List.of(
1293 new AuthorizationRule()
1294 .groupName("test-foo")
1295 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)),
1296 new AuthorizationRule()
1297 .groupName("test-bar")
1298 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))
1299 .setContentRoot(new AppContent()
1300 .addLayerNodesItem(new AppTreeLevelNode()
1301 .objectType("AppTreeLevelNode")
1302 .id("root")
1303 .root(true)
1304 .title("Layers")
1305 .childrenIds(List.of("lyr:needs-auth", "lyr:public")))
1306 .addLayerNodesItem(new AppTreeLevelNode()
1307 .objectType("AppTreeLevelNode")
1308 .id("lvl:public")
1309 .title("Public")
1310 .childrenIds(List.of("lyr:snapshot-geoserver:BGT")))
1311 .addLayerNodesItem(new AppTreeLevelNode()
1312 .objectType("AppTreeLevelNode")
1313 .id("lvl:needs-auth")
1314 .title("Needs auth")
1315 .childrenIds(List.of(
1316 "lyr:filtered-snapshot-geoserver:BGT",
1317 "lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1318 .addLayerNodesItem(new AppTreeLayerNode()
1319 .objectType("AppTreeLayerNode")
1320 .id("lyr:filtered-snapshot-geoserver:BGT")
1321 .serviceId("filtered-snapshot-geoserver")
1322 .layerName("BGT")
1323 .visible(true))
1324 .addLayerNodesItem(new AppTreeLayerNode()
1325 .objectType("AppTreeLayerNode")
1326 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1327 .serviceId("filtered-snapshot-geoserver")
1328 .layerName("postgis:begroeidterreindeel")
1329 .visible(true))
1330 .addLayerNodesItem(new AppTreeLayerNode()
1331 .objectType("AppTreeLayerNode")
1332 .id("lyr:snapshot-geoserver:BGT")
1333 .serviceId("snapshot-geoserver")
1334 .layerName("BGT")
1335 .visible(true)));
1336
1337 applicationRepository.save(app);
1338
1339 app = new Application()
1340 .setName("austria")
1341 .setCrs("EPSG:3857")
1342 .setAuthorizationRules(ruleAnonymousRead)
1343 .setTitle("Austria")
1344 .setInitialExtent(
1345 new Bounds().minx(987982d).miny(5799551d).maxx(1963423d).maxy(6320708d))
1346 .setMaxExtent(
1347 new Bounds().minx(206516d).miny(5095461d).maxx(3146930d).maxy(7096232d))
1348 .setContentRoot(new AppContent()
1349 .addBaseLayerNodesItem(new AppTreeLevelNode()
1350 .objectType("AppTreeLevelNode")
1351 .id("root-base-layers")
1352 .root(true)
1353 .title("Base layers")
1354 .childrenIds(List.of(
1355 "lyr:at-basemap:geolandbasemap",
1356 "lyr:at-basemap:orthofoto",
1357 "lvl:orthofoto-labels",
1358 "lyr:osm:xyz")))
1359 .addBaseLayerNodesItem(new AppTreeLayerNode()
1360 .objectType("AppTreeLayerNode")
1361 .id("lyr:at-basemap:geolandbasemap")
1362 .serviceId("at-basemap")
1363 .layerName("geolandbasemap")
1364 .visible(true))
1365 .addBaseLayerNodesItem(new AppTreeLayerNode()
1366 .objectType("AppTreeLayerNode")
1367 .id("lyr:at-basemap:orthofoto")
1368 .serviceId("at-basemap")
1369 .layerName("bmaporthofoto30cm")
1370 .visible(false))
1371 .addBaseLayerNodesItem(new AppTreeLevelNode()
1372 .objectType("AppTreeLevelNode")
1373 .id("lvl:orthofoto-labels")
1374 .title("Orthophoto with labels")
1375 .childrenIds(List.of("lyr:at-basemap:bmapoverlay", "lyr:at-basemap:orthofoto_2")))
1376 .addBaseLayerNodesItem(new AppTreeLayerNode()
1377 .objectType("AppTreeLayerNode")
1378 .id("lyr:at-basemap:bmapoverlay")
1379 .serviceId("at-basemap")
1380 .layerName("bmapoverlay")
1381 .visible(false))
1382 .addBaseLayerNodesItem(new AppTreeLayerNode()
1383 .objectType("AppTreeLayerNode")
1384 .id("lyr:at-basemap:orthofoto_2")
1385 .serviceId("at-basemap")
1386 .layerName("bmaporthofoto30cm")
1387 .visible(false))
1388 .addBaseLayerNodesItem(new AppTreeLayerNode()
1389 .objectType("AppTreeLayerNode")
1390 .id("lyr:osm:xyz")
1391 .serviceId("osm")
1392 .layerName("xyz")
1393 .visible(false)));
1394
1395 applicationRepository.save(app);
1396
1397 app = new Application()
1398 .setName("3d_utrecht")
1399 .setCrs("EPSG:3857")
1400 .setAuthorizationRules(ruleLoggedIn)
1401 .setTitle("3D Utrecht")
1402 .setInitialExtent(
1403 new Bounds().minx(558390d).miny(6818485d).maxx(566751d).maxy(6824036d))
1404 .setMaxExtent(
1405 new Bounds().minx(91467d).miny(6496479d).maxx(1037043d).maxy(7147453d))
1406 .setSettings(new AppSettings().uiSettings(new AppUiSettings().enable3D(true)))
1407 .setContentRoot(new AppContent()
1408 .addBaseLayerNodesItem(new AppTreeLevelNode()
1409 .objectType("AppTreeLevelNode")
1410 .id("root-base-layers")
1411 .root(true)
1412 .title("Base layers")
1413 .childrenIds(List.of("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", "lyr:osm:xyz")))
1414 .addBaseLayerNodesItem(new AppTreeLayerNode()
1415 .objectType("AppTreeLayerNode")
1416 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
1417 .serviceId("pdok-hwh-luchtfotorgb")
1418 .layerName("Actueel_orthoHR")
1419 .visible(true))
1420 .addBaseLayerNodesItem(new AppTreeLayerNode()
1421 .objectType("AppTreeLayerNode")
1422 .id("lyr:osm:xyz")
1423 .serviceId("osm")
1424 .layerName("xyz")
1425 .visible(false))
1426 .addLayerNodesItem(new AppTreeLevelNode()
1427 .objectType("AppTreeLevelNode")
1428 .id("root")
1429 .root(true)
1430 .title("Layers")
1431 .childrenIds(List.of(
1432 "lyr:3dbag_utrecht:tiles3d",
1433 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1434 "lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d",
1435 "lyr:3d_utrecht_proxied_auth:tiles3d")))
1436 .addLayerNodesItem(new AppTreeLayerNode()
1437 .objectType("AppTreeLayerNode")
1438 .id("lyr:3dbag_utrecht:tiles3d")
1439 .serviceId("3dbag_utrecht")
1440 .layerName("tiles3d")
1441 .visible(true))
1442 .addLayerNodesItem(new AppTreeLayerNode()
1443 .objectType("AppTreeLayerNode")
1444 .id("lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d")
1445 .serviceId("3d_basisvoorziening_gebouwen_proxy")
1446 .layerName("tiles3d")
1447 .visible(false))
1448 .addLayerNodesItem(new AppTreeLayerNode()
1449 .objectType("AppTreeLayerNode")
1450 .id("lyr:3d_utrecht_proxied_auth:tiles3d")
1451 .serviceId("3d_utrecht_proxied_auth")
1452 .layerName("tiles3d")
1453 .visible(false))
1454 .addLayerNodesItem(new AppTreeLayerNode()
1455 .objectType("AppTreeLayerNode")
1456 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1457 .serviceId("snapshot-geoserver")
1458 .layerName("postgis:begroeidterreindeel")
1459 .visible(true))
1460 .addTerrainLayerNodesItem(new AppTreeLevelNode()
1461 .objectType("AppTreeLevelNode")
1462 .id("root-terrain-layers")
1463 .root(true)
1464 .title("Terrain Layers")
1465 .childrenIds(List.of("lyr:ahn_terrain_model:quantizedmesh")))
1466 .addTerrainLayerNodesItem(new AppTreeLayerNode()
1467 .objectType("AppTreeLayerNode")
1468 .id("lyr:ahn_terrain_model:quantizedmesh")
1469 .serviceId("ahn_terrain_model")
1470 .layerName("quantizedmesh")
1471 .visible(false)));
1472
1473 applicationRepository.save(app);
1474
1475 Configuration config = new Configuration();
1476 config.setKey(Configuration.DEFAULT_APP);
1477 config.setValue("default");
1478 configurationRepository.save(config);
1479 config = new Configuration();
1480 config.setKey(Configuration.DEFAULT_BASE_APP);
1481 config.setValue("base");
1482 configurationRepository.save(config);
1483 }
1484
1485 private void createConfigurationTestData() throws JsonProcessingException {
1486 Configuration config = new Configuration();
1487 config.setKey("test");
1488 config.setAvailableForViewer(true);
1489 config.setValue("test value");
1490 config.setJsonValue(new ObjectMapper().readTree("{ \"someProperty\": 1, \"nestedObject\": { \"num\": 42 } }"));
1491 configurationRepository.save(config);
1492 }
1493
1494 @Transactional
1495 public void createSolrIndex() throws Exception {
1496 if (connectToSpatialDbs) {
1497
1498
1499 featureSourceRepository.flush();
1500
1501 logger.info("Creating Solr index");
1502 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
1503 final String solrUrl = "http://" + (connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "solr") + ":8983/solr/";
1504 this.solrService.setSolrUrl(solrUrl);
1505 SolrHelper solrHelper = new SolrHelper(this.solrService.getSolrClientForIndexing())
1506 .withBatchSize(solrBatchSize)
1507 .withGeometryValidationRule(solrGeometryValidationRule);
1508 GeoService geoService =
1509 geoServiceRepository.findById("snapshot-geoserver").orElseThrow();
1510 Application defaultApp = applicationRepository.findByName("default");
1511
1512 TMFeatureType begroeidterreindeelFT = geoService.findFeatureTypeForLayer(
1513 geoService.findLayer("postgis:begroeidterreindeel"), featureSourceRepository);
1514
1515 TMFeatureType wegdeelFT = geoService.findFeatureTypeForLayer(
1516 geoService.findLayer("sqlserver:wegdeel"), featureSourceRepository);
1517
1518 TMFeatureType kadastraalPerceelFT = geoService.findFeatureTypeForLayer(
1519 geoService.findLayer("postgis:kadastraal_perceel"), featureSourceRepository);
1520
1521 try (solrHelper) {
1522 SearchIndex begroeidterreindeelIndex = null;
1523 if (begroeidterreindeelFT != null) {
1524 begroeidterreindeelIndex = new SearchIndex()
1525 .setName("Begroeidterreindeel")
1526 .setFeatureTypeId(begroeidterreindeelFT.getId())
1527 .setSearchFieldsUsed(List.of("class", "plus_fysiekvoorkomen", "bronhouder"))
1528 .setSearchDisplayFieldsUsed(List.of("class", "plus_fysiekvoorkomen"));
1529 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1530 begroeidterreindeelIndex = solrHelper.addFeatureTypeIndex(
1531 begroeidterreindeelIndex,
1532 begroeidterreindeelFT,
1533 featureSourceFactoryHelper,
1534 searchIndexRepository);
1535 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1536 }
1537
1538 SearchIndex kadastraalPerceelIndex = null;
1539 if (kadastraalPerceelFT != null) {
1540 kadastraalPerceelIndex = new SearchIndex()
1541 .setName("kadastraal_perceel")
1542 .setFeatureTypeId(kadastraalPerceelFT.getId())
1543 .setSearchFieldsUsed(List.of("aanduiding"))
1544 .setSearchDisplayFieldsUsed(List.of("aanduiding"));
1545 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1546 kadastraalPerceelIndex = solrHelper.addFeatureTypeIndex(
1547 kadastraalPerceelIndex,
1548 kadastraalPerceelFT,
1549 featureSourceFactoryHelper,
1550 searchIndexRepository);
1551 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1552 }
1553
1554 SearchIndex wegdeelIndex = null;
1555 if (wegdeelFT != null) {
1556 wegdeelIndex = new SearchIndex()
1557 .setName("Wegdeel")
1558 .setFeatureTypeId(wegdeelFT.getId())
1559 .setSearchFieldsUsed(List.of(
1560 "function_", "plus_fysiekvoorkomenwegdeel", "surfacematerial", "bronhouder"))
1561 .setSearchDisplayFieldsUsed(List.of("function_", "plus_fysiekvoorkomenwegdeel"));
1562 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1563 wegdeelIndex = solrHelper.addFeatureTypeIndex(
1564 wegdeelIndex, wegdeelFT, featureSourceFactoryHelper, searchIndexRepository);
1565 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1566 }
1567
1568 featureSourceRepository
1569 .getByTitle("PostGIS")
1570 .flatMap(fs -> fs.getFeatureTypes().stream()
1571 .filter(ft -> ft.getName().equals("bak"))
1572 .findFirst())
1573 .ifPresent(ft -> {
1574 SearchIndex bak = new SearchIndex()
1575 .setName("bak")
1576 .setFeatureTypeId(ft.getId())
1577 .setSearchFieldsUsed(List.of("gmlid", "identificatie", "plus_type"))
1578 .setSearchDisplayFieldsUsed(List.of("gmlid", "plus_type", "bronhouder"));
1579 searchIndexRepository.save(bak);
1580 try {
1581 bak = solrHelper.addFeatureTypeIndex(
1582 bak, ft, featureSourceFactoryHelper, searchIndexRepository);
1583 searchIndexRepository.save(bak);
1584 } catch (IOException | SolrServerException e) {
1585 throw new RuntimeException(e);
1586 }
1587 });
1588
1589
1590 featureSourceRepository
1591 .getByTitle("PostGIS OSM")
1592 .flatMap(fs -> fs.getFeatureTypes().stream()
1593 .filter(ft -> ft.getName().equals("osm_roads"))
1594 .findFirst())
1595 .ifPresent(ft -> {
1596 SearchIndex osm_no_pk = new SearchIndex()
1597 .setName("osm_no_pk")
1598 .setFeatureTypeId(ft.getId())
1599 .setSearchFieldsUsed(List.of("landuse", "osm_id", "natural", "boundary"))
1600 .setSearchDisplayFieldsUsed(
1601 List.of("landuse", "osm_id", "natural", "amenity", "boundary"));
1602 searchIndexRepository.save(osm_no_pk);
1603 });
1604
1605 AppTreeLayerNode begroeidTerreindeelLayerNode = defaultApp
1606 .getAllAppTreeLayerNode()
1607 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
1608 .findFirst()
1609 .orElse(null);
1610
1611 if (begroeidTerreindeelLayerNode != null && begroeidterreindeelIndex != null) {
1612 defaultApp
1613 .getAppLayerSettings(begroeidTerreindeelLayerNode)
1614 .setSearchIndexId(begroeidterreindeelIndex.getId());
1615 }
1616
1617 AppTreeLayerNode kadastraalPerceelLayerNode = defaultApp
1618 .getAllAppTreeLayerNode()
1619 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
1620 .findFirst()
1621 .orElse(null);
1622
1623 if (kadastraalPerceelLayerNode != null && kadastraalPerceelIndex != null) {
1624 defaultApp
1625 .getAppLayerSettings(kadastraalPerceelLayerNode)
1626 .setSearchIndexId(kadastraalPerceelIndex.getId());
1627 }
1628
1629 AppTreeLayerNode wegdeel = defaultApp
1630 .getAllAppTreeLayerNode()
1631 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:sqlserver:wegdeel"))
1632 .findFirst()
1633 .orElse(null);
1634
1635 if (wegdeel != null && wegdeelIndex != null) {
1636 defaultApp.getAppLayerSettings(wegdeel).setSearchIndexId(wegdeelIndex.getId());
1637 }
1638
1639 applicationRepository.save(defaultApp);
1640 }
1641 }
1642 }
1643
1644 private void createScheduledTasks() {
1645 try {
1646 logger.info("Creating POC tasks");
1647 logger.info(
1648 "Created 15 minutely task with key: {}",
1649 taskManagerService.createTask(
1650 PocTask.class,
1651 new TMJobDataMap(Map.of(
1652 Task.TYPE_KEY,
1653 TaskType.POC.getValue(),
1654 "foo",
1655 "foobar",
1656 Task.DESCRIPTION_KEY,
1657 "POC task that runs every 15 minutes")),
1658 "0 0/15 * 1/1 * ? *"));
1659 logger.info(
1660 "Created hourly task with key: {}",
1661 taskManagerService.createTask(
1662 PocTask.class,
1663 new TMJobDataMap(Map.of(
1664 Task.TYPE_KEY,
1665 TaskType.POC.getValue(),
1666 "foo",
1667 "bar",
1668 Task.DESCRIPTION_KEY,
1669 "POC task that runs every hour",
1670 Task.PRIORITY_KEY,
1671 10)),
1672 "0 0 0/1 1/1 * ? *"));
1673
1674 logger.info(
1675 "Created hourly failing task with key: {}",
1676 taskManagerService.createTask(
1677 FailingPocTask.class,
1678 new TMJobDataMap(Map.of(
1679 Task.TYPE_KEY,
1680 TaskType.FAILINGPOC.getValue(),
1681 Task.DESCRIPTION_KEY,
1682 "POC task that fails every hour with low priority",
1683 Task.PRIORITY_KEY,
1684 100)),
1685 "0 0 0/1 1/1 * ? *"));
1686 logger.info(
1687 "Created daily task with key: {}",
1688 taskManagerService.createTask(
1689 InterruptablePocTask.class,
1690 new TMJobDataMap(Map.of(
1691 Task.TYPE_KEY,
1692 TaskType.INTERRUPTABLEPOC.getValue(),
1693 Task.DESCRIPTION_KEY,
1694 "Interruptable POC task that runs every 15 minutes",
1695 Task.PRIORITY_KEY,
1696 5)),
1697 "0 0/15 * 1/1 * ? *"));
1698 } catch (SchedulerException e) {
1699 logger.error("Error creating scheduled one or more poc tasks", e);
1700 }
1701
1702 if (categories.contains("search-index")) {
1703 logger.info("Creating INDEX tasks");
1704 List.of("Begroeidterreindeel", "kadastraal_perceel")
1705 .forEach(name -> searchIndexRepository.findByName(name).ifPresent(index -> {
1706 index.setSchedule(new TaskSchedule()
1707
1708 .cronExpression("0 0 0/1 1/1 * ? *")
1709
1710
1711 .description("Update Solr index \" " + name + "\" every hour"));
1712 try {
1713 final UUID uuid = taskManagerService.createTask(
1714 IndexTask.class,
1715 new TMJobDataMap(Map.of(
1716 Task.TYPE_KEY,
1717 TaskType.INDEX,
1718 Task.DESCRIPTION_KEY,
1719 index.getSchedule().getDescription(),
1720 IndexTask.INDEX_KEY,
1721 index.getId().toString(),
1722 Task.PRIORITY_KEY,
1723 10)),
1724 index.getSchedule().getCronExpression());
1725
1726 index.getSchedule().setUuid(uuid);
1727 searchIndexRepository.save(index);
1728
1729 logger.info("Created task to update Solr index with key: {}", uuid);
1730 } catch (SchedulerException e) {
1731 logger.error("Error creating scheduled solr index task", e);
1732 }
1733 }));
1734 }
1735 }
1736
1737 private void createPages() throws IOException {
1738 Upload logo = new Upload()
1739 .setCategory(Upload.CATEGORY_PORTAL_IMAGE)
1740 .setFilename("gradient.svg")
1741 .setMimeType("image/svg+xml")
1742 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
1743 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
1744 uploadRepository.save(logo);
1745
1746 Page about = new Page();
1747 about.setName("about");
1748 about.setType("page");
1749 about.setContent("About Tailormap");
1750 about.setContent("""
1751 # About Tailormap
1752
1753 This is a page about *Tailormap*. It doesn't say much yet.
1754 """);
1755 pageRepository.save(about);
1756
1757 Page page = new Page();
1758 page.setName("home");
1759 page.setType("page");
1760 page.setTitle("Tailormap - Home");
1761 page.setContent(
1762 """
1763 # Welcome to Tailormap!
1764
1765 This page is only visible when you implement a frontend to display pages, or get it (including a simple CMS)
1766 from [B3Partners](https:
1767 """);
1768 page.setClassName(null);
1769 page.setTiles(List.of(
1770 new PageTile()
1771 .id(UUID.randomUUID().toString())
1772 .title("Default app")
1773 .applicationId(Optional.ofNullable(applicationRepository.findByName("default"))
1774 .map(Application::getId)
1775 .orElse(null))
1776 .image(logo.getId().toString())
1777 .content("*Default app* tile content")
1778 .filterRequireAuthorization(false)
1779 .openInNewWindow(false),
1780 new PageTile()
1781 .id(UUID.randomUUID().toString())
1782 .title("Secured app")
1783 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
1784 .map(Application::getId)
1785 .orElse(null))
1786 .filterRequireAuthorization(true)
1787 .content("Secure app, only shown if user has authorization")
1788 .openInNewWindow(false),
1789 new PageTile()
1790 .id(UUID.randomUUID().toString())
1791 .title("Secured app (unfiltered)")
1792 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
1793 .map(Application::getId)
1794 .orElse(null))
1795 .filterRequireAuthorization(false)
1796 .content("Secure app, tile shown to everyone")
1797 .openInNewWindow(false),
1798 new PageTile()
1799 .id(UUID.randomUUID().toString())
1800 .title("About")
1801 .pageId(about.getId())
1802 .openInNewWindow(false),
1803 new PageTile()
1804 .id(UUID.randomUUID().toString())
1805 .title("B3Partners")
1806 .url("https://www.b3partners.nl/")
1807 .openInNewWindow(true)));
1808 pageRepository.save(page);
1809
1810 Configuration c = new Configuration();
1811 c.setKey(HOME_PAGE);
1812 c.setValue(page.getId().toString());
1813 configurationRepository.save(c);
1814
1815 List<MenuItem> globalMenuItems = List.of(
1816 new MenuItem().pageId(about.getId()).label("About").openInNewWindow(false),
1817 new MenuItem()
1818 .label("B3Partners website")
1819 .url("https://www.b3partners.nl/")
1820 .openInNewWindow(true)
1821 .exclusiveOnPageId(about.getId()));
1822 c = new Configuration();
1823 c.setKey(PORTAL_MENU);
1824 c.setJsonValue(new ObjectMapper().valueToTree(globalMenuItems));
1825 configurationRepository.save(c);
1826 }
1827
1828 private void insertTestDrawing() {
1829
1830 try {
1831 this.jdbcClient
1832 .sql(
1833 """
1834 INSERT INTO data.drawing (id,name,description,domain_data,"access",created_by,created_at,updated_by,updated_at,srid,"version") VALUES
1835 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid,'Testcase','A private access drawing that is inserted as part of the testdata','{"items": 1, "domain": "test drawings"}','private','tm-admin','2025-02-27 17:53:36.095164+01','tm-admin','2025-02-27 17:54:19.384961+01',28992,1);
1836 """)
1837 .update();
1838
1839 this.jdbcClient
1840 .sql(
1841 """
1842 INSERT INTO data.drawing_feature (drawing_id,id,geometry,properties) VALUES
1843 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '394e0d4a-b374-4d00-94c8-1758ea70e9d9'::uuid, 'SRID=28992;POLYGON ((131982.01 458929.27, 131957.31 458755.45, 132072.39 458736.69, 132099.06 458910.51, 131982.01 458929.27))'::public.geometry, '{"type": "POLYGON", "style": {"label": "", "marker": "circle", "fillColor": "rgb(117, 117, 117)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(98, 54, 255)", "strokeWidth": 3, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}}'::jsonb),
1844 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '89fc320c-41a3-4635-8d98-39d822339692'::uuid, 'SRID=28992;POINT (131897.55 458971.24)'::public.geometry, '{"type": "CIRCLE", "style": {"label": "CIRCLE", "marker": "circle", "fillColor": "rgb(117, 117, 117)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(98, 54, 255)", "strokeWidth": 3, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}, "radius": 14.989999999990687}'::jsonb),
1845 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '5d6252cc-25b6-4a43-9053-0779b86895a7'::uuid, 'SRID=28992;LINESTRING (131920.76 458754.96, 131923.73 458783.1, 131930.15 458793.97, 131945.95 458912.98, 131967.68 458946.06)'::public.geometry, '{"type": "LINE", "style": {"label": "", "marker": "circle", "fillColor": "rgb(255, 82, 82)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(255, 82, 82)", "strokeWidth": 13, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}}'::jsonb)
1846 """)
1847 .update();
1848 } catch (Exception any) {
1849 logger.error("Error inserting test drawing in data schema, some tests may fail", any);
1850 }
1851 }
1852 }