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