/** * Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * • Apache License, version 2.0 * • Apache Software License, version 1.0 * • GNU Lesser General Public License, version 3 * • Mozilla Public License, versions 1.0, 1.1 and 2.0 * • Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * License version 2 and the aforementioned licenses. * * 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. */ package org.n52.wps.webadmin; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.n52.wps.AlgorithmRepositoryListDocument.AlgorithmRepositoryList; import org.n52.wps.DatahandlersDocument.Datahandlers; import org.n52.wps.FormatDocument.Format; import org.n52.wps.GeneratorDocument.Generator; import org.n52.wps.GeneratorListDocument.GeneratorList; import org.n52.wps.ParserDocument.Parser; import org.n52.wps.ParserListDocument.ParserList; import org.n52.wps.PropertyDocument.Property; import org.n52.wps.RemoteRepositoryDocument.RemoteRepository; import org.n52.wps.RemoteRepositoryListDocument.RemoteRepositoryList; import org.n52.wps.RepositoryDocument.Repository; import org.n52.wps.ServerDocument.Server; import org.n52.wps.WPSConfigurationDocument; import org.n52.wps.WPSConfigurationDocument.WPSConfiguration; import org.n52.wps.commons.WPSConfig; /** * This Bean changes the WPSConfiguration of the Application by processing formdata * @author Florian van Keulen, Raphael Rupprecht */ public class ChangeConfigurationBean { private static transient Logger LOGGER = LoggerFactory.getLogger(ChangeConfigurationBean.class); /** * Types represents the different types of the Entries to proceed */ private enum Types {Server, Repository, Parser, Generator, Formelement, RemoteRepository}; private WPSConfigurationDocument wpsConfigurationDocument; private WPSConfiguration wpsConfiguration; private AlgorithmRepositoryList repositoryList; private RemoteRepositoryList remoteRepositoryList; private ParserList parserList; private GeneratorList generatorList; private Server server; private String serializedWPSConfiguraton = ""; public void setSerializedWPSConfiguraton(String data){ serializedWPSConfiguraton = data; processFormData(data); LOGGER.info("Saved and Activated new configuration!"); } public String getSerializedWPSConfiguraton (){ return serializedWPSConfiguraton; } /** * Processes the stringified formdata and updates the WPSConfiguration XML Bean * of the Application. * it is important, that the form input names are in a specific format. * Incorrect form input names will not processed. * * format: * for a item: * [Repository|Parser|Generator]-[number]_[Name|Class] * for a Property: * [Repository|Parser|Generator]-[number]_Property-[number]_[Name|Value] * * examples: * items: * Repository-13_Name * Repository-13_Class * properties: * Parser-9_Property-14_Name * Parser-9_Property-14_Value * * * @param formData stringified form data */ private void processFormData(String formData) { // get WPSConfiguration XML Bean and create new Lists to hold the data wpsConfigurationDocument = WPSConfigurationDocument.Factory.newInstance(); wpsConfiguration = wpsConfigurationDocument.addNewWPSConfiguration(); server = wpsConfiguration.addNewServer(); server.addNewDatabase(); repositoryList = wpsConfiguration.addNewAlgorithmRepositoryList(); remoteRepositoryList = wpsConfiguration.addNewRemoteRepositoryList(); Datahandlers datahandlers = wpsConfiguration.addNewDatahandlers(); parserList = datahandlers.addNewParserList(); generatorList = datahandlers.addNewGeneratorList(); //temporary maps to store data in order to proceed HashMap<String, String> serverValues = new HashMap<String, String>(); HashMap<String, String> repositoryValues = new HashMap<String, String>(); HashMap<String, String> remoteRepositoryValues = new HashMap<String, String>(); HashMap<String, String> parserValues = new HashMap<String, String>(); HashMap<String, String> generatorValues = new HashMap<String, String>(); // split the stringified formdata into an array String[] dataArr = formData.split("&"); String processingItemName = null; Types processingItemType = null; String[] formName; // main loop // loops over all entries and add them to the corresponding Map // if a item is completely proceed, it adds this to the WPSConfiguration for (int i = 0; i < dataArr.length; i++) { String dataStr = dataArr[i]; // splits name and value String[] entryArr = dataStr.split("="); if(entryArr.length==2){ // extracts the actual processing item type (enum Types) processingItemType = Types.valueOf(entryArr[0].split("-", 2)[0]); // which type is the entry switch (processingItemType) { case Server: serverValues.put(entryArr[0].split("-", 2)[1], entryArr[1]); break; case Repository: // splits the formname to the type with number // as identifier formName = entryArr[0].split("_", 2); if(formName.length==2){ // the first item to proceed if (processingItemName == null) { processingItemName = formName[0]; repositoryValues.put(formName[1], entryArr[1]); // this item belongs to the same entry as the one before } else if (processingItemName.equals(formName[0])) { repositoryValues.put(formName[1], entryArr[1]); // new item, does not belong to the one before } else { //checks if the one before was also the same type if (processingItemName.startsWith("Repository")) { // adds the colected repository values to WPSConfig createRepository(repositoryValues); repositoryValues.clear(); } processingItemName = formName[0]; repositoryValues.put(formName[1], entryArr[1]); } break; } case RemoteRepository: // splits the formname to the type with number // as identifier formName = entryArr[0].split("_", 2); if(formName.length==2){ // the first item to proceed if (processingItemName == null) { processingItemName = formName[0]; remoteRepositoryValues.put(formName[1], entryArr[1]); // this item belongs to the same entry as the one before } else if (processingItemName.equals(formName[0])) { remoteRepositoryValues.put(formName[1], entryArr[1]); // new item, does not belong to the one before } else { //checks if the one before was also the same type if (processingItemName.startsWith("RemoteRepository")) { // adds the colected repository values to WPSConfig createRemoteRepository(remoteRepositoryValues); remoteRepositoryValues.clear(); } processingItemName = formName[0]; remoteRepositoryValues.put(formName[1], entryArr[1]); } break; } case Parser: // splits the formname to the type with number // as identifier formName = entryArr[0].split("_", 2); if(formName.length==2){ // the first item to proceed if (processingItemName == null) { processingItemName = formName[0]; parserValues.put(formName[1], entryArr[1]); // this item belongs to the same entry as the one before } else if (processingItemName.equals(formName[0])) { parserValues.put(formName[1], entryArr[1]); // new item, does not belong to the one before } else { //checks if the one before was also the same type if (processingItemName.startsWith("Parser")) { // adds the collected parser values to WPSConfig createParser(parserValues); parserValues.clear(); } processingItemName = formName[0]; parserValues.put(formName[1], entryArr[1]); } break; } case Generator: // splits the formname to the type with number // as identifier formName = entryArr[0].split("_", 2); if(formName.length==2){ // the first item to proceed if (processingItemName == null) { processingItemName = formName[0]; generatorValues.put(formName[1], entryArr[1]); // this item belongs to the same entry as the one before } else if (processingItemName.equals(formName[0])) { generatorValues.put(formName[1], entryArr[1]); // new item, does not belong to the one before } else { //checks if the one before was also the same type if (processingItemName.startsWith("Generator")) { // adds the collected generator values to WPSConfig createGenerator(generatorValues); generatorValues.clear(); } processingItemName = formName[0]; generatorValues.put(formName[1], entryArr[1]); } break; } } } } //adds the server values to the WPSConfig createServer(serverValues); //adds the last not yet added repository to the WPSConfig if (!repositoryValues.isEmpty()) { createRepository(repositoryValues); } //adds the last not yet added remote repository to the WPSConfig if (!remoteRepositoryValues.isEmpty()) { createRemoteRepository(remoteRepositoryValues); } //adds the last not yet added parser to the WPSConfig if (!parserValues.isEmpty()) { createParser(parserValues); } //adds the last not yet added generator to the WPSConfig if (!generatorValues.isEmpty()) { createGenerator(generatorValues); } // writes the new WPSConfig to a file try { String configurationPath = WPSConfig.getConfigPath(); File XMLFile = new File(configurationPath); wpsConfigurationDocument.save(XMLFile, new org.apache.xmlbeans.XmlOptions().setUseDefaultNamespace().setSavePrettyPrint()); WPSConfig.forceInitialization(configurationPath); } catch (IOException e) { LOGGER.error("Could not write configuration to file: "+ e.getMessage()); } catch (org.apache.xmlbeans.XmlException e){ LOGGER.error("Could not generate XML File from Data: " + e.getMessage()); } } /** * adds the name value pairs to the Server instance of the WPSconfig * @param serverEntries map with the name value pairs */ private void createServer(HashMap<String, String> serverEntries) { if (serverEntries.containsKey("protocol")) { server.setProtocol(serverEntries.get("protocol")); } if (serverEntries.containsKey("hostname")) { server.setHostname(serverEntries.get("hostname")); } if (serverEntries.containsKey("hostport")) { server.setHostport(serverEntries.get("hostport")); } if (serverEntries.containsKey("includeDataInputsInResponse")) { server.setIncludeDataInputsInResponse(Boolean.valueOf(serverEntries.get("includeDataInputsInResponse"))); } if (serverEntries.containsKey("computationTimeoutMilliSeconds")) { server.setComputationTimeoutMilliSeconds(serverEntries.get("computationTimeoutMilliSeconds")); } if (serverEntries.containsKey("cacheCapabilites")) { server.setCacheCapabilites(Boolean.valueOf(serverEntries.get("cacheCapabilites"))); } if (serverEntries.containsKey("webappPath")) { server.setWebappPath(serverEntries.get("webappPath")); } if (serverEntries.containsKey("repoReloadInterval")) { server.setRepoReloadInterval(Double.parseDouble(serverEntries.get("repoReloadInterval"))); } if (serverEntries.containsKey("minPoolSize")) { server.setMinPoolSize(new BigInteger(serverEntries.get("minPoolSize"))); } if (serverEntries.containsKey("maxPoolSize")) { server.setMaxPoolSize(new BigInteger(serverEntries.get("maxPoolSize"))); } if (serverEntries.containsKey("keepAliveSeconds")) { server.setKeepAliveSeconds(new BigInteger(serverEntries.get("keepAliveSeconds"))); } if (serverEntries.containsKey("maxQueuedTasks")) { server.setMaxQueuedTasks(new BigInteger(serverEntries.get("maxQueuedTasks"))); } } /** * adds the name value pairs to the RepositoryList instance of the WPSconfig * @param repositoryEntries map with the name value pairs belonging to one Repository */ private void createRepository(HashMap<String, String> repositoryEntries) { // if Name or Class does not exist, Repository is not added if (repositoryEntries.isEmpty() || !repositoryEntries.containsKey("Name") || !repositoryEntries.containsKey("Class")) { return; } // get new repository and add Name and Class and Active state Repository repository = repositoryList.addNewRepository(); repository.setName(repositoryEntries.remove("Name")); repository.setClassName(repositoryEntries.remove("Class")); String activeString = repositoryEntries.remove("Activator"); boolean active = true; if(activeString == null){ // Activator=off will only be recognized when activeString is null, the jQuery form.serialize() method won't insert "Activator=off"! active = false; } else { if(activeString.equals("on")){ // everything is fine } else { LOGGER.error("Error - the Activator seems not to be set."); } } repository.setActive(active); // if the map has more entries, Properties are present and will be proceed if (!repositoryEntries.isEmpty()) { repository.setPropertyArray(getPropertyArray(repositoryEntries)); } } /** * adds the name value pairs to the RepositoryList instance of the WPSconfig * @param repositoryEntries map with the name value pairs belonging to one Repository */ private void createRemoteRepository(HashMap<String, String> repositoryEntries) { // if Name or Class does not exist, Repository is not added if (repositoryEntries.isEmpty() || !repositoryEntries.containsKey("Name")) { return; } // get new repository and add Name and Class and Active state RemoteRepository repository = remoteRepositoryList.addNewRemoteRepository(); repository.setName(repositoryEntries.remove("Name")); String activeString = repositoryEntries.remove("Activator"); boolean active = true; if(activeString == null){ // Activator=off will only be recognized when activeString is null, the jQuery form.serialize() method won't insert "Activator=off"! active = false; } else { if(activeString.equals("on")){ // everything is fine } else { LOGGER.error("Error - the Activator seems not to be set."); } } repository.setActive(active); // if the map has more entries, Properties are present and will be proceed if (!repositoryEntries.isEmpty()) { repository.setPropertyArray(getPropertyArray(repositoryEntries)); } } /** * adds the name value pairs to the ParserList instance of the WPSconfig * @param parserEntries map with the name value pairs belonging to one Parser */ private void createParser(HashMap<String, String> parserEntries) { // if Name or Class does not exist, Parser is not added if (parserEntries.isEmpty() || !parserEntries.containsKey("Name") || !parserEntries.containsKey("Class")) { return; } // get new parser and add Name and Class Parser parser = parserList.addNewParser(); parser.setName(parserEntries.remove("Name")); parser.setClassName(parserEntries.remove("Class")); String activeString = parserEntries.remove("Activator"); boolean active = true; if(activeString == null){ // Activator=off will only be recognized when activeString is null, the jQuery form.serialize() method won't insert "Activator=off"! active = false; } else { if(activeString.equals("on")){ // everything is fine } else { LOGGER.error("Error - the Activator seems not to be set."); } } parser.setActive(active); // if the map has more entries, Properties are present and will be proceed if (!parserEntries.isEmpty()) { try { parser.setFormatArray(getFormatArray(parserEntries)); } catch (UnsupportedEncodingException e) { LOGGER.error("Error decoding format attributes in UTF-8."); } parser.setPropertyArray(getPropertyArray(parserEntries)); } } /** * adds the name value pairs to the GeneratorList instance of the WPSconfig * @param generatorEntries map with the name value pairs belonging to one Generator */ private void createGenerator(HashMap<String, String> generatorEntries) { // if Name or Class does not exist, Generator is not added if (generatorEntries.isEmpty() || !generatorEntries.containsKey("Name") || !generatorEntries.containsKey("Class")) { return; } // get new generator and add Name and Class Generator generator = generatorList.addNewGenerator(); generator.setName(generatorEntries.remove("Name")); generator.setClassName(generatorEntries.remove("Class")); String activeString = generatorEntries.remove("Activator"); boolean active = true; if(activeString == null){ // Activator=off will only be recognized when activeString is null, the jQuery form.serialize() method won't insert "Activator=off"! active = false; } else { if(activeString.equals("on")){ // everything is fine } else { LOGGER.error("Error - the Activator seems not to be set."); } } generator.setActive(active); // if the map has more entries, Properties are present and will be proceed if (!generatorEntries.isEmpty()) { try { generator.setFormatArray(getFormatArray(generatorEntries)); } catch (UnsupportedEncodingException e) { LOGGER.error("Error decoding format attributes in UTF-8."); } generator.setPropertyArray(getPropertyArray(generatorEntries)); } } /** * generates a Property[] of the name value pairs in the map * @param properties map with name value pairs belonging to one entry * @return Property[] */ private Property[] getPropertyArray(HashMap<String, String> properties) { ArrayList<Property> propArr = new ArrayList<Property>(); Map<Integer, Property> propertyNumberPropertyMap = new HashMap<Integer, Property>(); for (String property : properties.keySet()) { /* * right now there are only Property and Format elements in the HashMap * here we are only interested in Property elements */ if(property.contains("Format")){ continue; } Integer propertyNumber = Integer.parseInt(property.substring(property.indexOf("-") + 1, property.indexOf("_"))); if(propertyNumberPropertyMap.keySet().contains(propertyNumber)){ continue; } String processingProperty = property.split("_")[0]; String propertyName = properties.get(processingProperty + "_Name"); if(propertyName == null){ continue; } try { propertyName = URLDecoder.decode(propertyName, "UTF-8"); } catch (UnsupportedEncodingException e) { LOGGER.error(e.getMessage(), e); } String propertyValue = properties.get(processingProperty + "_Value"); if(propertyValue == null){ continue; } try { propertyValue = URLDecoder.decode(propertyValue, "UTF-8"); } catch (UnsupportedEncodingException e) { LOGGER.error(e.getMessage(), e); } String propertyActiveString = properties.get(processingProperty + "_Activator"); boolean proptertyActive = false; if(propertyActiveString != null){ if(propertyActiveString.equals("on")){ proptertyActive = true; } } if (propertyName != null) { Property prop = Property.Factory.newInstance(); prop.setName(propertyName); prop.setActive(proptertyActive); if (propertyValue != null) { prop.setStringValue(propertyValue); } propertyNumberPropertyMap.put(propertyNumber, prop); propArr.add(prop); } } Property[] arr = {}; arr = propertyNumberPropertyMap.values().toArray(arr); Arrays.sort(arr, new PropertyComparator()); return arr; } /** * generates a Format[] of the name value pairs in the map * @param properties map with name value pairs belonging to one entry * @return Format[] * @throws UnsupportedEncodingException */ private Format[] getFormatArray(HashMap<String, String> properties) throws UnsupportedEncodingException { Map<Integer, Format> formatNumberFormatMap = new HashMap<Integer, Format>(); for (String property : properties.keySet()) { /* * right now there are only Property and Format elements in the HashMap * here we are only interested in Format elements */ if(property.contains("Property")){ continue; } Integer formatNumber = Integer.parseInt(property.substring(property.indexOf("-") + 1, property.indexOf("_"))); if(formatNumberFormatMap.keySet().contains(formatNumber)){ continue; } String processingProperty = property.split("_")[0]; String formatMimeType = properties.get(processingProperty + "_Mime"); if(formatMimeType == null){ continue; } formatMimeType = URLDecoder.decode(formatMimeType, "UTF-8"); String formatEncoding = properties.get(processingProperty + "_Enc"); if(formatEncoding != null){ formatEncoding = URLDecoder.decode(formatEncoding, "UTF-8"); } String formatSchema = properties.get(processingProperty + "_Schem"); if(formatSchema != null){ formatSchema = URLDecoder.decode(formatSchema, "UTF-8"); } if (formatMimeType != null) { Format format = Format.Factory.newInstance(); format.setMimetype(formatMimeType); if (formatEncoding != null && !formatEncoding.equals("default")) { format.setEncoding(formatEncoding); } if (formatSchema != null) { format.setSchema(formatSchema); } formatNumberFormatMap.put(formatNumber, format); } } Format[] arr = {}; return formatNumberFormatMap.values().toArray(arr); } /** * Comparator class. Used for sorting Properties. Algorithm-Properties will be put at the end, * Algorithm names descending. * */ class PropertyComparator implements Comparator<Property>{ @Override public int compare(Property o1, Property o2) { String o1Name = o1.getName(); String o2Name = o2.getName(); if(o1Name.equals("Algorithm") && !o2Name.equals("Algorithm")){ return 1; }else if(!o1Name.equals("Algorithm") && o2Name.equals("Algorithm")){ return -1; }else if(o1Name.equals("Algorithm") && o2Name.equals("Algorithm")){ return o1.getStringValue().compareTo(o2.getStringValue()); }else{ return o1Name.compareTo(o2Name); } } } }