/[schmitzm]/trunk/src/skrueger/geotools/StyledLayerUtil.java
ViewVC logotype

Contents of /trunk/src/skrueger/geotools/StyledLayerUtil.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 256 - (show annotations)
Fri Jul 31 14:43:47 2009 UTC (15 years, 7 months ago) by alfonx
File size: 30018 byte(s)
* Updated the license headers
* chart action going on...
1 /*******************************************************************************
2 * Copyright (c) 2009 Martin O. J. Schmitz.
3 *
4 * This file is part of the SCHMITZM library - a collection of utility
5 * classes based on Java 1.6, focusing (not only) on Java Swing
6 * and the Geotools library.
7 *
8 * The SCHMITZM project is hosted at:
9 * http://wald.intevation.org/projects/schmitzm/
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 3
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License (license.txt)
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 * or try this link: http://www.gnu.org/licenses/lgpl.html
25 *
26 * Contributors:
27 * Martin O. J. Schmitz - initial API and implementation
28 * Stefan A. Krüger - additional utility classes
29 ******************************************************************************/
30 package skrueger.geotools;
31
32 import java.io.File;
33 import java.io.FileNotFoundException;
34 import java.io.FileWriter;
35 import java.net.URL;
36 import java.text.DecimalFormat;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.SortedMap;
41 import java.util.TreeMap;
42
43 import org.apache.log4j.Logger;
44 import org.geotools.coverage.grid.GridCoverage2D;
45 import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
46 import org.geotools.feature.FeatureCollection;
47 import org.geotools.map.DefaultMapLayer;
48 import org.geotools.map.MapLayer;
49 import org.geotools.styling.ColorMap;
50 import org.geotools.styling.ColorMapEntry;
51 import org.geotools.styling.RasterSymbolizer;
52 import org.geotools.styling.Style;
53 import org.jdom.Document;
54 import org.jdom.Element;
55 import org.jdom.input.SAXBuilder;
56 import org.jdom.output.XMLOutputter;
57
58 import schmitzm.geotools.styling.StylingUtil;
59 import schmitzm.io.IOUtil;
60 import schmitzm.lang.LangUtil;
61 import schmitzm.swing.SwingUtil;
62 import skrueger.AttributeMetaData;
63 import skrueger.RasterLegendData;
64 import skrueger.i8n.Translation;
65
66 /**
67 * This class provides static helper methods for dealing with
68 * {@link StyledLayerInterface} stuff.
69 * @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany)
70 * @version 1.0
71 */
72 public class StyledLayerUtil {
73 private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class.getName());
74 private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
75 private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
76
77 /** URL for Atlas XML schema */
78 public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
79 /** Name of the XML Element for the attribute meta data map */
80 public static final String ELEM_NAME_AMD = "attributeMetaData";
81 /** Name of the XML Element for the raster legend data */
82 public static final String ELEM_NAME_RLD = "rasterLegendData";
83 /** Name of the XML Element for an attribute meta data map entry */
84 public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
85 /** Name of the XML Element for an raster legend data entry */
86 public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
87 /** Name of the XML Element for a translation */
88 public static final String ELEM_NAME_TRANSLATION = "translation";
89
90 /**
91 * Creates a Geotools {@link MapLayer} from an object. If the object is a
92 * {@link StyledLayerInterface} then its sytle is used. In case of direct
93 * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
94 * {@link FeatureCollection}) a default style is generated.
95 * @param object an Object
96 * @exception Exception if {@code null} is given as object or an error occurs during layer creation
97 */
98 public static MapLayer createMapLayer(Object object) throws Exception {
99 return createMapLayer(object,null);
100 }
101
102 /**
103 * Creates a Geotools {@link MapLayer} from an object. If the object is a
104 * {@link StyledLayerInterface} then its sytle is used. In case of direct
105 * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
106 * {@link FeatureCollection}) a default style is generated.
107 * @param object an Object
108 * @param forcedStyle (SLD-)Style to force for the object
109 * @exception Exception if {@code null} is given as object or an error occurs during layer creation
110 */
111 public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
112 MapLayer layer = null;
113 Style style = null;
114 if ( object instanceof StyledLayerInterface ) {
115 style = ((StyledLayerInterface<?>)object).getStyle();
116 object = ((StyledLayerInterface<?>)object).getGeoObject();
117 }
118 if ( forcedStyle != null )
119 style = forcedStyle;
120 if ( style == null )
121 style = StylingUtil.createDefaultStyle(object);
122
123 if (object instanceof GridCoverage2D)
124 layer = new DefaultMapLayer( (GridCoverage2D) object, style);
125 if (object instanceof AbstractGridCoverage2DReader)
126 layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
127 if (object instanceof FeatureCollection)
128 layer = new DefaultMapLayer( (FeatureCollection) object, style);
129
130 if ( layer == null )
131 throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
132
133 return layer;
134 }
135
136 /**
137 * Creates an default instance of {@link StyledLayerInterface} for a Geotools
138 * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
139 * style.
140 * @param object an Object
141 * @param title title for the object
142 * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
143 */
144 public static StyledLayerInterface<?> createStyledLayer(Object object, String title) {
145 return createStyledLayer(object, title, null);
146 }
147
148 /**
149 * Creates an default instance of {@link StyledLayerInterface} for a Geotools
150 * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
151 * style.
152 * @param object an Object
153 * @param title title for the object
154 * @param style style and meta data for the object
155 * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
156 */
157 public static StyledLayerInterface<?> createStyledLayer(Object object, String title, StyledLayerStyle style) {
158 StyledLayerInterface<?> styledLayer = null;
159
160 String id = (title != null) ? title : "defaultID";
161
162 if ( object instanceof GridCoverage2D )
163 styledLayer = new StyledGridCoverage(
164 (GridCoverage2D)object,
165 id,
166 title,
167 style
168 );
169 else if ( object instanceof AbstractGridCoverage2DReader )
170 styledLayer = new StyledGridCoverageReader(
171 (AbstractGridCoverage2DReader)object,
172 id,
173 title,
174 style
175 );
176 else if ( object instanceof FeatureCollection )
177 styledLayer = new StyledFeatureCollection(
178 (FeatureCollection)object,
179 id,
180 title,
181 style
182 );
183
184 if ( styledLayer == null )
185 throw new UnsupportedOperationException("Can not create StyledLayerInterface object from "+(object == null ? "null" : object.getClass()));
186
187 return styledLayer;
188 }
189
190 /**
191 * Return only the visible or invisible entries of an AttributeMetaData-Map.
192 * @param amdMap AttributeMetaData-Map
193 * @param visible indicated whether the visible or invisible entries are
194 * returned
195 */
196 public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
197 SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
198 for (AttributeMetaData amd : amdMap.values())
199 if ( amd.isVisible() )
200 filteredMap.put(amd.getColIdx(), amd);
201
202 return filteredMap;
203 }
204
205
206 /**
207 * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
208 * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
209 * but for JDOM.
210 * @param element {@link Element} to parse
211 */
212 public static AttributeMetaData parseAttributeMetaData(final Element element) {
213 final Integer col = Integer.valueOf(element.getAttributeValue("col"));
214 final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
215 final String unit = element.getAttributeValue("unit");
216
217 Translation name = new Translation();
218 Translation desc = new Translation();
219 for (final Element childElement : (List<Element>)element.getChildren()) {
220 if (childElement.getName() == null)
221 continue;
222
223 if (childElement.getName().equals("name"))
224 name = parseTranslation(childElement);
225 else if (childElement.getName().equals("desc"))
226 desc = parseTranslation(childElement);
227 }
228 return new AttributeMetaData(col, visible, name, desc, unit);
229 }
230
231 /**
232 * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
233 * with {@code <attribute>}-childs.
234 * @param element {@link Element} to parse
235 */
236 public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
237 HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
238 List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
239 for (Element attibuteElement : attributesElements)
240 {
241 AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
242 metaData.put( attrMetaData.getColIdx(), attrMetaData );
243 }
244 return metaData;
245 }
246
247 /**
248 * Loads a {@link AttributeMetaData} object from an URL.
249 * @param documentUrl {@link URL} to parse
250 * @see #parseAttributeMetaData(Element)
251 */
252 public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
253 Document document = SAX_BUILDER.build(documentUrl);
254 return parseAttributeMetaDataMap( document.getRootElement() );
255 }
256
257 /**
258 * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
259 * object.
260 * @param amd meta data for one attribute
261 */
262 public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
263 final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
264 element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
265 element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
266 element.setAttribute("unit", amd.getUnit() );
267 // Creating a aml:name tag...
268 element.addContent( createTranslationElement("name", amd.getTitle()) );
269 // Creating a aml:desc tag...
270 element.addContent( createTranslationElement("desc", amd.getDesc()) );
271 return element;
272 }
273
274 /**
275 * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
276 * map.
277 * @param amdMap map of attribute meta data
278 */
279 public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
280 final Element element = new Element( ELEM_NAME_AMD , AMLURI);
281 for (AttributeMetaData amd : amdMap.values())
282 element.addContent( createAttributeMetaDataElement( amd ) );
283 return element;
284 }
285
286 /**
287 * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
288 * @param amdMap map of {@link AttributeMetaData}
289 * @param documentUrl {@link URL} to store the XML
290 */
291 public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
292 // Create XML-Document
293 final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
294 XML_OUTPUTTER.output(
295 createAttributeMetaDataMapElement(amdMap),
296 out
297 );
298 out.flush();
299 out.close();
300 }
301
302
303
304 /**
305 * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
306 * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
307 * but for JDOM.
308 * @param element {@link Element} to parse
309 */
310 public static RasterLegendData parseRasterLegendData(Element element) {
311
312 final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
313
314 RasterLegendData rld = new RasterLegendData(paintGaps);
315
316 for ( Element childElement : (List<Element>)element.getChildren() ) {
317 final String name = childElement.getName();
318 // Cancel if it's an attribute
319 if ( childElement.getChildren().size() == 0 )
320 continue;
321
322 if (name.equals( ELEM_NAME_RASTERLEGEND )) {
323 final String valueAttr = childElement.getAttributeValue("value");
324 if ( valueAttr == null )
325 throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
326 final double value = Double.valueOf(valueAttr);
327
328 // first and only item should be the label
329 final Element labelElement = childElement.getChild("label");
330 // id label element is missing, the translation is searched directly
331 // as childs of the rasterLegendItem element
332 Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
333 rld.put(value, label);
334 }
335 }
336
337 return rld;
338 }
339
340 /**
341 * Loads a {@link RasterLegendData} object from an URL.
342 * @param documentUrl {@link URL} to parse
343 * @see #parseAttributeMetaData(Element)
344 */
345 public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
346 Document document = SAX_BUILDER.build(documentUrl);
347 return parseRasterLegendData( document.getRootElement() );
348 }
349
350 /**
351 * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
352 * map.
353 * @param rld raster legend data
354 */
355 public static Element createRasterLegendDataElement(final RasterLegendData rld) {
356 final Element element = new Element( ELEM_NAME_RLD , AMLURI);
357 element.setAttribute("paintGaps", rld.isPaintGaps().toString());
358 for (Double key : rld.getSortedKeys()) {
359 Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
360 item.setAttribute("value", key.toString());
361 item.addContent( createTranslationElement("label", rld.get(key)) );
362 element.addContent(item);
363 }
364 return element;
365 }
366
367 /**
368 * Creates {@link RasterLegendData} from a {@link ColorMap}.
369 * @param colorMap a color map
370 * @param paintGaps indicated whether gaps are painted between the legend items
371 * @param digits number of digits the grid value classes (and legend) are
372 * rounded to (null means no round; >= 0 means digits after comma;
373 * < 0 means digits before comma) */
374 public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
375 DecimalFormat decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
376 RasterLegendData rld = new RasterLegendData(paintGaps);
377 for (ColorMapEntry cme : colorMap.getColorMapEntries())
378 {
379 double value = StylingUtil.getQuantityFromColorMapEntry(cme);
380 String label = cme.getLabel();
381 // if no label is set (e.g. quantitative style),
382 // use the value as label
383 if ( label == null || label.equals("") )
384 if ( digits == null )
385 label = String.valueOf(value);
386 else
387 label = decFormat.format( LangUtil.round(value, digits) );
388 rld.put( value, new Translation(" "+label) );
389 }
390 return rld;
391 }
392
393 /**
394 * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
395 * @param style a raster style (must contain a {@link RasterSymbolizer})
396 * @param paintGaps indicated whether gaps are painted between the legend items
397 * @param digits number of digits the grid value classes (and legend) are
398 * rounded to (null means no round; >= 0 means digits after comma;
399 * < 0 means digits before comma) */
400 public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
401 ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
402 if ( colorMap == null)
403 throw new IllegalArgumentException("Color map can not be determined from style!");
404 return generateRasterLegendData(colorMap, paintGaps, digits);
405 }
406
407 /**
408 * Saves a {@link RasterLegendData} to an URL.
409 * @param rld raster legend data
410 * @param documentUrl {@link URL} to store the XML
411 */
412 public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
413 // Create XML-Document
414 final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
415 XML_OUTPUTTER.output(
416 createRasterLegendDataElement(rld),
417 out
418 );
419 out.flush();
420 out.close();
421 }
422
423 /**
424 * Parses a {@link Translation} object from an JDOM-{@link Element}.
425 * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
426 * but for JDOM.
427 * @param element {@link Element} to parse
428 */
429 public final static Translation parseTranslation(final Element element) {
430 Translation trans = new Translation();
431
432 if (element == null)
433 return trans;
434
435 for (final Element translationElement : (List<Element>)element.getChildren()) {
436 final String name = translationElement.getName();
437 if (name == null)
438 continue;
439
440 // lang attribute
441 String lang = translationElement.getAttributeValue("lang");
442 // set the default, if no language code is set
443 if ( lang == null )
444 lang = Translation.DEFAULT_KEY;
445
446 final String translationText = translationElement.getValue();
447 if (translationText == null)
448 trans.put(lang, "");
449 else
450 trans.put(lang, translationText);
451 }
452
453 // if no <translation> is given, the value of the node should
454 // be used as a default translation
455 if (trans.size() == 0)
456 trans.put( Translation.DEFAULT_KEY, element.getValue() );
457 // trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
458
459 return trans;
460 }
461
462 /**
463 * Creates an JDOM {@link Element} for the given {@link Translation}.
464 * @param tagname Name of the Element
465 * @param translation Translation to store in the Element
466 */
467 public final static Element createTranslationElement(String tagname, Translation translation) {
468 Element element = new Element(tagname, AMLURI);
469 if ( translation == null )
470 throw new UnsupportedOperationException("Translation element can not be created from null!");
471
472 // If only a default translation is set, the <translation lang="..">..</tranlation>
473 // part is not used
474 if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
475 element.addContent( translation.get(Translation.DEFAULT_KEY) );
476 return element;
477 }
478
479 // add a <translation lang="..">..</tranlation> part to the element for
480 // all languages
481 for (String lang : translation.keySet()) {
482 Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
483 translationElement.setAttribute("lang", lang);
484 String translationString = translation.get(lang);
485 if (translationString == null)
486 translationString = "";
487 translationElement.addContent( translationString );
488 element.addContent(translationElement);
489 }
490
491 return element;
492 }
493
494
495 /**
496 * Sets a style to {@link StyledLayerInterface}.
497 * @param styledObject a styled object
498 * @param style a Style
499 */
500 public static void setStyledLayerStyle(StyledLayerInterface styledObject, StyledLayerStyle<?> style) {
501 // set SLD style
502 styledObject.setStyle( style.getGeoObjectStyle() );
503 // set meta data
504 if ( styledObject instanceof StyledGridCoverageInterface &&
505 (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
506 RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
507 RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
508 if ( destRld != null && sourceRld != null ) {
509 destRld.setPaintGaps(sourceRld.isPaintGaps());
510 destRld.clear();
511 destRld.putAll( sourceRld );
512 }
513 return;
514 }
515 if ( styledObject instanceof StyledFeatureCollectionInterface &&
516 (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
517 Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
518 Map<Integer, AttributeMetaData> destAmd = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
519 if ( destAmd != null && sourceAmd != null ) {
520 destAmd.clear();
521 destAmd.putAll( sourceAmd );
522 }
523 return;
524 }
525
526 throw new UnsupportedOperationException("Style is not compatible to object: " +
527 (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
528 " <-> " +
529 (styledObject == null ? null : styledObject.getClass().getSimpleName()));
530 }
531
532 /**
533 * Returns the style a {@link StyledLayerInterface} as a {@link StyledLayerStyle}.
534 * @param styledObject a styled object
535 * @return {@code StyledLayerStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
536 * or {@code StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
537 * {@link StyledFeatureCollectionInterface}
538 */
539 public static StyledLayerStyle<?> getStyledLayerStyle(StyledLayerInterface styledObject) {
540 if ( styledObject instanceof StyledGridCoverageInterface )
541 return getStyledLayerStyle( (StyledGridCoverageInterface)styledObject );
542 if ( styledObject instanceof StyledFeatureCollectionInterface )
543 return getStyledLayerStyle( (StyledFeatureCollectionInterface)styledObject );
544 throw new UnsupportedOperationException("Unknown type of StyledLayerInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
545 }
546
547 /**
548 * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
549 * as a {@link StyledLayerStyle}.
550 * @param styledGC a styled grid coverage
551 */
552 public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(StyledGridCoverageInterface styledGC) {
553 return new StyledLayerStyle<RasterLegendData>(
554 styledGC.getStyle(),
555 styledGC.getLegendMetaData()
556 );
557 }
558
559 /**
560 * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
561 * as a {@link StyledLayerStyle}.
562 * @param styledFC a styled feature collection
563 */
564 public static StyledLayerStyle<Map<Integer,AttributeMetaData>> getStyledLayerStyle(StyledFeatureCollectionInterface styledFC) {
565 return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(
566 styledFC.getStyle(),
567 styledFC.getAttributeMetaDataMap()
568 );
569 }
570
571 /**
572 * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
573 * for a given geo-object (raster) source. The SLD file must be present. A missing
574 * raster legend-data file is tolerated.
575 * @param geoObjectURL URL of the (already read) raster object
576 * @param sldExt file extention for the SLD file
577 * @param rldExt file extention for the raster legend-data file
578 * @return {@code null} in case of any error
579 */
580 public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
581 RasterLegendData metaData = null;
582 Style sldStyle = null;
583 try {
584 Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
585 // SLD must be present
586 if ( styles == null || styles.length == 0 )
587 return null;
588 sldStyle = styles[0];
589 }
590 catch (Exception err) {
591 // SLD must be present
592 LangUtil.logDebugError(LOGGER,err);
593 return null;
594 }
595
596 try {
597 metaData = StyledLayerUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
598 } catch (FileNotFoundException err) {
599 // ignore missing raster legend data
600 } catch (Exception err) {
601 // any other error during legend data creation leads to error
602 LangUtil.logDebugError(LOGGER,err);
603 return null;
604 }
605 return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
606 }
607
608 /**
609 * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
610 * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
611 * for a given geo-object (raster) source. The SLD file must be present. A missing
612 * raster legend-data file is tolerated.
613 * @param geoObjectURL URL of the (already read) raster object
614 * @param sldExt file extention for the SLD file
615 * @param rldExt file extention for the raster legend-data file
616 * @return {@code null} in case of any error
617 */
618 public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
619 return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
620 }
621
622 /**
623 * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
624 * for a given geo-object (feature) source. The SLD file must be present. A missing
625 * attribute meta-data file is tolerated.
626 * @param geoObjectURL URL of the (already read) feature object
627 * @param sldExt file extention for the SLD file
628 * @param rldExt file extention for the raster legend-data file
629 * @return {@code null} in case of any error
630 */
631 public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
632 Map<Integer,AttributeMetaData> metaData = null;
633 Style sldStyle = null;
634 try {
635 Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
636 // SLD must be present
637 if ( styles == null || styles.length == 0 )
638 return null;
639 sldStyle = styles[0];
640 } catch (Exception err) {
641 // SLD must be present
642 LangUtil.logDebugError(LOGGER,err);
643 return null;
644 }
645
646 try {
647 metaData = StyledLayerUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
648 } catch (FileNotFoundException err) {
649 // ignore missing attribute meta data
650 } catch (Exception err) {
651 // any other error during meta data creation leads to error
652 LangUtil.logDebugError(LOGGER,err);
653 return null;
654 }
655
656 return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
657 }
658
659 /**
660 * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
661 * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
662 * for a given geo-object (feature) source. The SLD file must be present. A missing
663 * attribute meta-data file is tolerated.
664 * @param geoObjectURL URL of the (already read) feature object
665 * @param sldExt file extention for the SLD file
666 * @param rldExt file extention for the raster legend-data file
667 * @return {@code null} in case of any error
668 */
669 public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
670 return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
671 }
672
673 /**
674 * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
675 * for a given geo-object (raster) source.
676 * @param style style to save
677 * @param geoObjectURL URL of the raster object
678 * @param sldExt file extention for the SLD file
679 * @param mdExt file extention for the meta-data file
680 */
681 public static <T> void saveStyledLayerStyle(StyledLayerStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
682 // Store the SLD
683 Style sldStyle = style.getGeoObjectStyle();
684 if ( sldStyle != null ) {
685 StylingUtil.saveStyleToSLD(
686 sldStyle,
687 IOUtil.changeFileExt(
688 new File(geoObjectURL.toURI()),
689 sldExt
690 )
691 );
692 }
693
694 // Store the meta data
695 T metaData = style.getMetaData();
696 if ( metaData != null ) {
697 if ( metaData instanceof RasterLegendData ) {
698 saveRasterLegendData(
699 (RasterLegendData)metaData,
700 IOUtil.changeUrlExt(geoObjectURL,mdExt)
701 );
702 // } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
703 } else if ( metaData instanceof Map ) {
704 saveAttributeMetaDataMap(
705 (Map<Integer,AttributeMetaData>)metaData,
706 IOUtil.changeUrlExt(geoObjectURL,mdExt)
707 );
708 } else
709 throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
710 }
711 }
712
713 /**
714 * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
715 * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
716 * to a {@code .rld} or {@code .amd} file.
717 * for a given geo-object source.
718 * @param style style to save
719 * @param geoObjectURL URL of the (already read) raster object
720 */
721 public static void saveStyledLayerStyle(StyledLayerStyle<?> style, URL geoObjectURL) throws Exception {
722 if ( style.getMetaData() instanceof RasterLegendData )
723 saveStyledLayerStyle(style,geoObjectURL, "sld", "rld");
724 else
725 saveStyledLayerStyle(style,geoObjectURL, "sld", "amd");
726 }
727
728 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26