001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.ejb.cfg21;
031:
032: import com.caucho.ejb.cfg.*;
033: import com.caucho.amber.field.IdField;
034: import com.caucho.amber.field.KeyPropertyField;
035: import com.caucho.amber.manager.AmberPersistenceUnit;
036: import com.caucho.amber.table.Column;
037: import com.caucho.amber.type.EntityType;
038: import com.caucho.amber.type.Type;
039: import com.caucho.bytecode.JClassWrapper;
040: import com.caucho.config.ConfigException;
041: import com.caucho.jdbc.JdbcMetaData;
042: import com.caucho.util.CharBuffer;
043: import com.caucho.util.L10N;
044:
045: import javax.annotation.PostConstruct;
046: import javax.ejb.EJBLocalObject;
047: import javax.ejb.EJBObject;
048:
049: /**
050: * Configuraton for a cmp-field.
051: */
052: public class CmpField extends CmpProperty {
053: private static final L10N L = new L10N(CmpProperty.class);
054:
055: private String _sqlColumn;
056: private String _abstractSQLType;
057: private String _sqlType;
058: private boolean _isAutoGenerate = true;
059:
060: private Class _javaType = String.class;
061:
062: /**
063: * Creates a new cmp-field
064: *
065: * @param entity the owning entity bean
066: */
067: public CmpField(EjbEntityBean entity) {
068: super (entity);
069: }
070:
071: /**
072: * Returns the SQL column name.
073: */
074: public String getSQLColumn() {
075: return _sqlColumn;
076: }
077:
078: /**
079: * Sets the SQL column name.
080: */
081: public void setSQLColumn(String sqlColumn) {
082: _sqlColumn = sqlColumn;
083: }
084:
085: /**
086: * Returns the SQL type name.
087: */
088: public String getSQLType() {
089: return _sqlType;
090: }
091:
092: /**
093: * Sets the SQL type name.
094: */
095: public void setSQLType(String sqlType) {
096: _sqlType = sqlType;
097: }
098:
099: /**
100: * Returns the abstract SQL type name.
101: */
102: public String getAbstractSQLType() {
103: return _abstractSQLType;
104: }
105:
106: /**
107: * Sets the abstract SQL type name.
108: */
109: public void setAbstractSQLType(String sqlType) {
110: _abstractSQLType = sqlType;
111: }
112:
113: /**
114: * Sets the Java type.
115: */
116: public void setJavaType(Class javaType) {
117: if (javaType.getName().equals("java.util.Map"))
118: Thread.dumpStack();
119:
120: //_javaType = new ClassWrapper(javaType);
121: _javaType = javaType;
122: }
123:
124: /**
125: * Returns the Java type.
126: */
127: public Class getJavaType() {
128: return _javaType;
129: }
130:
131: /**
132: * Set true for auto-generation.
133: */
134: public void setAutoGenerate(boolean isAutoGenerate) {
135: _isAutoGenerate = isAutoGenerate;
136: }
137:
138: /**
139: * true for auto-generation.
140: */
141: public boolean isAutoGenerate() {
142: return _isAutoGenerate;
143: }
144:
145: /**
146: * Initialize the field.
147: */
148: @PostConstruct
149: public void init() throws ConfigException {
150: if (getEntity().isCMP1())
151: return;
152:
153: String name = getName();
154:
155: String getterName = ("get"
156: + Character.toUpperCase(name.charAt(0)) + name
157: .substring(1));
158:
159: ApiMethod getter = getEntity().getMethod(
160: getEntity().getEJBClassWrapper(), getterName,
161: new Class[0]);
162:
163: if (getter == null)
164: throw new ConfigException(
165: L
166: .l(
167: "{0}: '{1}' is an unknown cmp-field. cmp-fields must have matching getter methods.",
168: getEntity().getEJBClass().getName(),
169: name));
170: else if (!getter.isPublic()) {
171: throw new ConfigException(
172: L
173: .l(
174: "{0}: '{1}' must be public. cmp-fields getters must be public.",
175: getEntity().getEJBClass().getName(),
176: getter.getFullName()));
177: } else if (!getter.isAbstract() && !getEntity().isAllowPOJO()) {
178: throw new ConfigException(
179: L
180: .l(
181: "{0}: '{1}' must be abstract. cmp-fields getters must be abstract.",
182: getEntity().getEJBClass().getName(),
183: getter.getFullName()));
184: } else if (getter.getExceptionTypes().length != 0) {
185: throw new ConfigException(
186: L
187: .l(
188: "{0}: '{1}' must not throw {2}. Container managed fields and relations must not throw exceptions.",
189: getEntity().getEJBClass().getName(),
190: getter.getFullName(), getter
191: .getExceptionTypes()[0]
192: .getName()));
193: }
194:
195: _javaType = getter.getReturnType();
196:
197: if ("void".equals(_javaType.getName())) {
198: throw new ConfigException(
199: L
200: .l(
201: "{0}: '{1}' must not return void. CMP fields must not return void.",
202: getEntity().getEJBClass().getName(),
203: getName()));
204: } else if (EJBLocalObject.class.isAssignableFrom(_javaType)) {
205: throw new ConfigException(
206: L
207: .l(
208: "{0}: '{1}' must not return an EJB interface. CMP fields must return concrete values.",
209: getEntity().getEJBClass().getName(),
210: getName()));
211: } else if (EJBObject.class.isAssignableFrom(_javaType)) {
212: throw new ConfigException(
213: L
214: .l(
215: "{0}: '{1}' must not return an EJB interface. CMP fields must return concrete values.",
216: getEntity().getEJBClass().getName(),
217: getName()));
218: }
219:
220: String setterName = ("set"
221: + Character.toUpperCase(name.charAt(0)) + name
222: .substring(1));
223:
224: ApiMethod setter = getEntity().getMethod(
225: getEntity().getEJBClassWrapper(), setterName,
226: new Class[] { getter.getReturnType() });
227:
228: if (setter == null) {
229: } else if (!setter.isPublic()) {
230: throw new ConfigException(
231: L
232: .l(
233: "{0}: '{1}' must be public. cmp-fields setters must be public.",
234: getEntity().getEJBClass().getName(),
235: setter.getFullName()));
236: } else if (!"void".equals(setter.getReturnType().getName())) {
237: throw new ConfigException(
238: L
239: .l(
240: "{0}: '{1}' must return void. cmp-fields setters must return void.",
241: getEntity().getEJBClass().getName(),
242: setter.getFullName()));
243: } else if (!setter.isAbstract() && !getEntity().isAllowPOJO()) {
244: throw new ConfigException(
245: L
246: .l(
247: "{0}: '{1}' must be abstract. cmp-fields setters must be abstract.",
248: getEntity().getEJBClass().getName(),
249: setter.getFullName()));
250: } else if (setter.getExceptionTypes().length != 0) {
251: throw new ConfigException(
252: L
253: .l(
254: "{0}: '{1}' must not throw {2}. Container managed fields and relations must not throw exceptions.",
255: getEntity().getEJBClass().getName(),
256: setter.getFullName(), setter
257: .getExceptionTypes()[0]
258: .getName()));
259: }
260:
261: if (_sqlColumn == null)
262: _sqlColumn = toSqlName(getName());
263: }
264:
265: /**
266: * Amber creating the id field.
267: */
268: public IdField createId(AmberPersistenceUnit amberPersistenceUnit,
269: EntityType type) throws ConfigException {
270: String fieldName = getName();
271: String sqlName = getSQLColumn();
272:
273: if (sqlName == null)
274: sqlName = toSqlName(fieldName);
275:
276: Class dataType = getJavaType();
277:
278: if (dataType == null)
279: throw new NullPointerException(L.l(
280: "'{0}' is an unknown field", fieldName));
281:
282: Type amberType = amberPersistenceUnit.createType(JClassWrapper
283: .create(dataType));
284: Column column = type.getTable()
285: .createColumn(sqlName, amberType);
286:
287: KeyPropertyField idField = new KeyPropertyField(type,
288: fieldName, column);
289:
290: if (!isAutoGenerate()) {
291: } else if ("int".equals(dataType.getName())
292: || "long".equals(dataType.getName())
293: || "java.lang.Integer".equals(dataType.getName())
294: || "java.lang.Long".equals(dataType.getName())) {
295: JdbcMetaData metaData = amberPersistenceUnit.getMetaData();
296:
297: if (metaData.supportsIdentity()) {
298: idField.setGenerator("identity");
299: column.setGeneratorType("identity");
300: } else if (metaData.supportsSequences()) {
301: idField.setGenerator("sequence");
302: column.setGeneratorType("sequence");
303:
304: String name = type.getTable().getName() + "_cseq";
305:
306: type.setGenerator(idField.getName(),
307: amberPersistenceUnit.createSequenceGenerator(
308: name, 10));
309: } else {
310: // XXX: should try table
311: }
312: }
313:
314: return idField;
315: }
316:
317: static String toSqlName(String name) {
318: CharBuffer cb = new CharBuffer();
319:
320: for (int i = 0; i < name.length(); i++) {
321: char ch = name.charAt(i);
322:
323: if (!Character.isUpperCase(ch))
324: cb.append(ch);
325: else if (i > 0
326: && !Character.isUpperCase(name.charAt(i - 1))) {
327: cb.append("_");
328: cb.append(Character.toLowerCase(ch));
329: } else if (i + 1 < name.length()
330: && !Character.isUpperCase(name.charAt(i + 1))) {
331: cb.append("_");
332: cb.append(Character.toLowerCase(ch));
333: } else
334: cb.append(Character.toLowerCase(ch));
335: }
336:
337: return cb.toString();
338: }
339:
340: public String toString() {
341: return "CmpField[" + getName() + "]";
342: }
343: }
|