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.AmberField;
034: import com.caucho.amber.field.DependentEntityOneToOneField;
035: import com.caucho.amber.field.EntityManyToOneField;
036: import com.caucho.amber.field.Id;
037: import com.caucho.amber.field.IdField;
038: import com.caucho.amber.field.KeyManyToOneField;
039: import com.caucho.amber.manager.AmberPersistenceUnit;
040: import com.caucho.amber.table.Column;
041: import com.caucho.amber.table.ForeignColumn;
042: import com.caucho.amber.table.LinkColumns;
043: import com.caucho.amber.type.EntityType;
044: import com.caucho.config.ConfigException;
045: import com.caucho.util.L10N;
046: import com.caucho.util.Log;
047:
048: import java.util.ArrayList;
049: import java.util.logging.Logger;
050:
051: /**
052: * many-to-one relation
053: */
054: public class CmrManyToOne extends CmrRelation {
055: private static final L10N L = new L10N(CmrManyToOne.class);
056: private static final Logger log = Log.open(CmrManyToOne.class);
057:
058: private final EjbEntityBean _targetBean;
059:
060: private SqlRelation[] _sqlColumns;
061:
062: private EntityManyToOneField _amberManyToOne;
063: private DependentEntityOneToOneField _amberDependentOneToOne;
064:
065: private boolean _isDependent;
066: private boolean _isSourceCascadeDelete;
067: private boolean _isTargetCascadeDelete;
068:
069: /**
070: * Creates a new cmp-relation
071: */
072: public CmrManyToOne(EjbEntityBean entityBean, String fieldName,
073: EjbEntityBean targetBean) throws ConfigException {
074: super (entityBean, fieldName);
075:
076: _targetBean = targetBean;
077:
078: ApiMethod getter = getGetter();
079:
080: if (!getter.getReturnType().equals(_targetBean.getLocal()))
081: throw new ConfigException(
082: L
083: .l(
084: "{0}: '{1}' must return the local interface '{2}' of the EJB bean '{3}'.",
085: entityBean.getEJBClass().getName(),
086: getter.getFullName(), _targetBean
087: .getLocal().getName(),
088: _targetBean.getEJBName()));
089: }
090:
091: /**
092: * Returns the target bean
093: */
094: public EjbEntityBean getTargetBean() {
095: return _targetBean;
096: }
097:
098: /**
099: * Returns the target type.
100: */
101: public ApiClass getTargetType() {
102: return _targetBean.getLocal();
103: }
104:
105: /**
106: * Sets the column.
107: */
108: public void setSQLColumns(SqlRelation[] columns) {
109: _sqlColumns = columns;
110: }
111:
112: /**
113: * Gets the column.
114: */
115: public SqlRelation[] getSQLColumns() {
116: return _sqlColumns;
117: }
118:
119: /**
120: * Set true for a dependent one-to-one
121: */
122: public void setDependent(boolean isDependent) {
123: _isDependent = isDependent;
124: }
125:
126: /**
127: * Set true for a cascade-delete many-to-one
128: */
129: public void setSourceCascadeDelete(boolean isCascadeDelete) {
130: _isSourceCascadeDelete = isCascadeDelete;
131: }
132:
133: /**
134: * Set true for a cascade-delete many-to-one
135: */
136: public void setTargetCascadeDelete(boolean isCascadeDelete) {
137: _isTargetCascadeDelete = isCascadeDelete;
138: }
139:
140: /**
141: * Return true for a cascade-delete many-to-one
142: */
143: public boolean isCascadeDelete() {
144: return _isSourceCascadeDelete;
145: }
146:
147: /**
148: * Returns the amber many-to-one.
149: */
150: public EntityManyToOneField getAmberManyToOne() {
151:
152: if (_amberManyToOne == null) {
153: try {
154: EntityType sourceType = getEntity().getEntityType();
155:
156: _amberManyToOne = new EntityManyToOneField(sourceType,
157: getName());
158:
159: EntityType targetType = _targetBean.getEntityType();
160: _amberManyToOne.setType(targetType);
161:
162: _amberManyToOne.setLinkColumns(calculateColumns(
163: sourceType, targetType));
164:
165: if (!_isDependent) {
166: _amberManyToOne
167: .setSourceCascadeDelete(_isSourceCascadeDelete);
168: _amberManyToOne
169: .setTargetCascadeDelete(_isTargetCascadeDelete);
170: }
171:
172: _amberManyToOne.init();
173: } catch (RuntimeException e) {
174: throw e;
175: } catch (Exception e) {
176: throw new RuntimeException(e);
177: }
178: }
179:
180: return _amberManyToOne;
181: }
182:
183: /**
184: * Returns the amber one-to-one.
185: */
186: public DependentEntityOneToOneField getAmberOneToOne() {
187: return _amberDependentOneToOne;
188: }
189:
190: /**
191: * Amber creating the id field.
192: */
193: public IdField createId(AmberPersistenceUnit amberPersistenceUnit,
194: EntityType type) throws ConfigException {
195: String fieldName = getName();
196:
197: EntityType sourceType = getEntity().getEntityType();
198: EntityType targetType = getTargetBean().getEntityType();
199:
200: /*
201: columns.add(new ForeignColumn(sqlName, targetType.getId().getKeys().get(0)));
202: */
203:
204: KeyManyToOneField keyField = new KeyManyToOneField(type,
205: fieldName);
206: keyField.setType(targetType);
207:
208: keyField
209: .setLinkColumns(calculateColumns(sourceType, targetType));
210:
211: keyField.init();
212:
213: return keyField;
214: }
215:
216: /**
217: * Creates the amber type.
218: */
219: public AmberField assembleAmber(EntityType type)
220: throws ConfigException {
221: AmberPersistenceUnit manager = type.getPersistenceUnit();
222: EntityType targetType = getTargetBean().getEntityType();
223:
224: if (_isDependent) {
225: DependentEntityOneToOneField oneToOne;
226: oneToOne = new DependentEntityOneToOneField(type, getName());
227:
228: _amberDependentOneToOne = oneToOne;
229:
230: // oneToOne.setType(_targetBean.getEntityType());
231: //oneToOne.setCascadeDelete(_isCascadeDelete);
232:
233: return oneToOne;
234: } else {
235: EntityManyToOneField manyToOne;
236: manyToOne = new EntityManyToOneField(type, getName());
237:
238: _amberManyToOne = manyToOne;
239:
240: manyToOne.setType(_targetBean.getEntityType());
241:
242: manyToOne
243: .setLinkColumns(calculateColumns(type, targetType));
244:
245: manyToOne.setSourceCascadeDelete(_isSourceCascadeDelete);
246: manyToOne.setTargetCascadeDelete(_isTargetCascadeDelete);
247:
248: return manyToOne;
249: }
250: }
251:
252: private LinkColumns calculateColumns(EntityType type,
253: EntityType targetType) throws ConfigException {
254: ArrayList<ForeignColumn> columns = new ArrayList<ForeignColumn>();
255:
256: Id id = targetType.getId();
257:
258: if (id == null || id.getColumns() == null)
259: throw new IllegalStateException(L.l(
260: "Entity '{0}' has invalid id columns.", targetType
261: .getName()));
262:
263: ArrayList<Column> keys = id.getColumns();
264:
265: if (_sqlColumns != null && _sqlColumns.length == keys.size()) {
266: for (Column key : keys) {
267: String sqlColumn = getColumn(_sqlColumns, key.getName());
268: ForeignColumn column = type.getTable()
269: .createForeignColumn(sqlColumn, key);
270:
271: columns.add(column);
272: }
273: } else if (_sqlColumns != null && _sqlColumns.length == 1) {
274: String baseSqlColumn = _sqlColumns[0].getSQLColumn();
275:
276: for (Column key : keys) {
277: String sqlColumn = baseSqlColumn + "_" + key.getName();
278:
279: ForeignColumn column = type.getTable()
280: .createForeignColumn(sqlColumn, key);
281: columns.add(column);
282: }
283: } else if (_sqlColumns != null && _sqlColumns.length > 0) {
284: throw new IllegalStateException("Mismatched SQL columns");
285: } else if (keys.size() == 1) {
286: String sqlColumn = toSqlName(getName());
287:
288: ForeignColumn column = type.getTable().createForeignColumn(
289: sqlColumn, keys.get(0));
290: columns.add(column);
291: } else {
292: String baseSqlColumn = toSqlName(getName());
293: for (Column key : keys) {
294: String sqlColumn = baseSqlColumn + "_" + key.getName();
295:
296: ForeignColumn column = type.getTable()
297: .createForeignColumn(sqlColumn, key);
298: columns.add(column);
299: }
300: }
301:
302: return new LinkColumns(type.getTable(), targetType.getTable(),
303: columns);
304: }
305:
306: private String getColumn(SqlRelation[] sqlColumns, String sqlName)
307: throws ConfigException {
308: String fieldName = getFieldName(_targetBean.getEntityType(),
309: sqlName);
310:
311: if (sqlColumns.length == 1)
312: return sqlColumns[0].getSQLColumn();
313:
314: for (int i = 0; i < sqlColumns.length; i++) {
315: String ref = sqlColumns[i].getReferences();
316:
317: if (ref == null)
318: throw new ConfigException(
319: L
320: .l(
321: "sql-column '{0}' needs a references attribute.",
322: sqlColumns[i].getSQLColumn()));
323:
324: if (ref.equals(fieldName))
325: return sqlColumns[i].getSQLColumn();
326: }
327:
328: throw new ConfigException(L.l(
329: "key '{0}' has no matching sql-column", fieldName));
330: }
331:
332: private String getFieldName(EntityType type, String sqlName)
333: throws ConfigException {
334: for (IdField field : type.getId().getKeys()) {
335: ArrayList<Column> columns = field.getColumns();
336:
337: for (int i = 0; i < columns.size(); i++)
338: if (columns.get(i).getName().equals(sqlName))
339: return field.getName();
340: }
341:
342: return sqlName;
343: }
344:
345: /**
346: * Link amber.
347: */
348: public void linkAmber() throws ConfigException {
349: CmrRelation targetRelation = getTargetRelation();
350:
351: if (targetRelation == null)
352: return;
353: else if (!(targetRelation instanceof CmrManyToOne))
354: return;
355: else if (_isDependent) {
356: CmrManyToOne targetManyToOne = (CmrManyToOne) targetRelation;
357:
358: EntityManyToOneField amberTarget = targetManyToOne
359: .getAmberManyToOne();
360:
361: if (_amberDependentOneToOne == null) {
362: EntityType type = getEntity().getEntityType();
363:
364: DependentEntityOneToOneField oneToOne;
365: oneToOne = new DependentEntityOneToOneField(type,
366: getName());
367:
368: _amberDependentOneToOne = oneToOne;
369: }
370:
371: _amberDependentOneToOne.setTargetField(amberTarget);
372: } else {
373: CmrManyToOne targetManyToOne = (CmrManyToOne) targetRelation;
374:
375: DependentEntityOneToOneField amberTarget;
376: amberTarget = targetManyToOne.getAmberOneToOne();
377:
378: EntityManyToOneField manyToOne = getAmberManyToOne();
379:
380: if (amberTarget != null && manyToOne != null) {
381: manyToOne.setTargetField(amberTarget);
382: amberTarget.setTargetField(manyToOne);
383: }
384: }
385: }
386: }
|