/* * SLD Editor - The Open Source Java SLD Editor * * Copyright (C) 2016, SCISYS UK Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.sldeditor.extension.filesystem.file.sldeditor; import com.sldeditor.common.DataSourcePropertiesInterface; import com.sldeditor.common.NodeInterface; import com.sldeditor.common.SLDDataInterface; import com.sldeditor.common.console.ConsoleManager; import com.sldeditor.common.data.SLDData; import com.sldeditor.common.data.StyleWrapper; import com.sldeditor.common.filesystem.FileSystemInterface; import com.sldeditor.common.utils.ExternalFilenames; import com.sldeditor.common.vendoroption.VendorOptionManager; import com.sldeditor.common.vendoroption.VendorOptionVersion; import com.sldeditor.common.vendoroption.VersionData; import com.sldeditor.datasource.SLDEditorFile; import com.sldeditor.datasource.attribute.DataSourceAttributeData; import com.sldeditor.datasource.extension.filesystem.FileSystemUtils; import com.sldeditor.datasource.extension.filesystem.node.file.FileHandlerInterface; import com.sldeditor.datasource.extension.filesystem.node.file.FileTreeNode; import com.sldeditor.datasource.impl.DataSourceProperties; import com.sldeditor.extension.filesystem.file.sld.SLDFileHandler; import com.sldeditor.filter.v2.envvar.EnvVar; import com.sldeditor.ui.legend.option.LegendOptionData; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.tree.DefaultTreeModel; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * Class that handles read/writing SLD Editor project files. * * @author Robert Ward (SCISYS) */ public class SLDEditorFileHandler implements FileHandlerInterface { private static final String ROOT_ELEMENT = "SLDEditor"; private static final String YES = "yes"; private static final String DATASOURCE_ELEMENT = "datasource"; private static final String SLD_ELEMENT = "sld"; private static final String ENVVARLIST_ELEMENT = "EnvVarList"; private static final String ENVVAR_ELEMENT = "EnvVar"; private static final String ENVVAR_VALUE_ATTRIBUTE = "value"; private static final String ENVVAR_NAME_ATTRIBUTE = "name"; private static final String ENVVAR_TYPE_ATTRIBUTE = "type"; private static final String VENDOR_OPTION_ELEMENT = "vendorOption"; private static final String LEGEND_OPTION_ELEMENT = "legend"; /** The Constant RESOURCE_ICON. */ private static final String RESOURCE_ICON = "ui/filesystemicons/sldeditor.png"; /** The tree icon SLD. */ private transient Icon treeIcon = null; /** The Constant serialVersionUID. */ private static final long serialVersionUID = -3193761375262410975L; /* * (non-Javadoc) * * @see com.sldeditor.extension.input.FileHandlerInterface#getFileExtension() */ @Override public List<String> getFileExtensionList() { return Arrays.asList("sldeditor"); } /* * (non-Javadoc) * * @see * com.sldeditor.extension.input.file.FileHandlerInterface#populate(com.sldeditor.extension. * input.FileSystemInterface, javax.swing.tree.DefaultTreeModel, * com.sldeditor.extension.input.file.FileTreeNode) */ @Override public boolean populate( FileSystemInterface inputInferface, DefaultTreeModel treeModel, FileTreeNode node) { // Do nothing return false; } /* * (non-Javadoc) * * @see * com.sldeditor.extension.input.FileHandlerInterface#getSLDContents(com.sldeditor.extension. * input.NodeInterface) */ @Override public List<SLDDataInterface> getSLDContents(NodeInterface node) { if (node instanceof FileTreeNode) { FileTreeNode fileTreeNode = (FileTreeNode) node; File f = fileTreeNode.getFile(); if ((f != null) && FileSystemUtils.isFileExtensionSupported(f, getFileExtensionList())) { List<SLDDataInterface> list = new ArrayList<>(); SLDDataInterface sldData = readSLDEditorFile(f); list.add(sldData); return list; } } return null; } /** * Read sld editor file. * * @param file the file * @return the SLD data */ private SLDDataInterface readSLDEditorFile(File file) { SLDDataInterface sldData = null; DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder; try { documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(file); String sldFile = extractTextData(document, SLDEditorFileHandler.SLD_ELEMENT); DataSourcePropertiesInterface dataSourceProperties = DataSourceProperties.decodeXML( document, SLDEditorFileHandler.DATASOURCE_ELEMENT); List<VersionData> vendorOptionList = extractVendorOptionData(document, SLDEditorFileHandler.VENDOR_OPTION_ELEMENT); File f = new File(sldFile); String sldContents = readFile(f, Charset.defaultCharset()); sldData = new SLDData(new StyleWrapper(sldFile), sldContents); sldData.setDataSourceProperties(dataSourceProperties); sldData.setVendorOptionList(vendorOptionList); List<DataSourceAttributeData> fieldList = null; sldData.setFieldList(fieldList); sldData.setSLDFile(f); sldData.setReadOnly(false); sldData.setSldEditorFile(file); List<EnvVar> envVarList = extractEnvironmentVariables(document, SLDEditorFileHandler.ENVVAR_ELEMENT); sldData.setEnvVarList(envVarList); LegendOptionData legendOption = LegendOptionData.decodeXML( document, SLDEditorFileHandler.LEGEND_OPTION_ELEMENT); sldData.setLegendOptions(legendOption); } catch (ParserConfigurationException | SAXException | IOException e) { ConsoleManager.getInstance().exception(this, e); } return sldData; } /** * Extract environment variables. * * @param document the document * @param envvarElement the environment variable element * @return the list */ private List<EnvVar> extractEnvironmentVariables(Document document, String elementName) { List<EnvVar> list = new ArrayList<>(); NodeList nodeList = document.getElementsByTagName(elementName); for (int index = 0; index < nodeList.getLength(); index++) { Element element = (Element) nodeList.item(index); Class<?> type = null; try { type = Class.forName(element.getAttribute(ENVVAR_TYPE_ATTRIBUTE)); } catch (ClassNotFoundException e) { ConsoleManager.getInstance().exception(this, e); } // Assume not predefined, will get sorted out later EnvVar envVar = new EnvVar(element.getAttribute(ENVVAR_NAME_ATTRIBUTE), type, false); if (element.hasAttribute(ENVVAR_VALUE_ATTRIBUTE)) { envVar.setValue(element.getAttribute(ENVVAR_VALUE_ATTRIBUTE)); } list.add(envVar); } return list; } /** * Extract text data from XML node. * * @param document the document * @param elementName the element name * @return the string */ private static String extractTextData(Document document, String elementName) { String value = ""; NodeList nodeList = document.getElementsByTagName(elementName); if (nodeList.getLength() > 0) { value = nodeList.item(0).getTextContent(); } return value; } /** * Extract vendor option data. * * @param document the document * @param elementName the element name * @return the list */ private List<VersionData> extractVendorOptionData(Document document, String elementName) { List<VersionData> list = new ArrayList<>(); // Try and remove any duplicates List<String> nameList = new ArrayList<>(); nameList.add( VendorOptionManager.getInstance() .getDefaultVendorOptionVersion() .getLatest() .toString()); list.add(VendorOptionManager.getInstance().getDefaultVendorOptionVersion().getLatest()); NodeList nodeList = document.getElementsByTagName(elementName); for (int index = 0; index < nodeList.getLength(); index++) { String value = nodeList.item(index).getTextContent(); VendorOptionVersion vendorOption = VendorOptionVersion.fromString(value); VersionData newVersion = vendorOption.getLatest(); if (!nameList.contains(newVersion.toString())) { list.add(newVersion); nameList.add(newVersion.toString()); } } return list; } /** * Read file. * * @param file the file * @param encoding the encoding * @return the string * @throws IOException Signals that an I/O exception has occurred. */ private static String readFile(File file, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(file.getAbsolutePath())); return new String(encoded, encoding); } /* * (non-Javadoc) * * @see com.sldeditor.extension.input.file.FileHandlerInterface#open(java.io.File) */ @Override public List<SLDDataInterface> open(File file) { List<SLDDataInterface> list = null; if (FileSystemUtils.isFileExtensionSupported(file, getFileExtensionList())) { list = new ArrayList<>(); SLDDataInterface sldData = readSLDEditorFile(file); list.add(sldData); } return list; } /* * (non-Javadoc) * * @see com.sldeditor.extension.input.file.FileHandlerInterface#save(com.sldeditor.ui.iface. * SLDDataInterface) */ @Override public boolean save(SLDDataInterface sldData) { if (sldData == null) { return false; } File fileToSave = sldData.getSldEditorFile(); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = null; try { documentBuilder = documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { ConsoleManager.getInstance().exception(this, e); return false; } Document doc = documentBuilder.newDocument(); Element root = doc.createElement(SLDEditorFileHandler.ROOT_ELEMENT); doc.appendChild(root); // SLD contents Element sldElement = doc.createElement(SLDEditorFileHandler.SLD_ELEMENT); sldElement.appendChild(doc.createTextNode(sldData.getSLDFile().getAbsolutePath())); root.appendChild(sldElement); // Vendor options List<VersionData> vendorOptionList = sldData.getVendorOptionList(); if (vendorOptionList != null) { for (VersionData versionData : vendorOptionList) { Element vendorOptionElement = doc.createElement(SLDEditorFileHandler.VENDOR_OPTION_ELEMENT); VendorOptionVersion vendorOption = new VendorOptionVersion(versionData.getVendorOptionType(), versionData); vendorOptionElement.appendChild(doc.createTextNode(vendorOption.toString())); root.appendChild(vendorOptionElement); } } // Write out the data source connector DataSourcePropertiesInterface dataSourceProperties = sldData.getDataSourceProperties(); if (dataSourceProperties != null) { dataSourceProperties.encodeXML(doc, root, SLDEditorFileHandler.DATASOURCE_ELEMENT); } // Environment variables Element envVarListElement = doc.createElement(SLDEditorFileHandler.ENVVARLIST_ELEMENT); root.appendChild(envVarListElement); List<EnvVar> envVarList = sldData.getEnvVarList(); if (envVarList != null) { for (EnvVar envVar : envVarList) { Element envVarElement = doc.createElement(SLDEditorFileHandler.ENVVAR_ELEMENT); envVarElement.setAttribute( SLDEditorFileHandler.ENVVAR_NAME_ATTRIBUTE, envVar.getName()); envVarElement.setAttribute( SLDEditorFileHandler.ENVVAR_TYPE_ATTRIBUTE, envVar.getType().getName()); if (envVar.getValue() != null) { String value = envVar.getValue().toString(); envVarElement.setAttribute(SLDEditorFileHandler.ENVVAR_VALUE_ATTRIBUTE, value); } envVarListElement.appendChild(envVarElement); } } // Write out the legend options LegendOptionData legendOptions = sldData.getLegendOptions(); if (legendOptions != null) { legendOptions.encodeXML(doc, root, SLDEditorFileHandler.LEGEND_OPTION_ELEMENT); } // Generate the XML to write out String outputXML = generateXML(doc); if (outputXML == null) { return false; } try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileToSave))) { writer.write(outputXML); } catch (IOException e) { // Do nothing } return true; } /** * Generate XML. * * @param doc the doc * @return the string */ private String generateXML(Document doc) { StringWriter stringWriter = new StringWriter(); try { // Output the XML file contents TransformerFactory tf = TransformerFactory.newInstance(); tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, SLDEditorFileHandler.YES); transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, SLDEditorFileHandler.YES); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.transform(new DOMSource(doc), new StreamResult(stringWriter)); } catch (TransformerException e) { ConsoleManager.getInstance().exception(this, e); return null; } catch (TransformerFactoryConfigurationError e) { ConsoleManager.getInstance().exception(this, e.getException()); return null; } return stringWriter.getBuffer().toString(); } /* * (non-Javadoc) * * @see * com.sldeditor.extension.input.file.FileHandlerInterface#getSLDName(com.sldeditor.ui.iface. * SLDDataInterface) */ @Override public String getSLDName(SLDDataInterface sldData) { if (sldData != null) { return sldData.getLayerNameWithOutSuffix() + ExternalFilenames.addFileExtensionSeparator( SLDEditorFile.getSLDFileExtension()); } return ""; } /** * Returns if files selected are a data source, e.g. raster or vector. * * @return true, if is data source */ @Override public boolean isDataSource() { return false; } /* * (non-Javadoc) * * @see * com.sldeditor.datasource.extension.filesystem.node.file.FileHandlerInterface#getIcon(java. * lang.String, java.lang.String) */ @Override public Icon getIcon(String path, String filename) { if (treeIcon == null) { URL url = SLDFileHandler.class.getClassLoader().getResource(RESOURCE_ICON); treeIcon = new ImageIcon(url); } return treeIcon; } }