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:
016: Contributors:
017: 2004 Andy Jefferson - added toString(), MetaData docs, javadocs.
018: 2004 Andy Jefferson - added unique, indexed
019: ...
020: **********************************************************************/package org.jpox.metadata;
021:
022: import org.jpox.ClassLoaderResolver;
023: import org.jpox.exceptions.ClassNotResolvedException;
024: import org.jpox.exceptions.JPOXUserException;
025: import org.jpox.util.ClassUtils;
026:
027: /**
028: * This element specifies the mapping for the key component of maps.
029: * The serialized attribute specifies that the key values are to be serialized into the named column.
030: *
031: * @since 1.1
032: * @version $Revision: 1.28 $
033: */
034: public class KeyMetaData extends AbstractElementMetaData {
035: /**
036: * Constructor to create a copy of the passed metadata using the provided parent.
037: * @param parent The parent
038: * @param kmd The metadata to copy
039: */
040: public KeyMetaData(MetaData parent, KeyMetaData kmd) {
041: super (parent, kmd);
042: }
043:
044: /**
045: * Constructor.
046: * @param parent Parent MetaData
047: * @param column Name of column
048: * @param deleteAction attribute delete-action value
049: * @param updateAction attribute delete-action value
050: * @param indexed Whether to index this
051: * @param unique Whether to add a unique constraint
052: * @param mappedBy Field the key is mapped by in the value object
053: */
054: public KeyMetaData(MetaData parent, String column,
055: String deleteAction, String updateAction, String indexed,
056: String unique, String mappedBy) {
057: super (parent, column, deleteAction, updateAction, indexed,
058: unique, mappedBy);
059: }
060:
061: /**
062: * Populate the MetaData.
063: * @param clr Class loader to use
064: * @param primary the primary ClassLoader to use (or null)
065: */
066: public void populate(ClassLoaderResolver clr, ClassLoader primary) {
067: AbstractMemberMetaData fmd = (AbstractMemberMetaData) parent;
068: if (fmd.getMap() == null) {
069: // TODO Localise this
070: throw new JPOXUserException(
071: "The field "
072: + fmd.getFullFieldName()
073: + " is defined with <key>, however no <map> definition was found.")
074: .setFatal();
075: }
076:
077: String keyType = fmd.getMap().getKeyType();
078: Class keyTypeClass = null;
079: try {
080: keyTypeClass = clr.classForName(keyType, primary);
081: } catch (ClassNotResolvedException cnre) {
082: try {
083: // Maybe the user specified a java.lang class without fully-qualifying it
084: // This is beyond the scope of the JDO spec which expects java.lang cases to be fully-qualified
085: keyTypeClass = clr.classForName(ClassUtils
086: .getJavaLangClassForType(keyType), primary,
087: false);
088: fmd.getMap().key.type = keyTypeClass.getName(); // Update the MapMetaData since not yet populated
089: } catch (ClassNotResolvedException cnre2) {
090: throw new InvalidMetaDataException(LOCALISER, "044147",
091: fmd.getFullFieldName(),
092: fmd.getClassName(false), keyType);
093: }
094: }
095: if (embeddedMetaData != null
096: && (keyTypeClass.isInterface() || keyTypeClass
097: .getName().equals("java.lang.Object"))) {
098: throw new InvalidMetaDataException(LOCALISER, "044152", fmd
099: .getFullFieldName(), keyTypeClass.getName());
100: }
101:
102: // TODO This will not work currently since MapMetaData is populated *after* KeyMetaData and so the
103: // keyClassMetaData is not yet populated. What we should do is provide a postPopulate() method here
104: // that MapMetaData can call when it is populated
105: if (embeddedMetaData == null
106: && ((AbstractMemberMetaData) parent).hasMap()
107: && ((AbstractMemberMetaData) parent).getMap()
108: .isEmbeddedKey()
109: && ((AbstractMemberMetaData) parent).getJoinMetaData() != null
110: && ((AbstractMemberMetaData) parent).getMap()
111: .getKeyClassMetaData() != null) {
112: // User has specified that the key is embedded in a join table but not how we embed it
113: // so add a dummy definition
114: embeddedMetaData = new EmbeddedMetaData(this , null, null,
115: null);
116: }
117:
118: super .populate(clr, primary);
119: }
120:
121: // ------------------------------- Utilities -------------------------------
122:
123: /**
124: * Returns a string representation of the object using a prefix
125: * This can be used as part of a facility to output a MetaData file.
126: * @param prefix prefix string
127: * @param indent indent string
128: * @return a string representation of the object.
129: */
130: public String toString(String prefix, String indent) {
131: // Field needs outputting so generate metadata
132: StringBuffer sb = new StringBuffer();
133: sb.append(prefix).append("<key");
134: if (mappedBy != null) {
135: sb.append(" mapped-by=\"" + mappedBy + "\"");
136: }
137: if (columnName != null) {
138: sb.append("\n");
139: sb.append(prefix).append(
140: " column=\"" + columnName + "\"");
141: }
142: sb.append(">\n");
143:
144: // Add columns
145: for (int i = 0; i < columns.size(); i++) {
146: ColumnMetaData colmd = (ColumnMetaData) columns.get(i);
147: sb.append(colmd.toString(prefix + indent, indent));
148: }
149:
150: // Add index metadata
151: if (indexMetaData != null) {
152: sb.append(indexMetaData.toString(prefix + indent, indent));
153: }
154:
155: // Add unique metadata
156: if (uniqueMetaData != null) {
157: sb.append(uniqueMetaData.toString(prefix + indent, indent));
158: }
159:
160: // Add embedded metadata
161: if (embeddedMetaData != null) {
162: sb.append(embeddedMetaData
163: .toString(prefix + indent, indent));
164: }
165:
166: // Add foreign-key metadata
167: if (foreignKeyMetaData != null) {
168: sb.append(foreignKeyMetaData.toString(prefix + indent,
169: indent));
170: }
171:
172: // Add extensions
173: sb.append(super .toString(prefix + indent, indent));
174:
175: sb.append(prefix).append("</key>\n");
176: return sb.toString();
177: }
178: }
|