- Timestamp:
- 01/15/10 22:13:25 (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LogicMail/src/org/logicprobe/LogicMail/util/Connection.java
r477 r608 61 61 62 62 import net.rim.device.api.crypto.tls.tls10.TLS10Connection; 63 import net.rim.device.api.i18n.ResourceBundle; 63 64 import net.rim.device.api.system.EventLogger; 64 import net.rim.device.api.ui.UiApplication;65 import net.rim.device.api.ui.component.Dialog;66 65 import net.rim.device.api.util.DataBuffer; 67 66 import net.rim.device.cldc.io.ssl.TLSException; 68 67 69 68 import org.logicprobe.LogicMail.AppInfo; 69 import org.logicprobe.LogicMail.LogicMailResource; 70 import org.logicprobe.LogicMail.conf.ConnectionConfig; 70 71 import org.logicprobe.LogicMail.conf.GlobalConfig; 71 72 import org.logicprobe.LogicMail.conf.MailSettings; … … 77 78 import java.io.OutputStream; 78 79 79 import java.util.Vector;80 81 import javax.microedition.io.Connector;82 80 import javax.microedition.io.SocketConnection; 83 81 import javax.microedition.io.StreamConnection; … … 102 100 * is the only way to get rid of compile-time dependencies on these classes. 103 101 */ 104 public class Connection { 102 public abstract class Connection { 103 protected static ResourceBundle resources = ResourceBundle.getBundle(LogicMailResource.BUNDLE_ID, LogicMailResource.BUNDLE_NAME); 104 105 /** Select everything except WiFi */ 106 protected static final int TRANSPORT_AUTO = 0xFE; 107 /** Select WiFi */ 108 protected static final int TRANSPORT_WIFI = 0x01; 109 /** Select Direct TCP */ 110 protected static final int TRANSPORT_DIRECT_TCP = 0x02; 111 /** Select MDS */ 112 protected static final int TRANSPORT_MDS = 0x04; 113 /** Select WAP 2.0 */ 114 protected static final int TRANSPORT_WAP2 = 0x08; 115 105 116 /** 106 117 * Byte array holding carriage return and line feed … … 108 119 private static final byte[] CRLF = new byte[] { 13, 10 }; 109 120 110 /** 111 * Holds a list of open connections 112 */ 113 private static Vector openConnections = new Vector(); 114 private String serverName; 115 private int serverPort; 116 private boolean useSSL; 117 private boolean deviceSide; 121 private static UtilFactory connectionFactory; 122 protected String serverName; 123 protected int serverPort; 124 protected boolean useSSL; 125 protected int transports; 118 126 private StreamConnection socket; 119 127 private String localAddress; 120 pr ivateGlobalConfig globalConfig;128 protected GlobalConfig globalConfig; 121 129 protected InputStream input; 122 130 protected OutputStream output; 123 pr ivateboolean useWiFi;131 protected boolean useWiFi; 124 132 private int fakeAvailable = -1; 125 133 private int bytesSent = 0; 126 134 private int bytesReceived = 0; 127 135 128 136 /** 129 137 * Provides a buffer used for incoming data. … … 136 144 DataBuffer resultBuffer = new DataBuffer(); 137 145 138 public Connection(String serverName, int serverPort, boolean useSSL, 139 boolean deviceSide) { 140 this.serverName = serverName; 141 this.serverPort = serverPort; 142 this.useSSL = useSSL; 143 this.deviceSide = deviceSide; 146 /** 147 * Initializes a new connection object. 148 * 149 * @param connectionConfig Configuration data for the connection 150 */ 151 protected Connection(ConnectionConfig connectionConfig) { 152 this.globalConfig = MailSettings.getInstance().getGlobalConfig(); 153 154 this.serverName = connectionConfig.getServerName(); 155 this.serverPort = connectionConfig.getServerPort(); 156 this.useSSL = (connectionConfig.getServerSecurity() == ConnectionConfig.SECURITY_SSL); 157 158 int transportType; 159 boolean enableWiFi; 160 if(connectionConfig.getTransportType() == ConnectionConfig.TRANSPORT_GLOBAL) { 161 transportType = globalConfig.getTransportType(); 162 enableWiFi = globalConfig.getEnableWiFi(); 163 } 164 else { 165 transportType = connectionConfig.getTransportType(); 166 enableWiFi = connectionConfig.getEnableWiFi(); 167 } 168 169 // Populate the bit-flags for the selected transport types 170 // based on the configuration parameters. 171 switch(transportType) { 172 case ConnectionConfig.TRANSPORT_AUTO: 173 transports = Connection.TRANSPORT_AUTO; 174 break; 175 case ConnectionConfig.TRANSPORT_DIRECT_TCP: 176 transports = Connection.TRANSPORT_DIRECT_TCP; 177 break; 178 case ConnectionConfig.TRANSPORT_MDS: 179 transports = Connection.TRANSPORT_MDS; 180 break; 181 case ConnectionConfig.TRANSPORT_WAP2: 182 transports = Connection.TRANSPORT_WAP2; 183 break; 184 default: 185 // Should only get here in rare cases of invalid configuration 186 // data, so we select full automatic with WiFi. 187 transports = Connection.TRANSPORT_AUTO; 188 enableWiFi = true; 189 break; 190 } 191 if(enableWiFi) { transports |= Connection.TRANSPORT_WIFI; } 192 144 193 this.input = null; 145 194 this.output = null; 146 195 this.socket = null; 147 this.globalConfig = MailSettings.getInstance().getGlobalConfig(); 148 } 149 196 } 197 198 /** 199 * Sets the connection factory reference. 200 * 201 * @param connectionFactory connection factory reference 202 */ 203 static void setConnectionFactory(UtilFactory connectionFactory) { 204 Connection.connectionFactory = connectionFactory; 205 } 206 150 207 /** 151 208 * Opens a connection. … … 155 212 close(); 156 213 } 157 158 synchronized (openConnections) { 159 if (!openConnections.contains(this)) { 160 openConnections.addElement(this); 161 } 162 } 163 164 String protocolStr = (useSSL ? "ssl" : "socket"); 165 166 // This parameter, which allows bypassing the MDS proxy, should probably 167 // be a global user configurable option 168 String paramStr = (deviceSide ? ";deviceside=true" : ""); 169 170 useWiFi = false; 171 172 if (globalConfig.getWifiMode() == GlobalConfig.WIFI_PROMPT) { 173 UiApplication.getUiApplication().invokeAndWait(new Runnable() { 174 public void run() { 175 useWiFi = (Dialog.ask(Dialog.D_YES_NO, 176 "Connect through WiFi?") == Dialog.YES); 177 } 178 }); 179 } else if (globalConfig.getWifiMode() == GlobalConfig.WIFI_ALWAYS) { 180 useWiFi = true; 181 } 182 183 if (useWiFi) { 184 paramStr = paramStr + ";interface=wifi"; 185 } 186 187 String connectStr = protocolStr + "://" + serverName + ":" + 188 serverPort + paramStr; 189 190 if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 191 String msg = "Opening connection:\r\n" + connectStr + "\r\n"; 192 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), 193 EventLogger.INFORMATION); 194 } 195 196 socket = (StreamConnection) Connector.open(connectStr, 197 Connector.READ_WRITE, true); 214 215 connectionFactory.addOpenConnection(this); 216 217 socket = openStreamConnection(); 218 if(socket == null) { 219 throw new IOException(resources.getString(LogicMailResource.ERROR_UNABLE_TO_OPEN_CONNECTION)); 220 } 221 198 222 input = socket.openDataInputStream(); 199 223 output = socket.openDataOutputStream(); … … 201 225 bytesSent = 0; 202 226 bytesReceived = 0; 203 227 204 228 if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 205 229 String msg = "Connection established:\r\n" + "Socket: " + 206 socket.getClass().toString() + "\r\n" + "Local address: " +207 localAddress + "\r\n";230 socket.getClass().toString() + "\r\n" + "Local address: " + 231 localAddress + "\r\n"; 208 232 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), 209 EventLogger.INFORMATION); 210 } 211 } 233 EventLogger.INFORMATION); 234 } 235 } 236 237 /** 238 * Open a stream connection. 239 * This method should encapsulate all platform-specific logic for opening 240 * network connections. 241 * 242 * @return the stream connection 243 * 244 * @throws IOException Signals that an I/O exception has occurred. 245 */ 246 protected abstract StreamConnection openStreamConnection() throws IOException; 212 247 213 248 /** … … 242 277 } 243 278 244 synchronized (openConnections) { 245 if (openConnections.contains(this)) { 246 openConnections.removeElement(this); 247 } 248 } 279 connectionFactory.removeOpenConnection(this); 249 280 250 281 EventLogger.logEvent(AppInfo.GUID, "Connection closed".getBytes(), 251 EventLogger.INFORMATION); 252 } 253 254 /** 255 * Determine whether open connections exist 256 * 257 * @return True if there are open connections 258 */ 259 public static boolean hasOpenConnections() { 260 boolean result; 261 262 synchronized (openConnections) { 263 result = !openConnections.isEmpty(); 264 } 265 266 return result; 267 } 268 269 /** 270 * Close all open connections 271 */ 272 public static void closeAllConnections() { 273 synchronized (openConnections) { 274 int size = openConnections.size(); 275 276 for (int i = 0; i < size; i++) { 277 try { 278 ((Connection) openConnections.elementAt(i)).close(); 279 } catch (IOException e) { 280 } 281 } 282 283 openConnections.removeAllElements(); 284 } 282 EventLogger.INFORMATION); 285 283 } 286 284 … … 324 322 */ 325 323 public int getBytesSent() { 326 return bytesSent;327 } 328 324 return bytesSent; 325 } 326 329 327 /** 330 328 * Gets the number of bytes that have been received since the … … 338 336 */ 339 337 public int getBytesReceived() { 340 return bytesReceived;341 } 342 338 return bytesReceived; 339 } 340 343 341 /** 344 342 * Sends a string to the server. This method is used internally for … … 360 358 if (globalConfig.getConnDebug()) { 361 359 EventLogger.logEvent(AppInfo.GUID, "[SEND]".getBytes(), 362 EventLogger.DEBUG_INFO);360 EventLogger.DEBUG_INFO); 363 361 } 364 362 … … 386 384 if (globalConfig.getConnDebug()) { 387 385 EventLogger.logEvent(AppInfo.GUID, 388 ("[SEND] " + s.substring(i, j)).getBytes(),389 EventLogger.DEBUG_INFO);386 ("[SEND] " + s.substring(i, j)).getBytes(), 387 EventLogger.DEBUG_INFO); 390 388 } 391 389 … … 420 418 if (globalConfig.getConnDebug()) { 421 419 EventLogger.logEvent(AppInfo.GUID, ("[SEND CMD] " + s).getBytes(), 422 EventLogger.DEBUG_INFO);420 EventLogger.DEBUG_INFO); 423 421 } 424 422 … … 427 425 bytesSent += 2; 428 426 } else { 429 byte[] buf = (s + "\r\n").getBytes();427 byte[] buf = (s + "\r\n").getBytes(); 430 428 output.write(buf); 431 429 bytesSent += buf.length; … … 448 446 if (globalConfig.getConnDebug()) { 449 447 EventLogger.logEvent(AppInfo.GUID, 450 ("[SEND RAW]\r\n" + s).getBytes(), EventLogger.DEBUG_INFO);448 ("[SEND RAW]\r\n" + s).getBytes(), EventLogger.DEBUG_INFO); 451 449 } 452 450 453 451 output.write(buf, 0, buf.length); 454 452 bytesSent += buf.length; 455 453 456 454 output.flush(); 457 455 } … … 530 528 while (true) { 531 529 int actual = input.read(buffer, count, 1); 532 530 533 531 /** 534 532 * If -1 is returned, the InputStream is already closed, … … 539 537 if (actual == -1) { 540 538 EventLogger.logEvent(AppInfo.GUID, 541 "Unable to read from socket, closing connection".getBytes(),542 EventLogger.INFORMATION);539 "Unable to read from socket, closing connection".getBytes(), 540 EventLogger.INFORMATION); 543 541 544 542 try { … … 567 565 // approach which screws up on mid-line LFs. (DK) 568 566 else { 569 bytesReceived += actual;570 567 bytesReceived += actual; 568 571 569 byte b = buffer[count]; 572 570 readBytes++; … … 606 604 if (globalConfig.getConnDebug()) { 607 605 EventLogger.logEvent(AppInfo.GUID, 608 ("[RECV] " + result).getBytes(),609 EventLogger.DEBUG_INFO);606 ("[RECV] " + result).getBytes(), 607 EventLogger.DEBUG_INFO); 610 608 } 611 609 … … 619 617 } 620 618 621 /**622 * Switches the underlying connection to SSL mode, as commonly done after623 * sending a <tt>STARTTLS</tt> command to the server.624 *625 * @throws IOException Signals that an I/O exception has occurred.626 */627 public void startTLS() throws IOException {628 // Shortcut the method if we're already in SSL mode629 if(socket instanceof TLS10Connection) { return; }630 631 try {632 TLS10Connection tlsSocket = new TLS10Connection(633 new StreamConnectionWrapper(634 socket,635 (DataInputStream)input,636 (DataOutputStream)output),637 serverName + ':' + serverPort,638 true);639 640 socket = tlsSocket;641 input = socket.openDataInputStream();642 output = socket.openDataOutputStream();643 } catch (IOException e) {619 /** 620 * Switches the underlying connection to SSL mode, as commonly done after 621 * sending a <tt>STARTTLS</tt> command to the server. 622 * 623 * @throws IOException Signals that an I/O exception has occurred. 624 */ 625 public void startTLS() throws IOException { 626 // Shortcut the method if we're already in SSL mode 627 if(socket instanceof TLS10Connection) { return; } 628 629 try { 630 TLS10Connection tlsSocket = new TLS10Connection( 631 new StreamConnectionWrapper( 632 socket, 633 (DataInputStream)input, 634 (DataOutputStream)output), 635 serverName + ':' + serverPort, 636 true); 637 638 socket = tlsSocket; 639 input = socket.openDataInputStream(); 640 output = socket.openDataOutputStream(); 641 } catch (IOException e) { 644 642 EventLogger.logEvent(AppInfo.GUID, 645 643 ("Unable to switch to TLS mode: " + e.getMessage()).getBytes(), EventLogger.ERROR); 646 644 throw new IOException("Unable to switch to TLS mode"); 647 } catch (TLSException e) {645 } catch (TLSException e) { 648 646 EventLogger.logEvent(AppInfo.GUID, 649 647 ("Unable to switch to TLS mode: " + e.getMessage()).getBytes(), EventLogger.ERROR); 650 648 throw new IOException("Unable to switch to TLS mode"); 651 }652 }653 654 /**655 * Decorator to wrap an existing stream connection so its I/O streams656 * can be reopened without throwing exceptions.657 */658 private static class StreamConnectionWrapper implements StreamConnection {659 private StreamConnection stream;660 private DataInputStream dataInputStream;661 private DataOutputStream dataOutputStream;662 663 public StreamConnectionWrapper(StreamConnection stream, DataInputStream dataInputStream, DataOutputStream dataOutputStream) {664 this.stream = stream;665 this.dataInputStream = dataInputStream;666 this.dataOutputStream = dataOutputStream;667 }668 669 public DataInputStream openDataInputStream() throws IOException {670 return dataInputStream;671 }672 public InputStream openInputStream() throws IOException {673 return dataInputStream;674 }675 public void close() throws IOException {676 stream.close();677 }678 public DataOutputStream openDataOutputStream() throws IOException {679 return dataOutputStream;680 }681 public OutputStream openOutputStream() throws IOException {682 return dataOutputStream;683 }684 }649 } 650 } 651 652 /** 653 * Decorator to wrap an existing stream connection so its I/O streams 654 * can be reopened without throwing exceptions. 655 */ 656 private static class StreamConnectionWrapper implements StreamConnection { 657 private StreamConnection stream; 658 private DataInputStream dataInputStream; 659 private DataOutputStream dataOutputStream; 660 661 public StreamConnectionWrapper(StreamConnection stream, DataInputStream dataInputStream, DataOutputStream dataOutputStream) { 662 this.stream = stream; 663 this.dataInputStream = dataInputStream; 664 this.dataOutputStream = dataOutputStream; 665 } 666 667 public DataInputStream openDataInputStream() throws IOException { 668 return dataInputStream; 669 } 670 public InputStream openInputStream() throws IOException { 671 return dataInputStream; 672 } 673 public void close() throws IOException { 674 stream.close(); 675 } 676 public DataOutputStream openDataOutputStream() throws IOException { 677 return dataOutputStream; 678 } 679 public OutputStream openOutputStream() throws IOException { 680 return dataOutputStream; 681 } 682 } 685 683 }
Note: See TracChangeset
for help on using the changeset viewer.
