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