001package org.apache.commons.jcs.utils.props;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.commons.jcs.access.exception.ConfigurationException;
023
024import java.util.Properties;
025
026/**
027 * Provides a mechanism to load properties into objects.
028 * <p>
029 * Functions that depend on properties should call ensureProperties() before it uses any properties.
030 */
031public abstract class AbstractPropertyContainer
032{
033    /** File, db, etc */
034    private static final PropertiesFactory DEFAULT_PROPERTIES_FACTORY = new PropertiesFactoryFileImpl();
035
036    /**
037     * A property group is a subsection of properties. It's sent to the properties factory to
038     * specify which group of properties to pull back. This will probably mean different things to
039     * different property factories. For PropertiesFactoryFileImpl, the propertiesGroup maps to a
040     * filename.
041     */
042    private String propertiesGroup;
043
044    /**
045     * The property heading is used to specify a starting point in the properties object. This is
046     * used so that settings can be relative to this propertiesHeading, as opposed to being
047     * statically coded. There's no enforcement of this, but users are encouraged to call
048     * getProperties().get( getPropertiesHeading() + ".foo" );
049     */
050    private String propertiesHeading;
051
052    /** The factory to use. */
053    private PropertiesFactory propertiesFactory;
054
055    /** The loaded properties. */
056    private Properties properties;
057
058    /**
059     * Makes sure an AbstractPropertyClass has all the properties it needs.
060     * <p>
061     * Synchronized mutators so multiple threads cannot cause problems. We wouldn't want the
062     * properties heading to get changed as we were processing the properties.
063     * <p>
064     * @throws ConfigurationException on configuration failure
065     */
066    public synchronized void ensureProperties()
067        throws ConfigurationException
068    {
069        if ( getProperties() == null )
070        {
071            initializeProperties();
072        }
073    }
074
075    /**
076     * Loads the properties and then calls handleProperties. Typically, you don't need to call this.
077     * This is primarily intended for reinitialization.
078     * <p>
079     * If the properties object is null, when you call ensureProperties initialize will be called.
080     * <p>
081     * @throws ConfigurationException on configuration failure
082     */
083    public synchronized void initializeProperties()
084        throws ConfigurationException
085    {
086        loadProperties();
087
088        handleProperties();
089    }
090
091    /**
092     * This loads the properties regardless of whether or not they have already been loaded.
093     * <p>
094     * @throws ConfigurationException on configuration failure
095     */
096    private void loadProperties()
097        throws ConfigurationException
098    {
099        if ( getPropertiesGroup() == null )
100        {
101            throw new ConfigurationException( "Properties group is null and it shouldn't be" );
102        }
103
104        if ( getPropertiesHeading() == null )
105        {
106            throw new ConfigurationException( "Properties heading is null and it shouldn't be" );
107        }
108
109        if ( getPropertiesFactory() == null )
110        {
111            setProperties( DEFAULT_PROPERTIES_FACTORY.getProperties( getPropertiesGroup() ) );
112        }
113        else
114        {
115            setProperties( getPropertiesFactory().getProperties( getPropertiesGroup() ) );
116        }
117    }
118
119    /**
120     * Sets fields for properties, and verifies that all necessary properties are there.
121     * <p>
122     * @throws ConfigurationException on configuration failure
123     */
124    protected abstract void handleProperties()
125        throws ConfigurationException;
126
127    /**
128     * @return Returns the properties.
129     */
130    public synchronized Properties getProperties()
131    {
132        return properties;
133    }
134
135    /**
136     * @param properties The properties to set.
137     */
138    public synchronized void setProperties( Properties properties )
139    {
140        this.properties = properties;
141    }
142
143    /**
144     * @return Returns the propertiesHeading.
145     */
146    public synchronized String getPropertiesHeading()
147    {
148        return propertiesHeading;
149    }
150
151    /**
152     * @param propertiesHeading The propertiesHeading to set.
153     */
154    public synchronized void setPropertiesHeading( String propertiesHeading )
155    {
156        this.propertiesHeading = propertiesHeading;
157    }
158
159    /**
160     * @return Returns the propertiesFactory.
161     */
162    public PropertiesFactory getPropertiesFactory()
163    {
164        return propertiesFactory;
165    }
166
167    /**
168     * @param propertiesFactory The propertiesFactory to set.
169     */
170    public void setPropertiesFactory( PropertiesFactory propertiesFactory )
171    {
172        this.propertiesFactory = propertiesFactory;
173    }
174
175    /**
176     * @return Returns the propertiesGroup.
177     */
178    public String getPropertiesGroup()
179    {
180        return propertiesGroup;
181    }
182
183    /**
184     * @param propertiesGroup The propertiesGroup to set.
185     */
186    public void setPropertiesGroup( String propertiesGroup )
187    {
188        this.propertiesGroup = propertiesGroup;
189    }
190}