f6b61b330d42db88f9ffade8d36d36cc01fcc4fc
[cdmlib.git] / cdmlib-ext / src / main / java / eu / etaxonomy / cdm / ext / geo / GeoServiceArea.java
1 /**
2 * Copyright (C) 2009 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.ext.geo;
10
11 import java.io.ByteArrayInputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.StringWriter;
15 import java.net.URL;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.TreeSet;
21
22 import javax.xml.stream.XMLOutputFactory;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamWriter;
25
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.Logger;
28 import org.jdom.Element;
29 import org.jdom.JDOMException;
30 import org.jdom.Namespace;
31
32 import eu.etaxonomy.cdm.common.CdmUtils;
33 import eu.etaxonomy.cdm.common.XmlHelp;
34
35 /**
36 * Holds all values to map an NamedArea to a geo service area.
37 *
38 * TODO it must be possible to distinguish mappings for multiple layers in the same map service,
39 * that is the combination of GeoServiceType, URL and layer would be a unique key.
40 * This is however conflicting with the concept of the subAreas which allows to combine multiple
41 * polygons from different layers.
42 * <BR><BR>
43 * see also https://dev.e-taxonomy.eu/redmine/issues/4263
44 *
45 * @author a.mueller
46 * @since 11.08.2011
47 */
48 public class GeoServiceArea {
49 @SuppressWarnings("unused")
50 private static final Logger logger = LogManager.getLogger(GeoServiceArea.class);
51
52 private static final String VALUE = "value";
53 private static final String FIELD = "field";
54 private static final String LAYER = "layer";
55 private static final String AREA = "area";
56 private static final String MAP_SERVICE_NAMESPACE = "http://www.etaxonomy.eu/cdm";
57 private static final String MAP_SERVICE = "mapService";
58
59
60 public enum GeoServiceType{
61 EDIT("Edit Geo Service"),
62 WMS("WMS Service");
63
64 private final String label;
65
66 private GeoServiceType(String label){
67 this.label = label;
68 }
69
70 public String getLabel(){
71 return label;
72 }
73 }
74
75 private final TreeSet<SubArea> subAreas = new TreeSet<>();
76 private URL serviceUri;
77 private GeoServiceType type;
78
79
80 public class SubArea implements Comparable<SubArea>{
81 private String layer;
82 private String field;
83 private String value;
84
85 @Override
86 public int hashCode() {
87 int hash;
88 hash = 236435;
89 hash += layer != null ? layer.hashCode() * 29 : 32;
90 hash += field != null ? field.hashCode() * 31 : 32;
91 hash += value != null ? value.hashCode() * 37 : 32;
92 return hash;
93 }
94
95 @Override
96 public boolean equals(Object otherArea) {
97 if (! (otherArea instanceof SubArea)){
98 return false;
99 }
100 SubArea subArea = (SubArea)otherArea;
101 if (CdmUtils.nullSafeEqual(layer, subArea.layer)
102 && CdmUtils.nullSafeEqual(field, subArea.field)
103 && CdmUtils.nullSafeEqual(value, subArea.value)
104 ){
105 return true;
106 }else{
107 return false;
108 }
109 }
110 @Override
111 public int compareTo(SubArea otherArea) {
112 int compareLayer = CdmUtils.Nz(this.layer).compareToIgnoreCase(CdmUtils.Nz(otherArea.layer));
113 int compareField = CdmUtils.Nz(this.field).compareToIgnoreCase(CdmUtils.Nz(otherArea.field));
114 int compareValue = CdmUtils.Nz(this.value).compareToIgnoreCase(CdmUtils.Nz(otherArea.value));
115
116 if (compareLayer != 0){
117 return compareLayer;
118 }else if (compareField != 0 ){
119 return compareField;
120 }else {
121 return compareValue;
122 }
123 }
124 }
125
126 public void add(String layer, String field, String value){
127 SubArea newArea = new SubArea();
128 newArea.layer = layer;
129 newArea.field = field;
130 newArea.value = value;
131 subAreas.add(newArea);
132 }
133
134 /**
135 * Returns the areas as a layer, field, area nested map.
136 * @return
137 */
138 public Map<String, Map<String, List<String>>> getAreasMap(){
139 Map<String, Map<String, List<String>>> result = new HashMap<>();
140
141 for (SubArea area : subAreas){
142 //layer
143 Map<String, List<String>> layer = result.get(area.layer);
144 if (layer == null ){
145 layer = new HashMap<>();
146 result.put(area.layer, layer);
147 }
148 //field
149 List<String> field = layer.get(area.field);
150 if (field == null ){
151 field = new ArrayList<>();
152 layer.put(area.field, field);
153 }
154 //value
155 if (! field.contains(area.value)){
156 field.add(area.value);
157 }
158 }
159 return result;
160 }
161
162 public List<SubArea> getAreasList(){
163 List<SubArea> result = new ArrayList<>();
164 for (SubArea area : subAreas){
165 result.add(area);
166 }
167 return result;
168 }
169
170
171 public static boolean isAreaMapping(String xml){
172 //TODO check by parsing or only testing root + namespace
173 GeoServiceArea mapping = valueOf(xml);
174 if (mapping != null){
175 return true;
176 }else{
177 return false;
178 }
179 }
180
181 public static GeoServiceArea valueOf (String xml){
182 if (xml == null){
183 return null;
184 }
185
186 // StringReader reader = new StringReader (xml);
187 // (new InputSource(reader));
188 // InputStream is = new java.io.StringBufferInputStream(xml);
189 InputStream is = new ByteArrayInputStream(xml.getBytes());
190 GeoServiceArea result = new GeoServiceArea();
191
192 try {
193 Element root = XmlHelp.getRoot(is);
194 if (! root.getName().equals(MAP_SERVICE) || ! root.getNamespace().getURI().equals(MAP_SERVICE_NAMESPACE) ){
195 return null;
196 }else{
197 //TODO schema validation
198
199 Namespace ns = root.getNamespace();
200 List<Element> elAreas = root.getChildren(AREA, ns);
201 for (Element elArea : elAreas){
202 Element layer = elArea.getChild(LAYER, ns);
203 Element field = elArea.getChild(FIELD, ns);
204 //TODO multiple values
205 List<Element> values = elArea.getChildren(VALUE, ns);
206 for (Element value : values){
207 result.add(layer.getTextTrim(), field.getTextTrim(), value.getTextTrim());
208 }
209 }
210 return result;
211 }
212 } catch (JDOMException e) {
213 throw new RuntimeException(e);
214 } catch (IOException e) {
215 throw new RuntimeException(e);
216 }
217 }
218
219 //TODO use JAXB or other marshalling techniques
220 public String toXml() throws XMLStreamException{
221 XMLStreamWriter writer = null;
222 XMLOutputFactory factory = XMLOutputFactory.newInstance();
223 StringWriter stringWriter = new StringWriter();
224 writer = factory.createXMLStreamWriter(stringWriter);
225
226 String rootNamespace = MAP_SERVICE_NAMESPACE;
227 String rootName = MAP_SERVICE;
228
229 // create header
230 writer.writeStartDocument();
231 writer.setDefaultNamespace(rootNamespace);
232
233 // create root element
234 writer.writeStartElement(rootName);
235
236 writer.writeNamespace(null, rootNamespace);
237 writer.writeAttribute("type", "editMapService");
238
239 writeAreas(writer);
240
241 writer.writeEndElement();
242 writer.writeEndDocument();
243
244 return stringWriter.getBuffer().toString();
245 }
246
247 private void writeAreas(XMLStreamWriter writer) throws XMLStreamException {
248 Map<String, Map<String, List<String>>> areaMap = getAreasMap();
249 //TODO multiple
250 for (String layerKey : areaMap.keySet()){
251 Map<String, List<String>> layer = areaMap.get(layerKey);
252 for (String fieldKey: layer.keySet()){
253 List<String> field = layer.get(fieldKey);
254 //area
255 writer.writeStartElement(AREA);
256 //layer
257 writer.writeStartElement(LAYER);
258 writer.writeCharacters(layerKey);
259 writer.writeEndElement();
260 //field
261 writer.writeStartElement(FIELD);
262 writer.writeCharacters(fieldKey);
263 writer.writeEndElement();
264 //value
265 for (String value : field){
266 writer.writeStartElement(VALUE);
267 writer.writeCharacters(value);
268 writer.writeEndElement();
269 }
270 writer.writeEndElement();
271 }
272 }
273 }
274
275 public int size() {
276 return this.subAreas.size();
277 }
278 }