Background:
I have a list of classes (comm objects), which may or may not increase. They all implement the same method in an interface Comms:
public int send(Socket socket, byte[] message);
I get a list of these comm classes by specifying the package name in the method's packageName parameter (excluding the package name itself internally in the function and doing some filtering to get just the names package comm):
public static Class[] getClasses(String packageName); (modified it a bit from the link below)
http://www.dzone.com/snippets/get-all-classes-within-package
Then I have several plugins which are configurable to use one of the comm objects as base communication.
Comm objects:
serial
client
server
etc.
Plugins:
plugin1
plugin2
etc.
The manager class will receive a request for sending a control packet from a plugin, and the manager will just queue the requests and call the send function for each request on a
Question:
How do I access the method send(Socket socket, byte[] message); within manager or the plugin itself?
This involves creating a generic class object which may call send, which is cast from one of the comm classes, depending on the plugin configuration, from the string name of the comm object.
The configuration of which comm class is used for each plugin is stored within a database. Converting from string to a Class object works well. I just need to find a way to call the send function which resides in the interface Comm which is implemented by all the comm classes. This has to be generic. More comm classes may be added.
Give the manager a reference type Comm interface and call its send method.
When you instantiate the manager, inject it with the implementation that you wish.
It sounds like you already have the virtual constructor/factory pattern down for instantiating each type of Comm implementation.
This is a common pattern for all dependency injection engines (e.g. Spring, Guice, etc.)
Related
I have downloaded JBPM business application template from http://start.jbpm.org. I have added a custom data model in the model project and gave reference to the same in the kjar and service projects. I imported the project into the controller and then created a process with the custom object being one of the process input variables.
Then I fetched the bpmn process into code through git pull process as per documentation. The project got built and deployed successfully. However, when I try to create the process instance, it is giving me a class cast exception. My data model implements the java.io.Serializable interface and has a public constructor.
I am not able to find a solution in the documentation regarding this. Any help or pointers to a solution would help.
I have tried changing the input JSON formats which I post to create the process instances.
{
"employee": {
"lastName": "Sample1",
"firstName": "Sample2",
"employeeId": 1
}
}
I tried adding in type information in the JSON, but it did not work.
The REST API is being called through POSTMAN utility and there is no client code written as of now.
Unable to create response: [soap-client-kjar.OtherProcess:9 - LogAndSetupData:2] -- java.util.LinkedHashMap cannot be cast to com.test.Employee
The user-defined class definition must implement a no-arg constructor.
The class definition must be included in the deployment jar (kjar) of the deployment that the command (request) is sent to.
The class must implement java.io.Serializable.
These classes must also be annotated with one of the following type annotations: org.kie.api.remote.Remotable.
I'm kinda new on DDD and even after read the blue and red book I still have some questions about how to transform some principles to code, specifically using Kotlin and Java.
For example, I identify a Client aggregate root that receive some parameters need it for the creation like Name and Address:
class Client: AggregateRoot {
var clientId: ClienteId
var name: Name
var address: Address
constructor(name: Name,address: Address) : super(){
// validations ....
this.name = name
this.address = address
}
Easy part:
To create a new Client I receive a DTO inside the RS service and try to create a new Client class passing the parameters above, case everything was solid and all rules fulfilled I send the new instance of Client to the repository, pretty straight foward.
clientRepository.store(client)
Other part:
I need to search my Client to change the address so I send the id to the repository and find the Client inside the database then I need to convert the database entity to the aggregate root and return to the caller.
override fun getById(id: Long): Client {
val clientEntity = em.find(...)
val client: Client(.....) //But I need another constructor with ClientId
return client
}
Then I will need a new constructor one that receive more parameters like the ClientId
constructor(clientId: ClienteId,name: Name,address: Address) : super(){
The problem is that every service can call this new constructor and create a incorrect instance of my aggregation root, so my questions are:
Is there a way to hide the complete constructor just for the repository or specific layers to see. Like in C# when you could use internal.
Is there any solution for Java or Kotlin to not expose this constructor that should be used just on tests and integrations ?
Another example is if I didn't need the address to be passed every time a client is created but just after in another method like:
client.addAddress(address)
But in both cases I will need to fulfill the entire Client from the database so I will need a second constructor with the address parameter.
So, the problem is how to rehydrate an Aggregate from the persistence without breaking its encapsulation by exposing the wrong interface to the client code (i.e. the Application layer or the Presentation layer).
I see two solutions to this:
Use reflection to populate the fields. This is the solution that most ORMs use and it is also the most generic. It works for most persistence types, even when there is an impedance mismatch. Some ORMs need to annotate fields or relations.
Expose a different interface to the client code. This means that your Aggregate implementation is larger that the interface and contains additional initialization methods used only by the infrastructure.
As an example in pseudo-code your could have:
// what you want the upper layers to see
interface Client {
void addAddress(address);
}
// the actual implementations
public class ClientAggregate implements Client
{
void rehidrate(clientId,name,address){...}
void addAddress(address){...}
}
public class ClientRepository
{
// this method returns Client (interface)
Client getById(id){
val clientEntity = em.find(...)
val client = new ClientAggregate()
client.rehydrate(clientEntity.id, clientEntity.name, clientEntity.address)
return client //you are returning ClientAggregate but the other see only Client (interface)
}
}
As a side note, I don't expose the constructor to create an Aggregate from the Domain point of view. I like to have empty constructors and a dedicated method, named from the Ubiquitous language, that creates the Aggregate. The reason is that is not clear that the constructor creates a new Aggregate. The constructor instantiate a new instance of a class; it is more a implementation details than a domain concern. An example:
class Client {
constructor(){ //some internal initializations, if needed }
void register(name){ ... }
}
From Effective Java (Item 1: Consider static factory methods instead of constructors):
The class of the object returned by a static factory method need not even exist
at the time the class containing the method is written. Such flexible static factory
methods form the basis of service provider frameworks, such as the Java Database
Connectivity API (JDBC). A service provider framework is a system in which
multiple service providers implement a service, and the system makes the implementations
available to its clients, decoupling them from the implementations.
I specifically do not understand why the book is saying that The class of the object returned by a static factory method need not even exist at the time the class containing the method is written ? Can some one explain using JDBC as the example .
Consider something like the following:
public interface MyService {
void doSomething();
}
public class MyServiceFactory {
public static MyService getService() {
try {
(MyService) Class.forName(System.getProperty("MyServiceImplemetation")).newInstance();
} catch (Throwable t) {
throw new Error(t);
}
}
}
With this code, your library doesn't need to know about the implementations of the service. Users of your library would have to set a system property containing the name of the implementation they want to use.
This is what is meant by the sentence you don't understand: the factory method will return an instance of some class (which name is stored in the system property "MyServiceImplementation"), but it has absolutely no idea what class it is. All it knows is that it implements MyService and that it must have a public, no-arg constructor (otherwise, the factory above will throw an Error).
the system makes the implementations available to its clients, decoupling them from the implementations
Just to put it in simpler way you don't add any dependencies of these JDBC vendors at compile time. Clients can add their own at runtime
This question's background can be found from my previous question.
Previous question: http://tinyurl.com/chq4w7t
I have a interface Comm with a send function:
public interface Comm
{
public int send(Socket socket, byte[] bytes);
}
I have various classes (Server, Client, Serial, etc.) which implements the interface Comm. I can pass these class objects as a parameter to another send function in another class which acts as a manager between the Comm objects and various plugins which are configurable to use one of these Comm classes as a communication medium.
(Server, Client, Serial, etc.) may be passed as parameter to the send function below
public void Send(Comm com, Socket socket, byte[] message)
{
com.send(null, message);
}
From my previous question I have a getClasses function which returns a Class[] and takes a String as parameter. This is used to provide the different configuration options.
I use Class.forName("Client"); for example to return a Class object for Client.
Now finally my question is the following:
How do I convert from Class to a Comm type? I made the following attempt for you to get an idea: (cboxComm is a test combobox for testing my code. It contains the class names for the Comm objects)
// Some code I have no idea how it works, an explanation would be awesome
// regarding the diamond syntax
Class<? extends Comm> classComm = Class.forName(cboxComm.getSelectedItem().toString());
// Error here, I don't know how to convert or cast it
Comm com = classComm;
// Sending function as described above
send(com, null, null);
You can't convert from the Class object to an instance of the class. You need to create an instance, e.g. with the Class.newInstance() method:
Comm com = classComm.newInstance();
Note that this requires a public parameterless constructor in the class. Is that always the case in your code? If not, you'll need to fetch the appropriate constructor and invoke it using reflection, which will get a bit more complicated.
As an aside, I'm surprised this works at all for you:
Class<? extends Comm> classComm = Class.forName(...);
There's nothing really checking that the class returned by forName will implement Comm. I would have expected this to be required:
Class<?> classComm = Class.forName();
Comm comm = (Comm) classComm.newInstance();
At that point, the cast will perform the appropriate check.
There is a nice method provided by Bonjour: DNSSD.browse("_killerapp._tcp", this);. As the first argument of this method I give type of service which potentially can be available in the network, and as the second argument I give a "callback object". The considered method "browse" for the services of the indicated type (first argument).
During the browsing it can "find" and then "lose" a service. If service is found (lost) bonjour call serviceFound (serviceLost) method of the callback object. The serviceFound is called with some parameters of the found service. In more details:
serviceFound(DNSSDService browser, int flags, int ifIndex, String serviceName, String regType, String domain)
But to get the IP address and port of the service we need to do additional operation (people call it "to resolve a service"). This is logic is kind of strange to me. Why this information cannot be given by serviceFound? I mean why Bonjour cannot resolve the service automatically whenever it finds a service.
Anyway, I just accept the given logic and try to use it. From the serviceFound I call DNSSD.resolve(0, ifIndex, serviceName, regType, domain, this).
As before I give a callback object to the resolve (the last argument). Unfortunately I need to use different classes to provide the callback objects for browse and resolve. The reason for that is that browse and resolve can call a operationFailed method of the callback object and, if I use callback objects from the same class I will not know which method is calling the operationFailed (browse or resolve).
So, I create a separate class to instantiate a callback object for the resolve method. In this class I have a method called serviceResolved which is called by Bonjour with IP address and port of the resolved service:
serviceResolved(DNSSDService resolver, int flags, int ifIndex, String fullname, String hostname, int port, TXTRecord txtRecord)
I think that the IP address and port should be fields of the objects which perform browsing. So, in the serviceResolved I have IP and port and I want to set these values to the corresponding field of the instance which browse the service. But how can I do it? This instance is not given as an argument of the serviceResolved method. So, it is invisible!
Moreover, I see that serviceResolved and serviceFound take, as a first argument, DNSSDService resolver. Does anybody know what is it? May be this object can be used to set parameters of the service? I know that an object of this type is returned by the browse.
Not really an answer, but would like to point out that,
besides the Bonjour library, you may want to try JmDNS, which is a pure Java, open sourced module.