View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  package org.apache.commons.configuration;
    18
    19  import java.math.BigDecimal;
    20  import java.math.BigInteger;
    21  import java.util.ArrayList;
    22  import java.util.Collection;
    23  import java.util.HashMap;
    24  import java.util.Iterator;
    25  import java.util.List;
    26  import java.util.Map;
    27  import java.util.Properties;
    28  import java.util.Set;
    29
    30  import org.apache.commons.configuration.event.ConfigurationErrorListener;
    31  import org.apache.commons.configuration.event.ConfigurationListener;
    32  import org.apache.commons.configuration.tree.ConfigurationNode;
    33  import org.apache.commons.configuration.tree.ExpressionEngine;
    34  import org.apache.commons.configuration.tree.NodeCombiner;
    35
    36  /***
    37   * DynamicCombinedConfiguration allows a set of CombinedConfigurations to be used. Each CombinedConfiguration
    38   * is referenced by a key that is dynamically constructed from a key pattern on each call. The key pattern
    39   * will be resolved using the configured ConfigurationInterpolator.
    40   * @since 1.6
    41   * @author <a
    42   * href="http://commons.apache.org/configuration/team-list.html">Commons
    43   * Configuration team</a>
    44   * @version $Id: DynamicCombinedConfiguration.java 727955 2008-12-19 07:06:16Z oheger $
    45   */
    46  public class DynamicCombinedConfiguration extends CombinedConfiguration
    47  {
    48      /***
    49       * Prevent recursion while resolving unprefixed properties.
    50       */
    51      private static ThreadLocal recursive = new ThreadLocal()
    52      {
    53          protected synchronized Object initialValue()
    54          {
    55              return Boolean.FALSE;
    56          }
    57      };
    58
    59      /*** The CombinedConfigurations */
    60      private Map configs = new HashMap();
    61
    62      /*** Stores a list with the contained configurations. */
    63      private List configurations = new ArrayList();
    64
    65      /*** Stores a map with the named configurations. */
    66      private Map namedConfigurations = new HashMap();
    67
    68      /*** The key pattern for the CombinedConfiguration map */
    69      private String keyPattern;
    70
    71      /*** Stores the combiner. */
    72      private NodeCombiner nodeCombiner;
    73
    74      /***
    75       * Creates a new instance of <code>CombinedConfiguration</code> and
    76       * initializes the combiner to be used.
    77       *
    78       * @param comb the node combiner (can be <b>null</b>, then a union combiner
    79       * is used as default)
    80       */
    81      public DynamicCombinedConfiguration(NodeCombiner comb)
    82      {
    83          super();
    84          setNodeCombiner(comb);
    85      }
    86
    87      /***
    88       * Creates a new instance of <code>CombinedConfiguration</code> that uses
    89       * a union combiner.
    90       *
    91       * @see org.apache.commons.configuration.tree.UnionCombiner
    92       */
    93      public DynamicCombinedConfiguration()
    94      {
    95          super();
    96      }
    97
    98      public void setKeyPattern(String pattern)
    99      {
    100         this.keyPattern = pattern;
    101     }
    102
    103     public String getKeyPattern()
    104     {
    105         return this.keyPattern;
    106     }
    107
    108     /***
    109      * Returns the node combiner that is used for creating the combined node
    110      * structure.
    111      *
    112      * @return the node combiner
    113      */
    114     public NodeCombiner getNodeCombiner()
    115     {
    116         return nodeCombiner;
    117     }
    118
    119     /***
    120      * Sets the node combiner. This object will be used when the combined node
    121      * structure is to be constructed. It must not be <b>null</b>, otherwise an
    122      * <code>IllegalArgumentException</code> exception is thrown. Changing the
    123      * node combiner causes an invalidation of this combined configuration, so
    124      * that the new combiner immediately takes effect.
    125      *
    126      * @param nodeCombiner the node combiner
    127      */
    128     public void setNodeCombiner(NodeCombiner nodeCombiner)
    129     {
    130         if (nodeCombiner == null)
    131         {
    132             throw new IllegalArgumentException(
    133                     "Node combiner must not be null!");
    134         }
    135         this.nodeCombiner = nodeCombiner;
    136         invalidateAll();
    137     }
    138     /***
    139      * Adds a new configuration to this combined configuration. It is possible
    140      * (but not mandatory) to give the new configuration a name. This name must
    141      * be unique, otherwise a <code>ConfigurationRuntimeException</code> will
    142      * be thrown. With the optional <code>at</code> argument you can specify
    143      * where in the resulting node structure the content of the added
    144      * configuration should appear. This is a string that uses dots as property
    145      * delimiters (independent on the current expression engine). For instance
    146      * if you pass in the string <code>&quot;database.tables&quot;</code>,
    147      * all properties of the added configuration will occur in this branch.
    148      *
    149      * @param config the configuration to add (must not be <b>null</b>)
    150      * @param name the name of this configuration (can be <b>null</b>)
    151      * @param at the position of this configuration in the combined tree (can be
    152      * <b>null</b>)
    153      */
    154     public void addConfiguration(AbstractConfiguration config, String name,
    155             String at)
    156     {
    157         ConfigData cd = new ConfigData(config, name, at);
    158         configurations.add(cd);
    159         if (name != null)
    160         {
    161             namedConfigurations.put(name, config);
    162         }
    163     }
    164        /***
    165      * Returns the number of configurations that are contained in this combined
    166      * configuration.
    167      *
    168      * @return the number of contained configurations
    169      */
    170     public int getNumberOfConfigurations()
    171     {
    172         return configurations.size();
    173     }
    174
    175     /***
    176      * Returns the configuration at the specified index. The contained
    177      * configurations are numbered in the order they were added to this combined
    178      * configuration. The index of the first configuration is 0.
    179      *
    180      * @param index the index
    181      * @return the configuration at this index
    182      */
    183     public Configuration getConfiguration(int index)
    184     {
    185         ConfigData cd = (ConfigData) configurations.get(index);
    186         return cd.getConfiguration();
    187     }
    188
    189     /***
    190      * Returns the configuration with the given name. This can be <b>null</b>
    191      * if no such configuration exists.
    192      *
    193      * @param name the name of the configuration
    194      * @return the configuration with this name
    195      */
    196     public Configuration getConfiguration(String name)
    197     {
    198         return (Configuration) namedConfigurations.get(name);
    199     }
    200
    201     /***
    202      * Returns a set with the names of all configurations contained in this
    203      * combined configuration. Of course here are only these configurations
    204      * listed, for which a name was specified when they were added.
    205      *
    206      * @return a set with the names of the contained configurations (never
    207      * <b>null</b>)
    208      */
    209     public Set getConfigurationNames()
    210     {
    211         return namedConfigurations.keySet();
    212     }
    213
    214     /***
    215      * Removes the configuration with the specified name.
    216      *
    217      * @param name the name of the configuration to be removed
    218      * @return the removed configuration (<b>null</b> if this configuration
    219      * was not found)
    220      */
    221     public Configuration removeConfiguration(String name)
    222     {
    223         Configuration conf = getConfiguration(name);
    224         if (conf != null)
    225         {
    226             removeConfiguration(conf);
    227         }
    228         return conf;
    229     }
    230
    231     /***
    232      * Removes the specified configuration from this combined configuration.
    233      *
    234      * @param config the configuration to be removed
    235      * @return a flag whether this configuration was found and could be removed
    236      */
    237     public boolean removeConfiguration(Configuration config)
    238     {
    239         for (int index = 0; index < getNumberOfConfigurations(); index++)
    240         {
    241             if (((ConfigData) configurations.get(index)).getConfiguration() == config)
    242             {
    243                 removeConfigurationAt(index);
    244
    245             }
    246         }
    247
    248         return super.removeConfiguration(config);
    249     }
    250
    251     /***
    252      * Removes the configuration at the specified index.
    253      *
    254      * @param index the index
    255      * @return the removed configuration
    256      */
    257     public Configuration removeConfigurationAt(int index)
    258     {
    259         ConfigData cd = (ConfigData) configurations.remove(index);
    260         if (cd.getName() != null)
    261         {
    262             namedConfigurations.remove(cd.getName());
    263         }
    264         return super.removeConfigurationAt(index);
    265     }
    266     /***
    267      * Returns the configuration root node of this combined configuration. This
    268      * method will construct a combined node structure using the current node
    269      * combiner if necessary.
    270      *
    271      * @return the combined root node
    272      */
    273     public ConfigurationNode getRootNode()
    274     {
    275         return getCurrentConfig().getRootNode();
    276     }
    277
    278     public void setRootNode(ConfigurationNode rootNode)
    279     {
    280         if (configs != null)
    281         {
    282             this.getCurrentConfig().setRootNode(rootNode);
    283         }
    284         else
    285         {
    286             super.setRootNode(rootNode);
    287         }
    288     }
    289
    290     public void addProperty(String key, Object value)
    291     {
    292         this.getCurrentConfig().addProperty(key, value);
    293     }
    294
    295     public void clear()
    296     {
    297         if (configs != null)
    298         {
    299             this.getCurrentConfig().clear();
    300         }
    301     }
    302
    303     public void clearProperty(String key)
    304     {
    305         this.getCurrentConfig().clearProperty(key);
    306     }
    307
    308     public boolean containsKey(String key)
    309     {
    310         return this.getCurrentConfig().containsKey(key);
    311     }
    312
    313     public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
    314     {
    315         return this.getCurrentConfig().getBigDecimal(key, defaultValue);
    316     }
    317
    318     public BigDecimal getBigDecimal(String key)
    319     {
    320         return this.getCurrentConfig().getBigDecimal(key);
    321     }
    322
    323     public BigInteger getBigInteger(String key, BigInteger defaultValue)
    324     {
    325         return this.getCurrentConfig().getBigInteger(key, defaultValue);
    326     }
    327
    328     public BigInteger getBigInteger(String key)
    329     {
    330         return this.getCurrentConfig().getBigInteger(key);
    331     }
    332
    333     public boolean getBoolean(String key, boolean defaultValue)
    334     {
    335         return this.getCurrentConfig().getBoolean(key, defaultValue);
    336     }
    337
    338     public Boolean getBoolean(String key, Boolean defaultValue)
    339     {
    340         return this.getCurrentConfig().getBoolean(key, defaultValue);
    341     }
    342
    343     public boolean getBoolean(String key)
    344     {
    345         return this.getCurrentConfig().getBoolean(key);
    346     }
    347
    348     public byte getByte(String key, byte defaultValue)
    349     {
    350         return this.getCurrentConfig().getByte(key, defaultValue);
    351     }
    352
    353     public Byte getByte(String key, Byte defaultValue)
    354     {
    355         return this.getCurrentConfig().getByte(key, defaultValue);
    356     }
    357
    358     public byte getByte(String key)
    359     {
    360         return this.getCurrentConfig().getByte(key);
    361     }
    362
    363     public double getDouble(String key, double defaultValue)
    364     {
    365         return this.getCurrentConfig().getDouble(key, defaultValue);
    366     }
    367
    368     public Double getDouble(String key, Double defaultValue)
    369     {
    370         return this.getCurrentConfig().getDouble(key, defaultValue);
    371     }
    372
    373     public double getDouble(String key)
    374     {
    375         return this.getCurrentConfig().getDouble(key);
    376     }
    377
    378     public float getFloat(String key, float defaultValue)
    379     {
    380         return this.getCurrentConfig().getFloat(key, defaultValue);
    381     }
    382
    383     public Float getFloat(String key, Float defaultValue)
    384     {
    385         return this.getCurrentConfig().getFloat(key, defaultValue);
    386     }
    387
    388     public float getFloat(String key)
    389     {
    390         return this.getCurrentConfig().getFloat(key);
    391     }
    392
    393     public int getInt(String key, int defaultValue)
    394     {
    395         return this.getCurrentConfig().getInt(key, defaultValue);
    396     }
    397
    398     public int getInt(String key)
    399     {
    400         return this.getCurrentConfig().getInt(key);
    401     }
    402
    403     public Integer getInteger(String key, Integer defaultValue)
    404     {
    405         return this.getCurrentConfig().getInteger(key, defaultValue);
    406     }
    407
    408     public Iterator getKeys()
    409     {
    410         return this.getCurrentConfig().getKeys();
    411     }
    412
    413     public Iterator getKeys(String prefix)
    414     {
    415         return this.getCurrentConfig().getKeys(prefix);
    416     }
    417
    418     public List getList(String key, List defaultValue)
    419     {
    420         return this.getCurrentConfig().getList(key, defaultValue);
    421     }
    422
    423     public List getList(String key)
    424     {
    425         return this.getCurrentConfig().getList(key);
    426     }
    427
    428     public long getLong(String key, long defaultValue)
    429     {
    430         return this.getCurrentConfig().getLong(key, defaultValue);
    431     }
    432
    433     public Long getLong(String key, Long defaultValue)
    434     {
    435         return this.getCurrentConfig().getLong(key, defaultValue);
    436     }
    437
    438     public long getLong(String key)
    439     {
    440         return this.getCurrentConfig().getLong(key);
    441     }
    442
    443     public Properties getProperties(String key)
    444     {
    445         return this.getCurrentConfig().getProperties(key);
    446     }
    447
    448     public Object getProperty(String key)
    449     {
    450         return this.getCurrentConfig().getProperty(key);
    451     }
    452
    453     public short getShort(String key, short defaultValue)
    454     {
    455         return this.getCurrentConfig().getShort(key, defaultValue);
    456     }
    457
    458     public Short getShort(String key, Short defaultValue)
    459     {
    460         return this.getCurrentConfig().getShort(key, defaultValue);
    461     }
    462
    463     public short getShort(String key)
    464     {
    465         return this.getCurrentConfig().getShort(key);
    466     }
    467
    468     public String getString(String key, String defaultValue)
    469     {
    470         return this.getCurrentConfig().getString(key, defaultValue);
    471     }
    472
    473     public String getString(String key)
    474     {
    475         return this.getCurrentConfig().getString(key);
    476     }
    477
    478     public String[] getStringArray(String key)
    479     {
    480         return this.getCurrentConfig().getStringArray(key);
    481     }
    482
    483     public boolean isEmpty()
    484     {
    485         return this.getCurrentConfig().isEmpty();
    486     }
    487
    488     public void setProperty(String key, Object value)
    489     {
    490         if (configs != null)
    491         {
    492             this.getCurrentConfig().setProperty(key, value);
    493         }
    494     }
    495
    496     public Configuration subset(String prefix)
    497     {
    498         return this.getCurrentConfig().subset(prefix);
    499     }
    500
    501     public Node getRoot()
    502     {
    503         return this.getCurrentConfig().getRoot();
    504     }
    505
    506     public void setRoot(Node node)
    507     {
    508         if (configs != null)
    509         {
    510             this.getCurrentConfig().setRoot(node);
    511         }
    512         else
    513         {
    514             super.setRoot(node);
    515         }
    516     }
    517
    518     public ExpressionEngine getExpressionEngine()
    519     {
    520         return super.getExpressionEngine();
    521     }
    522
    523     public void setExpressionEngine(ExpressionEngine expressionEngine)
    524     {
    525         super.setExpressionEngine(expressionEngine);
    526     }
    527
    528     public void addNodes(String key, Collection nodes)
    529     {
    530         this.getCurrentConfig().addNodes(key, nodes);
    531     }
    532
    533     public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
    534     {
    535         return this.getCurrentConfig().configurationAt(key, supportUpdates);
    536     }
    537
    538     public SubnodeConfiguration configurationAt(String key)
    539     {
    540         return this.getCurrentConfig().configurationAt(key);
    541     }
    542
    543     public List configurationsAt(String key)
    544     {
    545         return this.getCurrentConfig().configurationsAt(key);
    546     }
    547
    548     public void clearTree(String key)
    549     {
    550         this.getCurrentConfig().clearTree(key);
    551     }
    552
    553     public int getMaxIndex(String key)
    554     {
    555         return this.getCurrentConfig().getMaxIndex(key);
    556     }
    557
    558     public Configuration interpolatedConfiguration()
    559     {
    560         return this.getCurrentConfig().interpolatedConfiguration();
    561     }
    562
    563
    564     /***
    565      * Returns the configuration source, in which the specified key is defined.
    566      * This method will determine the configuration node that is identified by
    567      * the given key. The following constellations are possible:
    568      * <ul>
    569      * <li>If no node object is found for this key, <b>null</b> is returned.</li>
    570      * <li>If the key maps to multiple nodes belonging to different
    571      * configuration sources, a <code>IllegalArgumentException</code> is
    572      * thrown (in this case no unique source can be determined).</li>
    573      * <li>If exactly one node is found for the key, the (child) configuration
    574      * object, to which the node belongs is determined and returned.</li>
    575      * <li>For keys that have been added directly to this combined
    576      * configuration and that do not belong to the namespaces defined by
    577      * existing child configurations this configuration will be returned.</li>
    578      * </ul>
    579      *
    580      * @param key the key of a configuration property
    581      * @return the configuration, to which this property belongs or <b>null</b>
    582      * if the key cannot be resolved
    583      * @throws IllegalArgumentException if the key maps to multiple properties
    584      * and the source cannot be determined, or if the key is <b>null</b>
    585      */
    586     public Configuration getSource(String key)
    587     {
    588         if (key == null)
    589         {
    590             throw new IllegalArgumentException("Key must not be null!");
    591         }
    592         return getCurrentConfig().getSource(key);
    593     }
    594
    595     public void addConfigurationListener(ConfigurationListener l)
    596     {
    597         super.addConfigurationListener(l);
    598
    599         Iterator iter = configs.values().iterator();
    600         while (iter.hasNext())
    601         {
    602             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    603             config.addConfigurationListener(l);
    604         }
    605     }
    606
    607     public boolean removeConfigurationListener(ConfigurationListener l)
    608     {
    609         Iterator iter = configs.values().iterator();
    610         while (iter.hasNext())
    611         {
    612             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    613             config.removeConfigurationListener(l);
    614         }
    615         return super.removeConfigurationListener(l);
    616     }
    617
    618     public Collection getConfigurationListeners()
    619     {
    620         return super.getConfigurationListeners();
    621     }
    622
    623     public void clearConfigurationListeners()
    624     {
    625         Iterator iter = configs.values().iterator();
    626         while (iter.hasNext())
    627         {
    628             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    629             config.clearConfigurationListeners();
    630         }
    631         super.clearConfigurationListeners();
    632     }
    633
    634     public void addErrorListener(ConfigurationErrorListener l)
    635     {
    636         Iterator iter = configs.values().iterator();
    637         while (iter.hasNext())
    638         {
    639             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    640             config.addErrorListener(l);
    641         }
    642         super.addErrorListener(l);
    643     }
    644
    645     public boolean removeErrorListener(ConfigurationErrorListener l)
    646     {
    647         Iterator iter = configs.values().iterator();
    648         while (iter.hasNext())
    649         {
    650             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    651             config.removeErrorListener(l);
    652         }
    653         return super.removeErrorListener(l);
    654     }
    655
    656     public void clearErrorListeners()
    657     {
    658         Iterator iter = configs.values().iterator();
    659         while (iter.hasNext())
    660         {
    661             CombinedConfiguration config = (CombinedConfiguration) iter.next();
    662             config.clearErrorListeners();
    663         }
    664         super.clearErrorListeners();
    665     }
    666
    667     public Collection getErrorListeners()
    668     {
    669         return super.getErrorListeners();
    670     }
    671
    672
    673
    674     /***
    675      * Returns a copy of this object. This implementation performs a deep clone,
    676      * i.e. all contained configurations will be cloned, too. For this to work,
    677      * all contained configurations must be cloneable. Registered event
    678      * listeners won't be cloned. The clone will use the same node combiner than
    679      * the original.
    680      *
    681      * @return the copied object
    682      */
    683     public Object clone()
    684     {
    685         return super.clone();
    686     }
    687
    688
    689
    690     /***
    691      * Invalidates the current combined configuration. This means that the next time a
    692      * property is accessed the combined node structure must be re-constructed.
    693      * Invalidation of a combined configuration also means that an event of type
    694      * <code>EVENT_COMBINED_INVALIDATE</code> is fired. Note that while other
    695      * events most times appear twice (once before and once after an update),
    696      * this event is only fired once (after update).
    697      */
    698     public void invalidate()
    699     {
    700         getCurrentConfig().invalidate();
    701     }
    702
    703     public void invalidateAll()
    704     {
    705         if (configs == null)
    706         {
    707             return;
    708         }
    709         Iterator iter = configs.values().iterator();
    710         while (iter.hasNext())
    711         {
    712            CombinedConfiguration config = (CombinedConfiguration) iter.next();
    713            config.invalidate();
    714         }
    715     }
    716
    717     /*
    718      * Don't allow resolveContainerStore to be called recursively.
    719      * @param key The key to resolve.
    720      * @return The value of the key.
    721      */
    722     protected Object resolveContainerStore(String key)
    723     {
    724         if (((Boolean) recursive.get()).booleanValue())
    725         {
    726             return null;
    727         }
    728         recursive.set(Boolean.TRUE);
    729         try
    730         {
    731             return super.resolveContainerStore(key);
    732         }
    733         finally
    734         {
    735             recursive.set(Boolean.FALSE);
    736         }
    737     }
    738
    739     private CombinedConfiguration getCurrentConfig()
    740     {
    741         String key = getSubstitutor().replace(keyPattern);
    742         CombinedConfiguration config;
    743         synchronized (getNodeCombiner())
    744         {
    745             config = (CombinedConfiguration) configs.get(key);
    746             if (config == null)
    747             {
    748                 config = new CombinedConfiguration(getNodeCombiner());
    749                 config.setExpressionEngine(this.getExpressionEngine());
    750                 Iterator iter = config.getErrorListeners().iterator();
    751                 while (iter.hasNext())
    752                 {
    753                     ConfigurationErrorListener listener = (ConfigurationErrorListener) iter.next();
    754                     config.addErrorListener(listener);
    755                 }
    756                 iter = config.getConfigurationListeners().iterator();
    757                 while (iter.hasNext())
    758                 {
    759                     ConfigurationListener listener = (ConfigurationListener) iter.next();
    760                     config.addConfigurationListener(listener);
    761                 }
    762                 config.setForceReloadCheck(isForceReloadCheck());
    763                 iter = configurations.iterator();
    764                 while (iter.hasNext())
    765                 {
    766                     ConfigData data = (ConfigData) iter.next();
    767                     config.addConfiguration(data.getConfiguration(), data.getName(),
    768                             data.getAt());
    769                 }
    770                 configs.put(key, config);
    771             }
    772         }
    773         return config;
    774     }
    775
    776     /***
    777      * Internal class that identifies each Configuration.
    778      */
    779     static class ConfigData
    780     {
    781         /*** Stores a reference to the configuration. */
    782         private AbstractConfiguration configuration;
    783
    784         /*** Stores the name under which the configuration is stored. */
    785         private String name;
    786
    787         /*** Stores the at string.*/
    788         private String at;
    789
    790                 /***
    791          * Creates a new instance of <code>ConfigData</code> and initializes
    792          * it.
    793          *
    794          * @param config the configuration
    795          * @param n the name
    796          * @param at the at position
    797          */
    798         public ConfigData(AbstractConfiguration config, String n, String at)
    799         {
    800             configuration = config;
    801             name = n;
    802             this.at = at;
    803         }
    804
    805                 /***
    806          * Returns the stored configuration.
    807          *
    808          * @return the configuration
    809          */
    810         public AbstractConfiguration getConfiguration()
    811         {
    812             return configuration;
    813         }
    814
    815         /***
    816          * Returns the configuration's name.
    817          *
    818          * @return the name
    819          */
    820         public String getName()
    821         {
    822             return name;
    823         }
    824
    825         /***
    826          * Returns the at position of this configuration.
    827          *
    828          * @return the at position
    829          */
    830         public String getAt()
    831         {
    832             return at;
    833         }
    834
    835     }
    836 }