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.ejb.cfg21.CmpField;
034: import com.caucho.amber.field.AmberField;
035: import com.caucho.amber.field.EntityOneToManyField;
036: import com.caucho.amber.field.Id;
037: import com.caucho.amber.manager.AmberPersistenceUnit;
038: import com.caucho.amber.table.Column;
039: import com.caucho.amber.table.ForeignColumn;
040: import com.caucho.amber.table.LinkColumns;
041: import com.caucho.amber.type.EntityType;
042: import com.caucho.config.ConfigException;
043: import com.caucho.ejb.ql.QLParser;
044: import com.caucho.java.JavaWriter;
045: import com.caucho.util.L10N;
046:
047: import java.io.IOException;
048: import java.util.ArrayList;
049:
050: /**
051: * one-to-many relation
052: */
053: public class CmrOneToMany extends CmrRelation {
054: private static final L10N L = new L10N(CmrOneToMany.class);
055:
056: private EjbEntityBean _targetBean;
057: private String _targetField;
058:
059: private ArrayList<String> _orderByFields;
060: private ArrayList<Boolean> _orderByAscending;
061:
062: private SqlRelation[] _sqlColumns;
063:
064: private EntityOneToManyField _amberOneToMany;
065:
066: /**
067: * Creates a new cmp-relation
068: */
069: public CmrOneToMany(EjbEntityBean entityBean, String fieldName,
070: EjbEntityBean targetBean, String targetField)
071: throws ConfigException {
072: super (entityBean, fieldName);
073:
074: _targetBean = targetBean;
075: _targetField = targetField;
076: }
077:
078: /**
079: * Returns the target bean
080: */
081: public EjbEntityBean getTargetBean() {
082: return _targetBean;
083: }
084:
085: /**
086: * Returns the target type.
087: */
088: public ApiClass getTargetType() {
089: return _targetBean.getLocal();
090: }
091:
092: /**
093: * Sets the column.
094: */
095: public void setSQLColumns(SqlRelation[] columns) {
096: _sqlColumns = columns;
097: }
098:
099: /**
100: * Gets the column.
101: */
102: public SqlRelation[] getSQLColumns() {
103: return _sqlColumns;
104: }
105:
106: /**
107: * Sets the order by.
108: */
109: public void setOrderBy(String orderBySQL) throws ConfigException {
110: if (orderBySQL != null) {
111: ArrayList<String> fields = new ArrayList<String>();
112: ArrayList<Boolean> asc = new ArrayList<Boolean>();
113:
114: QLParser.parseOrderBy(_targetBean, orderBySQL, fields, asc);
115:
116: _orderByFields = fields;
117: _orderByAscending = asc;
118: }
119: }
120:
121: /**
122: * The OneToMany is a collection.
123: */
124: public boolean isCollection() {
125: return true;
126: }
127:
128: /**
129: * Create any bean methods.
130: */
131: public EjbMethod createGetter(EjbView view, ApiMethod apiMethod,
132: ApiMethod implMethod) throws ConfigException {
133: return new EjbOneToManyMethod(view, apiMethod, implMethod, this );
134: }
135:
136: /**
137: * Creates the amber type.
138: */
139: public AmberField assembleAmber(EntityType type)
140: throws ConfigException {
141: EntityOneToManyField oneToMany = new EntityOneToManyField(type,
142: getName());
143:
144: AmberPersistenceUnit manager = type.getPersistenceUnit();
145:
146: EntityType targetType = _targetBean.getEntityType();
147: oneToMany.setType(targetType);
148:
149: // if bi-directional, then other side handles it
150: // if (! (getTargetRelation() instanceof CmrManyToOne)) {
151:
152: oneToMany.setOrderBy(_orderByFields, _orderByAscending);
153:
154: _amberOneToMany = oneToMany;
155:
156: return oneToMany;
157: }
158:
159: /**
160: * Link amber.
161: */
162: public void linkAmber() throws ConfigException {
163: CmrManyToOne manyToOne = (CmrManyToOne) getTargetRelation();
164:
165: _amberOneToMany.setSourceField(manyToOne.getAmberManyToOne());
166: _amberOneToMany.setLinkColumns(manyToOne.getAmberManyToOne()
167: .getLinkColumns());
168:
169: _amberOneToMany.init();
170: }
171:
172: /**
173: * Generates the destroy method.
174: */
175: public void generateAfterCommit(JavaWriter out) throws IOException {
176: if (getHasGetter())
177: out.println("__caucho_field_" + getName() + " = null;");
178: }
179:
180: private LinkColumns calculateColumn(EntityType parentType,
181: EntityType childType, String fieldName,
182: SqlRelation[] sqlColumns) throws ConfigException {
183: Id id = parentType.getId();
184: ArrayList<Column> keys = new ArrayList<Column>(id.getColumns());
185: ArrayList<ForeignColumn> columns = new ArrayList();
186:
187: // XXX: need to remove self from the keys if identifying
188: /*
189: for (int i = keys.size() - 1; i >= 0; i--) {
190: IdField key = keys.get(i);
191:
192: if (key instanceof KeyManyToOneField) {
193: KeyManyToOneField manyToOne = (KeyManyToOneField) key;
194:
195: if (manyToOne.getEntityType() == sourceType)
196: keys.remove(i);
197: }
198: }
199: */
200:
201: if (_sqlColumns != null && _sqlColumns.length == keys.size()) {
202: for (int i = 0; i < keys.size(); i++) {
203: Column key = keys.get(i);
204:
205: String sqlColumn = getColumn(_sqlColumns, key.getName());
206: ForeignColumn column = childType.getTable()
207: .createForeignColumn(sqlColumn, key);
208:
209: columns.add(column);
210: }
211: } else if (_sqlColumns != null && _sqlColumns.length == 1) {
212: String baseSqlColumn = _sqlColumns[0].getSQLColumn();
213:
214: for (Column key : keys) {
215: String sqlColumn;
216:
217: sqlColumn = baseSqlColumn + "_" + key.getName();
218:
219: ForeignColumn column = childType.getTable()
220: .createForeignColumn(sqlColumn, key);
221: columns.add(column);
222: }
223: } else if (_sqlColumns != null && _sqlColumns.length > 0) {
224: throw new IllegalStateException("Mismatched SQL columns");
225: } else if (keys.size() == 1) {
226: Column key = keys.get(0);
227:
228: String sqlColumn = CmpField.toSqlName(fieldName);
229:
230: ForeignColumn column = childType.getTable()
231: .createForeignColumn(sqlColumn, key);
232:
233: columns.add(column);
234: } else {
235: String baseSqlColumn = CmpField.toSqlName(fieldName);
236:
237: for (Column key : keys) {
238: String sqlColumn = baseSqlColumn + "_" + key.getName();
239:
240: ForeignColumn foreignColumn = childType.getTable()
241: .createForeignColumn(sqlColumn, key);
242:
243: columns.add(foreignColumn);
244: }
245: }
246:
247: return new LinkColumns(childType.getTable(), parentType
248: .getTable(), columns);
249: }
250:
251: private String getColumn(SqlRelation[] sqlColumns, String fieldName)
252: throws ConfigException {
253: if (sqlColumns.length == 1)
254: return sqlColumns[0].getSQLColumn();
255:
256: for (int i = 0; i < sqlColumns.length; i++) {
257: String ref = sqlColumns[i].getReferences();
258:
259: if (ref == null)
260: throw new ConfigException(
261: L
262: .l(
263: "sql-column '{0}' needs a references attribute.",
264: sqlColumns[i].getSQLColumn()));
265:
266: if (ref.equals(fieldName))
267: return sqlColumns[i].getSQLColumn();
268: }
269:
270: throw new ConfigException(L.l(
271: "key '{0}' has no matching sql-column", fieldName));
272: }
273: }
|