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: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.amber.table;
030:
031: import com.caucho.amber.manager.AmberPersistenceUnit;
032: import com.caucho.amber.type.Type;
033: import com.caucho.config.ConfigException;
034: import com.caucho.config.LineConfigException;
035: import com.caucho.java.JavaWriter;
036: import com.caucho.util.CharBuffer;
037: import com.caucho.util.L10N;
038:
039: import javax.sql.DataSource;
040: import java.io.IOException;
041: import java.sql.Connection;
042: import java.sql.ResultSet;
043: import java.sql.SQLException;
044: import java.sql.Statement;
045:
046: /**
047: * Column configuration.
048: */
049: public class Column {
050: private static final L10N L = new L10N(Column.class);
051:
052: private Table _table;
053:
054: private String _name;
055:
056: private String _configLocation;
057:
058: private Type _type;
059:
060: private boolean _isPrimaryKey;
061:
062: private String _sqlType;
063:
064: private boolean _isNotNull;
065: private boolean _isUnique;
066: private int _length;
067: private int _precision;
068: private int _scale;
069:
070: private String _generatorType;
071: private String _generator;
072:
073: // getter/setter stuff
074: private String _fieldName;
075:
076: Column(Table table, String name) {
077: _table = table;
078: _name = name;
079: }
080:
081: /**
082: * Creates the column.
083: *
084: * @param table the owning table
085: * @param name the column sql name
086: * @param type the column's type
087: */
088: public Column(Table table, String name, Type type) {
089: _table = table;
090: _name = name;
091: _type = type;
092: }
093:
094: /**
095: * Returns the owning table.
096: */
097: public Table getTable() {
098: return _table;
099: }
100:
101: /**
102: * Gets the column name.
103: */
104: public String getName() {
105: return _name;
106: }
107:
108: /**
109: * Sets the column name.
110: */
111: public void setName(String name) {
112: _name = name;
113: }
114:
115: /**
116: * Sets the config location.
117: */
118: public void setConfigLocation(String location) {
119: _configLocation = location;
120: }
121:
122: /**
123: * Returns the type.
124: */
125: public Type getType() {
126: return _type;
127: }
128:
129: /**
130: * Sets the primary key property.
131: */
132: public void setPrimaryKey(boolean isPrimaryKey) {
133: _isPrimaryKey = isPrimaryKey;
134: }
135:
136: /**
137: * Return true for a primary key column.
138: */
139: public boolean isPrimaryKey() {
140: return _isPrimaryKey;
141: }
142:
143: /**
144: * Sets the generator type.
145: */
146: public void setGeneratorType(String type) {
147: _generatorType = type;
148: }
149:
150: /**
151: * Generates the insert name.
152: */
153: public String generateInsertName() {
154: return _name;
155: }
156:
157: /**
158: * Sets the sql type for create table
159: */
160: public void setSQLType(String sqlType) {
161: _sqlType = sqlType;
162: }
163:
164: /**
165: * Gets the sql type for the create table
166: */
167: public String getSQLType() {
168: return _sqlType;
169: }
170:
171: /**
172: * Sets the length property.
173: */
174: public void setLength(int length) {
175: _length = length;
176: }
177:
178: /**
179: * Gets the length property.
180: */
181: public int getLength() {
182: return _length;
183: }
184:
185: /**
186: * Sets the not-null property.
187: */
188: public void setNotNull(boolean isNotNull) {
189: _isNotNull = isNotNull;
190: }
191:
192: /**
193: * Gets the not-null property.
194: */
195: public boolean isNotNull() {
196: return _isNotNull;
197: }
198:
199: /**
200: * Set the precision property.
201: */
202: public void setPrecision(int precision) {
203: _precision = precision;
204: }
205:
206: /**
207: * Gets the precision property.
208: */
209: public int getPrecision() {
210: return _precision;
211: }
212:
213: /**
214: * Set the scale property
215: */
216: public void setScale(int scale) {
217: _scale = scale;
218: }
219:
220: /**
221: * Get the scale property
222: */
223: public int getScale() {
224: return _scale;
225: }
226:
227: /**
228: * Sets the unique property.
229: */
230: public void setUnique(boolean isUnique) {
231: _isUnique = isUnique;
232: }
233:
234: /**
235: * Gets the unique property.
236: */
237: public boolean isUnique() {
238: return _isUnique;
239: }
240:
241: /**
242: * Generates the clause to create the column.
243: */
244: String generateCreateTableSQL(AmberPersistenceUnit manager) {
245: CharBuffer cb = new CharBuffer();
246: cb.append(_name + " ");
247: String sqlType = _sqlType;
248:
249: if (_sqlType != null)
250: sqlType = _sqlType;
251: else {
252: sqlType = _type.generateCreateColumnSQL(manager, _length,
253: _precision, _scale);
254: }
255:
256: if ("identity".equals(_generatorType)) {
257: cb.append(manager.getMetaData().createIdentitySQL(sqlType));
258: } else {
259: cb.append(sqlType);
260: }
261:
262: if (isPrimaryKey()) {
263: cb.append(" primary key");
264: } else if (!"identity".equals(_generatorType)) {
265: if (isNotNull())
266: cb.append(" not null");
267: if (isUnique())
268: cb.append(" unique");
269: }
270:
271: return cb.toString();
272: }
273:
274: /**
275: * Creates the table if missing.
276: */
277: void validateDatabase(AmberPersistenceUnit amberPersistenceUnit)
278: throws ConfigException {
279: try {
280: DataSource ds = amberPersistenceUnit.getDataSource();
281: Connection conn = ds.getConnection();
282: try {
283: Statement stmt = conn.createStatement();
284:
285: String sql = "select " + getName() + " from "
286: + _table.getName() + " where 1=0";
287:
288: try {
289: // If the table exists, return
290:
291: ResultSet rs = stmt.executeQuery(sql);
292: rs.close();
293: return;
294: } catch (SQLException e) {
295: throw error(
296: L
297: .l(
298: "'{0}' is not a valid database column in table '{1}'. Either the table needs to be created or the create-database-tables attribute must be set.\n\n {2}\n\n{3}",
299: getName(), getTable()
300: .getName(), sql, e
301: .toString()), e);
302: }
303: } finally {
304: conn.close();
305: }
306: } catch (ConfigException e) {
307: throw e;
308: } catch (Exception e) {
309: throw ConfigException.create(e);
310: }
311: }
312:
313: /**
314: * Generates the clause to load the column.
315: */
316: public String generateSelect(String id) {
317: if (id != null)
318: return id + "." + _name;
319: else
320: return _name;
321: }
322:
323: /**
324: * Generates the where clause.
325: */
326: public String generateMatchArgWhere(String id) {
327: if (id != null)
328: return id + "." + _name + "=?";
329: else
330: return _name + "=?";
331: }
332:
333: /**
334: * Generates the update clause.
335: */
336: public String generateUpdateSet() {
337: return _name + "=?";
338: }
339:
340: /**
341: * Generates the update clause setting to null.
342: */
343: public String generateUpdateSetNull() {
344: return _name + "=null";
345: }
346:
347: /**
348: * Generates the prologue.
349: */
350: public void generatePrologue(JavaWriter out) throws IOException {
351: }
352:
353: /**
354: * Returns the field name.
355: */
356: public String getFieldName() {
357: return "__amber_" + getName();
358: }
359:
360: /**
361: * Generates a string to load the type as a property.
362: */
363: public void generateSet(JavaWriter out, String pstmt, String index,
364: String value) throws IOException {
365: if (value != null)
366: _type.generateSet(out, pstmt, index, value);
367: else
368: _type.generateSetNull(out, pstmt, index);
369: }
370:
371: /**
372: * Generates a string to load the type as a property.
373: */
374: public void generateSetVersion(JavaWriter out, String pstmt,
375: String index, String value) throws IOException {
376: _type.generateSetVersion(out, pstmt, index, value);
377: }
378:
379: /**
380: * Generates a string to load the type as a property.
381: */
382: public int generateLoad(JavaWriter out, String rs, String indexVar,
383: int index) throws IOException {
384: return _type.generateLoad(out, rs, indexVar, index);
385: }
386:
387: /**
388: * Converts to the object key.
389: */
390: public Object toObjectKey(long value) {
391: return getType().toObject(value);
392: }
393:
394: protected ConfigException error(String msg, Throwable e) {
395: if (_configLocation != null)
396: return new LineConfigException(_configLocation + msg, e);
397: else if (_table.getLocation() != null)
398: return new LineConfigException(_table.getLocation() + msg,
399: e);
400: else
401: return new ConfigException(msg, e);
402: }
403:
404: /**
405: * Returns the name.
406: */
407: public String toString() {
408: return "Column[" + getName() + "]";
409: }
410: }
|