1 package net.sf.sapjcosupport.jdbc;
2
3 import com.sap.mw.jco.IRepository;
4 import com.sap.mw.jco.JCO;
5 import org.apache.commons.lang.Validate;
6 import org.apache.log4j.Logger;
7
8 import java.io.PrintWriter;
9 import java.sql.Connection;
10 import java.sql.SQLException;
11
12 /**
13 * Created by IntelliJ IDEA.
14 * User: NDE1677
15 * Date: Jul 5, 2006
16 * Time: 12:50:26 PM
17 * To change this template use File | Settings | File Templates.
18 */
19 public class SapDataSource implements javax.sql.DataSource {
20 /**
21 * Login time out in seconds.
22 * Defaults to one minute.
23 */
24 private int loginTimeout = 60;
25 private PrintWriter logWriter = null;
26
27 private static final Logger logger = Logger.getLogger(SapDataSource.class);
28
29 private static JCO.Pool pool;
30 private static IRepository repository;
31
32 private String username;
33 private String password;
34 private String host;
35 private String client;
36 private String systemNr;
37 private String language = "EN";
38 private int poolSize = 5;
39
40 /**
41 * Gets the maximum time in seconds that this data source can wait
42 * while attempting to connect to a database. A value of zero
43 * means that the timeout is the default system timeout
44 * if there is one; otherwise, it means that there is no timeout.
45 * When a <code>DataSource</code> object is created, the login timeout is
46 * initially zero.
47 *
48 * @return the data source login time limit
49 * @throws java.sql.SQLException if a database access error occurs.
50 * @see #setLoginTimeout
51 */
52 public int getLoginTimeout() throws SQLException {
53 return loginTimeout;
54 }
55
56 /**
57 * <p>Sets the maximum time in seconds that this data source will wait
58 * while attempting to connect to a database. A value of zero
59 * specifies that the timeout is the default system timeout
60 * if there is one; otherwise, it specifies that there is no timeout.
61 * When a <code>DataSource</code> object is created, the login timeout is
62 * initially zero.
63 *
64 * @param seconds the data source login time limit
65 * @throws java.sql.SQLException if a database access error occurs.
66 * @see #getLoginTimeout
67 */
68 public void setLoginTimeout(int seconds) throws SQLException {
69 this.loginTimeout = seconds;
70 }
71
72 /**
73 * <p>Retrieves the log writer for this <code>DataSource</code>
74 * object.
75 * <p/>
76 * <p>The log writer is a character output stream to which all logging
77 * and tracing messages for this data source will be
78 * printed. This includes messages printed by the methods of this
79 * object, messages printed by methods of other objects manufactured
80 * by this object, and so on. Messages printed to a data source
81 * specific log writer are not printed to the log writer associated
82 * with the <code>java.sql.Drivermanager</code> class. When a
83 * <code>DataSource</code> object is
84 * created, the log writer is initially null; in other words, the
85 * default is for logging to be disabled.
86 *
87 * @return the log writer for this data source or null if
88 * logging is disabled
89 * @throws java.sql.SQLException if a database access error occurs
90 * @see #setLogWriter
91 */
92 public PrintWriter getLogWriter() throws SQLException {
93 return logWriter;
94 }
95
96 /**
97 * <p>Sets the log writer for this <code>DataSource</code>
98 * object to the given <code>java.io.PrintWriter</code> object.
99 * <p/>
100 * <p>The log writer is a character output stream to which all logging
101 * and tracing messages for this data source will be
102 * printed. This includes messages printed by the methods of this
103 * object, messages printed by methods of other objects manufactured
104 * by this object, and so on. Messages printed to a data source-
105 * specific log writer are not printed to the log writer associated
106 * with the <code>java.sql.Drivermanager</code> class. When a
107 * <code>DataSource</code> object is created the log writer is
108 * initially null; in other words, the default is for logging to be
109 * disabled.
110 *
111 * @param out the new log writer; to disable logging, set to null
112 * @throws java.sql.SQLException if a database access error occurs
113 * @see #getLogWriter
114 */
115 public void setLogWriter(PrintWriter out) throws SQLException {
116 this.logWriter = out;
117 }
118
119 protected Connection getSapConnection() throws SQLException {
120 validateConnectionProperties();
121 try {
122 JCO.Pool pool = getConnectionPool();
123 JCO.Client nativeConnection = JCO.getClient(pool.getName());
124 return new SapConnection(nativeConnection, getRepository());
125 } catch (Exception e) {
126 logger.error("Error creating SAP connection", e);
127 throw new SapConnectException(SqlErrorCodes.ErrorCreatingConnection, e.getMessage());
128 }
129 }
130
131 private void validateConnectionProperties() throws SapConnectException {
132 try {
133 Validate.notEmpty(this.username);
134 Validate.notEmpty(this.password);
135 Validate.notEmpty(this.host);
136 Validate.notEmpty(this.client);
137 Validate.notEmpty(this.systemNr);
138 } catch (IllegalArgumentException e) {
139 throw new SapConnectException(SqlErrorCodes.MissingConnectionProperty, e.getMessage());
140 }
141 }
142
143 private IRepository getRepository() {
144 getConnectionPool();
145 return repository;
146 }
147
148 private synchronized JCO.Pool getConnectionPool() {
149 if (pool == null) {
150 String poolName = new StringBuffer("pool_").append(host).append(systemNr).append(client).toString();
151 pool = JCO.getClientPoolManager().getPool(poolName);
152 if (pool == null) {
153 logger.info(new StringBuffer("Creating new pool ").append(poolName).append(" , max size: ").append(
154 poolSize).toString());
155 JCO.addClientPool(poolName, poolSize,
156 client, username, password, language, host, systemNr);
157 pool = JCO.getClientPoolManager().getPool(poolName);
158 pool.setConnectionTimeout(60000);
159 pool.setMaxWaitTime(60000);
160 pool.setMaxConnections(poolSize * 2);
161 }
162
163 if (repository == null) {
164 repository = JCO.createRepository("DefaultRepository", poolName);
165 }
166 }
167 return pool;
168 }
169
170 /**
171 * <p>Attempts to establish a connection with the data source that
172 * this <code>DataSource</code> object represents.
173 *
174 * @return a connection to the data source
175 * @throws java.sql.SQLException if a database access error occurs
176 */
177 public Connection getConnection() throws SQLException {
178 return getSapConnection();
179 }
180
181 /**
182 * <p>Attempts to establish a connection with the data source that
183 * this <code>DataSource</code> object represents.
184 *
185 * @param username the database user on whose behalf the connection is
186 * being made
187 * @param password the user's password
188 * @return a connection to the data source
189 * @throws java.sql.SQLException if a database access error occurs
190 */
191 public Connection getConnection(String username, String password) throws SQLException {
192 setUsername(username);
193 setPassword(password);
194 return getSapConnection();
195 }
196
197 public void setProperties(String username, String password, String host, String client, String systemNr,
198 String language) {
199 this.username = username;
200 this.password = password;
201 this.host = host;
202 this.client = client;
203 this.systemNr = systemNr;
204 this.language = language;
205 }
206
207 public String getUsername() {
208 return username;
209 }
210
211 public void setUsername(String username) {
212 this.username = username;
213 }
214
215 public String getPassword() {
216 return password;
217 }
218
219 public void setPassword(String password) {
220 this.password = password;
221 }
222
223 public String getHost() {
224 return host;
225 }
226
227 public void setHost(String host) {
228 this.host = host;
229 }
230
231 public String getClient() {
232 return client;
233 }
234
235 public void setClient(String client) {
236 this.client = client;
237 }
238
239 public String getSystemNr() {
240 return systemNr;
241 }
242
243 public void setSystemNr(String systemNr) {
244 this.systemNr = systemNr;
245 }
246
247 public String getLanguage() {
248 return language;
249 }
250
251 public void setLanguage(String language) {
252 this.language = language;
253 }
254 }