Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / July 2007

Tip: Looking for answers? Try searching our database.

Java/OO techniques for modularity and re-use

Thread view: 
Richard Maher - 30 Jun 2007 04:28 GMT
Hi,

Please help if you can (with probably a very basic OO newbie question): -

I have created a class that uses the java.net.Socket class to talk to my
server and everything is great. I then converted the code to use the
javax.net.SSLSocket class and (thanks to how easy Java makes it for us!)
everything is still great. What I want to do now is parameterize/optionalize
the use of SSL or in-the-clear Sockets within my class, and I'm struggling
to find a modular, let alone elegant, solution.

At the moment I plan to add another Applet parameter called SSL_REQD and I
will pass that to my constructor, but because of Java's compile-time
resolution of methods-to-objects, I find myself having to duplicate code
that is erstwhile 99% identical or common. Is there some way (short of
Reflection) that I can leverage the fact SSLSocket class inherits most of
its methods from the Socket class so that I only need one method for each
socket function regardless of what flavour socket is in use?

For example: -

private someSocket t3Sock;

if (sssReqd)
 t3Sock = (SSLSocket)sockFactory.createSocket();
else
 t3Sock = new Socket();

t3Sock.setKeepAlive(true);

Am I stuck with "One's an Apple and the other's an Orange (albeit painted
red :-)"?

If few of the Socket methods are overridden by SSLSocket (and the
value-added encryption stuff happens at a lower/other level) can I just cast
my way around some of this? Just stick in a few "if" statements and stop
moanin'?

Cheers Richard Maher

Here is the complete Tier3Socket class definition: -

import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.SocketTimeoutException;
import java.lang.System;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class Tier3Socket
{
public  static final
        String                T3ID="T3$";
public  static final
        int                   USERSIZ=40;
public  static final
        int                   T3IDBUFSIZ=48;
public  static final
        int                   CREDBUFSIZ=80;
public  static final
        int                   CONTIMOUT=10000;

public  byte []               t3IdBuf;
public  byte []               readBuf;
public  byte []               writeBuf;

private String                host;
private int                   port;
private int                   maxBufSiz;
private int                   bytesIn;
private String                hostCharSet;
private SSLSocket             t3Sock;
private SSLSocketFactory      sockFactory;
private BufferedInputStream   in;
private BufferedOutputStream  out;
private byte []               outUser;
private byte []               outPwd;
private byte []               credBuf;
private String                inMsg;
private String                stringOut;

Tier3Socket (String host, int port, int maxBufSiz, String hostCharSet)
{
 this.host        = host;
 this.port        = port;
 this.maxBufSiz   = maxBufSiz;
 this.hostCharSet = hostCharSet;
 this.bytesIn     = 0;

 t3IdBuf  = new byte[T3IDBUFSIZ];
 readBuf  = new byte[maxBufSiz];

 sockFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
}

public void open() throws UnknownHostException, IOException
{
 t3Sock = (SSLSocket)sockFactory.createSocket();
 t3Sock.setKeepAlive(true);
 t3Sock.setReuseAddress(true);
 t3Sock.setTcpNoDelay(true);

 t3Sock.connect(new InetSocketAddress(host,port), CONTIMOUT);

 System.out.println("Connected OK");

 in  = new BufferedInputStream  (t3Sock.getInputStream() ,maxBufSiz);
 out = new BufferedOutputStream (t3Sock.getOutputStream(),maxBufSiz);

 t3Sock.setUseClientMode(true);

 System.out.println("Going for SSL");

 try {t3Sock.startHandshake();}
     catch (IOException e)
           {
            System.out.println("Failed SSL Handshake");
            throw new IOException("Can't SSL on Socket");
           }
}

public void handShake(String username, String password) throws IOException
{
 credBuf = new byte[CREDBUFSIZ];

 outUser = username.getBytes(hostCharSet);
 System.arraycopy(outUser, 0, credBuf, 0, outUser.length);

 outPwd  = password.getBytes(hostCharSet);
 System.arraycopy(outPwd, 0, credBuf, USERSIZ, outPwd.length);

 out.write(credBuf, 0, CREDBUFSIZ);
 out.flush();

 if (in.read(t3IdBuf) < t3IdBuf.length)
 {
     System.out.println("Read < " + Integer.toString(t3IdBuf.length) + "
bytes");
     throw new IOException();
 }

 inMsg = new String(t3IdBuf, 0, 3, hostCharSet);

 if (!inMsg.equals(T3ID))
 {
     throw new IOException();
 }
}

public void sendUrgentData (int oob) throws IOException
{
    t3Sock.sendUrgentData(oob);
}

public void setTimeout(int msecs) throws UnknownHostException, IOException
{
 t3Sock.setSoTimeout(msecs);
}

public void close () throws IOException
{
 if (t3Sock != null && !t3Sock.isClosed())
 {
     try {t3Sock.close();}
     catch (Exception e)
           {e.printStackTrace();}
 }
}

public void buffMessage (String message) throws IOException
{
 byte [] msg = message.getBytes(hostCharSet);

 out.write(msg);
}

public void sendMessage (String message) throws IOException
{
 byte [] msg = message.getBytes(hostCharSet);

 out.write(msg);
 flush();
}

public void flush () throws IOException
{
 out.flush();
}

public int readMessage () throws IOException
{
 return readMessage(readBuf.length);
}

public int readMessage (int bytes) throws IOException
{
 try
     {
     bytesIn = in.read(readBuf, 0, bytes);
     }
 catch (SocketTimeoutException e)
     {
     return 0;
     }

 return bytesIn;
}

public String getString () throws ArrayIndexOutOfBoundsException
{
 return getString(0, bytesIn);
}

public String getString (int offset, int length) throws
ArrayIndexOutOfBoundsException
{
 if ((offset + length) > bytesIn)
 {
     throw new ArrayIndexOutOfBoundsException();
 }
 try
     {
     stringOut = new String(readBuf, offset, length, hostCharSet);
     }
 catch (Exception e)
     {
     return null;
     }

 return stringOut;
}

}
Arne Vajhøj - 01 Jul 2007 00:45 GMT
> I have created a class that uses the java.net.Socket class to talk to my
> server and everything is great. I then converted the code to use the
[quoted text clipped - 29 lines]
> my way around some of this? Just stick in a few "if" statements and stop
> moanin'?

Since SSLSocket inherits from Socket then you can make your
t3sock of type Socket (you can assign from a subtype to a
super type).

If you need to use a SSL specific funtion you can use:
  ((SSLSocket)t3Sock).someSSLSOcketSpecificMethod()

But that is not "nice".

I would find it tempting to create a wrapper class hirachy:
CommonSocketWrapper, SocketWrapper and SSLSocketWrapper where
SocketWrapper has some do nothing methods for the SSL specific
stuff.

If that is not what you are looking for, then pleas explain.

Arne
Richard Maher - 01 Jul 2007 05:01 GMT
Hi Arne,

Thanks for the reply.

In the rest of this I'm not arguing against what you've said, I'm just
honestly trying to digest it

> Since SSLSocket inherits from Socket then you can make your
> t3sock of type Socket (you can assign from a subtype to a
> super type).

But because SSLSocket "extends" Socket, surely I have to instantiate a
SSLSocket object somewhere don't I?

Really no need for this: -
 sockFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
 t3Sock = (SSLSocket)sockFactory.createSocket();

What about all the Value-Added SSL bits that the SSLSocket class must
bolt-on to a Socket?

> If you need to use a SSL specific funtion you can use:
>    ((SSLSocket)t3Sock).someSSLSOcketSpecificMethod()

You're casting t3Sock (a Socket object) as a SSLSocket object there right? I
haven't missed some abstract-class or Interface wizardry? So I've got a
vanilla Socket and cast it as a SSLSocket to call, say startHandshake(), and
it's not gonna complain about a bodgy brick-veneer job, absent any
certificate or crypto-algorithm info?

I'd find it easier to picture it the other way around where we have a
SSLSocket and our casting it as a Socket effectively masks out all the SSL
bits, but who cares? I'll just code it like you've said and see how I get
on.

> But that is not "nice".

It's certainly more appealing than the attached code (look for "sslReqd")

I guess the least I can do is put the common stuff such as this. . .
    inSock.setKeepAlive(true);
    inSock.setReuseAddress(true);
    inSock.setTcpNoDelay(true);
    inSock.connect(new InetSocketAddress(host,port), CONTIMOUT);

    in  = new BufferedInputStream  (inSock.getInputStream() ,maxBufSiz);
    out = new BufferedOutputStream (inSock.getOutputStream(),maxBufSiz);

. . . in a private method with a Socket parameter "inSock" and cast the
SSLSocket to that (or vica versa).

Cheers Richard Maher

import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.SocketTimeoutException;
import java.lang.System;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class Tier3Socket
{
public  static final
        String                T3ID="T3$";
public  static final
        int                   USERSIZ=40;
public  static final
        int                   T3IDBUFSIZ=48;
public  static final
        int                   CREDBUFSIZ=80;
public  static final
        int                   CONTIMOUT=3000;

public  byte []               t3IdBuf;
public  byte []               readBuf;
public  byte []               writeBuf;

private String                host;
private int                   port;
private int                   maxBufSiz;
private int                   bytesIn;
private String                hostCharSet;
private Socket                t3Sock;
private SSLSocket             t3SSLSock;
private SSLSocketFactory      sockFactory;
private BufferedInputStream   in;
private BufferedOutputStream  out;
private byte []               outUser;
private byte []               outPwd;
private byte []               credBuf;
private String                inMsg;
private String                stringOut;
private boolean               sslReqd;

Tier3Socket (String host, int port, int maxBufSiz, String hostCharSet,
boolean sslReqd)
{
 this.host        = host;
 this.port        = port;
 this.maxBufSiz   = maxBufSiz;
 this.hostCharSet = hostCharSet;
 this.bytesIn     = 0;
 this.sslReqd     = sslReqd;

 t3IdBuf  = new byte[T3IDBUFSIZ];
 readBuf  = new byte[maxBufSiz];

 if (sslReqd)
    sockFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
}

public void open() throws UnknownHostException, IOException
{
 if (sslReqd)
    {
    t3SSLSock = (SSLSocket)sockFactory.createSocket();
    t3SSLSock.setKeepAlive(true);
    t3SSLSock.setReuseAddress(true);
    t3SSLSock.setTcpNoDelay(true);
    t3SSLSock.connect(new InetSocketAddress(host,port), CONTIMOUT);

    in  = new BufferedInputStream  (t3SSLSock.getInputStream() ,maxBufSiz);
    out = new BufferedOutputStream (t3SSLSock.getOutputStream(),maxBufSiz);

    t3SSLSock.setUseClientMode(true);

    try {t3SSLSock.startHandshake();}
        catch (IOException e)
              {
               System.out.println("Failed SSL Handshake");
               throw new IOException("Can't SSL on Socket");
              }
    }
 else
    {
    t3Sock = new Socket();
    t3Sock.setKeepAlive(true);
    t3Sock.setReuseAddress(true);
    t3Sock.setTcpNoDelay(true);
    t3Sock.connect(new InetSocketAddress(host,port), CONTIMOUT);

    in  = new BufferedInputStream  (t3Sock.getInputStream() ,maxBufSiz);
    out = new BufferedOutputStream (t3Sock.getOutputStream(),maxBufSiz);
    }
}

public void handShake(String username, String password) throws IOException
{
 credBuf = new byte[CREDBUFSIZ];

 outUser = username.getBytes(hostCharSet);
 System.arraycopy(outUser, 0, credBuf, 0, outUser.length);

 outPwd  = password.getBytes(hostCharSet);
 System.arraycopy(outPwd, 0, credBuf, USERSIZ, outPwd.length);

 out.write(credBuf, 0, CREDBUFSIZ);
 out.flush();

 if (in.read(t3IdBuf) < t3IdBuf.length)
 {
     System.out.println("Read < " + Integer.toString(t3IdBuf.length) + "
bytes");
     throw new IOException();
 }

 inMsg = new String(t3IdBuf, 0, 3, hostCharSet);

 if (!inMsg.equals(T3ID))
 {
     throw new IOException();
 }
}

public void sendUrgentData (int oob) throws IOException
{
 if (sslReqd)
    t3SSLSock.sendUrgentData(oob);
 else
    t3Sock.sendUrgentData(oob);
}

public void setTimeout(int msecs) throws UnknownHostException, IOException
{
 if (sslReqd)
    t3SSLSock.setSoTimeout(msecs);
 else
    t3Sock.setSoTimeout(msecs);
}

public void close () throws IOException
{
 if (t3Sock != null && !t3Sock.isClosed())
 {
     try {t3Sock.close();}
     catch (Exception e)
           {e.printStackTrace();}
 }

 if (t3SSLSock != null && !t3SSLSock.isClosed())
 {
     try {t3SSLSock.close();}
     catch (Exception e)
           {e.printStackTrace();}
 }
}

public void buffMessage (String message) throws IOException
{
 byte [] msg = message.getBytes(hostCharSet);

 out.write(msg);
}

public void sendMessage (String message) throws IOException
{
 byte [] msg = message.getBytes(hostCharSet);

 out.write(msg);
 flush();
}

public void flush () throws IOException
{
 out.flush();
}

public int readMessage () throws IOException
{
 return readMessage(readBuf.length);
}

public int readMessage (int bytes) throws IOException
{
 try
     {
     bytesIn = in.read(readBuf, 0, bytes);
     }
 catch (SocketTimeoutException e)
     {
     return 0;
     }

 return bytesIn;
}

public String getString () throws ArrayIndexOutOfBoundsException
{
 return getString(0, bytesIn);
}

public String getString (int offset, int length) throws
ArrayIndexOutOfBoundsException
{
 if ((offset + length) > bytesIn)
 {
     throw new ArrayIndexOutOfBoundsException();
 }
 try
     {
     stringOut = new String(readBuf, offset, length, hostCharSet);
     }
 catch (Exception e)
     {
     return null;
     }

 return stringOut;
}

}

> > I have created a class that uses the java.net.Socket class to talk to my
> > server and everything is great. I then converted the code to use the
[quoted text clipped - 47 lines]
>
> Arne
Arne Vajhøj - 01 Jul 2007 20:54 GMT
>> Since SSLSocket inherits from Socket then you can make your
>> t3sock of type Socket (you can assign from a subtype to a
[quoted text clipped - 6 lines]
>   sockFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
>   t3Sock = (SSLSocket)sockFactory.createSocket();

That works fine if t3Sock is declared to have type Socket.

And since all methods are virtual in Java, then if t2Sock is
a SSLSocket, then that class's methods will be used.

> What about all the Value-Added SSL bits that the SSLSocket class must
> bolt-on to a Socket?
[quoted text clipped - 7 lines]
> it's not gonna complain about a bodgy brick-veneer job, absent any
> certificate or crypto-algorithm info?

t3Sock is declared as a Socket, but it it actually is a SSLSocket, then
it can be cast to a SSLSocket and therefore use the SSLSocket
specific methods.

> I'd find it easier to picture it the other way around where we have a
> SSLSocket and our casting it as a Socket effectively masks out all the SSL
> bits, but who cares?

You can not assign a Socket to a SSLSocket, so it has to be this way
around.

>> But that is not "nice".
>
> It's certainly more appealing than the attached code (look for "sslReqd")

True.

Arne
Richard Maher - 02 Jul 2007 02:11 GMT
Thanks Arne. I really appreciate your help!

Cheers Richard Maher

> >> Since SSLSocket inherits from Socket then you can make your
> >> t3sock of type Socket (you can assign from a subtype to a
[quoted text clipped - 42 lines]
>
> Arne
Arne Vajhøj - 01 Jul 2007 23:11 GMT
>> Since SSLSocket inherits from Socket then you can make your
>> t3sock of type Socket (you can assign from a subtype to a
[quoted text clipped - 23 lines]
> bits, but who cares? I'll just code it like you've said and see how I get
> on.

Below are a little standalone console app client-server example.

I know you are in applet environment, but the idea is general.

Look for the hack section.

Arne

============================================================

import java.io.*;
import java.net.*;

import javax.net.ssl.*;

public class MultiServer {
    private final static int PORT = 12345;
    public static void main(String[] args) throws Exception {
        ServerSocket ss;
        if(args.length > 0 && args[0].equals("SSL")) {
            System.out.println("SSL");
            ss =
SSLServerSocketFactory.getDefault().createServerSocket(PORT);
        } else {
            System.out.println("Non-SSL");
            ss = new ServerSocket(PORT);
        }
        System.out.println("Accepting connection");
        Socket s = ss.accept();
        System.out.println("Reading");
        InputStream is = s.getInputStream();
        byte[] b = new byte[10000];
        int blen = 0;
        int n;
        while((n = is.read(b, blen, b.length - blen)) > 0) {
            blen += n;
        }
        System.out.print("Received " + blen + " bytes from client:");
        for(int i = 0; i < blen; i++) System.out.print(" " + b[i]);
        System.out.println();
        System.out.println("Closing");
        is.close();
        s.close();
        ss.close();
   }
}

import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;

import javax.net.ssl.*;

public class MultiClient {
    private final static String HOST = "localhost";
    private final static int PORT = 12345;
    public static void main(String[] args) throws Exception {
        Socket s;
        if(args.length > 0 && args[0].equals("SSL")) {
            System.out.println("Connecting via SSL");
            SSLContext sslctx = SSLContext.getInstance("SSL");
            sslctx.init(null, new X509TrustManager[] { new
MyTrustManager() }, null);
            SSLSocketFactory sf = sslctx.getSocketFactory();
            s = sf.createSocket(new Socket(HOST, PORT), HOST, PORT, true);
        } else {
            System.out.println("Connecting plain");
            s = new Socket(HOST, PORT);
        }
        // hack
        if(s instanceof SSLSocket) {
            SSLSession ses  = ((SSLSocket)s).getSession();
            System.out.println("Server: " + ses.getPeerPrincipal());
        }
        System.out.println("Sending 1 2 3 to server");
        OutputStream os = s.getOutputStream();
        byte[] b = { 1, 2, 3 };
        os.write(b);
        System.out.println("Closing");
        os.close();
        s.close();
   }
}

class MyTrustManager implements X509TrustManager
{
    public void checkClientTrusted(X509Certificate[] chain, String
authType) {
    }
    public void checkServerTrusted(X509Certificate[] chain, String
authType) {
    }
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

C:\>java MultiServer
Non-SSL
Accepting connection
Reading
Received 3 bytes from client: 1 2 3
Closing

C:\>java -Djavax.net.ssl.keyStore=server.jks
-Djavax.net.ssl.keyStorePassword=superhemmeligt MultiServer SSL
SSL
Accepting connection
Reading
Received 3 bytes from client: 1 2 3
Closing

C:\>java MultiClient
Connecting plain
Sending 1 2 3 to server
Closing

C:\>java MultiClient SSL
Connecting via SSL
Server: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
Sending 1 2 3 to server
Closing

Arne
Roedy Green - 01 Jul 2007 18:15 GMT
On Sat, 30 Jun 2007 11:28:30 +0800, "Richard Maher"
<maher_rj@hotspamnotmail.com> wrote, quoted or indirectly quoted
someone who said :

>I then converted the code to use the
>javax.net.SSLSocket class

oops I think you meant javax.net.ssl.SSLSocket
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.