Package com.substanceofcode.utils

Source Code of com.substanceofcode.utils.Settings

/*
* Settings.java
*
* Copyright (C) 2005-2006 Tommi Laukkanen
* http://www.substanceofcode.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*/

// Expand to define CLDC define
//#define DCLDCV10
// Expand to define logging define
//#define DNOLOGGING
// Expand to define test define
//#define DNOTEST
// Expand to define compatibility
//#define DNOCOMPAT
//#ifdef DCOMPATIBILITY1
//#define DCOMPATIBILITY12
//#elifdef DCOMPATIBILITY2
//#define DCOMPATIBILITY12
//#endif
package com.substanceofcode.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;

import com.substanceofcode.utils.CauseException;
import com.substanceofcode.utils.CauseRecStoreException;
import com.substanceofcode.utils.CauseMemoryException;

//#ifdef DLOGGING
//@import net.sf.jlogmicro.util.logging.Logger;
//@import net.sf.jlogmicro.util.logging.Level;
//#endif

/**
* A class for storing and retrieving application settings and properties.
* Class stores all settings into one Hashtable variable. Hashtable is loaded
* from RecordStore at initialization and it is stored back to the RecordStore
* with save method.
*
* @author  Tommi Laukkanen
* @version 1.0
*/
public class Settings {
   
    public static final int OLD_MAX_REGIONS = 1;
  //#ifdef DCOMPATIBILITY2
//@    public static final int MAX_REGIONS = 10;
  //#else
    public static final int MAX_REGIONS = 15;
  //#endif
    public static final String SETTINGS_NAME = "RssReader-setttings-vers";
  // The first settings did not have a version, so it ends up being
  // "" by default
    public static final String FIRST_SETTINGS_VERS = "";
    public static final String ITUNES_CAPABLE_VERS = "3";
    public static final String ENCODING_VERS = "4";
    public static final String ITEMS_ENCODED = "items-encoded";
    public static final String STORE_DATE = "store-date";
  //#ifdef DCOMPATIBILITY2
//@    public static final String SETTINGS_VERS = "2";
  //#elifdef DCOMPATIBILITY3
//@    public static final String SETTINGS_VERS = ITUNES_CAPABLE_VERS;
  //#else
    public static final String SETTINGS_VERS = ENCODING_VERS;
  //#endif
    private static Settings m_store;
    final private static String RECORD_STORE_NAME = "Store";
    private MIDlet          m_midlet;
    private boolean         m_valuesChanged = false;
    private boolean         m_initialized = true;
    private Hashtable       m_properties = new Hashtable();
    private int             m_region;
  //#ifdef DLOGGING
//@    private Logger logger = Logger.getLogger("Settings");
//@    private boolean fineLoggable = logger.isLoggable(Level.FINE);
//@    private boolean finestLoggable = logger.isLoggable(Level.FINEST);
  //#endif
   
    /**
     * Singleton pattern is used to return
     * only one instance of record store
     */
  //#ifdef DCLDCV11
//@    public static Settings getInstance( MIDlet midlet )
  //#else
    public static synchronized Settings getInstance( MIDlet midlet )
  //#endif
    throws IOException, CauseRecStoreException, CauseException {
    //#ifdef DCLDCV11
//@    synchronized(Settings.class) {
    //#endif
      if( m_store == null ) {
        m_store = new Settings( midlet );
      }
      return m_store;
    //#ifdef DCLDCV11
//@    }
    //#endif
    }

    /** Constructor */
    private Settings( MIDlet midlet )
    throws IOException, CauseRecStoreException, CauseException {
        m_midlet = midlet;
        load(0);
    }
   
    /** Return true if value exists in record store */
    private boolean exists( String name ) {
        return getProperty( name ) != null;
    }
   
    /** Get property from Hashtable*/
    private String getProperty( String name ) {
    synchronized(this) {
      String value = (String) m_properties.get( name );
      if( value == null && m_midlet != null ) {
        value = m_midlet.getAppProperty( name );
        if( value != null ) {
          m_properties.put( name, value );
        }
      }
      return value;
    }
    }
   
    /** Get boolean property */
    public boolean getBooleanProperty( String name, boolean defaultValue) {
        String value = getProperty( name );
        if( value != null ) {
            return value.equals( "true" ) || value.equals( "1" );
        }
        return defaultValue;
    }
   
    /** Get integer property */
    public int getIntProperty( String name, int defaultValue ) {
        String value = getProperty( name );
        if( value != null ) {
            try {
                return Integer.parseInt( value );
            } catch( NumberFormatException e ) {
            }
        }
        return defaultValue;
    }
   
    /** Get long property */
    public long getLongProperty( String name, long defaultValue ) {
        String value = getProperty( name );
        if( value != null ) {
            try {
                return Long.parseLong( value );
            } catch( NumberFormatException e ) {
        //#ifdef DLOGGING
//@        logger.warning("Warning parsing long name,value=" + name + "," + value, e);
        //#endif
            }
        }
        return defaultValue;
    }
   
  /** Locate the specified region if the current region is not already
      region.
  */
    final private void locateRegion(int region)
  throws CauseRecStoreException, CauseException {
    if (region != m_region) {
      try {
        load(region);
      } catch (IOException e) {
        CauseException ce = new CauseException(
            "IOException while loading region=" + region);
        //#ifdef DLOGGING
//@        logger.severe(ce.getMessage(), e);
        //#endif
        /** Error while executing constructor */
        System.out.println(ce.getMessage() + e.getMessage());
        e.printStackTrace();
        throw ce;
      } catch (CauseRecStoreException e) {
        throw e;
      } catch (CauseException e) {
        throw e;
      } catch (Exception e) {
        CauseException ce = new CauseException(
            "Internal error during load name,region=" + region);
        //#ifdef DLOGGING
//@        logger.severe(ce.getMessage(), e);
        //#endif
        System.out.println(ce.getMessage() + e.getMessage());
        e.printStackTrace();
        throw ce;
      }
    }
  }

    /** Get string property */
    public String getStringProperty(int region, String name,
                              String defaultValue )
  throws CauseRecStoreException, CauseException {
    locateRegion( region );
        Object value = getProperty( name );
        return ( value != null ) ? value.toString() : defaultValue;
    }
   
    /** Get string property */
    public String getStringProperty(String name, String defaultValue ) {
    try {
      return getStringProperty(0, name, defaultValue );
    } catch (Exception e) {
      System.out.println("load error");
      //#ifdef DLOGGING
//@      logger.severe("getStringProperty error =" + name, e);
      //#endif
      return defaultValue;
    }
    }
   
    /** Load properties from record store */
    private void load(int region)
    throws IOException, CauseRecStoreException, CauseException {
    synchronized(this) {
      RecordStore rs = null;
      ByteArrayInputStream bin = null;
      DataInputStream din = null;
     
      m_valuesChanged = false;
      m_properties.clear();
      boolean currentSettings = true;
      int numRecs = 0;
     
      try {
        rs = RecordStore.openRecordStore(RECORD_STORE_NAME, true );
        numRecs = rs.getNumRecords();
        boolean hasRec = false;
        //#ifdef DLOGGING
//@        if (fineLoggable) {logger.fine("region=" + region);}
//@        if (finestLoggable) {logger.finest("numRecs=" + numRecs);}
        //#endif
        //#ifdef DTEST
//@        System.out.println("region=" + region);
//@        System.out.println("numRecs=" + numRecs);
        //#endif
        if( numRecs == 0 ) {
          if (region == 0) {
            m_initialized = false;
            //#ifdef DLOGGING
//@            if (finestLoggable) {logger.finest("m_initialized=" + m_initialized);}
            //#endif
          }
        } else {
          if ( numRecs == OLD_MAX_REGIONS ) {
            currentSettings = false;
          }
          byte[] data = rs.getRecord( region + 1 );
          //#ifdef DLOGGING
//@          if (fineLoggable) {logger.fine("currentSettings,data.length=" + currentSettings + "," + ((data == null) ? "null" : Integer.toString(data.length)));}
          //#endif
          //#ifdef DTEST
//@          System.out.println("currentSettings,data.length=" + currentSettings + "," + ((data == null) ? "null" : Integer.toString(data.length)));
          //#endif
          if( data != null ) {
            bin = new ByteArrayInputStream( data );
            din = new DataInputStream( bin );
            int num = din.readInt();
            while( num-- > 0 ) {
              String name = din.readUTF();
              //#ifdef DLOGGING
//@              if (finestLoggable) {logger.finest("name=" + name);}
              //#endif
              String value;
              if (currentSettings) {
                final int blen = din.readInt();
                byte [] bvalue = new byte[blen];
                final int alen = din.read(bvalue);
                if (alen <= 0) {
                  value = "";
                } else {
                  try {
                    value = new String(bvalue, 0, alen,
                               "UTF-8");
                  } catch (UnsupportedEncodingException e) {
                    value = new String(bvalue, 0, alen);
                    //#ifdef DLOGGING
//@                    logger.severe("cannot convert load name=" + name, e);
                    //#endif
                    /** Error while executing constructor */
                    System.out.println("cannot convert load name=" +
                        name + e.getMessage());
                    e.printStackTrace();
                  } catch (IOException e) {
                    value = new String(bvalue);
                    //#ifdef DLOGGING
//@                    logger.severe("cannot convert load name=" + name, e);
                    //#endif
                    /** Error while executing constructor */
                    System.out.println("cannot convert load name=" +
                        name + e.getMessage());
                    e.printStackTrace();
                  }
                }
              } else {
                value = din.readUTF();
              }
              //#ifdef DLOGGING
//@              if (finestLoggable) {logger.finest("value=" + value);}
              //#endif
              m_properties.put( name, value );
            }
          }
        }
        for (int ic = numRecs; ic < MAX_REGIONS; ic++) {
          //#ifdef DLOGGING
//@          if (finestLoggable) {logger.finest("adding ic=" + ic);}
          //#endif
          rs.addRecord( null, 0, 0 );
        }
        m_region = region;
      } catch (RecordStoreException e) {
        //#ifdef DLOGGING
//@        logger.severe("load ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("load " + e.getMessage());
        e.printStackTrace();
        throw new CauseRecStoreException(
            "RecordStoreException while loading region=" +
            region, e);
      } catch (Exception e) {
        //#ifdef DLOGGING
//@        logger.severe("load ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("load " + e.getMessage());
        e.printStackTrace();
        throw new CauseException("Internal error while loading region=" +
            region, e);
      } catch (OutOfMemoryError e) {
        m_properties.clear();
        System.gc();
        //#ifdef DLOGGING
//@        logger.severe("load OutOfMemoryError ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("load OutOfMemoryError " + e.getMessage());
        e.printStackTrace();
        throw new CauseMemoryException("Out of memory while loading " +
            "region=" + region, e);
      } catch (Throwable e) {
        //#ifdef DLOGGING
//@        logger.severe("load throwable ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("load throwable " + e.getMessage());
        e.printStackTrace();
        throw new CauseException("Internal error while loading " +
            "region=" + region, e);
      } finally {
        if( din != null ) {
          try { din.close(); } catch( Exception e ){}
        }
       
        if( rs != null ) {
          try { rs.closeRecordStore(); } catch( Exception e ){}
        }
        if (!currentSettings && ( numRecs > 0 ) && (region == 0)) {
          // If not current settings, save them to udate to
          // current.
          save(0, true);
          // Update bookmark region too.
          save(1, true);
        }
      }
    }
    }
   
    /** Save property Hashtable to record store.
        Use MAX_REGIONS records in store to help with running out of memory.  */
    public void save( int region, boolean force )
  throws IOException, CauseMemoryException,
       CauseRecStoreException, CauseException {
    synchronized(this) {
      if( !m_valuesChanged && !force ) return;
     
      RecordStore rs = null;
      ByteArrayOutputStream bout = new ByteArrayOutputStream();
      DataOutputStream dout = new DataOutputStream( bout );
     
      try {
        String vers = null;
        if ( m_properties.containsKey(SETTINGS_NAME) ) {
          vers = (String)m_properties.get(SETTINGS_NAME);
        }
        //#ifdef DCOMPATIBILITY12
//@        Hashtable cproperties = m_properties;
        //#else
        Hashtable cproperties = m_properties;
        if (region > 0) {
          cproperties = new Hashtable();
          cproperties.put("bookmarks", m_properties.get("bookmarks"));
          cproperties.put(SETTINGS_NAME,
              m_properties.get(SETTINGS_NAME));
          cproperties.put(ITEMS_ENCODED, m_properties.get(ITEMS_ENCODED));
          cproperties.put(STORE_DATE, m_properties.get(STORE_DATE));
        }
        //#endif

        // Put version only if it is not DCOMPATIBILITY1 which is
        // the settings based on the first few versions before
        // the setting store was changed as the first few
        // versions did not have settings version in properties.
        //#ifndef DCOMPATIBILITY1
        cproperties.put(SETTINGS_NAME, SETTINGS_VERS);
        //#endif
        //#ifdef DLOGGING
//@        if (fineLoggable) {logger.fine("save region=" + region);}
        //#endif
        dout.writeInt( cproperties.size() );
        Enumeration e = cproperties.keys();
        while( e.hasMoreElements() ) {
          String name = (String) e.nextElement();
          String value = cproperties.get( name ).toString();
          //#ifdef DLOGGING
//@          if (finestLoggable) {logger.finest("name=" + name);}
          //#endif
          dout.writeUTF( name );
          byte[] bvalue;
          try {
            bvalue = value.getBytes("UTF-8");

          } catch (UnsupportedEncodingException uee) {
            bvalue = value.getBytes();
            //#ifdef DLOGGING
//@            logger.severe("cannot convert save name=" + name, uee);
            //#endif
            /** Error while executing constructor */
            System.out.println("cannot convert save name=" +
                name + uee.getMessage());
            uee.printStackTrace();
          } catch (IOException ioe) {
            bvalue = value.getBytes();
            //#ifdef DLOGGING
//@            logger.severe("cannot convert save name=" + name, ioe);
            //#endif
            /** Error while executing constructor */
            System.out.println("cannot convert save name=" +
                name + ioe.getMessage());
            ioe.printStackTrace();
          }
          //#ifdef DLOGGING
//@          if (finestLoggable) {logger.finest("value=" + value);}
          //#endif
          dout.writeInt( bvalue.length );
          dout.write( bvalue, 0, bvalue.length );
        }
       
        byte[] data = bout.toByteArray();
        //#ifdef DLOGGING
//@        if (fineLoggable) {logger.fine("save data.length=" + data.length);}
        //#endif
        //#ifdef DTEST
//@        System.out.println("save region,data.length=" + region + "," + data.length);
        //#endif
       
        rs = RecordStore.openRecordStore( RECORD_STORE_NAME, true );
        rs.setRecord( (region + 1), data, 0, data.length );
        //#ifdef DLOGGING
//@        if (fineLoggable) {logger.fine("stored region=" + region);}
        //#endif
        //#ifndef DCOMPATIBILITY1
        if ( vers != null) {
          cproperties.put(SETTINGS_NAME, vers);
        }
        //#endif
      } catch (RecordStoreFullException e) {
        //#ifdef DLOGGING
//@        logger.severe("catch RecordStoreFullException ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("catch RecordStoreFullException " +
                   e.getMessage());
        e.printStackTrace();
        throw new CauseRecStoreException(
            "RecordStoreFullException while saving.", e);
      } catch (RecordStoreException e) {
        //#ifdef DLOGGING
//@        logger.severe("catch RecordStoreException ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("catch RecordStoreException " +
                   e.getMessage());
        e.printStackTrace();
        throw new CauseRecStoreException(
            "RecordStoreException while saving.", e);
      } catch (Exception e) {
        //#ifdef DLOGGING
//@        logger.severe("catch ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("catch " + e.getMessage());
        e.printStackTrace();
        throw new CauseException("Internal error during save.", e);
      } catch (OutOfMemoryError e) {
        m_properties.clear();
        System.gc();
        //#ifdef DLOGGING
//@        logger.severe("catch OutOfMemoryError ", e);
        //#endif
        /** Error while executing constructor */
        System.out.println("catch OutOfMemoryError " + e.getMessage());
        e.printStackTrace();
        throw new CauseMemoryException("Out of memory while save.", e);
      } catch (Throwable e) {
        CauseException ce = new CauseException("Internal error while " +
            "processing save.", e);
        //#ifdef DLOGGING
//@        logger.severe(ce.getMessage(), ce);
        //#endif
        /** Error while executing constructor */
        System.out.println(ce.getMessage() + e.getMessage());
        e.printStackTrace();
        throw ce;
      } finally {
        try { dout.close(); } catch( Exception e ){}
       
        if( rs != null ) {
          try { rs.closeRecordStore(); } catch( Exception e ){}
        }
      }
    }
    }
   
    /** Get memory usage of the record store */
    public Hashtable getSettingMemInfo()
  throws IOException, RecordStoreException {
    synchronized(this) {
      try {
     
        RecordStore rs = null;
        Hashtable memInfo = null;
       
        try {
         
          rs = RecordStore.openRecordStore( RECORD_STORE_NAME, true );
          memInfo = new Hashtable(2);
          memInfo.put("used", Integer.toString(rs.getSize()));
          memInfo.put("available", Integer.toString(
              rs.getSizeAvailable()));
          return memInfo;
        } finally {
         
          if( rs != null ) {
            try { rs.closeRecordStore(); } catch( Exception e ){}
          }
        }
      } catch (RecordStoreNotFoundException re) {
        return new Hashtable(0);
      } catch (Exception e) {
        System.out.println("Error in getSettingMemInfo()");
        e.printStackTrace();
        return new Hashtable(0);
      }
    }
    }
   
    /** Set a boolean property */
    public void setBooleanProperty( String name, boolean value ) {
        setStringProperty( name, value ? "true" : "false" );
    }

  //#ifdef DTEST
//@  final static public void deleteStore() {
//@    try {
//@      RecordStore.deleteRecordStore( RECORD_STORE_NAME );
//@    } catch (RecordStoreNotFoundException e) {
      //#ifdef DLOGGING
//@      Logger logger = Logger.getLogger("Settings");
//@      logger.severe("Cannot deleteRecordStore " +
//@          "RecordStoreNotFoundException " + RECORD_STORE_NAME, e);
      //#endif
//@    } catch (RecordStoreException e) {
      //#ifdef DLOGGING
//@      Logger logger = Logger.getLogger("Settings");
//@      logger.severe("Cannot deleteRecordStore RecordStoreException " +
//@          RECORD_STORE_NAME, e);
      //#endif
//@    }
//@  }
  //#endif
   
    /** Set an integer property */
    public void setIntProperty( String name, int value ) {
        setStringProperty( name, Integer.toString( value ) );
    }
   
    /** Set an long property */
    public void setLongProperty( String name, long value ) {
        setStringProperty( name, Long.toString( value ) );
    }
   
    /** Set a string property */
    public boolean setStringProperty( String name, String value ) {
    synchronized(this) {
      if( name == null && value == null ) return false;
      m_properties.put( name, value );
      m_valuesChanged = true;
      return true;
    }
    }

    /** Set a StringBuffer property */
    public boolean setStringBufProperty( String name, StringBuffer value ) {
    synchronized(this) {
      if( name == null && value == null ) return false;
      m_properties.put( name, value );
      m_valuesChanged = true;
      return true;
    }
    }

  /** Get properties size to allow us to know if it was from a load or not.
    **/
  public boolean isInitialized() {
    //#ifdef DLOGGING
//@    if (finestLoggable) {logger.finest("m_initialized=" + m_initialized);}
    //#endif
    return m_initialized;
  }

}
TOP

Related Classes of com.substanceofcode.utils.Settings

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.