2005/5/9

     
 

Properties.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/util/Properties.h,v 1.24 2005/04/09 19:26:57 kommer Exp $
#ifndef acdk_util_Properties_h
#define acdk_util_Properties_h

#include <acdk.h>

#include <acdk/io/PrintWriter.h>
#include <acdk/io/Reader.h>

#include "HashMap.h"
#include "HashSet.h"

namespace acdk {
namespace util {



ACDK_DECL_CLASS(Properties);

/**
  used PropertiesChangeListener
*/
enum PropertiesChangeAction
{
  /**
    a single String was changed
  */
  PropChangeSetProperty       = 0x0001,
  /*
    a map of entries was changed
  */
  PropChangeSetMapProperty    = 0x0002,
  /**
    a array of string was changed
   */
  PropChangeSetArrayProperty  = 0x0004
};
ACDK_DEF_LIB_ENUM(ACDK_CORE_PUBLIC, PropertiesChangeAction);

ACDK_DECL_INTERFACE(PropertiesChangeListener);

/**
  interface to listen to changes on a Properties set.
  This callback is only called, if a modifing operation is
  called directly on the Properties.
  see also PropertiesChangeAction
*/
class ACDK_CORE_PUBLIC PropertiesChangeListener
      ACDK_INTERFACEBASE
{
  ACDK_WITH_METAINFO(PropertiesChangeListener)
public:
  /**
    Callback when Property was changed
    
    @param action see PropertiesChangeAction
    @param props the properties that was changed
    @param key the key changed
    @param value String, Map or StringArray, depending on action
  */
  virtual void propertyChanged(PropertiesChangeAction action, IN(RProperties) props, IN(RString) key, IN(acdk::lang::Object) value) = 0;
};

/**
  API: Java with extension<br/>

  @author Roger Rene Kommer (mailto:kommer@artefaktur.com)
  @version $Revision: 1.24 $
  @date $Date: 2005/04/09 19:26:57 $
  
*/
class ACDK_CORE_PUBLIC Properties
: extends HashMap
, implements ::acdk::io::Serializable
, implements ::acdk::lang::Cloneable
{
  ACDK_WITH_METAINFO(Properties)
protected:
  RProperties _defaults;
  RPropertiesChangeListenerArray _listener;
public:
  Properties(IN(RProperties) def = Nil);
  /**
    see RString getProperty(IN(RString) key, IN(RString) defaultValue, bool withDefaults = true);
  */
  RString getProperty(IN(RString) key);
  /**
    retrieve a property as String
    @param a key to the properties
    @param defaultValue will be returned if the property entry cannot be found
    @param withDefaults if true (default) the value will also be searched in the parent resp. default
           property set
    @return the found value or the param defaultValue if not found
  */
  RString getProperty(IN(RString) key, IN(RString) defaultValue, bool withDefaults = true);
  /**
    ACDK extension return a list of properties as map
    If keyStart is "my.prop" and the properties contains
    the values
      my.prop.a=A
      my.prop.b=B
      my.prop.c=C
    this method returns a map
      a => A
      b => B
      c => C
    
      If no element was found returns an empty map.

    This method computes the Map every time it will be called, so don't use it in inner loops.
    
  */
  RMap getMapProperty(IN(RString) keyStart, bool withDefaults = true);
  /**
    set the map of value/keys in current Property
    Before inserting all entries with starting keyStart + "." will be deleted
    @see getMapProperty
  */
  void setPropertyMap(IN(RString) keyStart, IN(RMap) map);
  
  /**
    ADCK extension return a list of property values a array
    if keyStart is "my.prop" and start = 1 (default is 0)
    and the properties contains following values:
      my.prop.1=A
      my.prop.2=C
      my.prop.3=B
      my.prop.5=X
    this method returns a string array containing "A", "C", "B"
    if no element was found returns an empty array
  */

  RStringArray getArrayProperty(IN(RString) keyStart, int start = 0, bool withDefaults = true);
  /**
    set the array of string in the current properties map
    Before inserting all entries with starting keyStart + "." will be deleted
    @param keyStart property key name
    @param values new values. If this is Nil only the old entries will be deleted
    @param start start number occour in the property keyname as keyStart.start
    @see getArrayProperty
  */
  void setArrayProperty(IN(RString) keyStart, IN(RStringArray) values, int start = 0);
  /**
    this method replaces $(KEY) with corresponding values in this properties.
    System::getProperties()->eval("$(ACDKHOME)/csf"); will expand for example to 
    "/artefaktur/acdk/csf" if ACDKHOME=/artefaktur/acdk
    If expr is "$(KEY)", but this property has no value for KEY the original expr
    will be in the resulting string.
    @param expr a string, which may contains $(KEY) 
    @param recursive call eval recursivelly, as long $(KEY) are in the evaluated string
  */
  RString eval(IN(RString) expr, bool recursive = false);
  /**
    writes the elements into the printwriter
  */
  void list(IN(acdk::io::RPrintWriter) out, bool withDefaults = true);
  /**
    Load a properties file using java literal decoding
  */
  void load(IN(acdk::io::RReader) in);
  /**
    get a iterator for all keys of this properties
    @param withDefaults if true (the default) also the names of parent resp. default
           property set will be returned
  */
  RIterator propertyNames(bool withDefaults = true);
  /**
    set the property value
  */
  acdk::lang::Object setProperty(IN(RString) key, IN(RString) value);

  void store(IN(acdk::io::RWriter) out, IN(RString) header, bool withDefaults = true);
  //void save(IN(acdk::io::RWriter) out, IN(RString) header, bool withDefaults = true);
  
  RProperties defaults() { return _defaults; }
  void setDefaults(IN(RProperties) defaults) { _defaults = defaults; }
  /** 
    merge existant properties with new properties.
    Property values with the same key from the new properties
    will be overwritten.
  */
  void mergeProperties(IN(RProperties) props);
  /**
    add a new listener
  */
  void addPropertyChangeListener(IN(RPropertiesChangeListener) listener);
  /**
    remove a previous added listener
    @param listener this has to be the same instance as previously added
  */
  void removePropertyChangeListener(IN(RPropertiesChangeListener) listener);
  /**
    Interface from cloneable.
    clone ignores all entries, where the key is not a string.
    clone only copy the reference, and do not clone the values itself
    clone will also clone Properties::_default.
  */
  foreign virtual acdk::lang::Object clone() { return clone(allocator()); }
  foreign virtual acdk::lang::Object clone(sys::Allocator* alloc);
  /**
    try to load properties file on given name.
    The name "acdk.util.MyProps" tries to load
    $ACDKHOME/cfg/acdk/util/MyProps.properties"
    @param name alternativally also acdk/util/MyProps notation is allowed
    @return Nil if not found
  */
  static RProperties loadProperties(IN(RString) name);
protected:
  static RString _format(IN(RString) key, IN(RString) value);
  /// deletes all entries with keys starting with keyStart in this properties
  foreign void _deleteKeys(IN(RString) keyStart); 
  /// used internally to notify listener
  foreign inline void _notifyListener(PropertiesChangeAction action, IN(RString) key, IN(acdk::lang::Object) obj)
  {
    if (_listener == Nil)
      return;
    _notifyListener2(action, key, obj);
  }
  foreign void _notifyListener2(PropertiesChangeAction action, IN(RString) key, IN(acdk::lang::Object) obj);
  friend class PropertiesIterator;
};


} // util
} // acdk

#endif //acdk_util_Properties_h