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
55 private Long version;
56
57 @Column(unique = true)
58 @NotNull 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 private AppContent contentRoot = new AppContent();
91
92 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
93 @Column(columnDefinition = "jsonb")
94 @NotNull private AppSettings settings = new AppSettings();
95
96 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
97 @Column(columnDefinition = "jsonb")
98 @NotNull private List<Component> components = new ArrayList<>();
99
100 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
101 @Column(columnDefinition = "jsonb")
102 @NotNull private AppStyling styling = new AppStyling();
103
104 @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
105 @Column(columnDefinition = "jsonb")
106 @NotNull private List<AuthorizationRule> authorizationRules = new ArrayList<>();
107
108
109 public Long getId() {
110 return id;
111 }
112
113 public Application setId(Long id) {
114 this.id = id;
115 return this;
116 }
117
118 public Long getVersion() {
119 return version;
120 }
121
122 public Application setVersion(Long version) {
123 this.version = version;
124 return this;
125 }
126
127 public String getName() {
128 return name;
129 }
130
131 public Application setName(String name) {
132 this.name = name;
133 return this;
134 }
135
136 public String getTitle() {
137 return title;
138 }
139
140 public Application setTitle(String title) {
141 this.title = title;
142 return this;
143 }
144
145 public String getAdminComments() {
146 return adminComments;
147 }
148
149 public Application setAdminComments(String adminComments) {
150 this.adminComments = adminComments;
151 return this;
152 }
153
154 public String getPreviewText() {
155 return previewText;
156 }
157
158 public Application setPreviewText(String previewText) {
159 this.previewText = previewText;
160 return this;
161 }
162
163 public String getCrs() {
164 return crs;
165 }
166
167 public Application setCrs(String crs) {
168 this.crs = crs;
169 return this;
170 }
171
172 public Bounds getInitialExtent() {
173 return initialExtent;
174 }
175
176 public Application setInitialExtent(Bounds initialExtent) {
177 this.initialExtent = initialExtent;
178 return this;
179 }
180
181 public Bounds getMaxExtent() {
182 return maxExtent;
183 }
184
185 public Application setMaxExtent(Bounds maxExtent) {
186 this.maxExtent = maxExtent;
187 return this;
188 }
189
190 public AppContent getContentRoot() {
191 return contentRoot;
192 }
193
194 public Application setContentRoot(AppContent contentRoot) {
195 this.contentRoot = contentRoot;
196 return this;
197 }
198
199 public AppSettings getSettings() {
200 return settings;
201 }
202
203 public Application setSettings(AppSettings layerSettings) {
204 this.settings = layerSettings;
205 return this;
206 }
207
208 public List<Component> getComponents() {
209 return components;
210 }
211
212 public Application setComponents(List<Component> components) {
213 this.components = components;
214 return this;
215 }
216
217 public AppStyling getStyling() {
218 return styling;
219 }
220
221 public Application setStyling(AppStyling styling) {
222 this.styling = styling;
223 return this;
224 }
225
226 public List<AuthorizationRule> getAuthorizationRules() {
227 return authorizationRules;
228 }
229
230 public Application setAuthorizationRules(List<AuthorizationRule> authorizationRules) {
231 this.authorizationRules = authorizationRules;
232 return this;
233 }
234
235
236
237 @JsonIgnore
238 public Stream<AppTreeLayerNode> getAllAppTreeLayerNode() {
239 if (this.getContentRoot() == null) {
240 return Stream.empty();
241 }
242 Stream<AppTreeLayerNode> baseLayers = Stream.empty();
243 if (this.getContentRoot().getBaseLayerNodes() != null) {
244 baseLayers = this.getContentRoot().getBaseLayerNodes().stream()
245 .filter(n -> "AppTreeLayerNode".equals(n.getObjectType()))
246 .map(n -> (AppTreeLayerNode) n);
247 }
248 Stream<AppTreeLayerNode> layers = Stream.empty();
249 if (this.getContentRoot().getLayerNodes() != null) {
250 layers = this.getContentRoot().getLayerNodes().stream()
251 .filter(n -> "AppTreeLayerNode".equals(n.getObjectType()))
252 .map(n -> (AppTreeLayerNode) n);
253 }
254 return Stream.concat(baseLayers, layers);
255 }
256
257
258
259
260
261
262
263 @JsonIgnore
264 public org.geotools.api.referencing.crs.CoordinateReferenceSystem getGeoToolsCoordinateReferenceSystem() {
265 org.geotools.api.referencing.crs.CoordinateReferenceSystem gtCrs = null;
266 try {
267 if (getCrs() != null) {
268 gtCrs = CRS.decode(getCrs());
269 }
270 } catch (Exception e) {
271 String message = String.format(
272 "Application %d: error decoding CRS from code \"%s\": %s: %s",
273 getId(), getCrs(), e.getClass(), e.getMessage());
274 if (logger.isDebugEnabled()) {
275 logger.error(message, e);
276 } else {
277 logger.error(message);
278 }
279 }
280 return gtCrs;
281 }
282
283 @JsonIgnore
284 public ViewerResponse getViewerResponse() {
285 return new ViewerResponse()
286 .kind(ViewerResponse.KindEnum.APP)
287 .name(getName())
288 .title(getTitle())
289 .styling(styling)
290 .components(components)
291 .i18nSettings(requireNonNullElse(
292 settings.getI18nSettings(), new AppI18nSettings().hideLanguageSwitcher(false)))
293 .uiSettings(requireNonNullElse(settings.getUiSettings(), new AppUiSettings().hideLoginButton(false)))
294 .projections(List.of(getCrs()));
295 }
296
297 @NotNull public AppLayerSettings getAppLayerSettings(@NotNull AppTreeLayerNode node) {
298 return Optional.ofNullable(getSettings())
299 .map(AppSettings::getLayerSettings)
300 .map(layerSettingsMap -> layerSettingsMap.get(node.getId()))
301 .orElseGet(AppLayerSettings::new);
302 }
303 }