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