001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * StyleKey.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.style;
030:
031: import java.io.ObjectStreamException;
032: import java.io.Serializable;
033: import java.lang.reflect.Field;
034: import java.lang.reflect.Modifier;
035: import java.util.HashMap;
036: import java.util.Iterator;
037:
038: import org.jfree.report.JFreeReportBoot;
039: import org.jfree.util.Configuration;
040: import org.jfree.util.Log;
041: import org.jfree.util.ObjectUtilities;
042:
043: /**
044: * A style key represents a (key, class) pair. Style keys are used to access style
045: * attributes defined in a <code>BandStyleSheet</code> or an <code>ElementStyleSheet</code>
046: * <p/>
047: * Note that this class also defines a static Hashtable in which all defined keys are
048: * stored.
049: *
050: * @author Thomas Morgner
051: * @see BandStyleKeys
052: * @see ElementStyleSheet
053: */
054: public final class StyleKey implements Serializable, Cloneable {
055: /**
056: * Shared storage for the defined keys.
057: */
058: private static HashMap definedKeys;
059: private static int definedKeySize;
060:
061: /**
062: * The name of the style key.
063: */
064: private String name;
065:
066: /**
067: * The class of the value.
068: */
069: private Class valueType;
070:
071: /**
072: * A unique int-key for the stylekey.
073: */
074: private int identifier;
075:
076: /**
077: * Whether this stylekey is transient. Transient keys will not be written when
078: * serializing a report.
079: */
080: private boolean trans;
081:
082: /**
083: * Whether this stylekey is inheritable.
084: */
085: private boolean inheritable;
086:
087: /**
088: * Creates a new style key.
089: *
090: * @param name the name (never null).
091: * @param valueType the class of the value for this key (never null).
092: */
093: private StyleKey(final String name, final Class valueType,
094: final boolean trans, final boolean inheritable) {
095: setName(name);
096: setValueType(valueType);
097: this .trans = trans;
098: this .inheritable = inheritable;
099: }
100:
101: /**
102: * Returns the name of the key.
103: *
104: * @return the name.
105: */
106: public String getName() {
107: return name;
108: }
109:
110: /**
111: * Sets the name of the key.
112: *
113: * @param name the name (null not permitted).
114: */
115: private void setName(final String name) {
116: if (name == null) {
117: throw new NullPointerException(
118: "StyleKey.setName(...): null not permitted.");
119: }
120: this .name = name;
121: this .identifier = definedKeys.size();
122: }
123:
124: /**
125: * Returns the class of the value for this key.
126: *
127: * @return the class.
128: */
129: public Class getValueType() {
130: return valueType;
131: }
132:
133: /**
134: * Sets the class of the value for this key.
135: *
136: * @param valueType the class.
137: */
138: private void setValueType(final Class valueType) {
139: if (valueType == null) {
140: throw new NullPointerException("ValueType must not be null");
141: }
142: this .valueType = valueType;
143: }
144:
145: /**
146: * Returns the key with the specified name. The given type is not checked against a
147: * possibly alredy defined definition, it is assumed that the type is only given for a
148: * new key definition.
149: *
150: * @param name the name.
151: * @param valueType the class.
152: * @return the style key.
153: */
154: public static StyleKey getStyleKey(final String name,
155: final Class valueType) {
156: return getStyleKey(name, valueType, false, true);
157: }
158:
159: /**
160: * Returns the key with the specified name. The given type is not checked against a
161: * possibly alredy defined definition, it is assumed that the type is only given for a
162: * new key definition.
163: *
164: * @param name the name.
165: * @param valueType the class.
166: * @return the style key.
167: */
168: public static synchronized StyleKey getStyleKey(final String name,
169: final Class valueType, final boolean trans,
170: final boolean inheritable) {
171: if (definedKeys == null) {
172: definedKeys = new HashMap();
173: definedKeySize = 0;
174: }
175: StyleKey key = (StyleKey) definedKeys.get(name);
176: if (key == null) {
177: key = new StyleKey(name, valueType, trans, inheritable);
178: definedKeys.put(name, key);
179: definedKeySize = definedKeys.size();
180: }
181: return key;
182: }
183:
184: /**
185: * Returns the key with the specified name.
186: *
187: * @param name the name.
188: * @return the style key.
189: */
190: public static synchronized StyleKey getStyleKey(final String name) {
191: if (definedKeys == null) {
192: return null;
193: } else {
194: return (StyleKey) definedKeys.get(name);
195: }
196: }
197:
198: /**
199: * Indicates whether some other object is "equal to" this one.
200: *
201: * @param o the reference object with which to compare.
202: * @return <code>true</code> if this object is the same as the obj argument;
203: * <code>false</code> otherwise.
204: */
205: public boolean equals(final Object o) {
206: if (this == o) {
207: return true;
208: }
209: if (!(o instanceof StyleKey)) {
210: return false;
211: }
212:
213: final StyleKey key = (StyleKey) o;
214:
215: if (!name.equals(key.name)) {
216: return false;
217: }
218: if (!valueType.equals(key.valueType)) {
219: return false;
220: }
221:
222: return true;
223: }
224:
225: /**
226: * Returns a hash code value for the object. This method is supported for the benefit of
227: * hashtables such as those provided by <code>java.util.Hashtable</code>.
228: * <p/>
229: *
230: * @return a hash code value for this object.
231: */
232: public int hashCode() {
233: return identifier;
234: }
235:
236: /**
237: * Replaces the automaticly generated instance with one of the defined stylekey
238: * instances or creates a new stylekey.
239: *
240: * @return the resolved element
241: *
242: * @throws ObjectStreamException if the element could not be resolved.
243: */
244: private Object readResolve() throws ObjectStreamException {
245: synchronized (StyleKey.class) {
246: final StyleKey key = getStyleKey(name);
247: if (key != null) {
248: return key;
249: }
250: return getStyleKey(name, valueType, trans, inheritable);
251: }
252: }
253:
254: public boolean isTransient() {
255: return trans;
256: }
257:
258: /**
259: * Returns a string representation of the object.
260: *
261: * @return a string representation of the object.
262: */
263: public String toString() {
264: final StringBuffer b = new StringBuffer();
265: b.append("StyleKey={name='");
266: b.append(getName());
267: b.append("', valueType='");
268: b.append(getValueType());
269: b.append("'}");
270: return b.toString();
271: }
272:
273: public Object clone() throws CloneNotSupportedException {
274: return super .clone();
275: }
276:
277: public boolean isInheritable() {
278: return inheritable;
279: }
280:
281: public int getIdentifier() {
282: return identifier;
283: }
284:
285: public static int getDefinedStyleKeyCount() {
286: return definedKeySize;
287: }
288:
289: public static synchronized StyleKey[] getDefinedStyleKeys() {
290: if (definedKeys == null) {
291: Log
292: .warn("The engine has not been booted and the default keys have no been registered yet.");
293: registerDefaults();
294: }
295: return (StyleKey[]) definedKeys.values().toArray(
296: new StyleKey[definedKeys.size()]);
297: }
298:
299: public static synchronized void registerDefaults() {
300: final Configuration config = JFreeReportBoot.getInstance()
301: .getGlobalConfig();
302: final Iterator it = config
303: .findPropertyKeys("org.jfree.report.stylekeys.");
304: final ClassLoader classLoader = ObjectUtilities
305: .getClassLoader(StyleKey.class);
306:
307: while (it.hasNext()) {
308: final String key = (String) it.next();
309: final String keyClass = config.getConfigProperty(key);
310: try {
311: final Class c = classLoader.loadClass(keyClass);
312: registerClass(c);
313: } catch (ClassNotFoundException e) {
314: // ignore that class
315: Log.warn("Unable to register keys from " + keyClass);
316: } catch (NullPointerException e) {
317: // ignore invalid values as well.
318: Log.warn("Unable to register keys from " + keyClass);
319: }
320: }
321:
322: }
323:
324: public static synchronized void registerClass(final Class c) {
325: // Log.debug ("Registering stylekeys from " + c);
326: try {
327: final Field[] fields = c.getFields();
328: for (int i = 0; i < fields.length; i++) {
329: final Field field = fields[i];
330: final int modifiers = field.getModifiers();
331: if (Modifier.isPublic(modifiers)
332: && Modifier.isStatic(modifiers)) {
333: if (Modifier.isFinal(modifiers) == false) {
334: Log
335: .warn("Invalid implementation: StyleKeys should be 'public static final': "
336: + c);
337: }
338: if (field.getType()
339: .isAssignableFrom(StyleKey.class)) {
340: final StyleKey value = (StyleKey) field
341: .get(null);
342: // ignore the returned value, all we want is to trigger the key
343: // creation
344: // Log.debug ("Loaded key " + value);
345: }
346: }
347: }
348: } catch (IllegalAccessException e) {
349: // wont happen, we've checked it..
350: Log.warn("Unable to register keys from " + c.getName());
351: }
352: }
353:
354: }
|