9

I am writing a server like below

public class Server<T extends RequestHandler> {

    public void start() {

        try{
            this.serverSocket = new ServerSocket(this.port, this.backLog);
        } catch (IOException e) {
            LOGGER.error("Could not listen on port " + this.port, e);
            System.exit(-1);
        }

        while (!stopTheServer) {
            socket = null;
            try {
                socket = serverSocket.accept();
                handleNewConnectionRequest(socket);
            } catch (IOException e) {
                LOGGER.warn("Accept failed at: " + this.port, e);
                e.printStackTrace();
            }
        }

    }

    protected void handleNewConnectionRequest(Socket socket) {
        try {
            executorService.submit(new T(socket));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

But in the handleNewConnectionRequest(...) method, I can't create an instance of T as it is actually not a class. Also I can't use the method mentioned here as I want to pass the socket instance so that the request handler can get OutputStream and InputStream on the socket.


Can't I make a generic server like above and have different protocol handlers e.g

public class HttpRequestHandler extends RequestHandler {
    ...
}

public class FtpRequestHandler extends RequestHandler {
    ...
}

public class SmtpRequestHandler extends RequestHandler {
    ...
}

and then use them like below

Server<HttpRequestHandler> httpServer = new Server<HttpRequestHandler>();
Server<FtpRequestHandler> ftpServer = new Server<FtpRequestHandler >();
Server<SmtpRequestHandler> smtpServer = new Server<SmtpRequestHandler >();
Community
  • 1
  • 1
Amit
  • 33,847
  • 91
  • 226
  • 299

5 Answers5

9

You'll need an instance of the class. The generic type T isn't enough. So you'll do:

class Server <T extends RequestHandler> {
    Class<T> clazz;
    public Server(Class<T> clazz) {
        this.clazz = clazz;
    }

    private T newRequest() {
        return clazz.newInstance();
    }
}
Kevin
  • 24,871
  • 19
  • 102
  • 158
5

Maybe make different Server subclasses befitting various handler types. One example:

public class HttpServer extends Server<HttpRequestHandler> {

    protected HttpRequestHandler wrapSocket(Socket socket) {
        return new HttpRequestHandler(socket);
    }

}

And adapt Server like so:

public abstract class Server<T extends RequestHandler> {

    protected abstract T wrapSocket(Socket socket);

    protected void handleNewConnectionRequest(Socket socket) {
        try {
            executorService.submit(wrapSocket(socket));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Just a thought...

G_H
  • 11,739
  • 3
  • 38
  • 82
  • 2
    +1. Or make the server use a RequestHandlerFactory and ask this factory to create a RequestHandler each time the server needs one. – JB Nizet Oct 28 '11 at 20:17
  • @JBNizet Hey, even better! I've found abstract classes/implementations and type parameters to be really good friends for OO design. – G_H Oct 28 '11 at 20:19
1

You don't. It doesn't make sense. In this case I'd probably avoid generics. Plain old interface or abstract class does job. You can make abstract server with abstract factory method.

abstract class Server {
    abstract protected RequestHandler newRequest(Socket socket);
    ... same as before
}
viktor
  • 1,277
  • 10
  • 16
  • +1 This seems to make the most sense and lends itself to easy reading. I'm not sure there's much to gain from the Factory pattern here. The language constructs are the way to go. – Daniel B. Chapman Oct 28 '11 at 20:49
0
/* =================|Cassandra to Java Connection|===================== */
package demo_cassandra_connection;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;

public class java_to_cassandra_connection 
{
    public static void main(String[] args) 
    {
        com.datastax.driver.core.Session ses;
        Cluster cluster= 
        Cluster.builder().addContactPoints("54.191.46.102", 
       "54.149.32.12", "54.191.43.254")
        .withPort(9042).withCredentials("cassandra","cassandra").build();
        ses = cluster.connect();
        Session session = (Session) cluster.connect();
        String cqlStatement = "SELECT * FROM testapp.user";
        for (Row row : ((com.datastax.driver.core.Session) 
        session).execute(cqlStatement)) 
        {
            System.out.println(row.toString());
        }

    }
}
0

You can't do it directly like that with generics in Java. You can use Reflection if you get the actual class object of RequestHandler with getClass(). You could try saving the class of the item in constructor and then write helper method like this:

Save the class object (in constructor for example):
this.clazz = requestHandler.getClass()

Then create new object of same class:
E instantiate(Class<E> clazz)
{
    return clazz.newInstance();
}
Lycha
  • 9,937
  • 3
  • 38
  • 43