001: /**********************************************************************
002: Copyright (c) 2004 Erik Bengtson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: 2005 Andy Jefferson - addition of states
017: 2007 Andy Jefferson - moved extensions to this class, javadocs
018: ...
019: **********************************************************************/package org.jpox.metadata;
020:
021: import java.io.Serializable;
022: import java.util.Collection;
023: import java.util.HashSet;
024: import java.util.Iterator;
025:
026: import org.jpox.exceptions.JPOXException;
027: import org.jpox.util.Localiser;
028:
029: /**
030: * Base class for all MetaData.
031: * <h3>MetaData Lifecycle</h3>
032: * The states represent the lifecycle of a MetaData object. The lifecycle goes as follows :
033: * <OL>
034: * <LI>MetaData object is created (values passed in from a parsed file, or manually generated)</LI>
035: * <LI>MetaData object is populated (maybe pass in a class that it represents, creating any additional
036: * information that wasn't in the initial data).</LI>
037: * <LI>MetaData object is initialised (any internal arrays are set up, and additions of data is blocked
038: * from this point).
039: * <LI>MetaData object is added to with runtime information like actual column names and types in use.</LI>
040: * </OL>
041: * <h3>MetaData Extensability</h3>
042: * <p>
043: * All MetaData elements are extensible with extensions for a "vendor-name". Extensions take the form
044: * of a key and a value.
045: *
046: * @version $Revision: 1.12 $
047: */
048: public class MetaData implements Serializable {
049: protected static Localiser LOCALISER = Localiser
050: .getInstance("org.jpox.metadata.Localisation");
051:
052: /** State representing the start state of MetaData, representing the initial values passed in. */
053: public static final int METADATA_CREATED_STATE = 0;
054:
055: /** State reflecting that MetaData has been populated with real class definition adding any defaulted info. */
056: public static final int METADATA_POPULATED_STATE = 1;
057:
058: /** State reflecting that MetaData object has been initialised with any internal info required. */
059: public static final int METADATA_INITIALISED_STATE = 2;
060:
061: /** State reflecting that MetaData object has been modified with usage information (e.g defaulted column names). */
062: public static final int METADATA_USED_STATE = 3;
063:
064: /** State of the MetaData. */
065: protected int metaDataState = METADATA_CREATED_STATE;
066:
067: /** Parent MetaData object, allowing hierarchical MetaData structure. */
068: protected MetaData parent;
069:
070: /** Vendor name used by JPOX for extensions. */
071: public static final String JPOX_VENDOR_NAME = "jpox";
072:
073: /** List of extensions for this MetaData element. */
074: protected Collection extensions = null;
075:
076: /**
077: * Constructor. Taking the parent MetaData object (if any).
078: * @param parent The parent MetaData object.
079: */
080: public MetaData(MetaData parent) {
081: this .parent = parent;
082: }
083:
084: // -------------------------------- Mutators -------------------------------
085:
086: /**
087: * Method to populate the object.
088: * The state changes to "POPULATED" after this call.
089: */
090: public void populate() {
091: setPopulated();
092: }
093:
094: /**
095: * Method to initialise the object.
096: * The state changes to "INITIALISED" after this call.
097: */
098: public void initialise() {
099: setInitialised();
100: }
101:
102: /**
103: * Utility to set the state as initialised.
104: */
105: public void setInitialised() {
106: metaDataState = METADATA_INITIALISED_STATE;
107: }
108:
109: /**
110: * Utility to set the state as populated.
111: */
112: public void setPopulated() {
113: metaDataState = METADATA_POPULATED_STATE;
114: }
115:
116: /**
117: * Utility to set the state as used.
118: */
119: public void setUsed() {
120: metaDataState = METADATA_USED_STATE;
121: }
122:
123: /**
124: * Convenience method to set the parent of this MetaData element.
125: * Only valid for calling until the MetaData is populated/initialised and throws a JPOXException
126: * thereafter.
127: * @param md The parent
128: */
129: public void setParent(MetaData md) {
130: if (isPopulated() || isInitialised()) {
131: throw new JPOXException("Cannot set parent of " + this
132: + " since it is already populated/initialised");
133: }
134: this .parent = md;
135: }
136:
137: /**
138: * Append new Extension (for the specified vendor).
139: * Will throw an InvalidMetaDataException if the input is invalid.
140: * @param vendor vendor-name tag value
141: * @param key key tag value
142: * @param value value tag value
143: */
144: public void addExtension(String vendor, String key, String value) {
145: if (vendor == null
146: || (vendor.equalsIgnoreCase(JPOX_VENDOR_NAME) && (key == null || value == null))) {
147: throw new InvalidMetaDataException(LOCALISER, "044160",
148: vendor, key, value);
149: }
150:
151: if (vendor.equals(JPOX_VENDOR_NAME) && hasExtension(key)) {
152: // Remove any existing value
153: removeExtension(key);
154: }
155:
156: if (extensions == null) {
157: // First extensions so allocate the collection. We dont need ordering so use HashSet
158: extensions = new HashSet(2);
159: }
160: extensions.add(new ExtensionMetaData(vendor, key, value));
161: }
162:
163: /**
164: * Append new Extension (for JPOX).
165: * Will throw an InvalidMetaDataException if the input is invalid.
166: * @param key key tag value
167: * @param value value tag value
168: */
169: public void addExtension(String key, String value) {
170: addExtension(JPOX_VENDOR_NAME, key, value);
171: }
172:
173: /**
174: * Method to remove a (JPOX) MetaData extension.
175: * @param key Key of the tag
176: */
177: public void removeExtension(String key) {
178: if (extensions == null) {
179: return;
180: }
181:
182: Iterator iter = extensions.iterator();
183: while (iter.hasNext()) {
184: ExtensionMetaData ex = (ExtensionMetaData) iter.next();
185: if (ex.getVendorName().equalsIgnoreCase(JPOX_VENDOR_NAME)
186: && ex.getKey().equals(key)) {
187: iter.remove();
188: break;
189: }
190: }
191: }
192:
193: // -------------------------------- Accessors ------------------------------
194:
195: /**
196: * Accessor for the parent MetaData object.
197: * @return Parent MetaData object.
198: */
199: public MetaData getParent() {
200: return parent;
201: }
202:
203: /**
204: * Accessor for whether the object state is "populated" (at least).
205: * @return Whether it is populated.
206: */
207: public boolean isPopulated() {
208: return (metaDataState >= METADATA_POPULATED_STATE);
209: }
210:
211: /**
212: * Accessor for whether the object state is "initialised" (at least).
213: * @return Whether it is initialised
214: */
215: public boolean isInitialised() {
216: return (metaDataState >= METADATA_INITIALISED_STATE);
217: }
218:
219: /**
220: * Accessor for whether the object state is "used" (has been modified with usage info).
221: * @return Whether it is used.
222: */
223: public boolean isUsed() {
224: return (metaDataState == METADATA_USED_STATE);
225: }
226:
227: /**
228: * Accessor for the number of extensions.
229: * @return Number of extensions
230: */
231: public int getNoOfExtensions() {
232: if (extensions == null) {
233: return 0;
234: }
235: return extensions.size();
236: }
237:
238: /**
239: * Accessor for the extensions.
240: * @return The extensions.
241: **/
242: public ExtensionMetaData[] getExtensions() {
243: if (extensions == null || extensions.size() == 0) {
244: return null;
245: }
246: return (ExtensionMetaData[]) extensions
247: .toArray(new ExtensionMetaData[extensions.size()]);
248: }
249:
250: /**
251: * Accessor for whether an extension exists (for JPOX).
252: * @param key The key of the extension
253: * @return Whether the extension exists
254: */
255: public boolean hasExtension(String key) {
256: if (extensions == null || key == null) {
257: return false;
258: }
259:
260: Iterator iter = extensions.iterator();
261: while (iter.hasNext()) {
262: ExtensionMetaData ex = (ExtensionMetaData) iter.next();
263: if (ex.getKey().equals(key)
264: && ex.getVendorName().equalsIgnoreCase(
265: JPOX_VENDOR_NAME)) {
266: return true;
267: }
268: }
269: return false;
270: }
271:
272: /**
273: * Accessor for the value of a particular extension (for JPOX).
274: * @param key The key of the extension
275: * @return The value of the extension (null if not existing)
276: */
277: public String getValueForExtension(String key) {
278: if (extensions == null || key == null) {
279: return null;
280: }
281:
282: Iterator iter = extensions.iterator();
283: while (iter.hasNext()) {
284: ExtensionMetaData ex = (ExtensionMetaData) iter.next();
285: if (ex.getKey().equals(key)
286: && ex.getVendorName().equalsIgnoreCase(
287: JPOX_VENDOR_NAME)) {
288: return ex.getValue();
289: }
290: }
291: return null;
292: }
293:
294: /**
295: * Accessor for the value of a particular extension (for JPOX), but
296: * splitting it into separate parts. This is for extension tags that have a
297: * value as comma separated.
298: * @param key The key of the extension
299: * @return The value(s) of the extension (null if not existing)
300: */
301: public String[] getValuesForExtension(String key) {
302: if (extensions == null || key == null) {
303: return null;
304: }
305:
306: Iterator iter = extensions.iterator();
307: while (iter.hasNext()) {
308: ExtensionMetaData ex = (ExtensionMetaData) iter.next();
309: if (ex.getKey().equals(key)
310: && ex.getVendorName().equalsIgnoreCase(
311: JPOX_VENDOR_NAME)) {
312: return MetaDataUtils.getInstance()
313: .getValuesForCommaSeparatedAttribute(
314: ex.getValue());
315: }
316: }
317: return null;
318: }
319:
320: // -------------------------------- Utilities ------------------------------
321:
322: /**
323: * Accessor for a string representation of the object.
324: * @return a string representation of the object.
325: */
326: public String toString() {
327: return toString("", "");
328: }
329:
330: /**
331: * Returns a string representation of the object.
332: * @param prefix prefix string
333: * @param indent indent string
334: * @return a string representation of the object.
335: */
336: public String toString(String prefix, String indent) {
337: if (extensions == null || extensions.size() == 0) {
338: return "";
339: }
340:
341: StringBuffer sb = new StringBuffer();
342: Iterator iter = extensions.iterator();
343: while (iter.hasNext()) {
344: ExtensionMetaData ex = (ExtensionMetaData) iter.next();
345: sb.append(prefix).append(ex.toString()).append("\n");
346: }
347: return sb.toString();
348: }
349: }
|