001 /*
002 
003    Derby - Class org.apache.derby.client.net.NetAgent
004 
005    Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable.
006 
007    Licensed under the Apache License, Version 2.0 (the "License");
008    you may not use this file except in compliance with the License.
009    You may obtain a copy of the License at
010 
011       http://www.apache.org/licenses/LICENSE-2.0
012 
013    Unless required by applicable law or agreed to in writing, software
014    distributed under the License is distributed on an "AS IS" BASIS,
015    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016    See the License for the specific language governing permissions and
017    limitations under the License.
018 
019 */
020 
021 package org.apache.derby.client.net;
022 
023 import org.apache.derby.client.am.Agent;
024 import org.apache.derby.client.am.DisconnectException;
025 import org.apache.derby.client.am.SqlException;
026 import org.apache.derby.client.am.Utils;
027 
028 public class NetAgent extends Agent {
029     //---------------------navigational members-----------------------------------
030 
031     // All these request objects point to the same physical request object.
032     public ConnectionRequestInterface connectionRequest_;
033     public NetConnectionRequest packageRequest_;
034     public StatementRequestInterface statementRequest_;
035     public ResultSetRequestInterface resultSetRequest_;
036 
037     // All these reply objects point to the same physical reply object.
038     public ConnectionReply connectionReply_;
039     public ConnectionReply packageReply_;
040     public StatementReply statementReply_;
041     public ResultSetReply resultSetReply_;
042 
043     //---------------------navigational cheat-links-------------------------------
044     // Cheat-links are for convenience only, and are not part of the conceptual model.
045     // Warning:
046     //   Cheat-links should only be defined for invariant state data.
047     //   That is, the state data is set by the constructor and never changes.
048 
049     // Alias for (NetConnection) super.connection
050     NetConnection netConnection_;
051 
052     // Alias for (Request) super.*Request, all in one
053     // In the case of the NET implementation, these all point to the same physical request object.
054     protected Request request_;
055     public NetConnectionRequest netConnectionRequest_;
056     public NetPackageRequest netPackageRequest_;
057     public NetStatementRequest netStatementRequest_;
058     public NetResultSetRequest netResultSetRequest_;
059 
060     // Alias for (Reply) super.*Reply, all in one.
061     // In the case of the NET implementation, these all point to the same physical reply object.
062     protected Reply reply_;
063     public NetConnectionReply netConnectionReply_;
064     public NetPackageReply netPackageReply_;
065     public NetStatementReply netStatementReply_;
066     public NetResultSetReply netResultSetReply_;
067 
068     //-----------------------------state------------------------------------------
069 
070     java.net.Socket socket_;
071     java.io.InputStream rawSocketInputStream_;
072     java.io.OutputStream rawSocketOutputStream_;
073 
074     String server_;
075     int port_;
076     public CcsidManager sourceCcsidManager_;
077     public CcsidManager targetCcsidManager_;
078     public Typdef typdef_;
079     public Typdef targetTypdef_;
080     public Typdef originalTargetTypdef_; // added to support typdef overrides
081 
082     protected int svrcod_;
083 
084     public int orignalTargetSqlam_ = NetConfiguration.MGRLVL_7;
085     public int targetSqlam_ = orignalTargetSqlam_;
086 
087     public SqlException exceptionOpeningSocket_ = null;
088 
089     //---------------------constructors/finalizer---------------------------------
090     public NetAgent(NetConnection netConnection,
091                     org.apache.derby.client.am.LogWriter logWriterthrows SqlException {
092         super(netConnection, logWriter);
093         this.netConnection_ = netConnection;
094     }
095 
096     NetAgent(NetConnection netConnection,
097              org.apache.derby.client.am.LogWriter netLogWriter,
098              int loginTimeout,
099              String server,
100              int portthrows SqlException {
101         super(netConnection, netLogWriter);
102 
103         server_ = server;
104         port_ = port;
105         netConnection_ = netConnection;
106         if (server_ == null) {
107             throw new DisconnectException(this, "Required property \"serverName\" not set");
108         }
109 
110         try {
111             socket_ = (java.net.Socketjava.security.AccessController.doPrivileged(new OpenSocketAction(server, port));
112         catch (java.security.PrivilegedActionException e) {
113             throw new DisconnectException(this,
114                     e.getClass().getName() " : Error opening socket to server " + server + " on port " + port + " with message : " + e.getMessage());
115         }
116 
117         // Set TCP/IP Socket Properties
118         try {
119             if (exceptionOpeningSocket_ == null) {
120                 socket_.setTcpNoDelay(true)// disables nagles algorithm
121                 socket_.setKeepAlive(true)// PROTOCOL Manual: TCP/IP connection allocation rule #2
122                 socket_.setSoTimeout(loginTimeout * 1000);
123             }
124         catch (java.net.SocketException e) {
125             try {
126                 socket_.close();
127             catch (java.io.IOException doNothing) {
128             }
129             exceptionOpeningSocket_ = new DisconnectException(this,
130                     "SocketException '" + e.getMessage() "'");
131         }
132 
133         try {
134             if (exceptionOpeningSocket_ == null) {
135                 rawSocketOutputStream_ = socket_.getOutputStream();
136                 rawSocketInputStream_ = socket_.getInputStream();
137             }
138         catch (java.io.IOException e) {
139             try {
140                 socket_.close();
141             catch (java.io.IOException doNothing) {
142             }
143             exceptionOpeningSocket_ = new DisconnectException(this, "unable to open stream on socket '"+e.getMessage() "'");
144         }
145 
146         sourceCcsidManager_ = new EbcdicCcsidManager()// delete these
147         targetCcsidManager_ = sourceCcsidManager_; // delete these
148 
149         if (netConnection_.isXAConnection()) {
150             NetXAConnectionReply netXAConnectionReply_ = new NetXAConnectionReply(this, netConnection_.commBufferSize_);
151             netResultSetReply_ = (NetResultSetReplynetXAConnectionReply_;
152             netStatementReply_ = (NetStatementReplynetResultSetReply_;
153             netPackageReply_ = (NetPackageReplynetStatementReply_;
154             netConnectionReply_ = (NetConnectionReplynetPackageReply_;
155             reply_ = (ReplynetConnectionReply_;
156 
157             resultSetReply_ = new ResultSetReply(this,
158                     netResultSetReply_,
159                     netStatementReply_,
160                     netConnectionReply_);
161             statementReply_ = (StatementReplyresultSetReply_;
162             packageReply_ = (ConnectionReplystatementReply_;
163             connectionReply_ = (ConnectionReplypackageReply_;
164             NetXAConnectionRequest netXAConnectionRequest_ = new NetXAConnectionRequest(this, sourceCcsidManager_, netConnection_.commBufferSize_);
165             netResultSetRequest_ = (NetResultSetRequestnetXAConnectionRequest_;
166             netStatementRequest_ = (NetStatementRequestnetResultSetRequest_;
167             netPackageRequest_ = (NetPackageRequestnetStatementRequest_;
168             netConnectionRequest_ = (NetConnectionRequestnetPackageRequest_;
169             request_ = (RequestnetConnectionRequest_;
170 
171             resultSetRequest_ = (ResultSetRequestInterfacenetResultSetRequest_;
172             statementRequest_ = (StatementRequestInterfacenetStatementRequest_;
173             packageRequest_ = (NetConnectionRequestnetPackageRequest_;
174             connectionRequest_ = (ConnectionRequestInterfacenetConnectionRequest_;
175         else {
176             netResultSetReply_ = new NetResultSetReply(this, netConnection_.commBufferSize_);
177             netStatementReply_ = (NetStatementReplynetResultSetReply_;
178             netPackageReply_ = (NetPackageReplynetStatementReply_;
179             netConnectionReply_ = (NetConnectionReplynetPackageReply_;
180             reply_ = (ReplynetConnectionReply_;
181 
182             resultSetReply_ = new ResultSetReply(this,
183                     netResultSetReply_,
184                     netStatementReply_,
185                     netConnectionReply_);
186             statementReply_ = (StatementReplyresultSetReply_;
187             packageReply_ = (ConnectionReplystatementReply_;
188             connectionReply_ = (ConnectionReplypackageReply_;
189             netResultSetRequest_ = new NetResultSetRequest(this, sourceCcsidManager_, netConnection_.commBufferSize_);
190             netStatementRequest_ = (NetStatementRequestnetResultSetRequest_;
191             netPackageRequest_ = (NetPackageRequestnetStatementRequest_;
192             netConnectionRequest_ = (NetConnectionRequestnetPackageRequest_;
193             request_ = (RequestnetConnectionRequest_;
194 
195             resultSetRequest_ = (ResultSetRequestInterfacenetResultSetRequest_;
196             statementRequest_ = (StatementRequestInterfacenetStatementRequest_;
197             packageRequest_ = (NetConnectionRequestnetPackageRequest_;
198             connectionRequest_ = (ConnectionRequestInterfacenetConnectionRequest_;
199         }
200     }
201 
202     protected void resetAgent_(org.apache.derby.client.am.LogWriter netLogWriter,
203                                //CcsidManager sourceCcsidManager,
204                                //CcsidManager targetCcsidManager,
205                                int loginTimeout,
206                                String server,
207                                int portthrows SqlException {
208 
209         // most properties will remain unchanged on connect reset.
210         targetTypdef_ = originalTargetTypdef_;
211         svrcod_ = 0;
212 
213         // Set TCP/IP Socket Properties
214         try {
215             socket_.setSoTimeout(loginTimeout * 1000);
216         catch (java.net.SocketException e) {
217             try {
218                 socket_.close();
219             catch (java.io.IOException doNothing) {
220             }
221             throw new SqlException(logWriter_, e, "SocketException '" + e.getMessage() "'");
222         }
223     }
224 
225 
226     void setSvrcod(int svrcod) {
227         if (svrcod > svrcod_) {
228             svrcod_ = svrcod;
229         }
230     }
231 
232     void clearSvrcod() {
233         svrcod_ = CodePoint.SVRCOD_INFO;
234     }
235 
236     int getSvrcod() {
237         return svrcod_;
238     }
239 
240     public void flush_() throws DisconnectException {
241         sendRequest();
242         reply_.initialize();
243     }
244 
245     // Close socket and its streams.
246     public void close_() throws SqlException {
247         // can we just close the socket here, do we need to close streams individually
248         SqlException accumulatedExceptions = null;
249         if (rawSocketInputStream_ != null) {
250             try {
251                 rawSocketInputStream_.close();
252             catch (java.io.IOException e) {
253                 // note when {6} = 0 it indicates the socket was closed.
254                 // this should be ok since we are going to go an close the socket
255                 // immediately following this call.
256                 // changing {4} to e.getMessage() may require pub changes
257                 accumulatedExceptions =
258                         new SqlException(logWriter_, e, "A communication error has been detected. " +
259                         "Communication protocol being used: {0}. " +
260                         "Communication API being used: {1}. " +
261                         "Location where the error was detected: {2}. " +
262                         "Communication function detecting the error: {3}. " +
263                         "Protocol specific error codes(s) {4}, {5}, {6}. " +
264                         "TCP/IP " "SOCKETS " "Agent.close() " +
265                         "InputStream.close() " + e.getMessage() " " "* " "0");
266                 //"08001",
267                 //-30081);
268             finally {
269                 rawSocketInputStream_ = null;
270             }
271         }
272 
273         if (rawSocketOutputStream_ != null) {
274             try {
275                 rawSocketOutputStream_.close();
276             catch (java.io.IOException e) {
277                 // note when {6} = 0 it indicates the socket was closed.
278                 // this should be ok since we are going to go an close the socket
279                 // immediately following this call.
280                 // changing {4} to e.getMessage() may require pub changes
281                 SqlException latestException = new SqlException(logWriter_,
282                         e,
283                         "A communication error has been detected. " +
284                         "Communication protocol being used: {0}. " +
285                         "Communication API being used: {1}. " +
286                         "Location where the error was detected: {2}. " +
287                         "Communication function detecting the error: {3}. " +
288                         "Protocol specific error codes(s) {4}, {5}, {6}. " +
289                         "TCP/IP " "SOCKETS " "Agent.close() " +
290                         "OutputStream.close() " + e.getMessage() " " "* " "0");
291                 accumulatedExceptions = Utils.accumulateSQLException(latestException, accumulatedExceptions);
292             finally {
293                 rawSocketOutputStream_ = null;
294             }
295         }
296 
297         if (socket_ != null) {
298             try {
299                 socket_.close();
300             catch (java.io.IOException e) {
301                 // again {6} = 0, indicates the socket was closed.
302                 // maybe set {4} to e.getMessage().
303                 // do this for now and but may need to modify or
304                 // add this to the message pubs.
305                 SqlException latestException = new SqlException(logWriter_,
306                         e,
307                         "A communication error has been detected. " +
308                         "Communication protocol being used: {0}. " +
309                         "Communication API being used: {1}. " +
310                         "Location where the error was detected: {2}. " +
311                         "Communication function detecting the error: {3}. " +
312                         "Protocol specific error codes(s) {4}, {5}, {6}. " +
313                         "TCP/IP " "SOCKETS " "Agent.close() " +
314                         "Socket.close() " + e.getMessage() " " "* " "0");
315                 accumulatedExceptions = Utils.accumulateSQLException(latestException, accumulatedExceptions);
316             finally {
317                 socket_ = null;
318             }
319         }
320 
321         if (accumulatedExceptions != null) {
322             throw accumulatedExceptions;
323         }
324     }
325 
326 
327     protected void sendRequest() throws DisconnectException {
328         try {
329             request_.flush(rawSocketOutputStream_);
330         catch (java.io.IOException e) {
331             throwCommunicationsFailure("NetAgent.sendRequest()",
332                     "OutputStream.flush()",
333                     e.getMessage(),
334                     "*");
335         }
336     }
337 
338     public java.io.InputStream getInputStream() {
339         return rawSocketInputStream_;
340     }
341 
342     public java.io.OutputStream getOutputStream() {
343         return rawSocketOutputStream_;
344     }
345 
346     void setInputStream(java.io.InputStream inputStream) {
347         rawSocketInputStream_ = inputStream;
348     }
349 
350     void setOutputStream(java.io.OutputStream outputStream) {
351         rawSocketOutputStream_ = outputStream;
352     }
353 
354     public void throwCommunicationsFailure(String location,
355                                            String function,
356                                            String rc1,
357                                            String rc2throws org.apache.derby.client.am.DisconnectException {
358         //org.apache.derby.client.am.DisconnectException
359         //accumulateReadExceptionAndDisconnect
360         // note when {6} = 0 it indicates the socket was closed.
361         // need to still validate any token values against message publications.
362         accumulateChainBreakingReadExceptionAndThrow(new org.apache.derby.client.am.DisconnectException(this,
363                 "A communication error has been detected. " +
364                 "Communication protocol being used: " + location + ". " +
365                 "Communication API being used: " + function + ". " +
366                 "Location where the error was detected: " + rc1 + ". " +
367                 "Communication function detecting the error: " + rc2 + ". " +
368                 "Protocol specific error codes(s) " +
369                 "TCP/IP SOCKETS "));  // hardcode tokens 0 and 1
370         //"08001"));  //derby code -30081, don't send 08001 now either
371     }
372 
373     // ----------------------- call-down methods ---------------------------------
374 
375     public org.apache.derby.client.am.LogWriter newLogWriter_(java.io.PrintWriter printWriter,
376                                                               int traceLevel) {
377         return new NetLogWriter(printWriter, traceLevel);
378     }
379 
380     protected void markChainBreakingException_() {
381         setSvrcod(CodePoint.SVRCOD_ERROR);
382     }
383 
384     public void checkForChainBreakingException_() throws SqlException {
385         int svrcod = getSvrcod();
386         clearSvrcod();
387         if (svrcod > CodePoint.SVRCOD_WARNING// Not for SQL warning, if svrcod > WARNING, then its a chain breaker
388         {
389             super.checkForExceptions()// throws the accumulated exceptions, we'll always have at least one.
390         }
391     }
392 
393     private void writeDeferredResetConnection() throws SqlException {
394         if (!netConnection_.resetConnectionAtFirstSql_) {
395             return;
396         }
397         try {
398             netConnection_.writeDeferredReset();
399         catch (SqlException sqle) {
400             DisconnectException de = new DisconnectException(this, "An error occurred during a deferred connect reset and the connection has been terminated.  See chained exceptions for details.");
401             de.setNextException(sqle);
402             throw de;
403         }
404     }
405 
406     public void beginWriteChainOutsideUOW() throws SqlException {
407         request_.initialize();
408         writeDeferredResetConnection();
409         super.beginWriteChainOutsideUOW();
410     }
411 
412     public void beginWriteChain(org.apache.derby.client.am.Statement statementthrows SqlException {
413         request_.initialize();
414         writeDeferredResetConnection();
415         super.beginWriteChain(statement);
416     }
417 
418     protected void endWriteChain() {
419         super.endWriteChain();
420     }
421 
422     private void readDeferredResetConnection() throws SqlException {
423         if (!netConnection_.resetConnectionAtFirstSql_) {
424             return;
425         }
426         try {
427             netConnection_.readDeferredReset();
428             checkForExceptions();
429         catch (SqlException sqle) {
430             DisconnectException de = new DisconnectException(this, "An error occurred during a deferred connect reset and the connection has been terminated.  See chained exceptions for details.");
431             de.setNextException(sqle);
432             throw de;
433         }
434     }
435 
436     protected void beginReadChain(org.apache.derby.client.am.Statement statementthrows SqlException {
437         readDeferredResetConnection();
438         super.beginReadChain(statement);
439     }
440 
441     protected void beginReadChainOutsideUOW() throws SqlException {
442         readDeferredResetConnection();
443         super.beginReadChainOutsideUOW();
444     }
445 
446     public void endReadChain() throws SqlException {
447         super.endReadChain();
448     }
449 
450 
451     public String convertToStringTcpIpAddress(int tcpIpAddress) {
452         StringBuffer ipAddrBytes = new StringBuffer();
453         ipAddrBytes.append((tcpIpAddress >> 240xff);
454         ipAddrBytes.append(".");
455         ipAddrBytes.append((tcpIpAddress >> 160xff);
456         ipAddrBytes.append(".");
457         ipAddrBytes.append((tcpIpAddress >> 80xff);
458         ipAddrBytes.append(".");
459         ipAddrBytes.append((tcpIpAddress0xff);
460 
461         return ipAddrBytes.toString();
462     }
463 
464     protected int getPort() {
465         return port_;
466     }
467 
468 }
469