001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2014-08-20 00:55:58 +0000 (Wed, 20 Aug 2014) $' 
007 * '$Revision: 32897 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.configuration;
031
032import java.util.ArrayList;
033import java.util.LinkedHashMap;
034import java.util.LinkedList;
035import java.util.List;
036import java.util.Map;
037
038import org.kepler.build.modules.Module;
039
040/** A collection of utilities to manage configuration properties.
041 * 
042 * @author Daniel Crawl
043 * @version $Id: ConfigurationUtilities.java 32897 2014-08-20 00:55:58Z crawl $
044 */
045public class ConfigurationUtilities 
046{
047    
048    /** Return a map from a list of name value pairs contained in a property.
049     *  This returns pairs any any depth of the property.
050     */
051    public static Map<String,String> getPairsMap(ConfigurationProperty property)
052    {
053        return getPairsMap(property, true);
054    }
055    
056    /** Return a map of name value pairs contained in a property.
057     *  @param property the property
058     *  @param recurse if true, look at all depths in the property for pairs.
059     *  if false, only return pairs from the top level.
060     */
061    public static Map<String,String> getPairsMap(ConfigurationProperty property, boolean recurse)
062    {
063        // NOTE: use a LinkedHashMap for predictable iteration order,
064        // e.g., so that the context menu items are always in the same order.
065        Map<String,String> retval = new LinkedHashMap<String,String>();
066        
067        List<ConfigurationProperty> nameList = property.getProperties("pair.name");
068        for(ConfigurationProperty nameProperty : nameList)
069        {
070            ConfigurationProperty parentProperty = nameProperty.getParent();
071            
072            if(parentProperty.getParent() == property || recurse) {
073                ConfigurationProperty valueProperty = parentProperty.getProperty("value");
074                if(valueProperty == null) {
075                    System.err.println("WARNING: missing value property in pair: " + nameProperty);
076                } else {
077                    retval.put(nameProperty.getValue(), valueProperty.getValue());
078                }
079            }
080        }
081        return retval;
082    }
083
084    /** Get a map of name value pairs in the property where each key can have multiple values. */
085    public static Map<String,List<String>> getMultiValuePairsMap(ConfigurationProperty property) {
086        
087        Map<String,List<String>> retval = new LinkedHashMap<String,List<String>>();
088        
089        List<ConfigurationProperty> nameList = property.getProperties("pair.name");
090        for(ConfigurationProperty nameProperty : nameList)
091        {
092            ConfigurationProperty parentProperty = nameProperty.getParent();
093            ConfigurationProperty valueProperty = parentProperty.getProperty("value");
094            if(valueProperty == null) {
095                System.err.println("WARNING: missing value property in pair: " + nameProperty);
096            } else {
097                String nameValue = nameProperty.getValue();
098                List<String> values = retval.get(nameValue);
099                if(values == null) {
100                    values = new LinkedList<String>();
101                    retval.put(nameValue,  values);
102                }
103                values.add(valueProperty.getValue());
104            }
105        }
106        return retval;
107    }
108    
109    /** Copy all the properties in a namespace from one module to another.
110     *  NOTE: the changes to the destination are not saved. 
111     *  
112     */
113    public static void copyAllProperties(String namespaceStr, String destModuleName, String srcModuleName)
114    {
115        copyProperties(namespaceStr, destModuleName, srcModuleName, null, null, false);
116    }
117
118    /** Copy a property or set of properties from one module to another using the default namespace.
119     *  NOTE: the changes to the destination are not saved. 
120     *  @param destModuleName name of destination module
121     *  @param srcModuleName name of source module
122     *  @param destPropertyName name of destination property
123     *  @param srcPropertyName name of property or properties in source module to copy. Can use "a.b.c"
124     *  format to denote a nested name.
125     */
126    public static void copyProperties(String destModuleName, String srcModuleName,
127            String destPropertyName, String srcPropertyNames)
128    {
129        copyProperties(ConfigurationProperty.namespaceDefault.getNamespace(), destModuleName, srcModuleName,
130                destPropertyName, srcPropertyNames, false);
131    }
132         
133    /** Copy a property or set of properties from one module to another for a specific namespace.
134     *  @param namespaceStr the namespace 
135     *  @param destModuleName name of destination module
136     *  @param srcModuleName name of source module
137     *  @param destPropertyName name of destination property
138     *  @param srcPropertyName name of property or properties in source module to copy. Can use "a.b.c"
139     *  format to denote a nested name.
140     *  @param setDirty If true, set the destination property dirty so that it will be saved.
141     */
142    public static void copyProperties(String namespaceStr, String destModuleName, String srcModuleName,
143        String destPropertyName, String srcPropertyNames, boolean setDirty)
144    {
145        final ConfigurationNamespace namespace = new ConfigurationNamespace(namespaceStr);
146
147        final ConfigurationManager manager = ConfigurationManager.getInstance();
148        
149        final Module destModule = ConfigurationManager.getModule(destModuleName);
150        final ConfigurationProperty destRoot = manager.getProperty(destModule, namespace);
151        final ConfigurationProperty destProperty;
152        if(destPropertyName != null)
153        {
154            destProperty = destRoot.getProperty(destPropertyName);
155        }
156        else
157        {
158            destProperty = destRoot;
159        }
160
161        final Module srcModule = ConfigurationManager.getModule(srcModuleName);
162        final ConfigurationProperty srcRoot = manager.getProperty(srcModule, namespace);
163        final List<ConfigurationProperty> srcProperties;
164        if(srcPropertyNames != null)
165        {
166            srcProperties = srcRoot.getProperties(srcPropertyNames);
167        }
168        else
169        {
170            srcProperties = srcRoot.getProperties();
171        }
172
173        for(ConfigurationProperty property : srcProperties)
174        {
175            try 
176            {
177                // only add the property if it is not already there
178                destProperty.addPropertyIfNotThere(property, setDirty);
179            }
180            catch (Exception e)
181            {
182                System.out.println("Could not add property: " + e.getMessage());
183            }
184        }
185        
186    }
187    
188    /** Copy a property or set of properties from one module to specific top level indices of another 
189     *  for a specific namespace.
190     *  @param namespaceStr the namespace 
191     *  @param destModuleName name of destination module
192     *  @param srcModuleName name of source module
193     *  @param destPropertyName name of destination property
194     *  @param srcPropertyName name of property or properties in source module to copy. Can use "a.b.c"
195     *  format to denote a nested name.
196     *  @param indices top level destination indices where properties will be placed
197     * @throws Exception 
198     */
199    public static void copyPropertiesToIndices(String namespaceStr, String destModuleName, String srcModuleName,
200        String destPropertyName, String srcPropertyNames, ArrayList<Integer> indices) throws Exception
201    {
202        
203        final ConfigurationNamespace namespace = new ConfigurationNamespace(namespaceStr);
204
205        final ConfigurationManager manager = ConfigurationManager.getInstance();
206        
207        final Module destModule = ConfigurationManager.getModule(destModuleName);
208        final ConfigurationProperty destRoot = manager.getProperty(destModule, namespace);
209        final ConfigurationProperty destProperty;
210        if(destPropertyName != null)
211        {
212            destProperty = destRoot.getProperty(destPropertyName);
213        }
214        else
215        {
216            destProperty = destRoot;
217        }
218
219        final Module srcModule = ConfigurationManager.getModule(srcModuleName);
220        final ConfigurationProperty srcRoot = manager.getProperty(srcModule, namespace);
221        final List<ConfigurationProperty> srcProperties;
222        if(srcPropertyNames != null)
223        {
224            srcProperties = srcRoot.getProperties(srcPropertyNames);
225        }
226        else
227        {
228            srcProperties = srcRoot.getProperties();
229        }
230
231        if (srcProperties.size() != indices.size()){
232                        throw new Exception("ConfigurationUtilities.copyPropertiesToIndices could not add " +
233                                        "properties because srcProperties.size():"+ srcProperties.size() + " != " +
234                                        "indices.size()" + indices.size());
235        }
236        
237        int index = 0;
238        for(ConfigurationProperty property : srcProperties)
239        {
240            try 
241            {
242                // only add the property if it is not already there
243                destProperty.addPropertyIfNotThereAtIndex(indices.get(index), property);
244                index++;
245            }
246            catch (Exception e)
247            {
248                System.out.println("Could not add property: " + e.getMessage());
249            }
250        }        
251    }
252    
253}