001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.core.search;
034:
035: import com.flexive.core.Database;
036: import com.flexive.core.DatabaseConst;
037: import com.flexive.core.storage.ContentStorage;
038: import com.flexive.core.storage.StorageManager;
039: import com.flexive.shared.exceptions.FxNotFoundException;
040: import com.flexive.shared.exceptions.FxSqlSearchException;
041: import com.flexive.shared.structure.FxDataType;
042: import com.flexive.shared.structure.TypeStorageMode;
043: import com.flexive.sqlParser.FxStatement;
044: import com.flexive.sqlParser.Property;
045: import org.apache.commons.logging.Log;
046: import org.apache.commons.logging.LogFactory;
047:
048: import java.sql.Connection;
049: import java.sql.ResultSet;
050: import java.sql.ResultSetMetaData;
051: import java.sql.Statement;
052: import java.util.*;
053:
054: /**
055: * A resolver for properties
056: *
057: * @author Gregor Schober (gregor.schober@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
058: * @version $Rev: 256 $
059: */
060: public class PropertyResolver {
061: public static enum Table {
062: T_CONTENT(DatabaseConst.TBL_CONTENT), T_CONTENT_DATA(
063: DatabaseConst.TBL_CONTENT_DATA);
064:
065: private final String tableName;
066:
067: Table(String tableName) {
068: this .tableName = tableName;
069: }
070:
071: public String getTableName() {
072: return tableName;
073: }
074: }
075:
076: private static final Log LOG = LogFactory
077: .getLog(PropertyResolver.class);
078: private static Map<String, FxDataType> CONTENT_PROPS = null;
079:
080: private ContentStorage hierarchicalStorage;
081: private Map<String, PropertyEntry> cache = new HashMap<String, PropertyEntry>(
082: 50);
083: private List<PropertyEntry> resultSetColumns;
084: private int resultSetPos = 4;
085: private int resultSetColumnCount = 0;
086:
087: protected PropertyResolver() throws FxSqlSearchException {
088: try {
089: this .hierarchicalStorage = StorageManager
090: .getContentStorage(TypeStorageMode.Hierarchical);
091: this .resultSetColumns = new ArrayList<PropertyEntry>(50);
092: } catch (FxNotFoundException e) {
093: throw new FxSqlSearchException(LOG, e);
094: } catch (Exception e) {
095: throw new FxSqlSearchException(LOG, "Init error:"
096: + e.getMessage());
097: }
098: initColumnInformations();
099: }
100:
101: public void addResultSetColumn(PropertyEntry e) {
102: // Store actuall resultset position
103: e.setPositionInResultSet(resultSetPos);
104: this .resultSetColumns.add(e);
105: // compute next position to use
106: resultSetPos += e.getReadColumns().length;
107: if (e.getTableType() == Table.T_CONTENT_DATA) {
108: // also select XPATH
109: resultSetPos += 1;
110: }
111: // compute total result set columns
112: resultSetColumnCount += e.getReadColumns().length;
113: }
114:
115: public int getResultSetColumnCount() {
116: return resultSetColumnCount;
117: }
118:
119: public List<PropertyEntry> getResultSetColumns() {
120: return resultSetColumns;
121: }
122:
123: public PropertyEntry get(FxStatement fx_stmt, Property prop)
124: throws FxSqlSearchException {
125: final com.flexive.sqlParser.Table tbl = fx_stmt
126: .getTableByAlias(prop.getTableAlias());
127: switch (tbl.getType()) {
128: case CONTENT:
129: return getByName(fx_stmt, prop);
130: default:
131: throw new FxSqlSearchException(LOG,
132: "ex.sqlSearch.table.typeNotSupported", tbl
133: .getType());
134: }
135: }
136:
137: private PropertyEntry getByName(final FxStatement fx_stmt,
138: final Property property) throws FxSqlSearchException {
139: final String key = fx_stmt.getIgnoreCase()
140: + "_"
141: + property.getPropertyName()
142: + (property.hasField() ? "_" + property.getField() : "");
143: PropertyEntry entry = cache.get(key);
144: if (entry == null) {
145: // first check hardcoded virtual properties like @pk and @path
146: for (PropertyEntry.Type type : PropertyEntry.Type.values()) {
147: if (type.matchesProperty(property.getPropertyName())) {
148: entry = type.createEntry();
149: break;
150: }
151: }
152: if (entry == null) {
153: entry = new PropertyEntry(property,
154: hierarchicalStorage, fx_stmt.getIgnoreCase());
155: }
156: cache.put(key, entry);
157: }
158: return entry;
159: }
160:
161: /**
162: * Initializes the column informations.
163: *
164: * @throws FxSqlSearchException if the init fails
165: */
166: private synchronized void initColumnInformations()
167: throws FxSqlSearchException {
168: if (CONTENT_PROPS != null) {
169: return;
170: }
171: Connection con = null;
172: Statement stmt = null;
173: try {
174: con = Database.getDbConnection();
175: stmt = con.createStatement();
176: final ResultSet rs = stmt.executeQuery("select * from "
177: + DatabaseConst.TBL_CONTENT + " where 1=2");
178: final ResultSetMetaData rsmd = rs.getMetaData();
179: CONTENT_PROPS = new Hashtable<String, FxDataType>(10);
180: for (int i = 0; i < rsmd.getColumnCount(); i++) {
181: final String columnName = rsmd.getColumnName(i + 1)
182: .trim().toUpperCase();
183: final int type = rsmd.getColumnType(i + 1);
184: final FxDataType dt;
185: switch (type) {
186: case java.sql.Types.BIGINT:
187: if (columnName.endsWith("_ED_AT")) { //CREATED_AT, MODIFIED_AT
188: dt = FxDataType.DateTime;
189: break;
190: }
191: case java.sql.Types.NUMERIC:
192: dt = FxDataType.LargeNumber;
193: break;
194: case java.sql.Types.INTEGER:
195: case java.sql.Types.SMALLINT:
196: case java.sql.Types.TINYINT:
197: dt = FxDataType.Number;
198: break;
199: case java.sql.Types.TIMESTAMP:
200: dt = FxDataType.DateTime;
201: break;
202: case java.sql.Types.VARCHAR:
203: dt = FxDataType.String1024;
204: break;
205: case java.sql.Types.BIT:
206: case java.sql.Types.BOOLEAN:
207: dt = FxDataType.Boolean;
208: break;
209: default:
210: throw new FxSqlSearchException(LOG,
211: "ex.sqlSearch.init.unknowColumnType",
212: columnName, DatabaseConst.TBL_CONTENT, type);
213: }
214: CONTENT_PROPS.put(columnName, dt);
215: }
216: } catch (FxSqlSearchException exc) {
217: throw exc;
218: } catch (Exception exc) {
219: throw new FxSqlSearchException(LOG,
220: "ex.sqlSearch.init.failedToReadTableMetadata",
221: DatabaseConst.TBL_CONTENT);
222: } finally {
223: Database.closeObjects(PropertyResolver.class, con, stmt);
224: }
225: }
226: }
|