1
2
3
4
5
6 package org.tailormap.api.persistence;
7
8 import static java.util.Objects.requireNonNullElse;
9
10 import com.fasterxml.jackson.annotation.JsonIgnore;
11 import jakarta.persistence.AttributeOverride;
12 import jakarta.persistence.AttributeOverrides;
13 import jakarta.persistence.Column;
14 import jakarta.persistence.Embedded;
15 import jakarta.persistence.Entity;
16 import jakarta.persistence.EntityListeners;
17 import jakarta.persistence.GeneratedValue;
18 import jakarta.persistence.GenerationType;
19 import jakarta.persistence.Id;
20 import jakarta.persistence.Version;
21 import jakarta.validation.constraints.NotNull;
22 import java.lang.invoke.MethodHandles;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.stream.Stream;
27 import org.geotools.referencing.CRS;
28 import org.hibernate.annotations.Type;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.tailormap.api.persistence.json.AppContent;
32 import org.tailormap.api.persistence.json.AppI18nSettings;
33 import org.tailormap.api.persistence.json.AppLayerSettings;
34 import org.tailormap.api.persistence.json.AppSettings;
35 import org.tailormap.api.persistence.json.AppTreeLayerNode;
36 import org.tailormap.api.persistence.json.AppUiSettings;
37 import org.tailormap.api.persistence.json.AuthorizationRule;
38 import org.tailormap.api.persistence.json.Bounds;
39 import org.tailormap.api.persistence.listener.EntityEventPublisher;
40 import org.tailormap.api.viewer.model.AppStyling;
41 import org.tailormap.api.viewer.model.Component;
42 import org.tailormap.api.viewer.model.ViewerResponse;
43
44 @Entity
45 @EntityListeners(EntityEventPublisher.class)
46 public class Application {
47 private static final Logger logger =
48 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
49
50 @Id
51 @GeneratedValue(strategy = GenerationType.IDENTITY)
52 private Long id;
53
54 @Version private Long version;
55
56 @Column(unique = true)
57 @NotNull
58 private String name;
59
60 private String title;
61
62 @Column(columnDefinition = "text")
63 private String adminComments;
64
65 @Column(columnDefinition = "text")
66 private String previewText;
67
68 @NotNull private String crs;
69
70 @Embedded
71 @AttributeOverrides({
72 @AttributeOverride(name = "minx", column = @Column(name = "initial_minx")),
73 @AttributeOverride(name = "maxx", column = @Column(name = "initial_maxx")),
74 @AttributeOverride(name = "miny", column = @Column(name = "initial_miny")),
75 @AttributeOverride(name = "maxy", column = @Column(name = "initial_maxy"))
76 })
77 private Bounds initialExtent;
78
79 @Embedded
80 @AttributeOverrides({
81 @AttributeOverride(name = "minx", column = @Column(name = "max_minx")),
82 @AttributeOverride(name = "maxx", column = @Column(name = "max_maxx")),
83 @AttributeOverride(name = "miny", column = @Column(name = "max_miny")),
84 @AttributeOverride(name = "maxy", column = @Column(name = "max_maxy"))
85 })
86 private Bounds maxExtent;
87
88 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
89 @Column(columnDefinition = "jsonb")
90 @NotNull
91 private AppContent contentRoot = new AppContent();
92
93 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
94 @Column(columnDefinition = "jsonb")
95 @NotNull
96 private AppSettings settings = new AppSettings();
97
98 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
99 @Column(columnDefinition = "jsonb")
100 @NotNull
101 private List<Component> components = new ArrayList<>();
102
103 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
104 @Column(columnDefinition = "jsonb")
105 @NotNull
106 private AppStyling styling = new AppStyling();
107
108 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
109 @Column(columnDefinition = "jsonb")
110 @NotNull
111 private List<AuthorizationRule> authorizationRules = new ArrayList<>();
112
113
114 public Long getId() {
115 return id;
116 }
117
118 public Application setId(Long id) {
119 this.id = id;
120 return this;
121 }
122
123 public Long getVersion() {
124 return version;
125 }
126
127 public Application setVersion(Long version) {
128 this.version = version;
129 return this;
130 }
131
132 public String getName() {
133 return name;
134 }
135
136 public Application setName(String name) {
137 this.name = name;
138 return this;
139 }
140
141 public String getTitle() {
142 return title;
143 }
144
145 public Application setTitle(String title) {
146 this.title = title;
147 return this;
148 }
149
150 public String getAdminComments() {
151 return adminComments;
152 }
153
154 public Application setAdminComments(String adminComments) {
155 this.adminComments = adminComments;
156 return this;
157 }
158
159 public String getPreviewText() {
160 return previewText;
161 }
162
163 public Application setPreviewText(String previewText) {
164 this.previewText = previewText;
165 return this;
166 }
167
168 public String getCrs() {
169 return crs;
170 }
171
172 public Application setCrs(String crs) {
173 this.crs = crs;
174 return this;
175 }
176
177 public Bounds getInitialExtent() {
178 return initialExtent;
179 }
180
181 public Application setInitialExtent(Bounds initialExtent) {
182 this.initialExtent = initialExtent;
183 return this;
184 }
185
186 public Bounds getMaxExtent() {
187 return maxExtent;
188 }
189
190 public Application setMaxExtent(Bounds maxExtent) {
191 this.maxExtent = maxExtent;
192 return this;
193 }
194
195 public AppContent getContentRoot() {
196 return contentRoot;
197 }
198
199 public Application setContentRoot(AppContent contentRoot) {
200 this.contentRoot = contentRoot;
201 return this;
202 }
203
204 public AppSettings getSettings() {
205 return settings;
206 }
207
208 public Application setSettings(AppSettings layerSettings) {
209 this.settings = layerSettings;
210 return this;
211 }
212
213 public List<Component> getComponents() {
214 return components;
215 }
216
217 public Application setComponents(List<Component> components) {
218 this.components = components;
219 return this;
220 }
221
222 public AppStyling getStyling() {
223 return styling;
224 }
225
226 public Application setStyling(AppStyling styling) {
227 this.styling = styling;
228 return this;
229 }
230
231 public List<AuthorizationRule> getAuthorizationRules() {
232 return authorizationRules;
233 }
234
235 public Application setAuthorizationRules(List<AuthorizationRule> authorizationRules) {
236 this.authorizationRules = authorizationRules;
237 return this;
238 }
239
240
241
242 @JsonIgnore
243 public Stream<AppTreeLayerNode> getAllAppTreeLayerNode() {
244 if (this.getContentRoot() == null) {
245 return Stream.empty();
246 }
247 Stream<AppTreeLayerNode> baseLayers = Stream.empty();
248 if (this.getContentRoot().getBaseLayerNodes() != null) {
249 baseLayers =
250 this.getContentRoot().getBaseLayerNodes().stream()
251 .filter(n -> "AppTreeLayerNode".equals(n.getObjectType()))
252 .map(n -> (AppTreeLayerNode) n);
253 }
254 Stream<AppTreeLayerNode> layers = Stream.empty();
255 if (this.getContentRoot().getLayerNodes() != null) {
256 layers =
257 this.getContentRoot().getLayerNodes().stream()
258 .filter(n -> "AppTreeLayerNode".equals(n.getObjectType()))
259 .map(n -> (AppTreeLayerNode) n);
260 }
261 return Stream.concat(baseLayers, layers);
262 }
263
264
265
266
267
268
269
270 @JsonIgnore
271 public org.geotools.api.referencing.crs.CoordinateReferenceSystem
272 getGeoToolsCoordinateReferenceSystem() {
273 org.geotools.api.referencing.crs.CoordinateReferenceSystem gtCrs = null;
274 try {
275 if (getCrs() != null) {
276 gtCrs = CRS.decode(getCrs());
277 }
278 } catch (Exception e) {
279 String message =
280 String.format(
281 "Application %d: error decoding CRS from code \"%s\": %s: %s",
282 getId(), getCrs(), e.getClass(), e.getMessage());
283 if (logger.isDebugEnabled()) {
284 logger.error(message, e);
285 } else {
286 logger.error(message);
287 }
288 }
289 return gtCrs;
290 }
291
292 @JsonIgnore
293 public ViewerResponse getViewerResponse() {
294 return new ViewerResponse()
295 .kind(ViewerResponse.KindEnum.APP)
296 .name(getName())
297 .title(getTitle())
298 .styling(styling)
299 .components(components)
300 .i18nSettings(
301 requireNonNullElse(
302 settings.getI18nSettings(), new AppI18nSettings().hideLanguageSwitcher(false)))
303 .uiSettings(
304 requireNonNullElse(
305 settings.getUiSettings(), new AppUiSettings().hideLoginButton(false)))
306 .projections(List.of(getCrs()));
307 }
308
309 @NotNull
310 public AppLayerSettings getAppLayerSettings(@NotNull AppTreeLayerNode node) {
311 return Optional.ofNullable(getSettings())
312 .map(AppSettings::getLayerSettings)
313 .map(layerSettingsMap -> layerSettingsMap.get(node.getId()))
314 .orElseGet(AppLayerSettings::new);
315 }
316 }