All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sunlabs.brazil.properties.PropertiesList Maven / Gradle / Ivy

The newest version!
/*
 * PropertiesList.java
 *
 * Brazil project web application toolkit,
 * export version: 2.3 
 * Copyright (c) 2001-2006 Sun Microsystems, Inc.
 *
 * Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License Version 
 * 1.0 (the "License"). You may not use this file except in compliance with 
 * the License. A copy of the License is included as the file "license.terms",
 * and also available at http://www.sun.com/
 * 
 * The Original Code is from:
 *    Brazil project web application toolkit release 2.3.
 * The Initial Developer of the Original Code is: drach.
 * Portions created by drach are Copyright (C) Sun Microsystems, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s): drach, suhler.
 *
 * Version:  2.8
 * Created by drach on 01/08/03
 * Last modified by suhler on 06/07/31 14:45:24
 *
 * Version Histories:
 *
 * 2.8 06/07/31-14:45:24 (suhler)
 *   added public removeProperty methods that will remove a property anywhere in
 *   a properties list chain
 *
 * 2.7 04/11/30-15:11:26 (suhler)
 *   fixed sccs version string
 *
 * 2.6 04/04/28-13:53:45 (suhler)
 *   addAfter skips all "transient properties" before inserting a new
 *   propertiesList into the chain.  The method "isTransient()" may be
 *   overridden in child classes to make a PropertiesList transient.
 *   This should be a backward compatible change
 *
 * 2.5 03/07/25-16:34:28 (drach)
 *   Create just one PropertiesList.java.  This will on compile on
 *   Java 2 compilers.
 *
 * 2.4 02/11/25-13:33:49 (drach)
 *   Minor cosmetic changes
 *
 * 2.3 02/11/25-12:31:05 (suhler)
 *   doc changes
 *
 * 2.2 02/11/25-12:28:14 (suhler)
 *   Merged changes between child workspace "/home/suhler/brazil/naws" and
 *   parent workspace "/net/mack.eng/export/ws/brazil/naws".
 *
 * 1.10.1.1 02/11/25-11:49:53 (suhler)
 *   Changed the semantics of getProperty() to look in all wrapped dictionaries, not just those that are\
 *   also Properties
 *   Changed the semantics of getNames() similar to the above
 *   .
 *
 * 2.1 02/10/01-16:39:52 (suhler)
 *   version change
 *
 * 1.10 02/05/17-09:42:54 (drach)
 *   Minor cosmetic fix
 *
 * 1.9 02/05/02-12:59:12 (drach)
 *   Update documentation.
 *
 * 1.8 02/05/01-08:52:25 (drach)
 *   Oops, forgot to change one method
 *
 * 1.7 02/05/01-08:45:41 (drach)
 *   Turn all private methods into protected methods
 *
 * 1.6 02/05/01-07:40:29 (drach)
 *   Change from PropertiesList to BasePropertiesList
 *
 * 1.5 01/11/21-11:43:42 (suhler)
 *   doc fixes
 *
 * 1.4 01/08/22-16:23:48 (drach)
 *   Change some methods so they correspond to Request documentation
 *
 * 1.3 01/08/22-14:41:53 (drach)
 *   Add comments to PropertiesList and change some methods.
 *
 * 1.2 01/08/07-14:21:23 (drach)
 *   Fix null pointer exception and add case where PL invokes PL
 *
 * 1.2 01/08/03-15:24:59 (Codemgr)
 *   SunPro Code Manager data about conflicts, renames, etc...
 *   Name history : 3 2 properties/PropertiesList.java
 *   Name history : 2 1 properties/BasePropertiesList.java
 *   Name history : 1 0 properties/PropertiesList.java
 *
 * 1.1 01/08/03-15:24:58 (drach)
 *   date and time created 01/08/03 15:24:58 by drach
 *
 */

package sunlabs.brazil.properties;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;

import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import sunlabs.brazil.util.Glob;

/**
 * A PropertiesList instance is intended to be an element of
 * a doubly linked list consisting of other PropertiesList
 * instances.  Each PropertiesList instance "wraps" a
 * Dictionary object.  A PropertiesList is a
 * subclass of Properties and therefore provides the same
 * API, including the methods and fields of Dictionary and
 * Hashtable.  The PropertiesList class
 * overrides all methods of the Properties API and delegates
 * the method evaluation to the wrapped Properties object.
 * 

* The linked list of PropertiesList objects is constructed * by Request for each incoming request. That is, there is * a unique PropertiesList linked list for each request. * The head of the initial list constructed by request is * Request.props and the tail of the two element list is * Request.serverProps. The former wraps an empty * Properties object, while the latter wraps * Server.props. Other PropertiesList objects * can be added, and removed, from this initial list as required. *

* Given a reference to a PropertiesList object on the * linked list (e.g. request.props), one typically "looks * up" the value associated with a name using the * getProperty method, which delegates to the wrapped * Properties.getProperty method. If the result is * null, meaning the name/value pair is not stored in the * wrapped Properties object, the request is "forwarded" to * the next object on the linked list, and so on until either the * name/value pair is found (and the value is returned) or the end of the * list is reached (and null is returned). *

* It may be desirable for the name/value lookup to be delayed until * after the lookup request has been passed on to subsequent objects on * the list. This can be done by using the two parameter constructor and * setting the second, boolean, parameter to true. Then the * getProperty request is forwarded to the next object in * the list rather than delegated to the wrapped Properties * object. If the result of the forwarded request is null, * the request is then passed to the wrapped Properties * object and it's result is returned. * * @author Steve Drach <[email protected]> * @version 2.8 * * @see java.util.Dictionary * @see java.util.Hashtable * @see java.util.Properties */ public class PropertiesList extends Properties { private Dictionary wrapped; private boolean searchNextFirst; private PropertiesList next, prior; /** * Constructs a new PropertiesList object that wraps * an empty new Properties object. */ public PropertiesList() { if (debug) { log("*** PL@" + id(this) + " created " + caller()); } wrapped = new Properties(); } /** * Constructs a new PropertiesList object that wraps * the input Dictionary. * * @param dict The Dictionary object wrapped * by this PropertiesList. */ public PropertiesList(Dictionary dict) { if (debug) { log("*** PL@" + id(this) + " created with dict " + id(dict) + " " + caller()); } wrapped = dict; } /** * Constructs a new PropertiesList object that wraps * the input Dictionary. If the boolean parameter * is set true, the wrapped Dictionary * is searched after subsequent PropertiesList * objects in the linked list are searched, and only if the * result of that search was null. * * @param dict The Dictionary object wrapped * by this PropertiesList. * * @param searchNextFirst If true all the following * objects in the list are searched before * this one. */ public PropertiesList(Dictionary dict, boolean searchNextFirst) { this(dict); this.searchNextFirst = searchNextFirst; } /** * Set true to turn on debug output. It's alot * of output and probably of use only to the author. Note, * if server.props contains the name debugProps * this variable will be set true by Server. */ public static boolean debug; /** * Returns the Dictionary object wrapped by this * PropertiesList. */ public Dictionary getWrapped() { return wrapped; } /** * Adds this PropertiesList object into * a linked list following the object referenced by * the cursor parameter. The result is * a list that could look like: * * request.props -> cursor -> this -> serverProps *

* Any transient properties lists's are skipped over before * this one is inserted into the list * * @param cursor The list object that will precede this object. */ public void addAfter(PropertiesList cursor) { while (cursor!=null && cursor.isTransient()) { if (debug) { log("*** addAfter skipping transient: " + cursor); } cursor = cursor.next; } if (cursor != null) { next = cursor.next; if (next != null) { next.prior = (PropertiesList)this; } prior = cursor; cursor.next = (PropertiesList)this; } if (debug) { log("*** addAfter " + cursor.toString()); getHead().dump(true, null); } } /** * Adds this PropertiesList object into * a linked list preceding the object referenced by * the cursor parameter. The result is * a list that could look like: * * request.props -> this -> cursor -> serverProps * * @param cursor The list object that will succede this object. */ public void addBefore(PropertiesList cursor) { if (cursor != null) { prior = cursor.prior; if (prior != null) { prior.next = (PropertiesList)this; } next = cursor; cursor.prior = (PropertiesList)this; } if (debug) { log("*** addBefore " + cursor.toString()); getHead().dump(true, null); } } /** * Remove this object from the list in which it's a member. * * @return true. */ public boolean remove() { PropertiesList head = null; if (debug) { if ((head = getHead()) == (PropertiesList)this) { head = head.next; } } if (next != null) { next.prior = prior; } if (prior != null) { prior.next = next; } next = prior = null; if (debug) { log("*** remove " + toString()); head.dump(true, null); } return true; } /** * Returns the PropertiesList object that succedes this * object on the list of which this object is a member. * * @return A PropertiesList object or * null. */ public PropertiesList getNext() { if (debug) { log("*** getNext: PropertyList@" + id(next)); } return next; } /** * Returns the PropertiesList object that precedes this * object on the list of which this object is a member. * * @return A PropertiesList object or * null. */ public PropertiesList getPrior() { if (debug) { log("*** getPrior: PropertyList@" + id(prior)); } return prior; } /** * Returns the PropertiesList object that is the first object * on the list of which this object is a member. Note that the first * object may be this object. * * @return A PropertiesList object. */ public PropertiesList getHead() { PropertiesList head = (PropertiesList)this; while (head.prior != null) { head = head.prior; } return head; } /** * Find the first PropertiesList object on the list of which * this object is a member that wraps the Dictionary * parameter. * * @param d The Dictionary that is compared with the * wrapped Dictionary's for a match. * * @return PropertiesList object that wraps the * input parameter, otherwise null. */ public PropertiesList wraps(Dictionary d) { PropertiesList cursor = getHead(); do { if (cursor.wrapped == d) { return cursor; } cursor = cursor.next; } while (cursor != null); return null; } /** * Starting with this object, print the contents of this and * succeeding objects that are on the same list as this object * is. * * @param full If true also print the contents of the * wrapped Dictionary object. * * @param msg If not null, add this message to the * header line. */ public void dump(boolean full, String msg) { boolean debug = this.debug; this.debug = full; if (msg == null) { log("***\ndumping PropertiesList"); } else { log("***\ndumping PropertiesList " + msg); } dump2(); this.debug = debug; } private void dump2() { log("-----\n" + toString()); if (next != null) { next.dump2(); } } /* * Dictionary methods */ /** * Invokes the same method on the wrapped Dictionary object. */ public synchronized Enumeration elements() { return wrapped.elements(); } /** * Invokes the same method on the wrapped Dictionary object. */ public synchronized Object get(Object key) { return wrapped.get(key); } /** * Invokes the same method on the wrapped Dictionary object. */ public boolean isEmpty() { return wrapped.isEmpty(); } /** * Invokes the same method on the wrapped Dictionary object. */ public synchronized Enumeration keys() { return wrapped.keys(); } /** * Invokes the same method on the wrapped Dictionary object. */ public synchronized Object put(Object key, Object value) { if (debug) { log("*** PL@" + id(this) + " put(" + key + ", " + value + ")"); } return wrapped.put(key, value); } /** * Invokes the same method on the wrapped Dictionary object. */ public synchronized Object remove(Object key) { return wrapped.remove(key); } /** * Invokes the same method on the wrapped Dictionary object. */ public int size() { return wrapped.size(); } /* * Hashtable methods */ /** * Invokes the same method on the wrapped Hashtable object. */ public synchronized void clear() { ((Hashtable)wrapped).clear(); } /** * Invokes the same method on the wrapped Hashtable object. */ public synchronized Object clone() { return ((Hashtable)wrapped).clone(); } /** * Invokes the same method on the wrapped Hashtable object. */ public synchronized boolean contains(Object value) { return ((Hashtable)wrapped).contains(value); } /** * Invokes the same method on the wrapped Hashtable object. */ public synchronized boolean containsKey(Object key) { return ((Hashtable)wrapped).containsKey(key); } /** * Invokes the same method on the wrapped Hashtable object. */ public Set entrySet() { return ((Hashtable)wrapped).entrySet(); } /** * Invokes the same method on the wrapped Hashtable object. */ public boolean equals(Object o) { return ((Hashtable)wrapped).equals(o); } /** * Invokes the same method on the wrapped Hashtable object. */ public int hashCode() { return ((Hashtable)wrapped).hashCode(); } /** * Invokes the same method on the wrapped Hashtable object. */ public Set keySet() { return ((Hashtable)wrapped).keySet(); } /** * Invokes the same method on the wrapped Hashtable object. */ public void putAll(Map t) { ((Hashtable)wrapped).putAll(t); } /** * Invokes the same method on the wrapped Hashtable object. */ public Collection values() { return ((Hashtable)wrapped).values(); } // There is no rational way to override rehash(), so it's not here /** * Returns a String containing the * System.identityHashCodes of this object, the wrapped * object, and the preceding and succeding objects on the list of * which this object is a member. Additionally, if debug * is true, the result of invoking toString * on the wrapped Dictionary is appended. * * @return String representation of this object. */ public synchronized String toString() { StringBuffer sb = new StringBuffer("PropertiesList@").append(id(this)); sb.append("\n next: ").append(id(next)); sb.append("\n prior: ").append(id(prior)); sb.append("\n wrapped: ").append(id(wrapped)); if (debug) { sb.append("\n ").append(wrapped.toString()); } return sb.toString(); } /* * Properties methods */ /** * Looks up key in the wrapped object. If the result is * null * the request is forwarded to the succeeding object in the list * of which this object is a member. If the search order was changed * by constructing this object with the two parameter constructor, the * request is first forwarded and then, if the result of the * forwarded request is null, the key is looked * up in the wrapped Properties object. * * @param key The key whose value is sought. * * @return The value or null. */ public String getProperty(String key) { String value = null; if (searchNextFirst) { if (next != null) { value = next.getProperty(key); } if (value == null) { value = getValue(key); } } else { value = getValue(key); if (value == null && next != null) { value = next.getProperty(key); } } if (debug) { log("*** PL@" + id(this) + " getProperty(" + key + ") => " + value); } return value; } /** * Uses getProperty(String) to look up the value associated * with the key. If the result is null, returns the default * value. * * @param key The key whose value is sought. * * @param defaultValue The default value. * * @return The value or null. */ public String getProperty(String key, String defaultValue) { String value = getProperty(key); if (value == null) { value = defaultValue; } if (debug) { log("*** PL@" + id(this) + " get(" + key + ") => " + value); } return value; } /** * Remove a property from a a chain of properties lists. * if "all" is specified, then remove all the keys and values from * all property lists in the chain instead of just the first one found. * @param key The key whose value is to be removed * @param all remove all matching keys. * @return true, if at least one key/value pair was removed. */ public boolean removeProperty(String key, boolean all) { boolean removed = false; if (searchNextFirst) { if (next != null) { removed = next.removeProperty(key, all); } if (removed==false || all) { removed = (remove(key) != null) || removed; } } else { removed = (remove(key) != null); if (removed==false || all) { removed = next.removeProperty(key, all) || removed; } } if (debug) { log("*** PL@" + id(this) + " removeProperty(" + key + ") => " + removed); } return removed; } /** * Remove the key and its associated value from the first properties * object in the chain that contains this key. * @return true, if the key was removed. */ public boolean removeProperty(String key) { return removeProperty(key, false); } /** * Invokes the same method on the wrapped Properties object. */ public void list(PrintStream out) { if (wrapped instanceof Properties) { ((Properties)wrapped).list(out); } } /** * Invokes the same method on the wrapped Properties object. */ public void list(PrintWriter out) { if (wrapped instanceof Properties) { ((Properties)wrapped).list(out); } } /** * Invokes the same method on the wrapped Properties object. */ public synchronized void load(InputStream in) throws IOException { if (wrapped instanceof Properties) { ((Properties)wrapped).load(in); } } /** * Invokes the same method on the wrapped Properties object. */ public Enumeration propertyNames() { Hashtable h = new Hashtable(); enumerate(h); return h.keys(); } /** * Invokes the same method on the wrapped Properties object. */ public synchronized void save(OutputStream out, String header) { if (wrapped instanceof Properties) { ((Properties)wrapped).save(out, header); } } /** * Invokes the same method on the wrapped Properties object * if it exists. Otherwise invokes put on the wrapped * Dictionary object. */ public Object setProperty(String key, String value) { if (wrapped instanceof Properties) { return ((Properties)wrapped).setProperty(key, value); } return wrapped.put(key, value); } /** * Invokes the same method on the wrapped Properties object. */ public void store(OutputStream out, String header) throws IOException { if (wrapped instanceof Properties) { ((Properties)wrapped).store(out, header); } } /* * Additional method on wrapped object */ /** * Returns an Enumeration of property names that * match a glob pattern. * * @param pattern The glob pattern to match. * * @return An Enumeration containing * matching property names, if any. */ public Enumeration propertyNames(String pattern) { Hashtable h = new Hashtable(); enumerate(h, pattern); return h.keys(); } /* * Helper methods */ private String getValue(String key) { if (wrapped instanceof Properties) { return ((Properties)wrapped).getProperty(key); } else { return (String)wrapped.get(key); } } private synchronized void enumerate(Hashtable h) { enumerate(h, null); } private synchronized void enumerate(Hashtable h, String pattern) { if (next != null && ! searchNextFirst) { next.enumerate(h, pattern); } Enumeration e; if (wrapped instanceof Properties) { e = ((Properties)wrapped).propertyNames(); } else { e = wrapped.keys(); } while (e.hasMoreElements()) { String s = null; try { s = (String)e.nextElement(); if (pattern == null || Glob.match(pattern, s)) { h.put(s, s); } } catch (ClassCastException x) {} } if (next != null && searchNextFirst) { next.enumerate(h, pattern); } } private String id(Object o) { if (o == null) { return "null"; } return Integer.toHexString(System.identityHashCode(o)); } private String caller() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter out = new PrintWriter(baos); (new Throwable()).printStackTrace(out); try { out.close(); BufferedReader in = new BufferedReader( new InputStreamReader( new ByteArrayInputStream(baos.toByteArray()))); String line = null; boolean found = false; while ((line = in.readLine()) != null) { if (line.indexOf("PropertiesList.") != -1) { found = true; continue; } if (found) { return line.trim(); } } } catch (IOException e) {} return ""; } // Can't use server.log since we don't have access to either a // Server object or a Request object private void log(Object msg) { if (msg == null) { return; } if (!(msg instanceof String)) { msg = msg.toString(); } System.out.println(msg); } /** * Sub-classes of PropertiesList can override this to mark * themselves "transient", in which case addAfter * will skip this list. */ public boolean isTransient() { return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy