So I am working on this project, and I am having trouble on how to structure this. Basically, this is what I have:
Main Class instansiates Listener Class.
Listener class listens for packets.
When I packet is recieved, the Listener class creates a new instance of the Handler class (which is a runnable). The Handler class then reads the packet data and determines the packet type (reboot, shutdown, etc) and does what it needs with it.
What I want to do, is have a parent class Packet, and then have subclasses with all the different packet types RebootPacket, ShutdownPacket, etc.
I was going to just use tons of IF statements in the Handler class to create instances of the packet classes (if packetType = "reboot", RebootPacket packet = new RebootPacket) however, I feel that there should be a better way to do this. Could I some how use polymorphism to do this? Any suggestions are appreciated.
Here is my understanding of your problem, please correct me if I am wrong:
You are being fed data in "packets" which are really just Strings. These packets can have multiple types, and each type of packet has a different action associated with it. Each time a packet is read in, a new instance of the Handler class is created, which does what it needs to with the packet, depending on type. I am going to assume that the type of packet is inherent to the input.
In this case, I would suggest using polymorphism. I would create one method to do each of the 'actions' associated with individual types of packets. Each of these methods would have identical method signatures, except the parameter would be of a different type. For example:
public void doSomething(RebootPacket p)
and
public void doSomething(ShutDownPacket p)
This could be done for every packet type you will use. What this allows you to do is simply call doSomething(packet) and have it handle the packet in the correct way, regardless of type.
I suggest not using inheritance in this situation. When you have a subclass and a superclass, you want the subclass to have all or most of the same methods as the superclass, plus some of its own that the superclass cannot have. It seems to me like there aren't many methods which all of the packets would have in common, but rather a different way of handling each. If this is a correct assumption, polymorphism makes the most sense. If not, please comment with more information.
Related
I thought the new Java Record data type in Java 14 should be suitable for data crossing the network because the data shouldn't change in the process which is the main feature of the record data type - immutable.
I use the data type in RSocket. On the sender side, I get an error on encoder. I haven't found what the encoder is about. On the receiver side, I get a deserializer error. To my knowledge, a record can't implement an interface such as the Serializable.
So, the record data type doesn't work for network programming, is that right?
Update:
I add the Serializable interface to the record definition on the both sender and receiver sides. After sending out a request, it is fine on the TCP sender side, but an error on the receiver side
No encoder for com.....data.Notification, current value type is class com.....data.Notification
Have those who marked this question have a different experience?
To my knowledge, a record can't implement an interface such as the
Serializable.
It can. Just add implements Serializable to its declaration. It cannot extend any other class because it already extends Record, if that's what you mean.
See JEP-359
Beyond the restrictions above, records behave like normal classes:
they can be declared top level or nested, they can be generic, they
can implement interfaces, and they are instantiated via the new
keyword.
After seeing some examples at my class, I know that if I want to send a "TypeA" object to server and receive a "ProcessedA" object as a result, I only need one client class.
But if I want to send "TypeA", "TypeB", and "TypeC" objects (not at the same time) to server, do I need to make 3 different client classes, each one of which sends objects of one of those data types, or I only need to make one client class and write 3 different "send" methods?
You can have only one method if the objects you send inherits from one unique class or interface, and the same logic is applied to the result class.
It's a bit hard to understand what you need if you don't include a sample code of what you are trying (as is noticed in another post related to your request).
If this condition can be met by your needs, you can use the instanceof operator inside the server method to detect the type of the received object and cast it to the known child type. And apply the same logic to proccess the response in the client.
Im currently learning about RMI.
I dont really understand the concept of the codebase. Every paper i read suggests, that the client, which calls the Remote object can load the Method definitions from the codebase.
The Problem is now: Dont I need the descriptions/interfaces in my classpath anyway? How can i call methods on the remote object, if i only know them during Runtime? This Wouldnt even compile.
Am i completely missing the point here? What exactly is the point of the codebase then? It seems like a lot of extra work and requirements to provide a codebase
thanks
Well, let's say you provide to your client only interfaces, and the implementations will be located in a given code base. Then the client requests the server to send a given object, the client expects to receive an object that implements a given interface, but the actual implementation is unknown to the client, when it deserializes the sent object is when it has to go to the code base and download the corresponding implementing class for the actual object being passed.
This will make the client very thin, and you will very easily update your classes in the code base without having to resort to updating every single client.
EDIT
Let's say you have a RMI server with the following interface
public interface MiddleEarth {
public List<Creature> getAllCreatures();
}
The client will only have the interfaces for MiddleEarth and Creature, but none of the implementations in the class path.
Where the implementations of Creature are serializable objects of type Elf, Man, Dwarf and Hobbit. And these implementations are located in your code base, but not in your client's class path.
When you ask your RMI server to send you the list of all creatures in Middle Earth, it will send objects that implement Creature, that is, any of the classes listed above.
When the client receives the serialized objects it has to look for the class files in order to deserialized them, but these are not located in the local class path. Every object in this stream comes tagged with the given code base that can be used to look for missing classes. Therefore, the client resort to the code base to look for these classes. There it will find the actual creature classes being used.
The code base works in both directions, so it means that if you send your server a Creature (i.e. an Ent) it will look for it in the code base as well.
This means that when both, client and server need to publish new types of creatures all they have to do is to update the creaturesImpl.jar in the code base, and nothing in the server or client applications themselves.
I am wondering if it's better to pass an instance of a whole class to another class or just specific properties of that class. For example if I want the height property of class A in class B do I pass just the height value into class B or the whole instance of the class and use classA.height in class B?
I am torn between having the flexibility and passing the whole class or encapsulation and passing specific properties.
Thanks
Chris
What are you logically passing? Are you logically passing information about the whole person, and it so happens that at the moment you're only interested in the height? Or is the operation in B naturally and clearly only interested in the height?
Go for whatever is most logical, even if it means there's more information available than you're currently using.
It depends on the function of your method and how you want to use it. If in your example, all your method cares about is the height, then pass in just the height. Be as specific as possible so that the functionality of your method is clear.
Remember, just like good variable names, sensible data types also make for good documentation and readability.
The advantages of passing a class (or {}, ie plain old object) instead of passing separate values are:
only one argument is passed (saves on register/stack space),
if the method that takes the class as an arg needs to read other properties sometime in the future, you don't have to change method signatures or refactor calling code, just the end points (ie the class or the guts of some other method that uses the class).
I find the second reason to be the strongest as you start to implement more event dispatching or message passing. At the point of event creation A, gather data and stuff data in event A, dispatch event A, B has an event listener for event A, picks up event A's data, possibly mucks with data, then needs to also dispatch N-many events C, D, and E with some of A's data, possibly appending new data.
Now say you want to pass a new 'foo' parameter from the dispatch point of event A that would be picked up by event C, D and E. If the data you stuff into event A is a class (or even just a {}, ie base Object) then you don't need to adjust event A or event C or any other listeners.
The point I am getting at when talking about dispatching events, handling events caught is that there can be what seems like a long "distance" between where an object is created and where it is used and passed. The farther an object (or set of properties) travels (from method call to method call to data stuffed into a dispatched event) from its source of instantiation the more you have to pay attention to how data is passed. By keeping it simple, ie a single class instance passed along, you just have to focus on creating object correctly and using objects correctly.
I have a queue of uniform message objects with multiple producers and a single consumer. The consumer is publishing the information and needs to be able to grant access based on the data's origin, so I want the producer send a suitable identifier along with the message. The producers themselves can't be responsible for the far side access restrictions.
The id should relate to the role of the producer in my application. I want to enforce that all producers have to define one and that a subclassed producer may choose to inherit or redefine it. The producer's class name would be a good approximation, but the property I want to identify is not really inherent in the class structure, it's rather something I define.
I could use reflection to find out the class name or maybe an interface name, but this smells of too much overhead. Also, I'm unsure what the appropriate property would be to look for.
As all producers subclass the same abstract parent class, I thought a good way would be to put a constant in there (or in an interface), but then I realised that in Java, a "constant" is really a "static final", which means I can't override it, so it doesn't work that way.
How would a more experienced Java programmer do this?
If there's a "type" that you need to identify, define an interface that forces a class to give you that type, then implement that interface everywhere.
Example:
public interface IHasType {
public String getTypeId();
}
However, if the list of types is fixed, I would go one step further and make the type an Enum:
public enum MyType {
TYPE_A, TYPE_B;
}
And then return this enum instead of a String.
Can the producer classes encapsulate the restrictions and "other things" in a method in themselves? That way each different producer could implement the appropriate method accordingly. Or just have that method return some sort of capability identifier, like an Enum of some sort.
If that won't work, like say if you want other consumers to do different things, then the obvious solution is to have a bunch of "if (object instanceof ....)" statements.
I've done it both ways, I can't say either is particularly "better" in all cases.
First I think you need to be clear about what you are trying to protect against. Are you protecting against malicious code? If not, then just use the queued object.
If you want to protect against malicious code, then the obvious route would be to distribute a enqueueing object for each producer. No other producer should be able to get hold of another enqueuer, so you can trust anything added to the queue.
Have your message object extend java.util.EventObject, and have the message producer set itself as the message source. Then, the message consumer can just call getSource() on the message and find out who sent it. Of course, this assumes that you trust the message producers to properly populate this field.