001: /*
002: * Copyright 2003 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package velosurf.validation;
018:
019: import java.util.ArrayList;
020: import java.util.List;
021: import java.util.Locale;
022: import java.sql.SQLException;
023:
024: import velosurf.sql.Database;
025: import velosurf.sql.PooledPreparedStatement;
026: import velosurf.util.Logger;
027:
028: /**
029: * <p>A foreign key constraint. Syntax is:</p>
030: * <pre>
031: * <<i>column</i> references="<i>table.foreign-key</i>">
032: * </pre>
033: * <p>Or:</p>
034: * <pre>
035: * <<i>column</i>>
036: * <references foreign-key="<i>table.foreign-key</i>" [message="<i>error-message</i>"]/>
037: * </<i>column</i>>
038: * </pre>
039: *
040: * <p>Note: his constraint is not meant to replace an internal SQL "references" clause in the database,
041: * since it cannot be made sure that complex updates will respect this constraint.</p>
042: *
043: * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
044: */
045: public class Reference extends FieldConstraint {
046:
047: /** database */
048: private Database db = null;
049: /** table */
050: private String table = null;
051: /** column */
052: private String column = null;
053:
054: /**
055: * Constructor.
056: * @param table the table name
057: * @param column the column name
058: */
059: public Reference(Database db, String table, String column) {
060: this .db = db;
061: this .table = table;
062: this .column = column;
063: setMessage("field {0}: value '{1}' not found in " + table + "."
064: + column);
065: }
066:
067: /**
068: * Validate data against this constraint.
069: * @param data the data to be validated
070: * @return true if data respects the specified reference
071: */
072: public boolean validate(Object data) {
073: try {
074: if (data == null || data.toString().length() == 0)
075: return true;
076: List<Object> param = new ArrayList<Object>();
077: param.add(data);
078: /* TODO this kind of query may vary with dbms...
079: - under Oracle, we need to add "from dual"
080: - does it return "1" or "true"?
081: So, need to add some stuff to DriverInfo.
082: For now, tweak the ping query.*/
083:
084: String query = db.getDriverInfo().getPingQuery();
085: query = query.replace("1", "? in (select distinct "
086: + column + " from " + table + ")");
087: PooledPreparedStatement stmt = db.prepare(query);
088: Object ret = stmt.evaluate(param);
089: return ret != null && ret.equals(Boolean.valueOf(true));
090: } catch (SQLException sqle) {
091: Logger
092: .warn("reference constraint validation threw an exception: "
093: + sqle.getMessage());
094: return false;
095: }
096: }
097:
098: /**
099: * return a string representation for this constraint.
100: * @return string
101: */
102: public String toString() {
103: return "references " + table + "." + column;
104: }
105:
106: }
|