001: /*
002: * Copyright 2002 Sun Microsystems, Inc. All
003: * rights reserved. Use of this product is subject
004: * to license terms. Federal Acquisitions:
005: * Commercial Software -- Government Users
006: * Subject to Standard License Terms and
007: * Conditions.
008: *
009: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
010: * are trademarks or registered trademarks of Sun Microsystems,
011: * Inc. in the United States and other countries.
012: */
013:
014: package com.sun.portal.providers.context;
015:
016: /**
017: * This class is an abstract PropertiesFilter class. Every PropertiesFilter
018: * implementation must extend this class.
019: * <br><br>
020: * A PropertiesFilter is used to describe an arbitrary filter
021: * which is used to selectively look up properties with
022: * certain criteria as well as when storing properties that are specific
023: * to certain setting.
024: * The PropertiesFilter itself does not compare any actual property values.
025: * Rather, it determines if the qualifiers ('<code>condition</code>' and
026: * '<code>value</code>') associated with the property match the filter
027: * criteria supplied in the PropertiesFilter.
028: * <br><br>
029: * PropertiesFilters are instantiated using methods provided in
030: * <code>PropertiesFilterFactory</code> and are not to be constructed directly.
031: * In addition, PropertiesFilter objects are meant to be immutable and
032: * stateless. Once a PropertiesFilter is initialized, the value cannot
033: * be modified.
034: * <br><br>
035: * Nevertheless, in some cases, having an access to stateful objects
036: * such as ProviderContext within the PropertiesFilter, especially in
037: * the match() method may become necessary. This can be achieved by
038: * extending the PropertierFilter in such a way that the stateful object(s)
039: * can be passed in the constructor and stored as a member variable.
040: * Instantiating such a PropertiesFilter is done by directly constructing
041: * the <code>PropertiesFilter</code>, bypassing the <code>PropertiesFilterFactory</code>.
042: * <br>
043: * Here is an example:<br>
044: * <pre><code>public class LoggingPropertiesFilter extends PropertiesFilter {<br>
045: * private ProviderContext pc = null;<br>
046: * public LoggingPropertiesFilter(ProviderContext pc, String value, boolean required) {<br>
047: * super();<br>
048: * this.pc = pc;<br>
049: * try {<br>
050: * init(value, required);<br>
051: * } catch (PropertiesFilterException pfe) {<br>
052: * pc.debugError("LoggingPropertiesFilter(): Failed to init." , pfe);<br>
053: * }<br>
054: * }<br>
055: * public String getCondition() {<br>
056: * return "loggingEnabled";<br>
057: * } <br>
058: * public boolean match(String condition, String value) throws PropertiesFilterException {<br>
059: * if (!condition.equals("loggingEnabled")) {<br>
060: * return false;<br>
061: * }<br>
062: * if (getValue().equals(value)) {<br>
063: * pc.debugMessage("LoggingPropertiesFilter(): matched loggingEnabled property. value=" value);<br>
064: * }<br>
065: * return true;<br>
066: * }<br>
067: * }<br><br>
068: *
069: * List pflist = new ArrayList();<br>
070: * pflist.add(new LoggingPropertiesFilter(getProviderContext(), "foo", true);<br>
071: *</code></pre>
072: * Note that bypassing <code>PropertiesFilterFactory</code> may have a
073: * performance impact. Also, <code>PropertiesContext</code> has a life-span
074: * of one session and should not be s
075: * <br><br>
076: * Properties are looked up using different types of get/set*Property()
077: * methods which are available in <code>ProviderContext</code>.
078: *
079: * @see com.sun.portal.providers.context.ProviderContext
080: * @see com.sun.portal.providers.context.PropertiesFilterFactory
081: */
082:
083: public abstract class PropertiesFilter {
084:
085: private boolean initialized = false;
086: private String value = null;
087: private boolean required = false;
088:
089: /**
090: * Constructor. In most cases, PropertiesFilters should not be
091: * constructed directly. Instead, use
092: * <code>PropertiesFilterFactory.get()</code>.
093: *
094: * @see PropertiesFilterFactory#get(String, String, boolean)
095: */
096: public PropertiesFilter() {
097: }
098:
099: /**
100: * Initialize PropertiesFilter with given values.
101: * PropertiesFilters are immutable. You cannot re-initialize an already
102: * initialized PropertiesFilter with new values. Doing so will results
103: * in no-op.
104: *
105: * @param value The value that gets associated with the filter.
106: * @param required Flag indicating whether this filter criteria
107: * is required or optional.
108: * @exception PropertiesFilterException there was an error while initializing values
109: */
110: protected void init(String value, boolean required)
111: throws PropertiesFilterException {
112:
113: //
114: // you cannot re-initialize because this will corrupt caching
115: //
116: if (initialized) {
117: return;
118: }
119:
120: this .value = value;
121: this .required = required;
122: initialized = true;
123: }
124:
125: /**
126: * By default, caching is on.
127: *
128: * @return true.
129: * @see PropertiesFilter.isCachable()
130: *
131: * DISABLED FOR NOW
132: *
133: public boolean isCachable() {
134: return true;
135: }
136: */
137:
138: /**
139: * Get the condition of the filter, such as <code>"locale"</code> and
140: * <code>"client"</code>.
141: * Filter condition is an unmodifiable constant value.
142: *
143: * @return filter condition
144: * @exception PropertiesFilterException if there is an error in getting
145: * the condition of the filter.
146: **/
147: public abstract String getCondition()
148: throws PropertiesFilterException;
149:
150: /**
151: * Get the value of the filter that is associated with the condition
152: * of the filter.
153: *
154: * @return filter value that was used to instantiate this PropertiesFilter.
155: */
156: public String getValue() {
157: return value;
158: }
159:
160: /**
161: * Is filter required?
162: * A conditional property lookup involves one or more property filters.
163: * If a filter in the filter list is required, then it must match for
164: * the overall conditional lookup to succeed. If a filter is not required,
165: * then it can fail to match without causing the overall lookup to fail.
166: * A chain of non-required filters can be used to implement a progressively
167: * less-specific filter lookup, similar to the semantics of Java resource
168: * bundle lookup.
169: * <br><br>
170: * For instance, an optional filter would be useful in a case where a
171: * locale lookup is followed by a date lookup.
172: * Given the filter <code>{locale=en, locale=US, date=03/03/2003}</code>,
173: * you can get it to successfully match a property with the qualifier
174: * <code>{locale=en; date=03/03/2003}</code> even though it does not exactly match
175: * the filter specification. This done by setting the locale filter
176: * to be optional.
177: *
178: * @return boolean indicating whether this filter is required or optional.
179: */
180: public boolean isRequired() {
181: return required;
182: }
183:
184: /**
185: * Does the given condition and value match the filter?
186: *
187: * @param pc ProviderContext object
188: * @param condition the condition to be matched against the filter condition
189: * @param value the value to be matched against the filter value
190: * @returns true if this filter object matches the condition and
191: * value that are passed in
192: * @exception PropertiesFilterException if there is an error in
193: * processing properties to be matched.
194: */
195: public abstract boolean match(String condition, String value)
196: throws PropertiesFilterException;
197:
198: /**
199: * Return a string representation of the PropertiesFilter.
200: * Useful for debugging.
201: *
202: * @return a String representation of the PropertiesFilter.
203: */
204: public String toString() {
205: StringBuffer b = new StringBuffer();
206: try {
207: b.append(getCondition()).append(":").append(value).append(
208: ":").append(required);
209: } catch (PropertiesFilterException pfe) {
210: }
211: return b.toString();
212: }
213: }
|