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.AuthorisationService.ACCESS_TYPE_VIEW;
19
20 import java.io.IOException;
21 import java.lang.invoke.MethodHandles;
22 import java.net.URI;
23 import java.nio.charset.StandardCharsets;
24 import java.sql.SQLException;
25 import java.time.OffsetDateTime;
26 import java.time.ZoneId;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.NoSuchElementException;
32 import java.util.Optional;
33 import java.util.Properties;
34 import java.util.Set;
35 import java.util.UUID;
36 import org.apache.solr.client.solrj.SolrServerException;
37 import org.quartz.SchedulerException;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.springframework.beans.factory.annotation.Value;
41 import org.springframework.boot.SpringApplication;
42 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
43 import org.springframework.boot.context.event.ApplicationReadyEvent;
44 import org.springframework.context.ApplicationContext;
45 import org.springframework.context.event.EventListener;
46 import org.springframework.core.io.ClassPathResource;
47 import org.springframework.jdbc.core.simple.JdbcClient;
48 import org.springframework.transaction.annotation.Transactional;
49 import org.springframework.util.PropertyPlaceholderHelper;
50 import org.tailormap.api.admin.model.CapabilitiesLoadingEvent;
51 import org.tailormap.api.admin.model.TaskSchedule;
52 import org.tailormap.api.geotools.featuresources.AttachmentsHelper;
53 import org.tailormap.api.geotools.featuresources.FeatureSourceFactoryHelper;
54 import org.tailormap.api.geotools.featuresources.JDBCFeatureSourceHelper;
55 import org.tailormap.api.geotools.featuresources.WFSFeatureSourceHelper;
56 import org.tailormap.api.persistence.Application;
57 import org.tailormap.api.persistence.Catalog;
58 import org.tailormap.api.persistence.Configuration;
59 import org.tailormap.api.persistence.GeoService;
60 import org.tailormap.api.persistence.Group;
61 import org.tailormap.api.persistence.Page;
62 import org.tailormap.api.persistence.SearchIndex;
63 import org.tailormap.api.persistence.TMFeatureSource;
64 import org.tailormap.api.persistence.TMFeatureType;
65 import org.tailormap.api.persistence.Upload;
66 import org.tailormap.api.persistence.UploadCategory;
67 import org.tailormap.api.persistence.User;
68 import org.tailormap.api.persistence.helper.CapabilitiesLoadingProgressReporting;
69 import org.tailormap.api.persistence.helper.GeoServiceHelper;
70 import org.tailormap.api.persistence.json.AppContent;
71 import org.tailormap.api.persistence.json.AppLayerSettings;
72 import org.tailormap.api.persistence.json.AppSettings;
73 import org.tailormap.api.persistence.json.AppTreeLayerNode;
74 import org.tailormap.api.persistence.json.AppTreeLevelNode;
75 import org.tailormap.api.persistence.json.AppTreeNode;
76 import org.tailormap.api.persistence.json.AppUiSettings;
77 import org.tailormap.api.persistence.json.AttachmentAttributeType;
78 import org.tailormap.api.persistence.json.AttributeSettings;
79 import org.tailormap.api.persistence.json.AttributeValueSettings;
80 import org.tailormap.api.persistence.json.AuthorizationRule;
81 import org.tailormap.api.persistence.json.AuthorizationRuleDecision;
82 import org.tailormap.api.persistence.json.Bounds;
83 import org.tailormap.api.persistence.json.CatalogNode;
84 import org.tailormap.api.persistence.json.FeatureTypeRef;
85 import org.tailormap.api.persistence.json.FeatureTypeTemplate;
86 import org.tailormap.api.persistence.json.Filter;
87 import org.tailormap.api.persistence.json.FilterEditConfiguration;
88 import org.tailormap.api.persistence.json.FilterGroup;
89 import org.tailormap.api.persistence.json.GeoServiceDefaultLayerSettings;
90 import org.tailormap.api.persistence.json.GeoServiceLayerSettings;
91 import org.tailormap.api.persistence.json.GeoServiceSettings;
92 import org.tailormap.api.persistence.json.JDBCConnectionProperties;
93 import org.tailormap.api.persistence.json.MenuItem;
94 import org.tailormap.api.persistence.json.PageTile;
95 import org.tailormap.api.persistence.json.ServiceAuthentication;
96 import org.tailormap.api.persistence.json.TailormapObjectRef;
97 import org.tailormap.api.persistence.json.TileLayerHiDpiMode;
98 import org.tailormap.api.persistence.json.WMSStyle;
99 import org.tailormap.api.repository.ApplicationRepository;
100 import org.tailormap.api.repository.CatalogRepository;
101 import org.tailormap.api.repository.ConfigurationRepository;
102 import org.tailormap.api.repository.FeatureSourceRepository;
103 import org.tailormap.api.repository.GeoServiceRepository;
104 import org.tailormap.api.repository.GroupRepository;
105 import org.tailormap.api.repository.PageRepository;
106 import org.tailormap.api.repository.SearchIndexRepository;
107 import org.tailormap.api.repository.UploadRepository;
108 import org.tailormap.api.repository.UserRepository;
109 import org.tailormap.api.scheduling.IndexTask;
110 import org.tailormap.api.scheduling.TMJobDataMap;
111 import org.tailormap.api.scheduling.Task;
112 import org.tailormap.api.scheduling.TaskManagerService;
113 import org.tailormap.api.scheduling.TaskType;
114 import org.tailormap.api.security.InternalAdminAuthentication;
115 import org.tailormap.api.service.UploadsService;
116 import org.tailormap.api.solr.SolrHelper;
117 import org.tailormap.api.solr.SolrService;
118 import org.tailormap.api.viewer.model.AppStyling;
119 import org.tailormap.api.viewer.model.Component;
120 import org.tailormap.api.viewer.model.ComponentConfig;
121 import tools.jackson.core.JacksonException;
122 import tools.jackson.databind.json.JsonMapper;
123
124
125
126
127
128 @org.springframework.context.annotation.Configuration
129 @ConditionalOnProperty(name = "tailormap-api.database.populate-testdata", havingValue = "true")
130 public class PopulateTestData {
131
132 private static final Logger logger =
133 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
134 private final ApplicationContext appContext;
135 private final UserRepository userRepository;
136 private final GroupRepository groupRepository;
137 private final CatalogRepository catalogRepository;
138 private final GeoServiceRepository geoServiceRepository;
139 private final GeoServiceHelper geoServiceHelper;
140 private final SolrService solrService;
141 private final TaskManagerService taskManagerService;
142 private final FeatureSourceRepository featureSourceRepository;
143 private final ApplicationRepository applicationRepository;
144 private final ConfigurationRepository configurationRepository;
145 private final SearchIndexRepository searchIndexRepository;
146 private final FeatureSourceFactoryHelper featureSourceFactoryHelper;
147 private final UploadRepository uploadRepository;
148 private final PageRepository pageRepository;
149 private final JdbcClient jdbcClient;
150
151 @Value("${spatial.dbs.connect:false}")
152 private boolean connectToSpatialDbs;
153
154 @Value("#{'${tailormap-api.database.populate-testdata.categories}'.split(',')}")
155 private Set<String> categories;
156
157 @Value("${spatial.dbs.localhost:true}")
158 private boolean connectToSpatialDbsAtLocalhost;
159
160 @Value("${tailormap-api.database.populate-testdata.admin-hashed-password}")
161 private String adminHashedPassword;
162
163 @Value("${tailormap-api.database.populate-testdata.management-hashed-password}")
164 private String managementHashedPassword;
165
166 @Value("${tailormap-api.database.populate-testdata.exit:false}")
167 private boolean exit;
168
169 @Value("${MAP5_URL:#{null}}")
170 private String map5url;
171
172 private final String tiles3dProxyUsername = "b3p";
173
174
175 private final String tiles3dProxyPassword = "cOxPlJFWmtndFk0eVg5VdL";
176
177 @Value("${tailormap-api.solr-batch-size:1000}")
178 private int solrBatchSize;
179
180 @Value("${tailormap-api.solr-geometry-validation-rule:repairBuffer0}")
181 private String solrGeometryValidationRule;
182
183 @Value("${tailormap-api.timeout}")
184 private int timeout;
185
186 private static final String PROVINCIE_FEATURE_TYPE_NAME = "bestuurlijkegebieden:Provinciegebied";
187
188 public PopulateTestData(
189 ApplicationContext appContext,
190 UserRepository userRepository,
191 GroupRepository groupRepository,
192 CatalogRepository catalogRepository,
193 GeoServiceRepository geoServiceRepository,
194 GeoServiceHelper geoServiceHelper,
195 SolrService solrService,
196 TaskManagerService taskManagerService,
197 FeatureSourceRepository featureSourceRepository,
198 ApplicationRepository applicationRepository,
199 ConfigurationRepository configurationRepository,
200 FeatureSourceFactoryHelper featureSourceFactoryHelper,
201 SearchIndexRepository searchIndexRepository,
202 UploadRepository uploadRepository,
203 PageRepository pageRepository,
204 JdbcClient jdbcClient) {
205 this.appContext = appContext;
206 this.userRepository = userRepository;
207 this.groupRepository = groupRepository;
208 this.catalogRepository = catalogRepository;
209 this.geoServiceRepository = geoServiceRepository;
210 this.geoServiceHelper = geoServiceHelper;
211 this.solrService = solrService;
212 this.taskManagerService = taskManagerService;
213 this.featureSourceRepository = featureSourceRepository;
214 this.applicationRepository = applicationRepository;
215 this.configurationRepository = configurationRepository;
216 this.featureSourceFactoryHelper = featureSourceFactoryHelper;
217 this.searchIndexRepository = searchIndexRepository;
218 this.uploadRepository = uploadRepository;
219 this.pageRepository = pageRepository;
220 this.jdbcClient = jdbcClient;
221 }
222
223 @EventListener(ApplicationReadyEvent.class)
224 @Transactional
225 public void populate() throws Exception {
226 InternalAdminAuthentication.setInSecurityContext();
227 try {
228
229
230 createTestUsersAndGroups();
231 createConfigurationTestData();
232 if (categories.contains("catalog")) {
233 createCatalogTestData();
234 }
235 if (categories.contains("apps")) {
236 createAppTestData();
237 }
238 if (categories.contains("search-index")) {
239 try {
240 createSolrIndex();
241 } catch (Exception e) {
242 logger.error("Exception creating Solr Index for testdata (continuing)", e);
243 }
244 }
245 if (categories.contains("search-index")) {
246 createSearchIndexTasks();
247 }
248 if (categories.contains("pages")) {
249 createPages();
250 }
251 logger.info("Test entities created");
252 if (categories.contains("uploads")) {
253 createUploads();
254 logger.info("Test uploads created");
255 }
256 if (categories.contains("drawing")) {
257 insertTestDrawing();
258 logger.info("Test drawing created");
259 try {
260 insertDrawingStyle();
261 logger.info("Test drawing style created");
262 } catch (Exception e) {
263 logger.error("Exception creating drawing style", e);
264 }
265 }
266 } finally {
267 InternalAdminAuthentication.clearSecurityContextAuthentication();
268 }
269 if (exit) {
270
271
272 new Thread(() -> {
273 try {
274 logger.info("Exiting in 10 seconds");
275 Thread.sleep(10000);
276 } catch (InterruptedException ignored) {
277
278 }
279 SpringApplication.exit(appContext, () -> 0);
280 System.exit(0);
281 })
282 .start();
283 }
284 }
285
286 public void createTestUsersAndGroups() throws NoSuchElementException {
287 Group groupFoo = new Group().setName("test-foo").setDescription("Used for integration tests.");
288 groupRepository.save(groupFoo);
289
290 Group groupBar = new Group().setName("test-bar").setDescription("Used for integration tests.");
291 groupBar.addOrUpdateAdminProperty("group-property", true, true);
292 groupBar.addOrUpdateAdminProperty("group-private-property", 999.9, false);
293 groupRepository.save(groupBar);
294
295 Group groupBaz = new Group().setName("test-baz").setDescription("Used for integration tests.");
296 groupRepository.save(groupBaz);
297
298
299 User u = new User().setUsername("user").setPassword("{noop}user").setEmail("user@example.com");
300 u.getGroups().addAll(List.of(groupFoo, groupBar, groupBaz));
301 userRepository.save(u);
302
303
304 u = new User()
305 .setUsername("foo")
306 .setPassword("{noop}foo")
307 .setEmail("foo@example.com")
308 .setName("Foo only user");
309 u.getGroups().add(groupFoo);
310 userRepository.save(u);
311
312 u = new User()
313 .setUsername("disabled")
314 .setPassword("{noop}disabled")
315 .setEmail("disabled@example.com")
316 .setEnabled(false);
317 userRepository.save(u);
318
319 u = new User()
320 .setUsername("expired")
321 .setPassword("{noop}expired")
322 .setEmail("expired@example.com")
323 .setValidUntil(
324 OffsetDateTime.now(ZoneId.systemDefault()).minusDays(1).toZonedDateTime());
325 userRepository.save(u);
326
327
328 u = new User().setUsername("tm-admin").setPassword(adminHashedPassword);
329 u.addOrUpdateAdminProperty("some-property", "some-value", true);
330 u.addOrUpdateAdminProperty("admin-property", "private-value", false);
331 u.getGroups().add(groupRepository.findById(Group.ADMIN).orElseThrow());
332 u.getGroups().add(groupBar);
333 userRepository.save(u);
334
335 u = new User().setUsername(Group.ACTUATOR).setPassword(managementHashedPassword);
336 u.getGroups().add(groupRepository.findById(Group.ACTUATOR).orElseThrow());
337 userRepository.save(u);
338 }
339
340 private final List<AuthorizationRule> ruleAnonymousRead = List.of(new AuthorizationRule()
341 .groupName(Group.ANONYMOUS)
342 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)));
343
344 private final List<AuthorizationRule> ruleLoggedIn = List.of(new AuthorizationRule()
345 .groupName(Group.AUTHENTICATED)
346 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)));
347
348 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
349 private void createCatalogTestData() throws Exception {
350 Catalog catalog = catalogRepository.findById(Catalog.MAIN).orElseThrow();
351 CatalogNode rootCatalogNode = catalog.getNodes().getFirst();
352 CatalogNode catalogNode = new CatalogNode().id("test").title("Test services");
353 rootCatalogNode.addChildrenItem(catalogNode.getId());
354 catalog.getNodes().add(catalogNode);
355
356 String osmAttribution = "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors";
357
358 Bounds rdTileGridExtent =
359 new Bounds().minx(-285401.92).maxx(595401.92).miny(22598.08).maxy(903401.92);
360
361 Upload legend = new Upload()
362 .setCategory(UploadCategory.LEGEND)
363 .setFilename("gemeentegebied-legend.png")
364 .setMimeType("image/png")
365 .setContent(new ClassPathResource("test/gemeentegebied-legend.png").getContentAsByteArray())
366 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
367 uploadRepository.save(legend);
368
369 Upload pdokLogo = uploadRepository.save(new Upload()
370 .setCategory(UploadCategory.LAYER_ATTACHED_FILE)
371 .setFilename("pdok_logo.png")
372 .setMimeType("image/png")
373 .setDescription("PDOK logo for testing layer attached uploads")
374 .setContent(new ClassPathResource("test/pdok_logo.png").getContentAsByteArray())
375 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault())));
376
377 Collection<GeoService> services = List.of(
378 new GeoService()
379 .setId("demo")
380 .setProtocol(WMS)
381 .setTitle("Demo")
382 .setPublished(true)
383 .setAuthorizationRules(ruleAnonymousRead)
384 .setUrl("https://demo.tailormap.com/geoserver/geodata/ows?SERVICE=WMS"),
385 new GeoService()
386 .setId("osm")
387 .setProtocol(XYZ)
388 .setTitle("OSM")
389 .setUrl("https://tile.openstreetmap.org/{z}/{x}/{y}.png")
390 .setAuthorizationRules(ruleAnonymousRead)
391 .setSettings(new GeoServiceSettings()
392 .xyzCrs("EPSG:3857")
393 .layerSettings(Map.of(
394 "xyz",
395 new GeoServiceLayerSettings()
396 .attribution(osmAttribution)
397 .maxZoom(19)))),
398
399 new GeoService()
400 .setId("snapshot-geoserver")
401 .setProtocol(WMS)
402 .setTitle("Test GeoServer")
403 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
404 .setAuthorizationRules(ruleAnonymousRead)
405 .setPublished(true),
406 new GeoService()
407 .setId("filtered-snapshot-geoserver")
408 .setProtocol(WMS)
409 .setTitle("Test GeoServer (with authorization rules)")
410 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
411 .setAuthorizationRules(List.of(
412 new AuthorizationRule()
413 .groupName("test-foo")
414 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)),
415 new AuthorizationRule()
416 .groupName("test-baz")
417 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))
418 .setSettings(new GeoServiceSettings()
419 .layerSettings(Map.of(
420 "BGT",
421 new GeoServiceLayerSettings()
422 .addAuthorizationRulesItem(new AuthorizationRule()
423 .groupName("test-foo")
424 .decisions(Map.of(
425 ACCESS_TYPE_VIEW, AuthorizationRuleDecision.DENY)))
426 .addAuthorizationRulesItem(new AuthorizationRule()
427 .groupName("test-baz")
428 .decisions(Map.of(
429 ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))))
430 .setPublished(true),
431 new GeoService()
432 .setId("snapshot-geoserver-proxied")
433 .setProtocol(WMS)
434 .setTitle("Test GeoServer (proxied)")
435 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
436 .setAuthorizationRules(ruleAnonymousRead)
437 .setSettings(new GeoServiceSettings().useProxy(true)),
438 new GeoService()
439 .setId("openbasiskaart")
440 .setProtocol(WMTS)
441 .setTitle("Openbasiskaart")
442 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
443 .setAuthorizationRules(ruleAnonymousRead)
444 .setSettings(new GeoServiceSettings()
445 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
446 .layerSettings(Map.of(
447 "osm",
448 new GeoServiceLayerSettings()
449 .title("Openbasiskaart")
450 .hiDpiDisabled(false)
451 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
452 .hiDpiSubstituteLayer("osm-hq")))),
453 new GeoService()
454 .setId("openbasiskaart-proxied")
455 .setProtocol(WMTS)
456 .setTitle("Openbasiskaart (proxied)")
457 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
458 .setAuthorizationRules(ruleAnonymousRead)
459
460
461 .setAuthentication(new ServiceAuthentication()
462 .method(ServiceAuthentication.MethodEnum.PASSWORD)
463 .username("test")
464 .password("test"))
465 .setSettings(new GeoServiceSettings()
466 .useProxy(true)
467 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
468 .layerSettings(Map.of(
469 "osm",
470 new GeoServiceLayerSettings()
471 .hiDpiDisabled(false)
472 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
473 .hiDpiSubstituteLayer("osm-hq")))),
474 new GeoService()
475 .setId("openbasiskaart-tms")
476 .setProtocol(XYZ)
477 .setTitle("Openbasiskaart (TMS)")
478 .setUrl("https://openbasiskaart.nl/mapcache/tms/1.0.0/osm@rd/{z}/{x}/{-y}.png")
479 .setAuthorizationRules(ruleAnonymousRead)
480 .setSettings(
481 new GeoServiceSettings()
482 .xyzCrs("EPSG:28992")
483 .defaultLayerSettings(
484 new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
485 .layerSettings(
486 Map.of(
487 "xyz",
488 new GeoServiceLayerSettings()
489 .maxZoom(15)
490 .tileGridExtent(rdTileGridExtent)
491 .hiDpiDisabled(false)
492 .hiDpiMode(
493 TileLayerHiDpiMode
494 .SUBSTITUTELAYERTILEPIXELRATIOONLY)
495 .hiDpiSubstituteLayer(
496 "https://openbasiskaart.nl/mapcache/tms/1.0.0/osm-hq@rd-hq/{z}/{x}/{-y}.png")))),
497 new GeoService()
498 .setId("pdok-hwh-luchtfotorgb")
499 .setProtocol(WMTS)
500 .setTitle("PDOK HWH luchtfoto")
501 .setUrl("https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0")
502 .setAuthorizationRules(ruleAnonymousRead)
503 .setPublished(true)
504 .setSettings(new GeoServiceSettings()
505 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
506 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
507 .hiDpiDisabled(false))
508 .putLayerSettingsItem(
509 "Actueel_orthoHR", new GeoServiceLayerSettings().title("Luchtfoto"))),
510 new GeoService()
511 .setId("b3p-mapproxy-luchtfoto")
512 .setProtocol(XYZ)
513 .setTitle("Luchtfoto (TMS)")
514 .setUrl("https://mapproxy.b3p.nl/tms/1.0.0/luchtfoto/EPSG28992/{z}/{x}/{-y}.jpeg")
515 .setAuthorizationRules(ruleAnonymousRead)
516 .setPublished(true)
517 .setSettings(new GeoServiceSettings()
518 .xyzCrs("EPSG:28992")
519 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
520 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
521 .hiDpiDisabled(false))
522 .layerSettings(Map.of(
523 "xyz",
524 new GeoServiceLayerSettings()
525 .maxZoom(14)
526 .tileGridExtent(rdTileGridExtent)
527 .hiDpiMode(TileLayerHiDpiMode.SHOWNEXTZOOMLEVEL)))),
528 new GeoService()
529 .setId("at-basemap")
530 .setProtocol(WMTS)
531 .setTitle("basemap.at")
532 .setUrl("https://mapsneu.wien.gv.at/basemapneu/1.0.0/WMTSCapabilities.xml")
533 .setAuthorizationRules(ruleAnonymousRead)
534 .setPublished(true)
535 .setSettings(new GeoServiceSettings()
536 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
537 .attribution("© [basemap.at](https://basemap.at)")
538 .hiDpiDisabled(true))
539 .layerSettings(Map.of(
540 "geolandbasemap",
541 new GeoServiceLayerSettings()
542 .title("Basemap")
543 .hiDpiDisabled(false)
544 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERTILEPIXELRATIOONLY)
545 .hiDpiSubstituteLayer("bmaphidpi"),
546 "bmaporthofoto30cm",
547 new GeoServiceLayerSettings()
548 .title("Orthophoto")
549 .hiDpiDisabled(false)))),
550 new GeoService()
551 .setId("pdok-kadaster-bestuurlijkegebieden")
552 .setProtocol(WMS)
553 .setUrl("https://service.pdok.nl/kadaster/brk-bestuurlijke-gebieden/wms/v1_0?service=WMS")
554 .setAuthorizationRules(ruleAnonymousRead)
555 .setSettings(new GeoServiceSettings()
556 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
557 .description("This layer shows an administrative boundary.\n\n[logo]("
558 + UploadsService.UPLOAD_MARKDOWN_SCHEME + pdokLogo.getId() + ")"))
559
560 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
561 .useProxy(true)
562 .putLayerSettingsItem(
563 "Gemeentegebied",
564 new GeoServiceLayerSettings()
565 .legendImageId(legend.getId().toString())))
566 .setPublished(true)
567 .setTitle("PDOK Kadaster bestuurlijke gebieden"),
568 new GeoService()
569 .setId("bestuurlijkegebieden-proxied")
570 .setProtocol(WMS)
571 .setUrl("https://service.pdok.nl/kadaster/brk-bestuurlijke-gebieden/wms/v1_0?service=WMS")
572 .setAuthorizationRules(ruleAnonymousRead)
573
574
575
576 .setAuthentication(new ServiceAuthentication()
577 .method(ServiceAuthentication.MethodEnum.PASSWORD)
578 .username("test")
579 .password("test"))
580 .setSettings(new GeoServiceSettings()
581
582 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
583 .useProxy(true))
584 .setPublished(true)
585 .setTitle("Bestuurlijke gebieden (proxied met auth)"),
586 new GeoService()
587 .setId("3dbag_utrecht")
588 .setProtocol(TILES3D)
589 .setUrl("https://3dtilesnederland.nl/tiles/1.0/implicit/nederland/344.json")
590 .setTitle("3D BAG Utrecht")
591 .setPublished(true)
592 .setAuthorizationRules(ruleAnonymousRead),
593 new GeoService()
594 .setId("ahn_terrain_model")
595 .setProtocol(QUANTIZEDMESH)
596 .setUrl(
597 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections/digitaalterreinmodel")
598 .setTitle("AHN Terrain Model")
599 .setPublished(true)
600 .setAuthorizationRules(ruleAnonymousRead),
601 new GeoService()
602 .setId("3d_basisvoorziening_gebouwen_proxy")
603 .setProtocol(TILES3D)
604 .setUrl(
605 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1_0/collections/gebouwen/3dtiles")
606 .setTitle("3D Basisvoorziening Gebouwen Proxy")
607 .setPublished(true)
608 .setAuthorizationRules(ruleAnonymousRead)
609 .setSettings(new GeoServiceSettings().useProxy(true)),
610 new GeoService()
611 .setId("3d_utrecht_proxied_auth")
612 .setProtocol(TILES3D)
613 .setUrl("https://snapshot.tailormap.nl/tiles3d-proxy/3dtiles")
614 .setTitle("3D Utrecht Proxied with Authorization")
615 .setPublished(true)
616 .setAuthorizationRules(ruleAnonymousRead)
617 .setAuthentication(new ServiceAuthentication()
618 .method(ServiceAuthentication.MethodEnum.PASSWORD)
619 .username(tiles3dProxyUsername)
620 .password(tiles3dProxyPassword))
621 .setSettings(new GeoServiceSettings().useProxy(true))
622
623 );
624
625 if (map5url != null) {
626 GeoServiceLayerSettings osmAttr = new GeoServiceLayerSettings().attribution(osmAttribution);
627 GeoServiceLayerSettings map5Attr = new GeoServiceLayerSettings()
628 .attribution("Kaarten: [Map5.nl](https://map5.nl), data: " + osmAttribution);
629 services = new ArrayList<>(services);
630 services.add(new GeoService()
631 .setId("map5")
632 .setProtocol(WMTS)
633 .setTitle("Map5")
634 .setUrl(map5url)
635 .setAuthorizationRules(ruleAnonymousRead)
636 .setSettings(new GeoServiceSettings()
637 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().hiDpiDisabled(true))
638 .layerSettings(Map.of(
639 "openlufo",
640 new GeoServiceLayerSettings()
641 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl), "
642 + osmAttribution),
643 "luforoadslabels",
644 osmAttr,
645 "map5topo",
646 new GeoServiceLayerSettings()
647 .attribution(map5Attr.getAttribution())
648 .hiDpiDisabled(false)
649 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
650 .hiDpiSubstituteLayer("map5topo_hq"),
651 "map5topo_gray",
652 map5Attr,
653 "map5topo_simple",
654 map5Attr,
655 "map5topo_simple_gray",
656 map5Attr,
657 "opensimpletopo",
658 osmAttr,
659 "opensimpletopo_gray",
660 osmAttr,
661 "opentopo",
662 osmAttr,
663 "opentopo_gray",
664 osmAttr))));
665 }
666
667 for (GeoService geoService : services) {
668 try {
669 geoServiceHelper.loadServiceCapabilities(geoService);
670 } catch (Exception e) {
671 logger.error(
672 "Error loading capabilities for {} service URL {}: {}, {}",
673 geoService.getProtocol().getValue(),
674 geoService.getUrl(),
675 e.getClass(),
676 e.getMessage());
677 }
678
679 geoServiceRepository.save(geoService);
680 catalogNode.addItemsItem(new TailormapObjectRef()
681 .kind(TailormapObjectRef.KindEnum.GEO_SERVICE)
682 .id(geoService.getId()));
683 }
684
685 List<TMFeatureSource> testWFS = List.of(
686
687 new TMFeatureSource()
688 .setProtocol(TMFeatureSource.Protocol.WFS)
689 .setUrl("https://demo.tailormap.com/geoserver/geodata/wfs")
690 .setTitle("WFS for Demo")
691 .setLinkedService(geoServiceRepository.findById("demo").orElseThrow()),
692
693 new TMFeatureSource()
694 .setProtocol(TMFeatureSource.Protocol.WFS)
695 .setUrl("https://snapshot.tailormap.nl/geoserver/wfs?")
696 .setTitle("WFS for Test GeoServer")
697 .setLinkedService(geoServiceRepository
698 .findById("snapshot-geoserver")
699 .orElseThrow()));
700 featureSourceRepository.saveAll(testWFS);
701
702 CatalogNode wfsFeatureSourceCatalogNode =
703 new CatalogNode().id("wfs_feature_sources").title("WFS feature sources");
704 rootCatalogNode.addChildrenItem(wfsFeatureSourceCatalogNode.getId());
705 catalog.getNodes().add(wfsFeatureSourceCatalogNode);
706
707 for (TMFeatureSource featureSource : testWFS) {
708 new WFSFeatureSourceHelper()
709 .loadCapabilities(
710 featureSource,
711 timeout,
712 (CapabilitiesLoadingProgressReporting) event -> {
713 logger.warn("WFS loading: {}", event);
714 },
715 new CapabilitiesLoadingEvent()
716 .id(featureSource.getId().toString())
717 .title(featureSource.getTitle())
718 .message("Loading capabilities for " + featureSource.getTitle()
719 + " feature source"));
720 wfsFeatureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
721 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
722 .id(featureSource.getId().toString()));
723 }
724
725 String geodataPassword = "980f1c8A-25933b2";
726
727 Map<String, TMFeatureSource> featureSources = Map.of(
728 "postgis",
729 new TMFeatureSource()
730 .setProtocol(TMFeatureSource.Protocol.JDBC)
731 .setTitle("PostGIS")
732 .setJdbcConnection(new JDBCConnectionProperties()
733 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
734 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
735 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
736 .database("geodata")
737 .schema("public")
738 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
739 .setAuthentication(new ServiceAuthentication()
740 .method(ServiceAuthentication.MethodEnum.PASSWORD)
741 .username("geodata")
742 .password(geodataPassword)),
743 "postgis_osm",
744 new TMFeatureSource()
745 .setProtocol(TMFeatureSource.Protocol.JDBC)
746 .setTitle("PostGIS OSM")
747 .setJdbcConnection(new JDBCConnectionProperties()
748 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
749 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
750 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
751 .database("geodata")
752 .schema("osm")
753 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
754 .setAuthentication(new ServiceAuthentication()
755 .method(ServiceAuthentication.MethodEnum.PASSWORD)
756 .username("geodata")
757 .password(geodataPassword)),
758 "oracle",
759 new TMFeatureSource()
760 .setProtocol(TMFeatureSource.Protocol.JDBC)
761 .setTitle("Oracle")
762 .setJdbcConnection(new JDBCConnectionProperties()
763 .dbtype(JDBCConnectionProperties.DbtypeEnum.ORACLE)
764 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "oracle")
765 .database("/FREEPDB1")
766 .schema("GEODATA")
767 .additionalProperties(Map.of("connectionOptions", "?oracle.jdbc.J2EE13Compliant=true")))
768 .setAuthentication(new ServiceAuthentication()
769 .method(ServiceAuthentication.MethodEnum.PASSWORD)
770 .username("geodata")
771 .password(geodataPassword)),
772 "sqlserver",
773 new TMFeatureSource()
774 .setProtocol(TMFeatureSource.Protocol.JDBC)
775 .setTitle("MS SQL Server")
776 .setJdbcConnection(new JDBCConnectionProperties()
777 .dbtype(JDBCConnectionProperties.DbtypeEnum.SQLSERVER)
778 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "sqlserver")
779 .database("geodata")
780 .schema("dbo")
781 .additionalProperties(Map.of("connectionOptions", ";encrypt=false")))
782 .setAuthentication(new ServiceAuthentication()
783 .method(ServiceAuthentication.MethodEnum.PASSWORD)
784 .username("geodata")
785 .password(geodataPassword)),
786 "pdok-kadaster-bestuurlijkegebieden",
787 new TMFeatureSource()
788 .setProtocol(TMFeatureSource.Protocol.WFS)
789 .setUrl(
790 "https://service.pdok.nl/kadaster/brk-bestuurlijke-gebieden/wfs/v1_0?service=WFS&VERSION=2.0.0")
791 .setTitle("Bestuurlijke gebieden")
792 .setNotes(
793 "Overzicht van de bestuurlijke indeling van Nederland in gemeenten en provincies alsmede de rijksgrens. Gegevens zijn afgeleid uit de Basisregistratie Kadaster (BRK)."));
794 featureSourceRepository.saveAll(featureSources.values());
795
796 new WFSFeatureSourceHelper()
797 .loadCapabilities(
798 featureSources.get("pdok-kadaster-bestuurlijkegebieden"),
799 timeout,
800 (CapabilitiesLoadingProgressReporting) event -> {
801 logger.warn("WFS loading: {}", event);
802 },
803 new CapabilitiesLoadingEvent()
804 .id("pdok-kadaster-bestuurlijkegebieden")
805 .title(featureSources
806 .get("pdok-kadaster-bestuurlijkegebieden")
807 .getTitle())
808 .message("Loading capabilities for pdok-kadaster-bestuurlijkegebieden feature source"));
809 geoServiceRepository.findById("pdok-kadaster-bestuurlijkegebieden").ifPresent(geoService -> {
810 geoService
811 .getSettings()
812 .getLayerSettings()
813 .put(
814 "Provinciegebied",
815 new GeoServiceLayerSettings()
816 .description("The administrative boundary of Dutch Provinces, connected to a WFS.")
817 .descriptionInPopup(true)
818 .featureType(new FeatureTypeRef()
819 .featureSourceId(featureSources
820 .get("pdok-kadaster-bestuurlijkegebieden")
821 .getId())
822 .featureTypeName(PROVINCIE_FEATURE_TYPE_NAME))
823 .title("Provinciegebied (WFS)"));
824 geoServiceRepository.save(geoService);
825 });
826
827 geoServiceRepository.findById("bestuurlijkegebieden-proxied").ifPresent(geoService -> {
828 geoService
829 .getSettings()
830 .getLayerSettings()
831 .put(
832 "Provinciegebied",
833 new GeoServiceLayerSettings()
834 .featureType(new FeatureTypeRef()
835 .featureSourceId(featureSources
836 .get("pdok-kadaster-bestuurlijkegebieden")
837 .getId())
838 .featureTypeName(PROVINCIE_FEATURE_TYPE_NAME))
839 .title("Provinciegebied (WFS, proxied met auth)"));
840 geoServiceRepository.save(geoService);
841 });
842
843 CatalogNode featureSourceCatalogNode =
844 new CatalogNode().id("feature_sources").title("Test feature sources");
845 rootCatalogNode.addChildrenItem(featureSourceCatalogNode.getId());
846 catalog.getNodes().add(featureSourceCatalogNode);
847
848 CatalogNode geoServiceAdminControllerNode =
849 new CatalogNode().id("GeoServiceAdminController").title("GeoServiceAdminController test node");
850 rootCatalogNode.addChildrenItem(geoServiceAdminControllerNode.getId());
851 catalog.getNodes().add(geoServiceAdminControllerNode);
852 CatalogNode featureSourceAdminControllerNode =
853 new CatalogNode().id("FeatureSourceAdminController").title("FeatureSourceAdminController test node");
854 rootCatalogNode.addChildrenItem(featureSourceAdminControllerNode.getId());
855 catalog.getNodes().add(featureSourceAdminControllerNode);
856
857 for (TMFeatureSource featureSource : featureSources.values()) {
858 featureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
859 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
860 .id(featureSource.getId().toString()));
861 }
862 catalogRepository.save(catalog);
863
864 if (connectToSpatialDbs) {
865 featureSources.values().forEach(fs -> {
866 try {
867 if (fs.getProtocol() == TMFeatureSource.Protocol.JDBC) {
868 new JDBCFeatureSourceHelper()
869 .loadCapabilities(
870 fs,
871 timeout,
872 (CapabilitiesLoadingProgressReporting) event -> {
873 logger.debug("JDBC loading: {}", event);
874 },
875 new CapabilitiesLoadingEvent()
876 .id(fs.getId().toString())
877 .title(fs.getTitle())
878 .message("Loading JDBC capabilities for " + fs.getTitle()
879 + " feature source"));
880 } else if (fs.getProtocol() == TMFeatureSource.Protocol.WFS) {
881 new WFSFeatureSourceHelper()
882 .loadCapabilities(
883 fs,
884 timeout,
885 (CapabilitiesLoadingProgressReporting) event -> {
886 logger.warn("WFS loading: {}", event);
887 },
888 new CapabilitiesLoadingEvent()
889 .id(fs.getId().toString())
890 .title(fs.getTitle())
891 .message("Loading WFS capabilities for " + fs.getTitle()
892 + " feature source"));
893 }
894 } catch (Exception e) {
895 logger.error("Error loading capabilities for feature source {}", fs.getTitle(), e);
896 }
897 });
898
899 services.stream()
900
901
902 .filter(s -> s.getId().startsWith("snapshot-geoserver"))
903 .forEach(s -> s.getSettings()
904 .layerSettings(Map.of(
905 "postgis:begroeidterreindeel",
906 new GeoServiceLayerSettings()
907 .description("""
908 This layer shows data from https:
909
910 https:
911 .featureType(new FeatureTypeRef()
912 .featureSourceId(featureSources
913 .get("postgis")
914 .getId())
915 .featureTypeName("begroeidterreindeel")),
916 "postgis:bak",
917 new GeoServiceLayerSettings()
918 .featureType(new FeatureTypeRef()
919 .featureSourceId(featureSources
920 .get("postgis")
921 .getId())
922 .featureTypeName("bak")),
923 "postgis:kadastraal_perceel",
924 new GeoServiceLayerSettings()
925 .description("cadastral parcel label points")
926 .featureType(new FeatureTypeRef()
927 .featureSourceId(featureSources
928 .get("postgis")
929 .getId())
930 .featureTypeName("kadastraal_perceel")),
931 "sqlserver:wegdeel",
932 new GeoServiceLayerSettings()
933 .attribution(
934 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)")
935 .description("""
936 This layer shows data from [MS SQL Server](https:
937
938 https:
939 .featureType(new FeatureTypeRef()
940 .featureSourceId(featureSources
941 .get("sqlserver")
942 .getId())
943 .featureTypeName("wegdeel")),
944 "oracle:WATERDEEL",
945 new GeoServiceLayerSettings()
946 .description("This layer shows data from Oracle Spatial.")
947 .featureType(new FeatureTypeRef()
948 .featureSourceId(featureSources
949 .get("oracle")
950 .getId())
951 .featureTypeName("WATERDEEL")),
952 "postgis:osm_polygon",
953 new GeoServiceLayerSettings()
954 .description("This layer shows OSM data from postgis.")
955 .featureType(new FeatureTypeRef()
956 .featureSourceId(featureSources
957 .get("postgis_osm")
958 .getId())
959 .featureTypeName("osm_polygon")))));
960 }
961
962 featureSources.get("pdok-kadaster-bestuurlijkegebieden").getFeatureTypes().stream()
963 .filter(ft -> ft.getName().equals(PROVINCIE_FEATURE_TYPE_NAME))
964 .findFirst()
965 .ifPresent(ft -> {
966 ft.getSettings().addHideAttributesItem("identificatie");
967 ft.getSettings().addHideAttributesItem("ligtInLandCode");
968 ft.getSettings().addHideAttributesItem("fuuid");
969 ft.getSettings().putAttributeSettingsItem("naam", new AttributeSettings().title("Naam"));
970 ft.getSettings()
971 .setTemplate(new FeatureTypeTemplate()
972 .templateLanguage("simple")
973 .markupLanguage("markdown")
974 .template("""
975 ### Provincie
976 Deze provincie heet **{{naam}}** en ligt in _{{ligtInLandNaam}}_.
977
978 | Attribuut | Waarde |
979 | --------- | ------------------ |
980 | `code` | {{code}} |
981 | `naam` | {{naam}} |
982 | `ligt in` | {{ligtInLandNaam}} |"""));
983 });
984
985 featureSources.get("postgis").getFeatureTypes().stream()
986 .filter(ft -> ft.getName().equals("begroeidterreindeel"))
987 .findFirst()
988 .ifPresent(ft -> {
989 ft.getSettings().addHideAttributesItem("terminationdate");
990 ft.getSettings().addHideAttributesItem("geom_kruinlijn");
991 ft.getSettings().putAttributeSettingsItem("gmlid", new AttributeSettings().title("GML ID"));
992 ft.getSettings()
993 .putAttributeSettingsItem("identificatie", new AttributeSettings().title("Identificatie"));
994 ft.getSettings()
995 .putAttributeSettingsItem(
996 "tijdstipregistratie", new AttributeSettings().title("Registratie"));
997 ft.getSettings()
998 .putAttributeSettingsItem(
999 "eindregistratie", new AttributeSettings().title("Eind registratie"));
1000 ft.getSettings().putAttributeSettingsItem("class", new AttributeSettings().title("Klasse"));
1001 ft.getSettings()
1002 .putAttributeSettingsItem("bronhouder", new AttributeSettings().title("Bronhouder"));
1003 ft.getSettings()
1004 .putAttributeSettingsItem("inonderzoek", new AttributeSettings().title("In onderzoek"));
1005 ft.getSettings()
1006 .putAttributeSettingsItem(
1007 "relatievehoogteligging", new AttributeSettings().title("Relatieve hoogteligging"));
1008 ft.getSettings()
1009 .putAttributeSettingsItem("bgt_status", new AttributeSettings().title("BGT status"));
1010 ft.getSettings()
1011 .putAttributeSettingsItem("plus_status", new AttributeSettings().title("Plus-status"));
1012 ft.getSettings()
1013 .putAttributeSettingsItem(
1014 "plus_fysiekvoorkomen", new AttributeSettings().title("Plus-fysiek voorkomen"));
1015 ft.getSettings()
1016 .putAttributeSettingsItem(
1017 "begroeidterreindeeloptalud", new AttributeSettings().title("Op talud"));
1018 ft.getSettings().addAttributeOrderItem("identificatie");
1019 ft.getSettings().addAttributeOrderItem("bronhouder");
1020 ft.getSettings().addAttributeOrderItem("class");
1021 ft.getSettings()
1022 .addAttachmentAttributesItem(new AttachmentAttributeType()
1023 .attributeName("bijlage")
1024 .maxAttachmentSize(4_000_000L)
1025 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
1026 try {
1027 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
1028 } catch (IOException | SQLException e) {
1029 throw new RuntimeException("Failed to create attachments table", e);
1030 }
1031 ft.getSettings().addEditableAttributesItem("identificatie");
1032 ft.getSettings().addEditableAttributesItem("bronhouder");
1033 ft.getSettings().addEditableAttributesItem("class");
1034 ft.getSettings().addEditableAttributesItem("gmlid");
1035 ft.getSettings().addEditableAttributesItem("lv_publicatiedatum");
1036 ft.getSettings().addEditableAttributesItem("creationdate");
1037 ft.getSettings().addEditableAttributesItem("tijdstipregistratie");
1038 ft.getSettings().addEditableAttributesItem("eindregistratie");
1039 ft.getSettings().addEditableAttributesItem("terminationdate");
1040 ft.getSettings().addEditableAttributesItem("inonderzoek");
1041 ft.getSettings().addEditableAttributesItem("relatievehoogteligging");
1042 ft.getSettings().addEditableAttributesItem("bgt_status");
1043 ft.getSettings().addEditableAttributesItem("plus_status");
1044 ft.getSettings().addEditableAttributesItem("plus_fysiekvoorkomen");
1045 ft.getSettings().addEditableAttributesItem("begroeidterreindeeloptalud");
1046 });
1047
1048 featureSources.get("postgis").getFeatureTypes().stream()
1049 .filter(ft -> ft.getName().equals("bak"))
1050 .findFirst()
1051 .ifPresent(ft -> {
1052 ft.getSettings().addHideAttributesItem("gmlid");
1053 ft.getSettings().addHideAttributesItem("lv_publicatiedatum");
1054 ft.getSettings().addHideAttributesItem("creationdate");
1055 ft.getSettings().addHideAttributesItem("tijdstipregistratie");
1056 ft.getSettings().addHideAttributesItem("eindregistratie");
1057 ft.getSettings().addHideAttributesItem("terminationdate");
1058 ft.getSettings().addHideAttributesItem("inonderzoek");
1059 ft.getSettings().addHideAttributesItem("relatievehoogteligging");
1060 ft.getSettings().addHideAttributesItem("bgt_status");
1061 ft.getSettings().addHideAttributesItem("plus_status");
1062 ft.getSettings().addHideAttributesItem("function_");
1063 ft.getSettings().addHideAttributesItem("plus_type");
1064 });
1065
1066 featureSources.get("oracle").getFeatureTypes().stream()
1067 .filter(ft -> ft.getName().equals("WATERDEEL"))
1068 .findFirst()
1069 .ifPresent(ft -> {
1070 ft.getSettings()
1071 .addAttachmentAttributesItem(new AttachmentAttributeType()
1072 .attributeName("bijlage")
1073 .maxAttachmentSize(4_000_000L)
1074 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
1075 try {
1076 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
1077 } catch (IOException | SQLException e) {
1078 throw new RuntimeException("Failed to create attachments table", e);
1079 }
1080 ft.getSettings().addEditableAttributesItem("GMLID");
1081 ft.getSettings().addEditableAttributesItem("IDENTIFICATIE");
1082 ft.getSettings().addEditableAttributesItem("LV_PUBLICATIEDATUM");
1083 ft.getSettings().addEditableAttributesItem("CREATIONDATE");
1084 ft.getSettings().addEditableAttributesItem("TIJDSTIPREGISTRATIE");
1085 ft.getSettings().addEditableAttributesItem("EINDREGISTRATIE");
1086 ft.getSettings().addEditableAttributesItem("TERMINATIONDATE");
1087 ft.getSettings().addEditableAttributesItem("BRONHOUDER");
1088 ft.getSettings().addEditableAttributesItem("INONDERZOEK");
1089 ft.getSettings().addEditableAttributesItem("RELATIEVEHOOGTELIGGING");
1090 ft.getSettings().addEditableAttributesItem("BGT_STATUS");
1091 ft.getSettings().addEditableAttributesItem("PLUS_STATUS");
1092 ft.getSettings().addEditableAttributesItem("CLASS");
1093 ft.getSettings().addEditableAttributesItem("PLUS_TYPE");
1094 });
1095 featureSources.get("sqlserver").getFeatureTypes().stream()
1096 .filter(ft -> ft.getName().equals("wegdeel"))
1097 .findFirst()
1098 .ifPresent(ft -> {
1099 ft.getSettings()
1100 .addAttachmentAttributesItem(new AttachmentAttributeType()
1101 .attributeName("bijlage")
1102 .maxAttachmentSize(4_000_000L)
1103 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
1104 try {
1105 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
1106 } catch (IOException | SQLException e) {
1107 throw new RuntimeException("Failed to create attachments table", e);
1108 }
1109 ft.getSettings().addEditableAttributesItem("gmlid");
1110 ft.getSettings().addEditableAttributesItem("identificatie");
1111 ft.getSettings().addEditableAttributesItem("lv_publicatiedatum");
1112 ft.getSettings().addEditableAttributesItem("creationdate");
1113 ft.getSettings().addEditableAttributesItem("tijdstipregistratie");
1114 ft.getSettings().addEditableAttributesItem("eindregistratie");
1115 ft.getSettings().addEditableAttributesItem("terminationdate");
1116 ft.getSettings().addEditableAttributesItem("bronhouder");
1117 ft.getSettings().addEditableAttributesItem("inonderzoek");
1118 ft.getSettings().addEditableAttributesItem("relatievehoogteligging");
1119 ft.getSettings().addEditableAttributesItem("bgt_status");
1120 ft.getSettings().addEditableAttributesItem("plus_status");
1121 ft.getSettings().addEditableAttributesItem("function_");
1122 ft.getSettings().addEditableAttributesItem("plus_functiewegdeel");
1123 ft.getSettings().addEditableAttributesItem("plus_fysiekvoorkomenwegdeel");
1124 ft.getSettings().addEditableAttributesItem("surfacematerial");
1125 ft.getSettings().addEditableAttributesItem("wegdeeloptalud");
1126 });
1127
1128 featureSources.get("postgis").getFeatureTypes().stream()
1129 .filter(ft -> ft.getName().equals("kadastraal_perceel"))
1130 .findFirst()
1131 .ifPresent(ft -> {
1132 ft.getSettings()
1133 .addAttachmentAttributesItem(new AttachmentAttributeType()
1134 .attributeName("bijlage")
1135 .maxAttachmentSize(4_000_000L)
1136 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
1137 try {
1138 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
1139 } catch (IOException | SQLException e) {
1140 throw new RuntimeException("Failed to create attachments table for kadastraal_perceel", e);
1141 }
1142
1143 ft.getSettings().addHideAttributesItem("gml_id");
1144
1145 ft.getSettings().addEditableAttributesItem("begin_geldigheid");
1146 ft.getSettings().addEditableAttributesItem("tijdstip_registratie");
1147 });
1148
1149 featureSources.get("postgis_osm").getFeatureTypes().stream()
1150 .filter(ft -> ft.getName().equals("osm_polygon"))
1151 .findFirst()
1152 .ifPresent(ft -> {
1153 ft.getSettings().addEditableAttributesItem("osm_id");
1154 ft.getSettings().addEditableAttributesItem("building");
1155 ft.getSettings().addEditableAttributesItem("z_order");
1156 });
1157 }
1158
1159 public void createAppTestData() throws Exception {
1160 Upload logo = new Upload()
1161 .setCategory(UploadCategory.APP_LOGO)
1162 .setFilename("gradient.svg")
1163 .setMimeType("image/svg+xml")
1164 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
1165 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
1166 uploadRepository.save(logo);
1167
1168 List<AppTreeNode> baseNodes = List.of(
1169 new AppTreeLayerNode()
1170 .objectType("AppTreeLayerNode")
1171 .id("lyr:openbasiskaart:osm")
1172 .serviceId("openbasiskaart")
1173 .layerName("osm")
1174 .visible(true),
1175 new AppTreeLayerNode()
1176 .objectType("AppTreeLayerNode")
1177 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
1178 .serviceId("pdok-hwh-luchtfotorgb")
1179 .layerName("Actueel_orthoHR")
1180 .visible(false));
1181
1182 Application app = new Application()
1183 .setName("default")
1184 .setTitle("Tailormap demo")
1185 .setCrs("EPSG:28992")
1186 .setAuthorizationRules(ruleAnonymousRead)
1187 .setComponents(List.of(
1188 new Component()
1189 .type("SIMPLE_SEARCH")
1190 .config(new ComponentConfig()
1191 .enabled(true)
1192 .putAdditionalProperty("municipalities", List.of("0344"))),
1193 new Component().type("EDIT").config(new ComponentConfig().enabled(true)),
1194 new Component()
1195 .type("TOC")
1196 .config(new ComponentConfig()
1197 .enabled(true)
1198 .putAdditionalProperty("showEditLayerIcon", true)),
1199 new Component()
1200 .type("COORDINATE_LINK_WINDOW")
1201 .config(new ComponentConfig()
1202 .enabled(true)
1203 .putAdditionalProperty(
1204 "urls",
1205 List.of(
1206 Map.of(
1207 "id",
1208 "google-maps",
1209 "url",
1210 "https://www.google.com/maps/@[lat],[lon],18z",
1211 "alias",
1212 "Google Maps",
1213 "projection",
1214 "EPSG:4326"),
1215 Map.of(
1216 "id",
1217 "tm-demo",
1218 "url",
1219 "https://demo.tailormap.com/#@[X],[Y],18",
1220 "alias",
1221 "Tailormap demo",
1222 "projection",
1223 "EPSG:28992"))))))
1224 .setContentRoot(new AppContent()
1225 .addBaseLayerNodesItem(new AppTreeLevelNode()
1226 .objectType("AppTreeLevelNode")
1227 .id("root-base-layers")
1228 .root(true)
1229 .title("Base layers")
1230 .childrenIds(List.of(
1231 "lyr:openbasiskaart:osm",
1232 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1233 "lyr:openbasiskaart-proxied:osm",
1234 "lyr:openbasiskaart-tms:xyz",
1235 "lyr:b3p-mapproxy-luchtfoto:xyz")))
1236 .addBaseLayerNodesItem(
1237
1238
1239 new AppTreeLayerNode()
1240 .objectType("AppTreeLayerNode")
1241 .id("lyr:openbasiskaart-proxied:osm")
1242 .serviceId("openbasiskaart-proxied")
1243 .layerName("osm")
1244 .visible(false))
1245 .addBaseLayerNodesItem(new AppTreeLayerNode()
1246 .objectType("AppTreeLayerNode")
1247 .id("lyr:openbasiskaart-tms:xyz")
1248 .serviceId("openbasiskaart-tms")
1249 .layerName("xyz")
1250 .visible(false))
1251 .addBaseLayerNodesItem(new AppTreeLayerNode()
1252 .objectType("AppTreeLayerNode")
1253 .id("lyr:b3p-mapproxy-luchtfoto:xyz")
1254 .serviceId("b3p-mapproxy-luchtfoto")
1255 .layerName("xyz")
1256 .visible(false))
1257 .addLayerNodesItem(new AppTreeLevelNode()
1258 .objectType("AppTreeLevelNode")
1259 .id("root")
1260 .root(true)
1261 .title("Layers")
1262 .childrenIds(List.of(
1263 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1264 "lyr:bestuurlijkegebieden-proxied:Provinciegebied",
1265 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1266 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1267 "lyr:snapshot-geoserver:postgis:bak",
1268 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1269 "lyr:snapshot-geoserver:sqlserver:wegdeel",
1270 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1271 "lyr:snapshot-geoserver:BGT",
1272 "lvl:proxied",
1273 "lvl:osm",
1274 "lvl:archeo")))
1275 .addLayerNodesItem(new AppTreeLayerNode()
1276 .objectType("AppTreeLayerNode")
1277 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1278 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1279 .layerName("Provinciegebied")
1280 .visible(true))
1281
1282
1283
1284 .addLayerNodesItem(new AppTreeLayerNode()
1285 .objectType("AppTreeLayerNode")
1286 .id("lyr:bestuurlijkegebieden-proxied:Provinciegebied")
1287 .serviceId("bestuurlijkegebieden-proxied")
1288 .layerName("Provinciegebied")
1289 .visible(false))
1290 .addLayerNodesItem(new AppTreeLayerNode()
1291 .objectType("AppTreeLayerNode")
1292 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1293 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1294 .layerName("Gemeentegebied")
1295 .visible(true))
1296 .addLayerNodesItem(new AppTreeLayerNode()
1297 .objectType("AppTreeLayerNode")
1298 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1299 .serviceId("snapshot-geoserver")
1300 .layerName("postgis:begroeidterreindeel")
1301 .visible(true))
1302 .addLayerNodesItem(new AppTreeLayerNode()
1303 .objectType("AppTreeLayerNode")
1304 .id("lyr:snapshot-geoserver:postgis:bak")
1305 .serviceId("snapshot-geoserver")
1306 .layerName("postgis:bak")
1307 .visible(false))
1308 .addLayerNodesItem(new AppTreeLayerNode()
1309 .objectType("AppTreeLayerNode")
1310 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
1311 .serviceId("snapshot-geoserver")
1312 .layerName("postgis:kadastraal_perceel")
1313 .visible(false))
1314 .addLayerNodesItem(new AppTreeLayerNode()
1315 .objectType("AppTreeLayerNode")
1316 .id("lyr:snapshot-geoserver:sqlserver:wegdeel")
1317 .serviceId("snapshot-geoserver")
1318 .layerName("sqlserver:wegdeel")
1319 .visible(true))
1320 .addLayerNodesItem(new AppTreeLayerNode()
1321 .objectType("AppTreeLayerNode")
1322 .id("lyr:snapshot-geoserver:oracle:WATERDEEL")
1323 .serviceId("snapshot-geoserver")
1324 .layerName("oracle:WATERDEEL")
1325 .visible(true))
1326 .addLayerNodesItem(new AppTreeLayerNode()
1327 .objectType("AppTreeLayerNode")
1328 .id("lyr:snapshot-geoserver:BGT")
1329 .serviceId("snapshot-geoserver")
1330 .layerName("BGT")
1331 .visible(false))
1332 .addLayerNodesItem(new AppTreeLevelNode()
1333 .objectType("AppTreeLevelNode")
1334 .id("lvl:proxied")
1335 .title("Proxied")
1336 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1337 .addLayerNodesItem(new AppTreeLayerNode()
1338 .objectType("AppTreeLayerNode")
1339 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1340 .serviceId("snapshot-geoserver-proxied")
1341 .layerName("postgis:begroeidterreindeel")
1342 .visible(false))
1343 .addLayerNodesItem(new AppTreeLevelNode()
1344 .objectType("AppTreeLevelNode")
1345 .id("lvl:osm")
1346 .title("OSM")
1347 .childrenIds(List.of("lyr:snapshot-geoserver:postgis:osm_polygon")))
1348 .addLayerNodesItem(new AppTreeLayerNode()
1349 .objectType("AppTreeLayerNode")
1350 .id("lyr:snapshot-geoserver:postgis:osm_polygon")
1351 .serviceId("snapshot-geoserver")
1352 .layerName("postgis:osm_polygon")
1353 .visible(false))
1354 .addLayerNodesItem(new AppTreeLevelNode()
1355 .objectType("AppTreeLevelNode")
1356 .id("lvl:archeo")
1357 .title("Archeology")
1358 .childrenIds(List.of("lyr:demo:geomorfologie")))
1359 .addLayerNodesItem(new AppTreeLayerNode()
1360 .objectType("AppTreeLayerNode")
1361 .id("lyr:demo:geomorfologie")
1362 .serviceId("demo")
1363 .layerName("geomorfologie")
1364 .visible(true)))
1365 .setStyling(new AppStyling().logo(logo.getId().toString()))
1366 .setSettings(new AppSettings()
1367 .putLayerSettingsItem("lyr:openbasiskaart:osm", new AppLayerSettings().title("Openbasiskaart"))
1368 .putLayerSettingsItem(
1369 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", new AppLayerSettings().title("Luchtfoto"))
1370 .putLayerSettingsItem(
1371 "lyr:openbasiskaart-proxied:osm",
1372 new AppLayerSettings().title("Openbasiskaart (proxied)"))
1373 .putLayerSettingsItem(
1374 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1375 new AppLayerSettings()
1376 .opacity(50)
1377 .title("Waterdeel overridden title")
1378 .editable(true)
1379 .description("This is the layer description from the app layer setting.")
1380 .attribution(
1381 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)"))
1382 .putLayerSettingsItem(
1383 "lyr:snapshot-geoserver:postgis:osm_polygon",
1384 new AppLayerSettings()
1385 .description("OpenStreetMap polygon data in EPSG:3857")
1386 .opacity(60)
1387 .editable(true)
1388 .title("OSM Polygon (EPSG:3857)")
1389 .attribution(
1390 "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors"))
1391 .putLayerSettingsItem(
1392 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1393 new AppLayerSettings()
1394 .editable(true)
1395 .addHideAttributesItem("begroeidterreindeeloptalud")
1396 .addReadOnlyAttributesItem("eindregistratie")
1397 .selectedStyles(
1398 List.of(
1399 new WMSStyle()
1400 .name("begroeidterreindeel")
1401 .title("Visualisatie van de begroeide terreindelen")
1402 .abstractText(
1403 "Deze stylesheet bevat de regels voor de visualisatie van het objecttype Begroeid Terreindeel")
1404 .legendUrl(
1405 URI.create(
1406 "https://snapshot.tailormap.nl/geoserver/ows?service=WMS&version=1.3.0&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=test%3Apostgis_begroeidterreindeel")),
1407 new WMSStyle()
1408 .name("purple_polygon")
1409 .title("purple_polygon")
1410 .abstractText(null)
1411 .legendUrl(
1412 URI.create(
1413 "https://snapshot.tailormap.nl/geoserver/ows?service=WMS&version=1.3.0&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=test%3Apostgis_begroeidterreindeel&style=purple_polygon")))))
1414 .putLayerSettingsItem(
1415 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1416 new AppLayerSettings().editable(true).addReadOnlyAttributesItem("aanduiding"))
1417 .putLayerSettingsItem(
1418 "lyr:snapshot-geoserver:sqlserver:wegdeel", new AppLayerSettings().editable(true))
1419 .putLayerSettingsItem(
1420 "lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel",
1421 new AppLayerSettings().editable(false))
1422 .putLayerSettingsItem(
1423 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1424 new AppLayerSettings()
1425 .hiddenFunctionality(Set.of(FEATURE_INFO, ATTRIBUTE_LIST, EXPORT)))
1426 .addFilterGroupsItem(new FilterGroup()
1427 .id("filtergroup1")
1428 .source("PRESET")
1429 .type(FilterGroup.TypeEnum.ATTRIBUTE)
1430 .layerIds(List.of("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
1431 .operator(FilterGroup.OperatorEnum.AND)
1432 .addFiltersItem(new Filter()
1433 .id("filter1")
1434 .type(Filter.TypeEnum.ATTRIBUTE)
1435 .condition(Filter.ConditionEnum.BEFORE)
1436 .addValueItem("2025-06-05")
1437 .attribute("creationdate")
1438 .attributeType(Filter.AttributeTypeEnum.DATE))
1439 .addFiltersItem(new Filter()
1440 .id("filter2")
1441 .type(Filter.TypeEnum.ATTRIBUTE)
1442 .condition(Filter.ConditionEnum.UNIQUE_VALUES)
1443 .addValueItem("bodembedekkers")
1444 .addValueItem("bosplantsoen")
1445 .addValueItem("gras- en kruidachtigen")
1446 .attribute("plus_fysiekvoorkomen")
1447 .attributeType(Filter.AttributeTypeEnum.STRING)
1448 .editConfiguration(new FilterEditConfiguration()
1449 .filterTool(FilterEditConfiguration.FilterToolEnum.CHECKBOX)
1450 .attributeValuesSettings(List.of(
1451 new AttributeValueSettings()
1452 .value("bodembedekkers")
1453 .initiallySelected(true)
1454 .selectable(true)
1455 .alias("Bodembedekkers"),
1456 new AttributeValueSettings()
1457 .value("bosplantsoen")
1458 .initiallySelected(true)
1459 .selectable(true)
1460 .alias("Bosplantsoen"),
1461 new AttributeValueSettings()
1462 .value("gras- en kruidachtigen")
1463 .initiallySelected(true)
1464 .selectable(true)
1465 .alias("Gras- en kruidachtigen"),
1466 new AttributeValueSettings()
1467 .value("griend en hakhout")
1468 .initiallySelected(false)
1469 .selectable(true),
1470 new AttributeValueSettings()
1471 .value("heesters")
1472 .initiallySelected(false)
1473 .selectable(true),
1474 new AttributeValueSettings()
1475 .value("planten")
1476 .initiallySelected(false)
1477 .selectable(true),
1478 new AttributeValueSettings()
1479 .value("struikrozen")
1480 .initiallySelected(false)
1481 .selectable(true),
1482 new AttributeValueSettings()
1483 .value("waardeOnbekend")
1484 .initiallySelected(false)
1485 .selectable(true))))))
1486 .addFilterGroupsItem(new FilterGroup()
1487 .id("filtergroup2")
1488 .source("PRESET")
1489 .type(FilterGroup.TypeEnum.ATTRIBUTE)
1490 .layerIds(List.of("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
1491 .operator(FilterGroup.OperatorEnum.AND)
1492 .addFiltersItem(new Filter()
1493 .id("filter3")
1494 .type(Filter.TypeEnum.ATTRIBUTE)
1495 .condition(Filter.ConditionEnum.u)
1496 .addValueItem("1")
1497 .addValueItem("12419")
1498 .attribute("perceelnummer")
1499 .attributeType(Filter.AttributeTypeEnum.DOUBLE)
1500 .editConfiguration(new FilterEditConfiguration()
1501 .filterTool(FilterEditConfiguration.FilterToolEnum.SLIDER)
1502 .initialLowerValue(1d)
1503 .initialUpperValue(12419d)
1504 .minimumValue(1d)
1505 .maximumValue(12419d)))));
1506
1507 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1508 app.setInitialExtent(
1509 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d));
1510 app.setMaxExtent(new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d));
1511
1512 if (map5url != null) {
1513 AppTreeLevelNode root =
1514 (AppTreeLevelNode) app.getContentRoot().getBaseLayerNodes().getFirst();
1515 List<String> childrenIds = new ArrayList<>(root.getChildrenIds());
1516 childrenIds.add("lyr:map5:map5topo");
1517 childrenIds.add("lyr:map5:map5topo_simple");
1518 childrenIds.add("lvl:luchtfoto-labels");
1519 root.setChildrenIds(childrenIds);
1520 app.getSettings()
1521 .putLayerSettingsItem("lyr:map5:map5topo", new AppLayerSettings().title("Map5"))
1522 .putLayerSettingsItem("lyr:map5:map5topo_simple", new AppLayerSettings().title("Map5 simple"));
1523 app.getContentRoot()
1524 .addBaseLayerNodesItem(new AppTreeLayerNode()
1525 .objectType("AppTreeLayerNode")
1526 .id("lyr:map5:map5topo")
1527 .serviceId("map5")
1528 .layerName("map5topo")
1529 .visible(false))
1530 .addBaseLayerNodesItem(new AppTreeLayerNode()
1531 .objectType("AppTreeLayerNode")
1532 .id("lyr:map5:map5topo_simple")
1533 .serviceId("map5")
1534 .layerName("map5topo_simple")
1535 .visible(false))
1536 .addBaseLayerNodesItem(new AppTreeLevelNode()
1537 .objectType("AppTreeLevelNode")
1538 .id("lvl:luchtfoto-labels")
1539 .title("Luchtfoto met labels")
1540 .addChildrenIdsItem("lyr:map5:luforoadslabels")
1541 .addChildrenIdsItem("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2"))
1542 .addBaseLayerNodesItem(new AppTreeLayerNode()
1543 .objectType("AppTreeLayerNode")
1544 .id("lyr:map5:luforoadslabels")
1545 .serviceId("map5")
1546 .layerName("luforoadslabels")
1547 .visible(false))
1548 .addBaseLayerNodesItem(new AppTreeLayerNode()
1549 .objectType("AppTreeLayerNode")
1550 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2")
1551 .serviceId("pdok-hwh-luchtfotorgb")
1552 .layerName("Actueel_orthoHR")
1553 .visible(false));
1554 }
1555
1556 applicationRepository.save(app);
1557
1558 app = new Application()
1559 .setName("base")
1560 .setTitle("Service base app")
1561 .setCrs("EPSG:28992")
1562 .setAuthorizationRules(ruleAnonymousRead)
1563 .setContentRoot(new AppContent()
1564 .addBaseLayerNodesItem(new AppTreeLevelNode()
1565 .objectType("AppTreeLevelNode")
1566 .id("root-base-layers")
1567 .root(true)
1568 .title("Base layers")
1569 .childrenIds(List.of(
1570 "lyr:openbasiskaart:osm", "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR"))));
1571 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1572 applicationRepository.save(app);
1573
1574 app = new Application()
1575 .setName("secured")
1576 .setTitle("secured app")
1577 .setCrs("EPSG:28992")
1578 .setAuthorizationRules(ruleLoggedIn)
1579 .setContentRoot(new AppContent()
1580 .addBaseLayerNodesItem(new AppTreeLevelNode()
1581 .objectType("AppTreeLevelNode")
1582 .id("root-base-layers")
1583 .root(true)
1584 .title("Base layers")
1585 .childrenIds(List.of(
1586 "lyr:openbasiskaart:osm",
1587 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1588 "lyr:openbasiskaart-proxied:osm")))
1589 .addBaseLayerNodesItem(new AppTreeLayerNode()
1590 .objectType("AppTreeLayerNode")
1591 .id("lyr:openbasiskaart-proxied:osm")
1592 .serviceId("openbasiskaart-proxied")
1593 .layerName("osm")
1594 .visible(false))
1595 .addLayerNodesItem(new AppTreeLevelNode()
1596 .objectType("AppTreeLevelNode")
1597 .id("root")
1598 .root(true)
1599 .title("Layers")
1600 .childrenIds(List.of(
1601 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1602 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1603 "lvl:proxied")))
1604 .addLayerNodesItem(new AppTreeLayerNode()
1605 .objectType("AppTreeLayerNode")
1606 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1607 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1608 .layerName("Gemeentegebied")
1609 .visible(true))
1610 .addLayerNodesItem(new AppTreeLayerNode()
1611 .objectType("AppTreeLayerNode")
1612 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1613 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1614 .layerName("Provinciegebied")
1615 .visible(false))
1616 .addLayerNodesItem(new AppTreeLevelNode()
1617 .objectType("AppTreeLevelNode")
1618 .id("lvl:proxied")
1619 .title("Proxied")
1620 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1621 .addLayerNodesItem(new AppTreeLayerNode()
1622 .objectType("AppTreeLayerNode")
1623 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1624 .serviceId("snapshot-geoserver-proxied")
1625 .layerName("postgis:begroeidterreindeel")
1626 .visible(false)))
1627 .setSettings(
1628 new AppSettings()
1629 .putLayerSettingsItem(
1630 "lyr:openbasiskaart-proxied:osm",
1631 new AppLayerSettings().title("Openbasiskaart (proxied)"))
1632 .putLayerSettingsItem(
1633 "lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel",
1634 new AppLayerSettings()
1635 .description("This layer should render using purple polygons")
1636 .selectedStyles(
1637 List.of(
1638 new WMSStyle()
1639 .name("purple_polygon")
1640 .title("purple_polygon")
1641 .abstractText(null)
1642 .legendUrl(
1643 URI.create(
1644 "https://snapshot.tailormap.nl/geoserver/ows?service=WMS&version=1.3.0&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=test%3Apostgis_begroeidterreindeel&style=purple_polygon"))))));
1645
1646 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1647 applicationRepository.save(app);
1648
1649 app = new Application()
1650 .setName("secured-auth")
1651 .setTitle("secured (with authorizations)")
1652 .setCrs("EPSG:28992")
1653 .setAuthorizationRules(List.of(
1654 new AuthorizationRule()
1655 .groupName("test-foo")
1656 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)),
1657 new AuthorizationRule()
1658 .groupName("test-bar")
1659 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))
1660 .setContentRoot(new AppContent()
1661 .addLayerNodesItem(new AppTreeLevelNode()
1662 .objectType("AppTreeLevelNode")
1663 .id("root")
1664 .root(true)
1665 .title("Layers")
1666 .childrenIds(List.of("lvl:needs-auth", "lvl:public")))
1667 .addLayerNodesItem(new AppTreeLevelNode()
1668 .objectType("AppTreeLevelNode")
1669 .id("lvl:public")
1670 .title("Public")
1671 .childrenIds(List.of("lyr:snapshot-geoserver:BGT")))
1672 .addLayerNodesItem(new AppTreeLevelNode()
1673 .objectType("AppTreeLevelNode")
1674 .id("lvl:needs-auth")
1675 .title("Needs auth")
1676 .childrenIds(List.of(
1677 "lyr:filtered-snapshot-geoserver:BGT",
1678 "lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1679 .addLayerNodesItem(new AppTreeLayerNode()
1680 .objectType("AppTreeLayerNode")
1681 .id("lyr:filtered-snapshot-geoserver:BGT")
1682 .serviceId("filtered-snapshot-geoserver")
1683 .layerName("BGT")
1684 .visible(true))
1685 .addLayerNodesItem(new AppTreeLayerNode()
1686 .objectType("AppTreeLayerNode")
1687 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1688 .serviceId("filtered-snapshot-geoserver")
1689 .layerName("postgis:begroeidterreindeel")
1690 .visible(true))
1691 .addLayerNodesItem(new AppTreeLayerNode()
1692 .objectType("AppTreeLayerNode")
1693 .id("lyr:snapshot-geoserver:BGT")
1694 .serviceId("snapshot-geoserver")
1695 .layerName("BGT")
1696 .visible(true)));
1697
1698 applicationRepository.save(app);
1699
1700 app = new Application()
1701 .setName("austria")
1702 .setCrs("EPSG:3857")
1703 .setAuthorizationRules(ruleAnonymousRead)
1704 .setTitle("Austria")
1705 .setInitialExtent(
1706 new Bounds().minx(987982d).miny(5799551d).maxx(1963423d).maxy(6320708d))
1707 .setMaxExtent(
1708 new Bounds().minx(206516d).miny(5095461d).maxx(3146930d).maxy(7096232d))
1709 .setContentRoot(new AppContent()
1710 .addBaseLayerNodesItem(new AppTreeLevelNode()
1711 .objectType("AppTreeLevelNode")
1712 .id("root-base-layers")
1713 .root(true)
1714 .title("Base layers")
1715 .childrenIds(List.of(
1716 "lyr:at-basemap:geolandbasemap",
1717 "lyr:at-basemap:orthofoto",
1718 "lvl:orthofoto-labels",
1719 "lyr:osm:xyz")))
1720 .addBaseLayerNodesItem(new AppTreeLayerNode()
1721 .objectType("AppTreeLayerNode")
1722 .id("lyr:at-basemap:geolandbasemap")
1723 .serviceId("at-basemap")
1724 .layerName("geolandbasemap")
1725 .visible(true))
1726 .addBaseLayerNodesItem(new AppTreeLayerNode()
1727 .objectType("AppTreeLayerNode")
1728 .id("lyr:at-basemap:orthofoto")
1729 .serviceId("at-basemap")
1730 .layerName("bmaporthofoto30cm")
1731 .visible(false))
1732 .addBaseLayerNodesItem(new AppTreeLevelNode()
1733 .objectType("AppTreeLevelNode")
1734 .id("lvl:orthofoto-labels")
1735 .title("Orthophoto with labels")
1736 .childrenIds(List.of("lyr:at-basemap:bmapoverlay", "lyr:at-basemap:orthofoto_2")))
1737 .addBaseLayerNodesItem(new AppTreeLayerNode()
1738 .objectType("AppTreeLayerNode")
1739 .id("lyr:at-basemap:bmapoverlay")
1740 .serviceId("at-basemap")
1741 .layerName("bmapoverlay")
1742 .visible(false))
1743 .addBaseLayerNodesItem(new AppTreeLayerNode()
1744 .objectType("AppTreeLayerNode")
1745 .id("lyr:at-basemap:orthofoto_2")
1746 .serviceId("at-basemap")
1747 .layerName("bmaporthofoto30cm")
1748 .visible(false))
1749 .addBaseLayerNodesItem(new AppTreeLayerNode()
1750 .objectType("AppTreeLayerNode")
1751 .id("lyr:osm:xyz")
1752 .serviceId("osm")
1753 .layerName("xyz")
1754 .visible(false)));
1755
1756 applicationRepository.save(app);
1757
1758 app = new Application()
1759 .setName("3d_utrecht")
1760 .setCrs("EPSG:3857")
1761 .setAuthorizationRules(ruleLoggedIn)
1762 .setTitle("3D Utrecht")
1763 .setInitialExtent(
1764 new Bounds().minx(558390d).miny(6818485d).maxx(566751d).maxy(6824036d))
1765 .setMaxExtent(
1766 new Bounds().minx(91467d).miny(6496479d).maxx(1037043d).maxy(7147453d))
1767 .setSettings(new AppSettings().uiSettings(new AppUiSettings().enable3D(true)))
1768 .setContentRoot(new AppContent()
1769 .addBaseLayerNodesItem(new AppTreeLevelNode()
1770 .objectType("AppTreeLevelNode")
1771 .id("root-base-layers")
1772 .root(true)
1773 .title("Base layers")
1774 .childrenIds(List.of("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", "lyr:osm:xyz")))
1775 .addBaseLayerNodesItem(new AppTreeLayerNode()
1776 .objectType("AppTreeLayerNode")
1777 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
1778 .serviceId("pdok-hwh-luchtfotorgb")
1779 .layerName("Actueel_orthoHR")
1780 .visible(true))
1781 .addBaseLayerNodesItem(new AppTreeLayerNode()
1782 .objectType("AppTreeLayerNode")
1783 .id("lyr:osm:xyz")
1784 .serviceId("osm")
1785 .layerName("xyz")
1786 .visible(false))
1787 .addLayerNodesItem(new AppTreeLevelNode()
1788 .objectType("AppTreeLevelNode")
1789 .id("root")
1790 .root(true)
1791 .title("Layers")
1792 .childrenIds(List.of(
1793 "lyr:3dbag_utrecht:tiles3d",
1794 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1795 "lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d",
1796 "lyr:3d_utrecht_proxied_auth:tiles3d")))
1797 .addLayerNodesItem(new AppTreeLayerNode()
1798 .objectType("AppTreeLayerNode")
1799 .id("lyr:3dbag_utrecht:tiles3d")
1800 .serviceId("3dbag_utrecht")
1801 .layerName("tiles3d")
1802 .visible(true))
1803 .addLayerNodesItem(new AppTreeLayerNode()
1804 .objectType("AppTreeLayerNode")
1805 .id("lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d")
1806 .serviceId("3d_basisvoorziening_gebouwen_proxy")
1807 .layerName("tiles3d")
1808 .visible(false))
1809 .addLayerNodesItem(new AppTreeLayerNode()
1810 .objectType("AppTreeLayerNode")
1811 .id("lyr:3d_utrecht_proxied_auth:tiles3d")
1812 .serviceId("3d_utrecht_proxied_auth")
1813 .layerName("tiles3d")
1814 .visible(false))
1815 .addLayerNodesItem(new AppTreeLayerNode()
1816 .objectType("AppTreeLayerNode")
1817 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1818 .serviceId("snapshot-geoserver")
1819 .layerName("postgis:begroeidterreindeel")
1820 .visible(true))
1821 .addTerrainLayerNodesItem(new AppTreeLevelNode()
1822 .objectType("AppTreeLevelNode")
1823 .id("root-terrain-layers")
1824 .root(true)
1825 .title("Terrain Layers")
1826 .childrenIds(List.of("lyr:ahn_terrain_model:quantizedmesh")))
1827 .addTerrainLayerNodesItem(new AppTreeLayerNode()
1828 .objectType("AppTreeLayerNode")
1829 .id("lyr:ahn_terrain_model:quantizedmesh")
1830 .serviceId("ahn_terrain_model")
1831 .layerName("quantizedmesh")
1832 .visible(false)));
1833
1834 applicationRepository.save(app);
1835
1836 app = new Application()
1837 .setName("public-with-auth")
1838 .setTitle("Public app with one restricted layer in a group")
1839 .setCrs("EPSG:28992")
1840 .setAuthorizationRules(ruleAnonymousRead)
1841 .setInitialExtent(
1842 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d))
1843 .setMaxExtent(
1844 new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d))
1845 .setStyling(new AppStyling().logo(logo.getId().toString()))
1846 .setContentRoot(new AppContent()
1847 .addBaseLayerNodesItem(new AppTreeLevelNode()
1848 .objectType("AppTreeLevelNode")
1849 .id("root")
1850 .root(true)
1851 .title("Basemaps")
1852 .childrenIds(List.of("lyr:openbasiskaart:osm")))
1853 .addBaseLayerNodesItem(new AppTreeLayerNode()
1854 .objectType("AppTreeLayerNode")
1855 .id("lyr:openbasiskaart:osm")
1856 .serviceId("openbasiskaart")
1857 .layerName("osm")
1858 .visible(true))
1859 .addLayerNodesItem(new AppTreeLevelNode()
1860 .objectType("AppTreeLevelNode")
1861 .id("root")
1862 .root(true)
1863 .title("Application layers")
1864 .childrenIds(List.of(
1865 "lyr:snapshot-geoserver:postgis:kadastraal_perceel", "xpfhl34VmghkU12nP9Jer")))
1866 .addLayerNodesItem(new AppTreeLayerNode()
1867 .objectType("AppTreeLayerNode")
1868 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
1869 .serviceId("snapshot-geoserver")
1870 .layerName("postgis:kadastraal_perceel")
1871 .visible(true))
1872 .addLayerNodesItem(new AppTreeLevelNode()
1873 .id("xpfhl34VmghkU12nP9Jer")
1874 .root(false)
1875 .title("restricted")
1876 .objectType("AppTreeLevelNode")
1877 .childrenIds(List.of("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1878 .addLayerNodesItem(new AppTreeLayerNode()
1879 .objectType("AppTreeLayerNode")
1880 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1881 .visible(true)
1882 .serviceId("filtered-snapshot-geoserver")
1883 .layerName("postgis:begroeidterreindeel")))
1884 .setSettings(new AppSettings());
1885
1886 applicationRepository.save(app);
1887
1888 Configuration config = new Configuration();
1889 config.setKey(Configuration.DEFAULT_APP);
1890 config.setValue("default");
1891 configurationRepository.save(config);
1892 config = new Configuration();
1893 config.setKey(Configuration.DEFAULT_BASE_APP);
1894 config.setValue("base");
1895 configurationRepository.save(config);
1896 }
1897
1898 private void createConfigurationTestData() throws JacksonException {
1899 Configuration config = new Configuration();
1900 config.setKey("test");
1901 config.setAvailableForViewer(true);
1902 config.setValue("test value");
1903 config.setJsonValue(new JsonMapper().readTree("{ \"someProperty\": 1, \"nestedObject\": { \"num\": 42 } }"));
1904 configurationRepository.save(config);
1905 }
1906
1907 @Transactional
1908 public void createSolrIndex() throws Exception {
1909 if (connectToSpatialDbs) {
1910
1911
1912 featureSourceRepository.flush();
1913
1914 logger.info("Creating Solr index");
1915 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
1916 final String solrUrl = "http://" + (connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "solr") + ":8983/solr/";
1917 this.solrService.setSolrUrl(solrUrl);
1918 SolrHelper solrHelper = new SolrHelper(this.solrService.getSolrClientForIndexing())
1919 .withBatchSize(solrBatchSize)
1920 .withGeometryValidationRule(solrGeometryValidationRule);
1921 GeoService geoService =
1922 geoServiceRepository.findById("snapshot-geoserver").orElseThrow();
1923 Application defaultApp = applicationRepository.findByName("default");
1924
1925 TMFeatureType begroeidterreindeelFT = geoService.findFeatureTypeForLayer(
1926 geoService.findLayer("postgis:begroeidterreindeel"), featureSourceRepository);
1927
1928 TMFeatureType wegdeelFT = geoService.findFeatureTypeForLayer(
1929 geoService.findLayer("sqlserver:wegdeel"), featureSourceRepository);
1930
1931 TMFeatureType kadastraalPerceelFT = geoService.findFeatureTypeForLayer(
1932 geoService.findLayer("postgis:kadastraal_perceel"), featureSourceRepository);
1933
1934 try (solrHelper) {
1935 SearchIndex begroeidterreindeelIndex = null;
1936 if (begroeidterreindeelFT != null) {
1937 begroeidterreindeelIndex = new SearchIndex()
1938 .setName("Begroeidterreindeel")
1939 .setFeatureTypeId(begroeidterreindeelFT.getId())
1940 .setSearchFieldsUsed(List.of("class", "plus_fysiekvoorkomen", "bronhouder"))
1941 .setSearchDisplayFieldsUsed(List.of("class", "plus_fysiekvoorkomen"));
1942 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1943 begroeidterreindeelIndex = solrHelper.addFeatureTypeIndex(
1944 begroeidterreindeelIndex,
1945 begroeidterreindeelFT,
1946 featureSourceFactoryHelper,
1947 searchIndexRepository);
1948 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1949 }
1950
1951 SearchIndex kadastraalPerceelIndex = null;
1952 if (kadastraalPerceelFT != null) {
1953 kadastraalPerceelIndex = new SearchIndex()
1954 .setName("kadastraal_perceel")
1955 .setFeatureTypeId(kadastraalPerceelFT.getId())
1956 .setSearchFieldsUsed(List.of("aanduiding"))
1957 .setSearchDisplayFieldsUsed(List.of("aanduiding"));
1958 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1959 kadastraalPerceelIndex = solrHelper.addFeatureTypeIndex(
1960 kadastraalPerceelIndex,
1961 kadastraalPerceelFT,
1962 featureSourceFactoryHelper,
1963 searchIndexRepository);
1964 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1965 }
1966
1967 SearchIndex wegdeelIndex = null;
1968 if (wegdeelFT != null) {
1969 wegdeelIndex = new SearchIndex()
1970 .setName("Wegdeel")
1971 .setFeatureTypeId(wegdeelFT.getId())
1972 .setSearchFieldsUsed(List.of(
1973 "function_", "plus_fysiekvoorkomenwegdeel", "surfacematerial", "bronhouder"))
1974 .setSearchDisplayFieldsUsed(List.of("function_", "plus_fysiekvoorkomenwegdeel"));
1975 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1976 wegdeelIndex = solrHelper.addFeatureTypeIndex(
1977 wegdeelIndex, wegdeelFT, featureSourceFactoryHelper, searchIndexRepository);
1978 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1979 }
1980
1981 featureSourceRepository
1982 .getByTitle("PostGIS")
1983 .flatMap(fs -> fs.getFeatureTypes().stream()
1984 .filter(ft -> ft.getName().equals("bak"))
1985 .findFirst())
1986 .ifPresent(ft -> {
1987 SearchIndex bak = new SearchIndex()
1988 .setName("bak")
1989 .setFeatureTypeId(ft.getId())
1990 .setSearchFieldsUsed(List.of("gmlid", "identificatie", "plus_type"))
1991 .setSearchDisplayFieldsUsed(List.of("gmlid", "plus_type", "bronhouder"));
1992 searchIndexRepository.save(bak);
1993 try {
1994 bak = solrHelper.addFeatureTypeIndex(
1995 bak, ft, featureSourceFactoryHelper, searchIndexRepository);
1996 searchIndexRepository.save(bak);
1997 } catch (IOException | SolrServerException e) {
1998 throw new RuntimeException(e);
1999 }
2000 });
2001
2002
2003
2004 featureSourceRepository
2005 .getByTitle("PostGIS OSM")
2006 .flatMap(fs -> fs.getFeatureTypes().stream()
2007 .filter(ft -> ft.getName().equals("osm_roads"))
2008 .findFirst())
2009 .ifPresent(ft -> {
2010 SearchIndex osm_no_pk = new SearchIndex()
2011 .setName("osm_no_pk")
2012 .setFeatureTypeId(ft.getId())
2013 .setSearchFieldsUsed(List.of("landuse", "osm_id", "natural", "boundary"))
2014 .setSearchDisplayFieldsUsed(
2015 List.of("landuse", "osm_id", "natural", "amenity", "boundary"));
2016 searchIndexRepository.save(osm_no_pk);
2017 });
2018
2019 AppTreeLayerNode begroeidTerreindeelLayerNode = defaultApp
2020 .getAllAppTreeLayerNode()
2021 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
2022 .findFirst()
2023 .orElse(null);
2024
2025 if (begroeidTerreindeelLayerNode != null && begroeidterreindeelIndex != null) {
2026 defaultApp
2027 .getAppLayerSettings(begroeidTerreindeelLayerNode)
2028 .setSearchIndexId(begroeidterreindeelIndex.getId());
2029 }
2030
2031 AppTreeLayerNode kadastraalPerceelLayerNode = defaultApp
2032 .getAllAppTreeLayerNode()
2033 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
2034 .findFirst()
2035 .orElse(null);
2036
2037 if (kadastraalPerceelLayerNode != null && kadastraalPerceelIndex != null) {
2038 defaultApp
2039 .getAppLayerSettings(kadastraalPerceelLayerNode)
2040 .setSearchIndexId(kadastraalPerceelIndex.getId());
2041 }
2042
2043 AppTreeLayerNode wegdeel = defaultApp
2044 .getAllAppTreeLayerNode()
2045 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:sqlserver:wegdeel"))
2046 .findFirst()
2047 .orElse(null);
2048
2049 if (wegdeel != null && wegdeelIndex != null) {
2050 defaultApp.getAppLayerSettings(wegdeel).setSearchIndexId(wegdeelIndex.getId());
2051 }
2052
2053 applicationRepository.save(defaultApp);
2054 }
2055 }
2056 }
2057
2058 private void createSearchIndexTasks() {
2059 logger.info("Creating search index tasks");
2060 List.of("Begroeidterreindeel", "kadastraal_perceel")
2061 .forEach(name -> searchIndexRepository.findByName(name).ifPresent(index -> {
2062 index.setSchedule(new TaskSchedule()
2063
2064 .cronExpression("0 0 0/1 1/1 * ? *")
2065
2066
2067 .description("Update Solr index \"" + name + "\" every hour"));
2068 try {
2069 final UUID uuid = taskManagerService.createTask(
2070 IndexTask.class,
2071 new TMJobDataMap(Map.of(
2072 Task.TYPE_KEY,
2073 TaskType.INDEX,
2074 Task.DESCRIPTION_KEY,
2075 index.getSchedule().getDescription(),
2076 IndexTask.INDEX_KEY,
2077 index.getId().toString(),
2078 Task.PRIORITY_KEY,
2079 10)),
2080 index.getSchedule().getCronExpression());
2081
2082 index.getSchedule().setUuid(uuid);
2083 searchIndexRepository.save(index);
2084
2085 logger.info("Created task to update Solr index with key: {}", uuid);
2086 } catch (SchedulerException e) {
2087 logger.error("Error creating scheduled solr index task", e);
2088 }
2089 }));
2090 }
2091
2092 private void createUploads() throws IOException {
2093 for (int i = 0; i < 4; i++) {
2094
2095 uploadRepository.save(new Upload()
2096 .setCategory(UploadCategory.UNRESTRICTED)
2097 .setFilename("upload" + i + ".png")
2098 .setMimeType("image/png")
2099 .setContent(new ClassPathResource("test/upload.png").getContentAsByteArray())
2100 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault())));
2101 }
2102 }
2103
2104 private void createPages() throws IOException {
2105 Upload logo = new Upload()
2106 .setCategory(UploadCategory.PORTAL_IMAGE)
2107 .setFilename("gradient-portal.svg")
2108 .setMimeType("image/svg+xml")
2109 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
2110 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2111 uploadRepository.save(logo);
2112
2113 Page loggedIn = new Page();
2114 loggedIn.setAuthorizationRules(ruleLoggedIn);
2115 loggedIn.setName("loggedIn");
2116 loggedIn.setType("page");
2117 loggedIn.setContent("About Tailormap");
2118 loggedIn.setContent("""
2119 # About Tailormap
2120 This is a page for logged in users.
2121 """);
2122 pageRepository.save(loggedIn);
2123
2124 Page about = new Page();
2125 about.setAuthorizationRules(ruleAnonymousRead);
2126 about.setName("about");
2127 about.setType("page");
2128 about.setContent("About Tailormap");
2129 about.setContent("""
2130 # About Tailormap
2131
2132 This is a page about *Tailormap*. It doesn't say much yet.
2133 """);
2134 pageRepository.save(about);
2135
2136 Page page = new Page();
2137 page.setAuthorizationRules(ruleAnonymousRead);
2138 page.setName("home");
2139 page.setType("page");
2140 page.setTitle("Tailormap - Home");
2141 page.setContent("""
2142 # Welcome to Tailormap!
2143
2144 This page is only visible when you implement a frontend to display pages, or get it (including a simple CMS)
2145 from [B3Partners](https:
2146 """);
2147 page.setClassName(null);
2148 page.setTiles(List.of(
2149 new PageTile()
2150 .authorizationRules(ruleAnonymousRead)
2151 .id(UUID.randomUUID().toString())
2152 .title("Default app")
2153 .tileType(PageTile.TileTypeEnum.APPLICATION)
2154 .applicationId(Optional.ofNullable(applicationRepository.findByName("default"))
2155 .map(Application::getId)
2156 .orElse(null))
2157 .image(logo.getId().toString())
2158 .content("*Default app* tile content")
2159 .filterRequireAuthorization(false)
2160 .openInNewWindow(false),
2161 new PageTile()
2162 .authorizationRules(ruleAnonymousRead)
2163 .id(UUID.randomUUID().toString())
2164 .title("Secured app")
2165 .tileType(PageTile.TileTypeEnum.APPLICATION)
2166 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
2167 .map(Application::getId)
2168 .orElse(null))
2169 .filterRequireAuthorization(true)
2170 .content("Secure app, only shown if user has authorization")
2171 .openInNewWindow(false),
2172 new PageTile()
2173 .authorizationRules(ruleAnonymousRead)
2174 .id(UUID.randomUUID().toString())
2175 .title("Secured app (unfiltered)")
2176 .tileType(PageTile.TileTypeEnum.APPLICATION)
2177 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
2178 .map(Application::getId)
2179 .orElse(null))
2180 .filterRequireAuthorization(false)
2181 .content("Secure app, tile shown to everyone")
2182 .openInNewWindow(false),
2183 new PageTile()
2184 .authorizationRules(ruleAnonymousRead)
2185 .id(UUID.randomUUID().toString())
2186 .title("About")
2187 .tileType(PageTile.TileTypeEnum.PAGE)
2188 .pageId(about.getId())
2189 .openInNewWindow(false),
2190 new PageTile()
2191 .authorizationRules(ruleAnonymousRead)
2192 .id(UUID.randomUUID().toString())
2193 .title("B3Partners")
2194 .tileType(PageTile.TileTypeEnum.URL)
2195 .url("https://www.b3partners.nl/")
2196 .openInNewWindow(true),
2197 new PageTile()
2198 .authorizationRules(ruleLoggedIn)
2199 .id(UUID.randomUUID().toString())
2200 .title("Github repository")
2201 .tileType(PageTile.TileTypeEnum.URL)
2202 .url("https://github.com/Tailormap/tailormap-viewer")
2203 .openInNewWindow(true),
2204 new PageTile()
2205 .authorizationRules(ruleAnonymousRead)
2206 .id(UUID.randomUUID().toString())
2207 .tileType(PageTile.TileTypeEnum.PAGE)
2208 .title("Secured page")
2209 .pageId(loggedIn.getId())
2210 .filterRequireAuthorization(true)
2211 .openInNewWindow(true),
2212 new PageTile()
2213 .authorizationRules(ruleAnonymousRead)
2214 .id(UUID.randomUUID().toString())
2215 .tileType(PageTile.TileTypeEnum.PAGE)
2216 .title("Secured page (unfiltered)")
2217 .pageId(loggedIn.getId())
2218 .filterRequireAuthorization(false)
2219 .openInNewWindow(true)));
2220 pageRepository.save(page);
2221
2222 Configuration c = new Configuration();
2223 c.setKey(HOME_PAGE);
2224 c.setValue(page.getId().toString());
2225 configurationRepository.save(c);
2226
2227 List<MenuItem> globalMenuItems = List.of(
2228 new MenuItem().pageId(about.getId()).label("About").openInNewWindow(false),
2229 new MenuItem()
2230 .label("B3Partners website")
2231 .url("https://www.b3partners.nl/")
2232 .openInNewWindow(true)
2233 .exclusiveOnPageId(about.getId()));
2234 c = new Configuration();
2235 c.setKey(PORTAL_MENU);
2236 c.setJsonValue(new JsonMapper().valueToTree(globalMenuItems));
2237 configurationRepository.save(c);
2238 }
2239
2240 private void insertTestDrawing() {
2241
2242 try {
2243 this.jdbcClient.sql("""
2244 INSERT INTO data.drawing (id,name,description,domain_data,created_by,created_at,updated_by,updated_at,srid,"version") VALUES
2245 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid,'Testcase','A drawing that is inserted as part of the testdata','{"items": 1, "domain": "test drawings"}','tm-admin','2025-02-27 17:53:36.095164+01','tm-admin','2025-02-27 17:54:19.384961+01',28992,1);
2246 """).update();
2247
2248 this.jdbcClient.sql("""
2249 INSERT INTO data.drawing_feature (drawing_id,id,geometry,properties) VALUES
2250 ('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),
2251 ('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),
2252 ('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)
2253 """).update();
2254 } catch (Exception any) {
2255 logger.error("Error inserting test drawing in data schema, some tests may fail", any);
2256 }
2257 }
2258
2259 private void insertDrawingStyle() throws IOException {
2260 Upload upload = new Upload()
2261 .setCategory(UploadCategory.DRAWING_STYLE_IMAGE)
2262 .setMimeType("image/svg+xml")
2263 .setFilename("ISO_7001_PI_PF_007.svg")
2264 .setContent(new ClassPathResource("test/ISO_7001_PI_PF_007.svg").getContentAsByteArray())
2265 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2266 upload = uploadRepository.save(upload);
2267 UUID drinkwaterImageId = upload.getId();
2268
2269 upload = new Upload()
2270 .setCategory(UploadCategory.DRAWING_STYLE_IMAGE)
2271 .setMimeType("image/svg+xml")
2272 .setFilename("lichtpunt.svg")
2273 .setContent(new ClassPathResource("test/lichtpunt.svg").getContentAsByteArray())
2274 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2275 upload = uploadRepository.save(upload);
2276 UUID lichtpuntImageId = upload.getId();
2277
2278 upload = new Upload()
2279 .setCategory(UploadCategory.DRAWING_STYLE_IMAGE)
2280 .setMimeType("image/svg+xml")
2281 .setFilename("ISO_7010_E003_-_First_aid_sign.svg")
2282 .setContent(new ClassPathResource("test/ISO_7010_E003_-_First_aid_sign.svg").getContentAsByteArray())
2283 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2284 upload = uploadRepository.save(upload);
2285 UUID firstAidImageId = upload.getId();
2286
2287 Properties props = new Properties();
2288 props.putAll(Map.of(
2289 "water-uuid", drinkwaterImageId.toString(),
2290 "lichtpunt-uuid", lichtpuntImageId.toString(),
2291 "first-aid-uuid", firstAidImageId.toString()));
2292
2293 String drawingStyles =
2294 new ClassPathResource("test/object-drawing-style.json").getContentAsString(StandardCharsets.UTF_8);
2295 drawingStyles = new PropertyPlaceholderHelper("${", "}").replacePlaceholders(drawingStyles, props);
2296
2297
2298 upload = new Upload()
2299 .setCategory(UploadCategory.DRAWING_STYLE)
2300 .setMimeType("application/json")
2301 .setFilename("object-drawing-style.json")
2302 .setContent(drawingStyles.getBytes(StandardCharsets.UTF_8))
2303 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2304 uploadRepository.save(upload);
2305 }
2306 }