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