001: /**
002: * Copyright (C) 2003 Manfred Andres
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU General Public License
006: * as published by the Free Software Foundation; either version 2
007: * of the License, or (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: * Created on 04.05.2004
019: */package freecs.auth.sqlConnectionPool;
020:
021: import java.sql.ResultSet;
022: import java.sql.ResultSetMetaData;
023: import java.sql.SQLException;
024: import java.util.Enumeration;
025: import java.util.Properties;
026: import java.util.Vector;
027:
028: import freecs.Server;
029:
030: /**
031: * @author Manfred Andres
032: *
033: * freecs.auth.sqlConnectionPool
034: */
035: /**
036: * An instance of DbProperties represents a parsed and validated db-properties file
037: * @author Manfred Andres
038: *
039: * freecs.auth.sqlConnectionPool
040: */
041: public class DbProperties {
042: public boolean readOnly = false;
043: public String url, table, idField, fc_username, fc_password;
044: public String[] columns, names, updCols, updNames;
045: public Vector colV, nameV;
046: private boolean cachedMetaData = false;
047: public int[] types;
048: public Properties conProps = new Properties();
049: public int poolsize = 10, maxStmtPerCon = 1000, queryTimeout = 0;
050: public long conTTL = 3600000;
051:
052: /**
053: * Creates a new DbProperties-instance. All values are checked for
054: * validity. If properties are missing or invalid, an exception will
055: * be thrown.
056: * @param p db-properties
057: * @throws Exception if properties are missing or invalid
058: */
059: public DbProperties(Properties props, Properties mapping)
060: throws Exception {
061:
062: int err = 0, warn = 0;
063:
064: colV = new Vector();
065: nameV = new Vector();
066:
067: Vector updColV = new Vector();
068: Vector updNamV = new Vector();
069:
070: // try to load jdbc driver
071: try {
072: Class.forName(props.getProperty("driver"));
073: } catch (Exception ex) {
074: StringBuffer tsb = new StringBuffer(
075: "Unable to load jdbc-driver '").append(
076: props.getProperty("driver")).append("'");
077: throw new Exception(tsb.toString(), ex);
078: }
079:
080: StringBuffer warnMsg = new StringBuffer();
081:
082: // copy/parse values from properties
083: table = props.getProperty("table");
084: url = props.getProperty("url");
085: queryTimeout = parseInt("queryTimeout", props
086: .getProperty("queryTimeout"), 0, warnMsg);
087: poolsize = parseInt("poolsize", props.getProperty("poolsize"),
088: 10, warnMsg);
089: maxStmtPerCon = parseInt("conStatements", props
090: .getProperty("conStatements"), 1000, warnMsg);
091: conTTL = parseInt("conValidityTime", props
092: .getProperty("conValidityTime"), 60, warnMsg);
093: conTTL = conTTL * 60000;
094: if ("true".equalsIgnoreCase(props.getProperty("readOnly"))
095: || "1".equalsIgnoreCase(props.getProperty("readOnly"))) {
096: readOnly = true;
097: } else if ("false".equalsIgnoreCase(props
098: .getProperty("readOnly"))
099: || "0".equalsIgnoreCase(props.getProperty("readOnly"))) {
100: readOnly = false;
101: } else {
102: warnMsg.append(".) Readonly-Flag has unknown value (");
103: warnMsg.append(props.getProperty("readOnly"));
104: warnMsg.append("). Defaulting to false.");
105: }
106: conProps.setProperty("user", props.getProperty("username"));
107: conProps.setProperty("password", props.getProperty("password"));
108:
109: // then we copy the column-2-property-mappings
110: for (Enumeration e = mapping.keys(); e.hasMoreElements();) {
111: String key = (String) e.nextElement();
112: String val = mapping.getProperty(key);
113: if ("id".equalsIgnoreCase(key)) {
114: idField = val;
115: nameV.add(key);
116: colV.add(val);
117: } else if ("username".equals(key)) {
118: fc_username = val;
119: } else if ("password".equals(key)) {
120: fc_password = val;
121: } else if (key.startsWith("db.")) {
122: // further jdbc properties possible
123: conProps.setProperty(key.substring(3), val);
124: } else if (key.equalsIgnoreCase("userrights")
125: && val.equalsIgnoreCase("serverconfig")) {
126: continue;
127: } else {
128: if ("chattime".equalsIgnoreCase(key)
129: || "userrights".equalsIgnoreCase(key)
130: || "color".equalsIgnoreCase(key)
131: || "cookie".equalsIgnoreCase(key)
132: // FIXME: why not load the friendslist etc?
133: /* || "friends".equalsIgnoreCase(key)
134: || "notifyfriends".equalsIgnoreCase(key)
135: || "extratitle".equalsIgnoreCase(key)
136: || "blocked".equalsIgnoreCase(key) */) {
137: updNamV.add(key.toLowerCase());
138: updColV.add(val);
139: }
140: nameV.add(key.toLowerCase());
141: colV.add(val);
142: }
143: }
144:
145: // and now we check the crucial values
146: StringBuffer errMsg = new StringBuffer();
147: if (table == null) {
148: err++;
149: errMsg
150: .append(".) No tablename defined (SQLAuthenticator.table)\r\n");
151: }
152: if (url == null) {
153: errMsg
154: .append(".) No URL to locate the database (SQLAuthenticator.url)\r\n");
155: err++;
156: }
157: if (fc_username == null || fc_password == null) {
158: errMsg
159: .append(".) No columns given to check user-credentials for users logging in (username, password)\r\n");
160: err++;
161: }
162: if (!conProps.containsKey("user")
163: || !conProps.containsKey("password")) {
164: errMsg
165: .append(".) No connection-credentials given (SQLAuthenticator.mapping.username and SQLAuthenticator.mapping.password)\r\n");
166: err++;
167: }
168: if (warn > 0) {
169: warnMsg.insert(0, "Encountered warnings:\r\n");
170: Server.log(this , warnMsg.toString(), Server.MSG_CONFIG,
171: Server.LVL_MAJOR);
172: }
173: if (err > 0) {
174: errMsg.insert(0, " errors:\r\n");
175: errMsg.insert(0, err);
176: errMsg.insert(0, "Encountered ");
177: throw new Exception(errMsg.toString());
178: }
179: columns = (String[]) colV.toArray(new String[0]);
180: names = (String[]) nameV.toArray(new String[0]);
181: updCols = (String[]) updColV.toArray(new String[0]);
182: updNames = (String[]) updNamV.toArray(new String[0]);
183: if (Server.TRACE_CREATE_AND_FINALIZE)
184: Server.log(this ,
185: "++++++++++++++++++++++++++++++++++++++++CREATE",
186: Server.MSG_STATE, Server.LVL_VERY_VERBOSE);
187: }
188:
189: public String column4property(String prop) {
190: int idx = nameV.indexOf(prop);
191: if (idx == -1)
192: return null;
193: return columns[idx];
194: }
195:
196: public synchronized void cacheMetaData(ResultSet rs)
197: throws SQLException {
198: if (cachedMetaData)
199: return;
200: Server
201: .log(Thread.currentThread(), this .toString()
202: + " cacheMetaData", Server.MSG_AUTH,
203: Server.LVL_VERBOSE);
204: ResultSetMetaData rsm = rs.getMetaData();
205: Vector v = new Vector();
206: types = new int[rsm.getColumnCount()];
207: for (int i = 1; i < rsm.getColumnCount(); i++) {
208: types[i - 1] = rsm.getColumnType(i);
209: }
210: cachedMetaData = true;
211: }
212:
213: public String toString() {
214: return "[DbProperties]";
215: }
216:
217: public void finalize() {
218: if (Server.TRACE_CREATE_AND_FINALIZE)
219: Server
220: .log(
221: this ,
222: "----------------------------------------FINALIZED",
223: Server.MSG_STATE, Server.LVL_VERY_VERBOSE);
224: }
225:
226: /**
227: * helper method to parse and check string values from config into integers
228: * @param name name of property (used for logging)
229: * @param value value of property
230: * @param def default value
231: * @param logger stringbuffer for error messages
232: */
233: private int parseInt(String name, String value, int def,
234: StringBuffer logger) {
235: try {
236: int i = Integer.parseInt(value);
237: if (i < 0) {
238: logger
239: .append(".) SQLAuthenticator."
240: + name
241: + " was set to a value below zero. Corrected to default of "
242: + def + ".\r\n");
243: return def;
244: } else {
245: return i;
246: }
247: } catch (NumberFormatException nfe) {
248: logger.append(".) SQLAuthenticator." + name
249: + " wasn't a number. Corrected to default of "
250: + def + ".\r\n");
251: return def;
252: }
253: }
254:
255: }
|