er.corebusinesslogic.ERCoreUserPreferences.java Source code

Java tutorial

Introduction

Here is the source code for er.corebusinesslogic.ERCoreUserPreferences.java

Source

/*
 * Copyright (C) NetStruxr, Inc. All rights reserved.
 *
 * This software is published under the terms of the NetStruxr
 * Public Software License version 0.5, a copy of which has been
 * included with this distribution in the LICENSE.NPL file.  */
package er.corebusinesslogic;

import java.util.Enumeration;

import org.apache.commons.lang.ObjectUtils;
import org.apache.log4j.Logger;

import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOKeyValueArchiver;
import com.webobjects.eocontrol.EOKeyValueUnarchiver;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSNotification;
import com.webobjects.foundation.NSNotificationCenter;
import com.webobjects.foundation.NSPropertyListSerialization;
import com.webobjects.foundation.NSSelector;

import er.extensions.batching.ERXBatchNavigationBar;
import er.extensions.components.ERXSortOrder;
import er.extensions.eof.ERXConstant;
import er.extensions.eof.ERXEC;
import er.extensions.eof.ERXEOControlUtilities;
import er.extensions.foundation.ERXProperties;
import er.extensions.foundation.ERXRetainer;
import er.extensions.foundation.ERXValueUtilities;

/**
 *
 * @property er.corebusinesslogic.ERCoreUserPreferences.handlerClassName
 */
public class ERCoreUserPreferences implements NSKeyValueCoding {

    //   ===========================================================================
    //   Class Constant(s)
    //   ---------------------------------------------------------------------------    

    /** Logging support */
    public static final Logger log = Logger.getLogger(ERCoreUserPreferences.class);

    /** EOEncoding key */
    private final static String VALUE = "_V";

    /** Notification that is posted when preferences change */
    public final static String PreferenceDidChangeNotification = "PreferenceChangedNotification";

    //   ===========================================================================
    //   Class Variable(s)
    //   ---------------------------------------------------------------------------    

    /** caches the singleton user preference object */
    private static ERCoreUserPreferences _userPreferences;

    //   ===========================================================================
    //   Class Method(s)
    //   ---------------------------------------------------------------------------

    /**
     * Gets the singleton instance for interacting with
     * the user preference system.
     * @return single instance of the user preferences
     */
    public static ERCoreUserPreferences userPreferences() {
        if (_userPreferences == null) {
            _userPreferences = new ERCoreUserPreferences();
        }
        return _userPreferences;
    }

    //   ===========================================================================
    //   Instance Method(s)
    //   ---------------------------------------------------------------------------    

    /**
     * Registers notification handlers for user preference notifications. These
     * are mainly used within the context of D2W pages.
     */
    public void registerHandlers() {
        log.debug("Registering preference handlers");
        Object handler = null;
        String handlerClassName = ERXProperties
                .stringForKey("er.corebusinesslogic.ERCoreUserPreferences.handlerClassName");
        if (handlerClassName != null) {
            try {
                handler = Class.forName(handlerClassName).newInstance();
            } catch (Exception e) {
                throw NSForwardException._runtimeExceptionForThrowable(e);
            }
        }
        if (handler == null) {
            handler = new _UserPreferenceHandler();
        }
        ERXRetainer.retain(handler);
    }

    protected NSArray preferences(EOEditingContext ec) {
        ERCoreUserInterface user = (ERCoreUserInterface) ERCoreBusinessLogic.actor(ec);
        return user != null ? user.preferences() : NSArray.EmptyArray;
    }

    protected EOEnterpriseObject preferenceRecordForKey(String key, EOEditingContext ec) {
        EOEnterpriseObject result = null;
        if (key != null) {
            if (log.isDebugEnabled())
                log.debug("Preference value for Key = " + key);
            for (Enumeration e = preferences(ec).objectEnumerator(); e.hasMoreElements();) {
                EOEnterpriseObject pref = (EOEnterpriseObject) e.nextElement();
                String prefKey = (String) pref.valueForKey("key");
                if (log.isDebugEnabled()) {
                    log.debug("prefKey \"" + prefKey + "\"");
                }
                if (prefKey != null && prefKey.equals(key)) {
                    result = pref;
                    break;
                }
            }
        }
        return result;
    }

    protected String encodedValue(Object value) {
        EOKeyValueArchiver archiver = new EOKeyValueArchiver();
        archiver.encodeObject(value, VALUE);
        String encodedValue = NSPropertyListSerialization.stringFromPropertyList(archiver.dictionary());
        return encodedValue;
    }

    protected Object decodedValue(String encodedValue) {
        NSDictionary d = (NSDictionary) NSPropertyListSerialization.propertyListFromString(encodedValue);
        EOKeyValueUnarchiver u = new EOKeyValueUnarchiver(d);
        return u.decodeObjectForKey(VALUE);
    }

    //   ===========================================================================
    //   Implementation of NSKeyValueCoding
    //   ---------------------------------------------------------------------------    

    // FIXME -- unarchiving - archiving probably could use optimization
    public Object valueForKey(String key) {
        Object result = null;
        EOEditingContext ec = ERXEC.newEditingContext();
        ec.lock();
        try {
            EOEnterpriseObject pref = preferenceRecordForKey(key, ec);
            if (pref != null) {
                String encodedValue = (String) pref.valueForKey("value");
                if (encodedValue != null) {
                    result = decodedValue(encodedValue);
                }
            }
        } catch (RuntimeException ex) {
            log.error("Error while getting preference " + key + ": " + ex);
        } finally {
            ec.unlock();
        }
        ec.dispose();
        if (log.isDebugEnabled())
            log.debug("Prefs vfk " + key + " = " + result);
        return result;
    }

    public void takeValueForKey(Object value, String key) {
        // we first make sure there is no cruft left
        // !! locking is turned off on the value attribute of UserPreference
        // so that if a user opens two sessions they don't get locking failures
        // this is OK for display style prefs (how many items, how they are sorted)
        // but might not be for more behavior-style prefs!!
        EOEditingContext ec = ERXEC.newEditingContext();
        ec.lock();
        try {
            EOEnterpriseObject pref = preferenceRecordForKey(key, ec);
            ERCoreUserInterface u = (ERCoreUserInterface) ERCoreBusinessLogic.actor(ec);
            if (pref != null) {
                if (value != null) {
                    String encodedValue = encodedValue(value);
                    if (ObjectUtils.notEqual(encodedValue, pref.valueForKey("value"))) {
                        if (log.isDebugEnabled())
                            log.debug("Updating preference " + u + ": " + key + "=" + encodedValue);
                        pref.takeValueForKey(encodedValue, "value");
                    }
                } else {
                    if (log.isDebugEnabled())
                        log.debug("Removing preference " + u + ": " + key);
                    ec.deleteObject(pref);
                }
            } else if (value != null) {
                pref = ERXEOControlUtilities.createAndInsertObject(ec, "ERCPreference");
                u.newPreference(pref);
                // done this way to not force you to sub-class our User entity
                pref.takeValueForKey(ERXEOControlUtilities.primaryKeyObjectForObject((EOEnterpriseObject) u),
                        "userID");
                pref.takeValueForKey(key, "key");
                pref.takeValueForKey(encodedValue(value), "value");
                if (log.isDebugEnabled())
                    log.debug(
                            "Creating preference " + u + ": " + key + " - " + value + " -- " + encodedValue(value));
            }
            if (ec.hasChanges()) {
                ec.saveChanges();
            }
        } catch (RuntimeException ex) {
            log.error("Error while setting preference " + key + ": " + ex);
        } finally {
            ec.unlock();
        }
        ec.dispose();
        NSNotificationCenter.defaultCenter().postNotification(PreferenceDidChangeNotification,
                new NSDictionary(value, key));
    }

    public boolean booleanValueForKey(String key) {
        return booleanValueForKeyWithDefault(key, false);
    }

    public boolean booleanValueForKeyWithDefault(String key, boolean def) {
        return ERXValueUtilities.booleanValueWithDefault(valueForKey(key), def);
    }

    public static class _UserPreferenceHandler {
        public _UserPreferenceHandler() {
            NSNotificationCenter.defaultCenter().addObserver(this,
                    new NSSelector("handleBatchSizeChange", ERXConstant.NotificationClassArray),
                    ERXBatchNavigationBar.BatchSizeChanged, null);
            NSNotificationCenter.defaultCenter().addObserver(this,
                    new NSSelector("handleSortOrderingChange", ERXConstant.NotificationClassArray),
                    ERXSortOrder.SortOrderingChanged, null);
        }

        public void handleBatchSizeChange(NSNotification n) {
            handleChange("batchSize", n);
        }

        public void handleSortOrderingChange(NSNotification n) {
            handleChange("sortOrdering", n);
        }

        public void handleChange(String prefName, NSNotification n) {
            if (ERCoreBusinessLogic.actor() != null) {
                NSKeyValueCoding context = (NSKeyValueCoding) n.userInfo().objectForKey("d2wContext");
                if (context != null && context.valueForKey("pageConfiguration") != null) {
                    userPreferences().takeValueForKey(n.object(),
                            prefName + "." + (String) context.valueForKey("pageConfiguration"));
                }
            }
        }
    }
}