View Javadoc
1   /*
2    * Copyright (C) 2023 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.persistence;
7   
8   import com.fasterxml.jackson.core.JsonProcessingException;
9   import com.fasterxml.jackson.databind.ObjectMapper;
10  import jakarta.persistence.Basic;
11  import jakarta.persistence.CascadeType;
12  import jakarta.persistence.Column;
13  import jakarta.persistence.Entity;
14  import jakarta.persistence.EntityListeners;
15  import jakarta.persistence.EnumType;
16  import jakarta.persistence.Enumerated;
17  import jakarta.persistence.GeneratedValue;
18  import jakarta.persistence.GenerationType;
19  import jakarta.persistence.Id;
20  import jakarta.persistence.JoinColumn;
21  import jakarta.persistence.JoinTable;
22  import jakarta.persistence.ManyToOne;
23  import jakarta.persistence.OneToMany;
24  import jakarta.persistence.OrderBy;
25  import jakarta.persistence.Table;
26  import jakarta.persistence.Transient;
27  import jakarta.persistence.Version;
28  import jakarta.validation.constraints.NotNull;
29  import java.util.ArrayList;
30  import java.util.List;
31  import org.hibernate.annotations.Type;
32  import org.tailormap.api.persistence.json.JDBCConnectionProperties;
33  import org.tailormap.api.persistence.json.ServiceAuthentication;
34  import org.tailormap.api.persistence.json.TMServiceCaps;
35  import org.tailormap.api.persistence.listener.EntityEventPublisher;
36  
37  @Entity
38  @Table(name = "feature_source")
39  @EntityListeners(EntityEventPublisher.class)
40  public class TMFeatureSource {
41  
42    public enum Protocol {
43      WFS("wfs"),
44  
45      JDBC("jdbc");
46  
47      private final String value;
48  
49      Protocol(String value) {
50        this.value = value;
51      }
52  
53      public String getValue() {
54        return value;
55      }
56  
57      @Override
58      public String toString() {
59        return String.valueOf(value);
60      }
61  
62      public static TMFeatureSource.Protocol fromValue(String value) {
63        for (TMFeatureSource.Protocol p : TMFeatureSource.Protocol.values()) {
64          if (p.value.equals(value)) {
65            return p;
66          }
67        }
68        throw new IllegalArgumentException("Unexpected value '" + value + "'");
69      }
70    }
71  
72    @Id
73    @GeneratedValue(strategy = GenerationType.IDENTITY)
74    private Long id;
75  
76    @Version private Long version;
77  
78    @Transient private boolean refreshCapabilities;
79  
80    @Column(columnDefinition = "text")
81    private String notes;
82  
83    @NotNull
84    @Enumerated(EnumType.STRING)
85    private TMFeatureSource.Protocol protocol;
86  
87    @Basic private String title;
88  
89    @Column(length = 2048)
90    private String url;
91  
92    @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
93    @Column(columnDefinition = "jsonb")
94    private JDBCConnectionProperties jdbcConnection;
95  
96    @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
97    @Column(columnDefinition = "jsonb")
98    private ServiceAuthentication authentication;
99  
100   @ManyToOne
101   @JoinColumn(name = "linked_service")
102   private GeoService linkedService;
103 
104   @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
105   @Column(columnDefinition = "jsonb")
106   private TMServiceCaps serviceCapabilities;
107 
108   @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
109   @JoinTable(
110       name = "feature_source_feature_types",
111       inverseJoinColumns = @JoinColumn(name = "feature_type"),
112       joinColumns = @JoinColumn(name = "feature_source", referencedColumnName = "id"))
113   @OrderBy("name asc")
114   private List<TMFeatureType> featureTypes = new ArrayList<>();
115 
116   @Override
117   public String toString() {
118     try {
119       return "TMFeatureSource{"
120           + "id="
121           + id
122           + ", protocol="
123           + protocol
124           + ", title='"
125           + title
126           + '\''
127           + ", url='"
128           + url
129           + '\''
130           + ", jdbcConnection="
131           + new ObjectMapper().writeValueAsString(jdbcConnection)
132           + '}';
133     } catch (JsonProcessingException e) {
134       throw new RuntimeException(e);
135     }
136   }
137 
138   // <editor-fold desc="getters and setters">
139   public Long getId() {
140     return id;
141   }
142 
143   public TMFeatureSource setId(Long id) {
144     this.id = id;
145     return this;
146   }
147 
148   public Long getVersion() {
149     return version;
150   }
151 
152   public TMFeatureSource setVersion(Long version) {
153     this.version = version;
154     return this;
155   }
156 
157   public boolean isRefreshCapabilities() {
158     return refreshCapabilities;
159   }
160 
161   public void setRefreshCapabilities(boolean refreshCapabilities) {
162     this.refreshCapabilities = refreshCapabilities;
163   }
164 
165   public String getNotes() {
166     return notes;
167   }
168 
169   public TMFeatureSource setNotes(String notes) {
170     this.notes = notes;
171     return this;
172   }
173 
174   public Protocol getProtocol() {
175     return protocol;
176   }
177 
178   public TMFeatureSource setProtocol(Protocol protocol) {
179     this.protocol = protocol;
180     return this;
181   }
182 
183   public String getTitle() {
184     return title;
185   }
186 
187   public TMFeatureSource setTitle(String title) {
188     this.title = title;
189     return this;
190   }
191 
192   public String getUrl() {
193     return url;
194   }
195 
196   public TMFeatureSource setUrl(String url) {
197     this.url = url;
198     return this;
199   }
200 
201   public JDBCConnectionProperties getJdbcConnection() {
202     return jdbcConnection;
203   }
204 
205   public TMFeatureSource setJdbcConnection(JDBCConnectionProperties jdbcConnection) {
206     this.jdbcConnection = jdbcConnection;
207     return this;
208   }
209 
210   public ServiceAuthentication getAuthentication() {
211     return authentication;
212   }
213 
214   public TMFeatureSource setAuthentication(ServiceAuthentication authentication) {
215     this.authentication = authentication;
216     return this;
217   }
218 
219   public GeoService getLinkedService() {
220     return linkedService;
221   }
222 
223   public TMFeatureSource setLinkedService(GeoService linkedService) {
224     this.linkedService = linkedService;
225     return this;
226   }
227 
228   public TMServiceCaps getServiceCapabilities() {
229     return serviceCapabilities;
230   }
231 
232   public TMFeatureSource setServiceCapabilities(TMServiceCaps serviceCapabilities) {
233     this.serviceCapabilities = serviceCapabilities;
234     return this;
235   }
236 
237   // Added this extra getter to work around Spring Data Rest
238   // By adding a repository for feature types SDR does not add feature types when fetching a feature
239   // source, while the front-end currently depends on having all feature types available.
240   // In the future we could refactor this to give only a list of names and fetch the type itself
241   // when needed.
242   public List<TMFeatureType> getAllFeatureTypes() {
243     return featureTypes;
244   }
245 
246   public List<TMFeatureType> getFeatureTypes() {
247     return featureTypes;
248   }
249 
250   public TMFeatureSource setFeatureTypes(List<TMFeatureType> featureTypes) {
251     this.featureTypes = featureTypes;
252     return this;
253   }
254 
255   // </editor-fold>
256 
257   public TMFeatureType findFeatureTypeByName(String featureTypeName) {
258     return getFeatureTypes().stream()
259         .filter(ft -> featureTypeName.equals(ft.getName()))
260         .findFirst()
261         .orElse(null);
262   }
263 }