View Javadoc

1   /**
2   * Copyright (C) 2009 EDIT
3   * European Distributed Institute of Taxonomy
4   * http://www.e-taxonomy.eu
5   *
6   * The contents of this file are subject to the Mozilla Public License Version 1.1
7   * See LICENSE.TXT at the top of this package for the full license terms.
8   */ 
9   
10  package eu.etaxonomy.cdm.io.common;
11  
12  /*
13   * Created on 14.05.2005
14   * @author Andreas M�ller
15   * Updated 20.08.2006
16   */
17  
18  
19  import java.sql.*;
20  import java.io.*;
21  
22  import javax.mail.MethodNotSupportedException;
23  
24  import org.apache.log4j.Logger;
25  
26  import eu.etaxonomy.cdm.database.ICdmDataSource;
27  
28  
29  /**
30   *  
31   *  Creates Cursors from extern relational DB.
32   *  Used only for developpers convienence hence undocumented.
33   *  You may create input cursors in any other way you want
34   *  @author Andreas Müller
35   */
36  public class Source {
37  	static Logger logger = Logger.getLogger(Source.class);
38  
39  /* ************ Constants **************************************/
40      //Mode
41  	private final static boolean DEBUG_MODE = false;
42      private final static boolean DEBUG_LOG_WRITER = false;
43  	
44      //DB info
45  //	public final static String SQL_SERVER_2000 = "SQLServer2000";
46  	public final static String SQL_SERVER_2005 = "SQLServer2005";
47  	public final static String SQL_SERVER_2008 = "SQLServer2008";
48  	public final static String ACCESS = "Access";
49  	public final static String EXCEL = "Excel";
50  	public final static String ODDBC = "ODBC";
51  	public final static String ORACLE = "Oracle";
52  	public final static String DB2 = "DB2";
53  	
54  	//coursor mode
55  	public final static String SELECT_DIRECT = "direct";
56  	public final static String SELECT_CURSOR = "cursor";
57  		
58      //driver class
59  //    private static String clsSQLServer2000 = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
60      private static String clsSQLServer2005 = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
61      private static String clsSQLServer2008 = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
62      private static String clsODBC = "sun.jdbc.odbc.JdbcOdbcDriver";
63      private static String clsOracle = "oracle.jdbc.driver.OracleDriver";
64      private static String clsDB2 = "COM.ibm.db2.jdbc.net.DB2Driver";
65      private static String clsSQLServerDdtek = "com.ddtek.jdbc.sqlserver.SQLServerDriver";
66      private static String clsDefault = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
67      
68      //url
69  //    private static String urlSQLServer = "jdbc:microsoft:sqlserver://";
70      private static String urlSQLServer2005 = "jdbc:sqlserver://";
71      private static String urlSQLServer2008 = "jdbc:sqlserver://";
72      private static String urlDB2 = "jdbc:db2://";
73      private static String urlOracle = "jdbc:oracle:thin:@:1243:";
74      private static String urlDataDirectSQLServer = "jdbc:datadirect:sqlserver://";
75      private static String urlODBC = "jdbc:odbc:";
76      // FIXME this default is not acceptable
77      private static String urlDefault = "jdbc:microsoft:sqlserver://LAPI:1433;DatabaseName=studienarbeit;SelectMethod=direct";
78      
79      
80  /* *************** VARIABLES *******************************/
81      private Connection mConn;
82      private Statement mStmt;
83      private String mQuery;
84      private String mUrl = null;
85      private String mDb = null; 
86      private int mPort = 1433; //default port TODO 2 derzeit nur f�r SQLServer, m�sste auch f�r andere Datenbanken umgesetzt werden
87      private String mDbms = null;
88      private String mServer = null;
89      private boolean isCursor;
90      private boolean connExist = false; //does a Connection exist?
91      private String mUserName; 
92      private String mPwd;
93  
94  	private boolean doLog = false; 
95  
96  
97  	private static String userNameDefault = "sa"; //default user
98      private static String pwdDefault = "sa"; //default PWD
99      
100     
101 /* ******************** CONSTRUCTORS **********************************/
102     
103     
104     /**
105      * Creates a source and sets the according variables
106      * @param dbms name of database management system (e.g. "SQLServer", "Access", "Excel", "Oracle"
107 	 * @param server name of server, if dbms is ODBC, this must be the ODBC name
108 	 * @param db name of database
109 	*/
110     public Source(String dbms, String server, String db){
111     	mDbms = dbms;
112         mServer = server;
113         mDb = db;
114         this.mPwd = pwdDefault;
115         this.mUserName = userNameDefault;
116     }
117 
118     /**
119      * Creates a source and sets the query string
120      * @param dbms name of database management system (e.g. "SQLServer", "Access", "Excel", "Oracle"
121 	 * @param server name of server, if dbms is ODBC, this must be the ODBC name
122 	 * @param db name of database
123      * @param query the query
124      */
125     public Source(String dbms, String server, String db, String query){
126         this(dbms, server, db);
127         this.setQuery(query);
128     }
129 
130     /**
131     * Creates a source and sets the parameter.
132      * @param cursor access mode, if true 'cursor', if false 'direct'
133     */
134     public Source(String dbms, String server, String db, boolean cursor)   {
135         this(dbms, server, db);
136     	isCursor = cursor;
137     }
138     
139 
140     /**
141     * Creates a source and sets the parameter. If port is -1 the databases default port is used.
142     * @param dbms name of database management system (e.g. "SQLServer", "Access", "Excel", "Oracle"
143     * @param server name of server, if dbms is ODBC, this must be the ODBC name
144     * @param db name of database
145     * @param port the databases port (-1: use default port)
146     */
147     public Source(String dbms, String server, String db, int port) {
148         this(dbms, server, db);
149         if (port != -1){
150         	this.setPort(port);
151         };
152     }
153     
154     /**
155      * Creates a source with parameters of a ICdmDataSource instance
156      * 
157      * @param cdmDataSource
158      */
159     public Source(ICdmDataSource cdmDataSource){
160     	mDbms = cdmDataSource.getDatabaseType().getName();
161         mServer = cdmDataSource.getServer();
162         mDb = cdmDataSource.getDatabase();
163         mPwd = cdmDataSource.getPassword();
164         mUserName = cdmDataSource.getUsername();
165         this.setPort(cdmDataSource.getPort());
166     }
167     
168 //********************* METHODS *****************************************************/
169    
170     //******* RESULTSETS *******************//
171     /**
172      * Returns the Resultset for query 'query'. 
173      * Does not change the Sources query-string!!
174      * @return Resultset for the query.
175      */
176     public ResultSet getResultSet (String query){
177     	ResultSet rs;
178     	try {
179             this.getConnection(); //establish connection
180         	if (query == null){
181         		return null;
182         	}
183             mStmt = mConn.createStatement();
184             rs = mStmt.executeQuery(query);
185             return rs;
186         }catch(SQLException e){
187             logger.error("Problems when creating Resultset for query \n  " + query + " \n" + "Exception: " + e);
188             return null;
189         }
190     }
191 
192     //******* INSERT, UPDATE, DELETE *******************//
193     /**
194      * Executes an insert, update or delete statement.
195      * Returns the number of rows changed or -1 if updatedStatement was 0 or and error occurred. 
196      * Does not change the Sources query-string!!
197      * @return Resultset for the query.
198      */
199     public int update (String updateStatement){
200     	int result;
201     	try {
202             this.getConnection(); //establish connection
203         	if (updateStatement == null){
204         		return -1;
205         	}
206             mStmt = mConn.createStatement();
207             result = mStmt.executeUpdate(updateStatement);
208             return result;
209         }catch(SQLException e){
210             logger.error("Problems when creating Resultset for query \n  " + updateStatement + " \n" + "Exception: " + e);
211             return -1;
212         }
213     }
214 
215     
216     /** 
217      * Returns the Resultset for Sources query. 
218      * @return Resultset for the Sources query
219      */
220     public ResultSet getResultSet (){
221     	return getResultSet(mQuery);  
222     }
223 
224     
225     // ***************CONNECTION *************************************//
226     /**
227      * Returns the connection.
228      * @return the Sources connection
229      */
230     public Connection getConnection(){
231     	try {
232 			if (this.connExist == false){
233 				if (mConn != null){ 
234 					mConn.close();
235 				}
236 				this.makeConnection() ;
237     		}
238 			return this.mConn;
239 		} catch (SourceConnectionException e) {
240 			//TODO error weitergabe des Fehlers nach oben?
241 			logger.error("Error when establishing Connection");
242 			return null;
243 		} catch (SQLException e) {
244 			logger.error("SQLException in getConnection.");
245 			return null;
246 		}
247     }
248     
249     
250     /**
251      * Makes the connection.
252      * @return true if connection created
253      * @throws SourceConnectionException
254      */
255     private boolean makeConnection()throws SourceConnectionException {
256     	if (doLog ){
257     		DriverManager.setLogWriter(new PrintWriter(System.out));
258     	}
259     	try {
260 			if (makeConnectionString() == false){
261 				throw new SourceConnectionException ("Error in Connection String");
262 			}
263 			if (mDbms.equalsIgnoreCase(ODDBC) ){
264 				//not necessarily limited to ODBC
265 				java.util.Properties prop = new java.util.Properties();
266 //			    prop.put("charSet", "Big5");
267 			    prop.put("user", mUserName);
268 			    prop.put("password", mPwd);
269 //			    DriverManager.setLogWriter(new PrintWriter(System.out));
270 			    mConn = DriverManager.getConnection(mUrl, prop);
271 			}else{
272 				mConn = DriverManager.getConnection(mUrl, mUserName, mPwd);				
273 			}
274 
275 			
276 			
277 			mConn.setCatalog(mDb);  //
278 			logger.info("Connected to " + mConn.getCatalog());
279 			mStmt = mConn.createStatement();
280 			this.connExist = true;
281 			return true;
282 		}catch (SQLException e){
283             logger.error("Problems when trying to open the database !!!\n" + 
284                     "URL: " + mUrl  + "\n" +
285                     "Exception: " + e);
286             throw new SourceConnectionException ();
287         } 
288     }
289     
290     /**
291      * Makes the connection string 
292      * @return false if ClassNotFoundException, else true
293      */
294     private boolean makeConnectionString(){
295     	String selectMethod; 
296         String server;
297         
298     	if (isCursor)
299 	    	selectMethod = SELECT_CURSOR;
300 	    else
301 	    	selectMethod = SELECT_DIRECT;
302 	    try{
303 	        if (DEBUG_LOG_WRITER) DriverManager.setLogWriter((new PrintWriter(System.out)));
304 //	        if (mDbms.equalsIgnoreCase(SQL_SERVER_2000)) {
305 //	            Class.forName(clsSQLServer2000);
306 //	            server = mServer + ":" + mPort;
307 //	            mUrl = urlSQLServer + server + ";DataBase=" + mDb + ";SelectMethod="+ selectMethod; 
308 //	        }
309 	        else if (mDbms.equalsIgnoreCase(SQL_SERVER_2005)) {
310 	            Class.forName(clsSQLServer2005);
311 	            server = mServer + ":" + mPort;
312 	            mUrl = urlSQLServer2005 + server + ";databaseName=" + mDb +";SelectMethod="+ selectMethod; 
313 	        }
314 	        else if (mDbms.equalsIgnoreCase(SQL_SERVER_2008)) {
315 	            Class.forName(clsSQLServer2008);
316 	            server = mServer + ":" + mPort;
317 	            mUrl = urlSQLServer2008 + server + ";databaseName=" + mDb +";SelectMethod="+ selectMethod; 
318 	        }
319 	        else if (mDbms.equalsIgnoreCase(ACCESS)) {
320 	        	Class.forName(clsODBC);
321 	            
322 	        	//mDb must be the file path
323 	        	mUrl = urlODBC + "Driver={Microsoft Access Driver (*.mdb)};DBQ=";
324 	        	mUrl += mDb.trim() + ";DriverID=22;READONLY=false}";  
325 	        }
326 	        else if (mDbms.equalsIgnoreCase(EXCEL)) {
327 	            Class.forName(clsODBC);
328 	            mUrl = urlODBC + "jdbc:odbc:Driver={Microsoft Excel Driver (*.xls)};DBQ=";
329 	            mUrl += mDb.trim() + ";DriverID=22;READONLY=false";
330 	        }
331 	        else if (mDbms.equalsIgnoreCase(ODDBC)) {
332 	            //mDb must be the System DNS name
333 	        	Class.forName(clsODBC);
334 	            mUrl = urlODBC + mDb ; 
335 	        }
336 	        else if (mDbms.equalsIgnoreCase(ORACLE)) {
337 	            Class.forName(clsOracle);
338 	            mUrl = urlOracle + mDb ;
339 	        }
340 	        else if (mDbms.equalsIgnoreCase(DB2)) {
341 	            Class.forName(clsDB2);
342 	            mUrl = urlDB2 + mDb; 
343 	        }
344 	        else if (mDbms.equalsIgnoreCase("SQLServerDdtek")) {
345 	             Class.forName(clsSQLServerDdtek);
346 	             mUrl = urlDataDirectSQLServer + mServer;
347 	         }
348 	        else {
349 	            Class.forName(clsSQLServer2005);
350 	            mUrl = urlDefault; 
351 	        }
352 	        logger.debug("Connection String: " + mUrl);	
353 	        return true;
354 	    }catch (ClassNotFoundException e){
355 	        logger.error("Datenbank-Treiber-Klasse konnte nicht geladen werden\n" + "Exception: " + e.toString());
356 	        return false;
357 	    }
358     }
359  
360     
361 /* ******************** SETTER *************************************/
362 
363     /**
364      * @param query
365      */
366     public Source setQuery (String query){
367         mQuery = query;
368         return this;
369     }
370     
371     /**
372      * Sets the username.
373      * @param userName
374      */
375     public Source setUsername (String userName){
376     	if (userName == null){
377     		this.mUserName = userNameDefault;
378     	}else{
379     		this.mUserName = userName;
380     	}
381     	this.connExist = false;
382 		return this;
383     }
384         
385     /**
386      * Sets the password.
387      * @param pwd
388      */
389     public Source setPassword (String pwd){
390     	if (pwd == null){
391     		this.mPwd = pwdDefault;
392     	}else{
393     		this.mPwd = pwd;
394     	}
395     	this.connExist = false;
396 		return this;
397 	}
398     
399     /**
400      * Sets the username and password.
401      * @param userName
402      * @param pwd
403      */
404     public Source setUserAndPwd (String userName, String pwd){
405     	setUsername(userName);
406     	setPassword(pwd);
407     	return this;
408 	}
409     
410     /**
411      * Sets the port.
412      * @param userName
413      * @param pwd
414      */
415     public Source setPort (int port){
416     	this.mPort = port;
417 		this.connExist = false;
418 		return this;
419 	}
420     
421     public String getDatabase(){
422     	return mDb;
423     }
424     
425     public String getServer(){
426     	return mServer;
427     }
428     
429     
430     public boolean isDoLog() {
431 		return doLog;
432 	}
433 
434 	public void setDoLog(boolean doLog) {
435 		this.doLog = doLog;
436 	}
437     
438     /**
439      * Checks if an attribute exists in the database schema. At the moment only supported
440      * for SQL Server.
441      * TODO implement for others.
442      * @param tableName
443      * @param dbAttribute
444      * @return
445      * @throws MethodNotSupportedException
446      */
447     public boolean checkColumnExists(String tableName, String dbAttribute) throws MethodNotSupportedException{
448     	if (mDbms.equalsIgnoreCase(SQL_SERVER_2005)|| mDbms.equalsIgnoreCase(SQL_SERVER_2008) ){
449     		String strQuery = "SELECT  Count(t.id) as n " +
450 				" FROM sysobjects AS t " +
451 				" INNER JOIN syscolumns AS c ON t.id = c.id " +
452 				" WHERE (t.xtype = 'U') AND " + 
453 				" (t.name = '" + tableName + "') AND " + 
454 				" (c.name = '" + dbAttribute + "')";
455 			ResultSet rs = getResultSet(strQuery) ;		
456 			int n;
457 			try {
458 				rs.next();
459 				n = rs.getInt("n");
460 				return n>0;
461 			} catch (SQLException e) {
462 				e.printStackTrace();
463 				return false;
464 			}
465     	}else{
466     		throw new MethodNotSupportedException("Check column exist is not supported by the database system");
467     	}
468     }
469 
470     @Override
471     public String toString(){
472     	if (mDb != null){
473     		return mDb;
474     	}else if (mUrl == null){
475     		return super.toString();
476     	}else{
477         	return mUrl;
478     	}
479     }
480     
481 
482 }