001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket;
018:
019: import java.io.Serializable;
020:
021: import org.apache.wicket.util.lang.Classes;
022:
023: /**
024: * A key to a piece of metadata associated with a Component at runtime. The key
025: * contains type information that can be used to check the type of any metadata
026: * value for the key when the value is set on the given Component. MetaDataKey
027: * is abstract in order to force the creation of a subtype. That subtype is used
028: * to test for identity when looking for the metadata because actual object
029: * identity would suffer from problems under serialization. So, the correct way
030: * to declare a MetaDataKey is like this: public static MetaDataKey ROLE = new
031: * MetaDataKey(Role.class) { }
032: *
033: * @author Jonathan Locke
034: */
035: public abstract class MetaDataKey implements IClusterable {
036: private static final long serialVersionUID = 1L;
037:
038: /** Type of data associated with this key */
039: private final String typeName;
040:
041: /**
042: * Constructor.
043: *
044: * @param type
045: * The type of value stored under this key
046: */
047: public MetaDataKey(final Class type) {
048: this .typeName = type.getName();
049: }
050:
051: /**
052: * @see java.lang.Object#equals(java.lang.Object)
053: */
054: public boolean equals(Object obj) {
055: return obj != null && getClass().isInstance(obj);
056: }
057:
058: /**
059: * @param metaData
060: * Array of metadata to search
061: * @return The entry value
062: */
063: Serializable get(MetaDataEntry[] metaData) {
064: if (metaData != null) {
065: for (int i = 0; i < metaData.length; i++) {
066: MetaDataEntry m = metaData[i];
067: if (equals(m.key)) {
068: return m.object;
069: }
070: }
071: }
072: return null;
073: }
074:
075: /**
076: * @param metaData
077: * The array of metadata
078: * @param object
079: * The object to set, null to remove
080: * @return Any new metadata array (if it was reallocated)
081: */
082: MetaDataEntry[] set(MetaDataEntry[] metaData,
083: final Serializable object) {
084: checkType(object);
085: boolean set = false;
086: if (metaData != null) {
087: for (int i = 0; i < metaData.length; i++) {
088: MetaDataEntry m = metaData[i];
089: if (equals(m.key)) {
090: if (object != null) {
091: // set new value
092: m.object = object;
093: } else {
094: // remove value and shrink or null array
095: if (metaData.length > 1) {
096: int l = metaData.length - 1;
097: MetaDataEntry[] newMetaData = new MetaDataEntry[l];
098: System.arraycopy(metaData, 0, newMetaData,
099: 0, i);
100: System.arraycopy(metaData, i + 1,
101: newMetaData, i, l - i);
102: metaData = newMetaData;
103: } else {
104: metaData = null;
105: break;
106: }
107: }
108: set = true;
109: }
110: }
111: }
112: if (!set && object != null) {
113: MetaDataEntry m = new MetaDataEntry(this , object);
114: if (metaData == null) {
115: metaData = new MetaDataEntry[1];
116: metaData[0] = m;
117: } else {
118: final MetaDataEntry[] newMetaData = new MetaDataEntry[metaData.length + 1];
119: System.arraycopy(metaData, 0, newMetaData, 0,
120: metaData.length);
121: newMetaData[metaData.length] = m;
122: metaData = newMetaData;
123: }
124: }
125: return metaData;
126: }
127:
128: /**
129: * Checks the type of the given object against the type for this metadata
130: * key.
131: *
132: * @param object
133: * The object to check
134: * @throws IllegalArgumentException
135: * Thrown if the type of the given object does not match the
136: * type for this key.
137: */
138: void checkType(final Object object) {
139: Class clazz = Classes.resolveClass(typeName);
140: if (object != null
141: && !clazz.isAssignableFrom(object.getClass())) {
142: throw new IllegalArgumentException("MetaDataKey "
143: + getClass() + " requires argument of " + clazz
144: + ", not " + object.getClass());
145: }
146: }
147:
148: /**
149: * @see java.lang.Object#toString()
150: */
151: public String toString() {
152: return getClass() + "[type=" + typeName + "]";
153: }
154: }
|