alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Groovy example source code file (ConfigObject.groovy)

This example Groovy source code file (ConfigObject.groovy) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

bufferedwriter, bufferedwriter, configobject, configobject, keywords, linkedhashmap, map, map, properties, properties, tab_character, tab_character*tab, url, writable

The Groovy ConfigObject.groovy source code

/*
 * Copyright 2003-2009 the original author or authors.
 *
 * Licensed 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 groovy.util

import org.codehaus.groovy.syntax.Types

/**
* A ConfigObject at a simple level is a Map that creates configuration entries (other ConfigObjects) when referencing them.
* This means that navigating to foo.bar.stuff will not return null but nested ConfigObjects which are of course empty maps
* The Groovy truth can be used to check for the existence of "real" entries.
*
* @author Graeme Rocher
* @since 1.5
*/
class ConfigObject extends LinkedHashMap implements Writable {

    static final KEYWORDS = Types.getKeywords()

    static final TAB_CHARACTER = '\t'

    /**
     * The config file that was used when parsing this ConfigObject
     */
    URL configFile

    ConfigObject(URL file) {
        this.configFile = file
    }

    ConfigObject() {}

    /**
     * Writes this config object into a String serialized representation which can later be parsed back using the parse()
     * method
     *
     * @see groovy.lang.Writable#writeTo(java.io.Writer)
     */
    Writer writeTo(Writer outArg) {
        def out
        try {
            out = new BufferedWriter(outArg)
            writeConfig("",this, out, 0, false)
        } finally {
            out.flush()
        }

        return outArg
    }
                  

    /**
     * Overrides the default getProperty implementation to create nested ConfigObject instances on demand
     * for non-existent keys
     */
    def getProperty(String name) {  
        if(name == 'configFile') return this.configFile
        if(!containsKey (name)) {
           ConfigObject prop = new ConfigObject(this.configFile)
           put(name, prop)
           return prop
        }
        return get(name)
    }
    
    /**
     * A ConfigObject is a tree structure consisting of nested maps. This flattens the maps into
     * a single level structure like a properties file
     */
    Map flatten() {
        return flatten(null)
    }

    /**
     * Flattens this ConfigObject populating the results into the target Map
     *
     * @see ConfigObject#flatten()
     */
    Map flatten(Map target) {
        if(target == null)target = new ConfigObject()
        populate("", target, this)
        target
    }

    /**
     * Merges the given map with this ConfigObject overriding any matching configuration entries in this ConfigObject
     *
     * @param other The ConfigObject to merge with
     * @return The result of the merge
     */
    Map merge(ConfigObject other) {
        return merge(this,other)
    }


    /**
     * Converts this ConfigObject into a the java.util.Properties format, flattening the tree structure beforehand
     * @return A java.util.Properties instance
     */
    Properties toProperties() {
        def props = new Properties()
        flatten(props)
        props = convertValuesToString(props)
        return props
    }

    /**
     * Converts this ConfigObject ino the java.util.Properties format, flatten the tree and prefixing all entries with the given prefix
     * @param prefix The prefix to append before property entries
     * @return A java.util.Properties instance
     */
    Properties toProperties(String prefix) {
        def props = new Properties()
        populate("${prefix}.", props, this)
        props = convertValuesToString(props)
        return props
    }

    private merge(Map config, Map other) {
        for(entry in other) {

            def configEntry = config[entry.key]
            if(configEntry == null) {
                config[entry.key] = entry.value
                continue
            }
            else {
                if(configEntry instanceof Map && configEntry.size() > 0 && entry.value instanceof Map) {
                    // recur
                    merge(configEntry, entry.value)
               }
               else {
                    config[entry.key] = entry.value
               }
            }
        }
        return config

    }

    private writeConfig(String prefix,ConfigObject map, out, Integer tab, boolean apply) {
        def space = apply ? TAB_CHARACTER*tab : ''
        for(key in map.keySet()) {
            def value = map.get(key)

            if(value instanceof ConfigObject) {
                if(!value.isEmpty()) {
                  def dotsInKeys = value.find { entry -> entry.key.indexOf('.') > -1 }
                  def configSize = value.size()
                  def firstKey = value.keySet().iterator().next()
                  def firstValue = value.values().iterator().next()
                  def firstSize
                  if(firstValue instanceof ConfigObject){
                      firstSize = firstValue.size()
                  }
                  else { firstSize = 1 }
                  if(configSize == 1|| dotsInKeys )  {

                      if(firstSize == 1 && firstValue instanceof ConfigObject) {
                          key = KEYWORDS.contains(key) ? key.inspect() : key
                          def writePrefix = "${prefix}${key}.${firstKey}."
                          writeConfig(writePrefix, firstValue, out, tab, true)
                      }
                      else if(!dotsInKeys && firstValue instanceof ConfigObject) {
                          writeNode(key, space, tab,value, out)
                      }  else {
                          for(j in value.keySet()) {
                              def v2 = value.get(j)
                              def k2 = j.indexOf('.') > -1 ? j.inspect() : j
                              if(v2 instanceof ConfigObject) {
                                  key = KEYWORDS.contains(key) ? key.inspect() : key
                                  writeConfig("${prefix}${key}", v2, out, tab, false)
                              }
                              else {
                                  writeValue("${key}.${k2}", space, prefix, v2, out)
                              }
                          }
                      }

                  }
                  else {
                      writeNode(key, space,tab, value, out)
                  }                  
                }
            }
            else {
                writeValue(key, space, prefix, value, out)
            }
        }
    }

    private writeValue(key, space, prefix, value, out) {
        key = key.indexOf('.') > -1 ? key.inspect() : key
        boolean isKeyword = KEYWORDS.contains(key)
        key = isKeyword ? key.inspect() : key

        if(!prefix && isKeyword) prefix = "this."
        out << "${space}${prefix}$key=${value.inspect()}"
        out.newLine()
    }

    private writeNode(key, space, tab, value, out) {
        key = KEYWORDS.contains(key) ? key.inspect() : key
        out << "${space}$key {"
        out.newLine()
        writeConfig("",value, out, tab+1, true)
        def last = "${space}}"
        out << last
        out.newLine()
    }

    private convertValuesToString(props) {
        def newProps = [:]
        for(e in props) {
            newProps[e.key] = e.value?.toString()
        }
        return newProps
    }

    private populate(suffix, config, map) {
        for(key in map.keySet()) {
            def value = map.get(key)
            if(value instanceof Map) {
                populate(suffix+"${key}.", config, value)
            }
            else {
                try {
                  config[suffix+key] = value
                }
                catch (java.lang.NullPointerException e) {
                    // it is idiotic story but if config map doesn't allow null values (like Hashtable)
                    // we can't do too much
                }
            }
        }
    }
}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy ConfigObject.groovy source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.