This is a very simple concern, could somebody take a look at a few lines of my code? I'm writing a simple Java multi-user messenger, it is structured in a desktop client with a Swing GUI, a java server based on plain sockets and a service library holding general utilities... At the moment I transmit messages through a ObjectOutputStream
/ObjectInputStream
with a custom Packet
class...
package org.x1c1b.carrierpigeon.service.packet;
import java.io.Serializable;
import java.util.Objects;
public class Packet implements Serializable
{
protected String source;
protected String destination;
protected int type;
protected String payload;
public Packet(String source, String destination, PacketType type, String payload)
{
this.source = source;
this.destination = destination;
this.type = type.getIdentifier();
this.payload = payload;
}
public Packet(Packet packet)
{
this.source = packet.source;
this.destination = packet.destination;
this.type = packet.type;
this.payload = packet.payload;
}
protected Packet(PacketBuilder builer)
{
this.source = builer.source;
this.destination = builer.destination;
this.type = builer.type;
this.payload = builer.payload;
}
public String getSource()
{
return this.source;
}
public String getDestination()
{
return this.destination;
}
public PacketType getType()
{
return PacketType.getByIdentifier(this.type);
}
public String getPayload()
{
return this.payload;
}
@Override public boolean equals(Object object)
{
if(this == object)
{
return true;
}
if(object == null || getClass() != object.getClass())
{
return false;
}
Packet packet = (Packet) object;
return type == packet.type && Objects.equals(source, packet.source) && Objects
.equals(destination, packet.destination) && Objects.equals(payload, packet.payload);
}
@Override public int hashCode()
{
return Objects.hash(this.source, this.destination, this.type, this.payload);
}
}
This is the Packet
class used to transmit the message, for identifying the message purpose I uses a Enum defining different PacketType
's...
package org.x1c1b.carrierpigeon.service.packet;
import java.util.NoSuchElementException;
public enum PacketType
{
HANDSHAKE_REQUEST(1),
HANDSHAKE_REPLY(2),
HANDSHAKE_ERROR(3),
AUTHENTICATION_REQUEST(4),
AUTHENTICATION_REPLY(5),
AUTHENTICATION_ERROR(6),
CONNECTIVITY_ESTABLISHED(7),
CONNECTIVITY_HALTED(8),
CONNECTIVITY_STATUS(9),
CONNECTIVITY_SETUP(10),
CONNECTIVITY_ERROR(11),
DATA_TRANSFER(12),
DATA_TRANSFER_ERROR(13);
private int identifier;
private PacketType(int identifier)
{
this.identifier = identifier;
}
public int getIdentifier()
{
return this.identifier;
}
public static PacketType getByIdentifier(int identifier)
{
for(PacketType type : PacketType.values())
{
if(type.identifier == identifier)
{
return type;
}
}
throw new NoSuchElementException("Identifier: " + identifier);
}
}
Maybe for taking a look at the whole project:
- Service Library Containing basic API and Packet implementations
- Server
- Desktop Client
I'm not that much expired in network development with java, so are there any improvements by transmission of messages? Is it common practice to use ObjectStream
's with a custom "Protocol"/Packet to transmit data or should I use already existing protocols like HTTP
instead? I tried to hold it simple without REST or huge webservers...
I will be glad about any improvements or tips for the data transmission...
EDIT
I also anticipate to write a basic API with the Remote Procedure Call
pattern, here a basic example to illustrate what I mean:
public interface MessengerServiceAPI
{
public abstract boolean login(String name);
}
Here the server-side implementation of the service API:
public class MessengerService implements MessengerServiceAPI
{
@Override public boolean login(String name)
{
// Some login logic and database interaction on server-side
}
}
Now I superior to call this server-side method with RPC through a ObjectStream
:
// Method used on client-side to call remote method of service API
public Object call(String name, Object [] params) throws Exception
{
try(Socket socket = new Socket(this.address, this.port);
ObjectOutputStream sout = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream sin = new ObjectInputStream(socket.getInputStream()))
{
sout.writeObject(name);
sout.writeObject(params);
sout.flush();
Object object = sin.readObject();
if(object instanceof Exception)
{
throw (Exception) object;
}
return object;
}
}
// The server-side handler to handle API requests, which execute the requested action on server-side and return the return value of it
@Override public void handle(Socket socket)
{
try (ObjectInputStream sin = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream sout = new ObjectOutputStream(socket.getOutputStream()))
{
Object object;
String name = (String) sin.readObject();
Object [] params = (Object[]) sin.readObject();
try
{
Class <?> [] paramTypes = null;
if(null != params)
{
types = new Class[params.length];
for(int index = 0; index < params.length; ++index)
{
paramTypes[index] = params[index].getClass();
}
}
Method method = this.service.getClass().getMethod(name, paramTypes);
object = method.invoke(this.service, params);
}
catch(InvocationTargetException exc)
{
object = exc.getTargetException();
}
catch(Exception exc)
{
object = exc;
}
sout.writeObject(object);
sout.flush();
}
catch(Exception exc)
{
exc.printStackTrace();
}
}
This is one possible implementation of such a service handling, but is it recommended to write such a basic API and service? Or is it recommended to send a string or packet instead with a identifier and the server executes the action by parsing this identifier?
Sorry because it is also in big parts software design not just code review but I'm waiting for somebody who takes a look on my code to give tips or improvements...