Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.taverna.configuration; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVPrinter; import org.apache.log4j.Logger; /** * A utility abstract class that simplifies implementing a Configurable. * <br> * <p>A concrete version of this class needs to define the name,category, * UUID string and the set of default values.</p> * * @author Stuart Owen * */ public abstract class AbstractConfigurable implements Configurable { private Map<String, String> propertyMap = new HashMap<String, String>(); private static Logger logger = Logger.getLogger(AbstractConfigurable.class); public static final String DELETED_VALUE_CODE = "~~DELETED~~"; private ConfigurationManager configurationManager; public Set<String> getKeys() { return getInternalPropertyMap().keySet(); } /** * Constructs the AbstractConfigurable by either reading from a previously stored set of properties, * or by using the default values which results in them being stored for subsequent usage. */ public AbstractConfigurable(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; try { configurationManager.populate(this); } catch (Exception e) { logger.error("There was an error reading the properties for the Configurable:" + getFilePrefix(), e); } } public synchronized String getProperty(String key) { String val = getInternalPropertyMap().get(key); if (val == null) val = getDefaultProperty(key); if (DELETED_VALUE_CODE.equals(val)) val = null; return val; } public String getDefaultProperty(String key) { return getDefaultPropertyMap().get(key); } protected void store() { try { configurationManager.store(this); } catch (Exception e) { logger.error("There was an error storing the new configuration for: " + this.getFilePrefix(), e); } } public void clear() { getInternalPropertyMap().clear(); } public synchronized void setProperty(String key, String value) { Object oldValue = getInternalPropertyMap().get(key); if (value == null) { deleteProperty(key); } else { getInternalPropertyMap().put(key, value); } if (value == null || !value.equals(oldValue)) { store(); } } /** * Provides access to the internal map. * <br> * Note that this map will contain entries for deleted values that also have corresponding default values. * For this reason using this map directly is discouraged, and #getProperty(String)} should be used instead. * @return */ public Map<String, String> getInternalPropertyMap() { return propertyMap; } public void restoreDefaults() { propertyMap.clear(); propertyMap.putAll(getDefaultPropertyMap()); store(); } public void deleteProperty(String key) { if (getDefaultPropertyMap().containsKey(key)) { propertyMap.put(key, DELETED_VALUE_CODE); } else { propertyMap.remove(key); } } /** * Returns an unmodifiable List<String> for the given key. Internally the value is stored as a single String, but converted to a list when calling this method. * <br> * The list is unmodifiable to prevent the mistake of trying <pre>getPropertyStringList(..).add("new element");</pre> which will not affect the stored * list. For the property to be updated this{@link #setPropertyStringList(String, List)} must be used. */ public List<String> getPropertyStringList(String key) { String value = getProperty(key); if (value != null) { return Collections.unmodifiableList(fromListText(value)); } else { return null; } } private List<String> fromListText(String property) { List<String> result = new ArrayList<String>(); if (property.length() > 0) { //an empty string as assumed to be an empty list, rather than a list with 1 empty string in it! StringReader reader = new StringReader(property); CSVParser csvReader = new CSVParser(reader); try { for (String v : csvReader.getLine()) { result.add(v); } } catch (IOException e) { logger.error("Exception occurred parsing CSV properties:" + property, e); } } return result; } /** * Set a value that is known to be a list. The value can be retrieved using this{@link #getPropertyStringList(String)} * <br> * Within the file, the value is stored as a single Comma Separated Value */ public void setPropertyStringList(String key, List<String> value) { setProperty(key, toListText(value)); } private String toListText(List<String> values) { StringWriter writer = new StringWriter(); CSVPrinter csvWriter = new CSVPrinter(writer); csvWriter.println(values.toArray(new String[] {})); return writer.getBuffer().toString().trim(); } }