enzom83
enzom83

Reputation: 8320

How to separate the layer of the communication and processing?

I created an application that provides several services. Each service provides a specific processing capabilities, except one service (that is the main service) that returns true or false to the clients which request if the specified processing capabilities is available or not.

Now I would modify the application, leaving the main service unchanged and adding the support for the installation of plugin with new processing capabilities: each plugin should add new processing capabilities without the need of implement a new service, but after installing the new plugin, a new service should be avaible. In this way, a plugin should not handle the communication layer. In other words, I would like to separate the layer of the communication and processing, in order to simplify the creation of new plugins.

Is it possible?

I could create two services: the main service and the service for processing. The first service may be used by clients to know if a certain feature is present on the server (for example, clients may ask the server if it has installed the plugin that provides the functionality for solving differential equations). The second service could be used to send a generic task and to receive a general result, for example:

Result executeTask(Task task);

where Result and Task are abstract classes...

For example, if I develop a plugin to solve the differential equations, I first create the classes for transferring data:

public class DifferentialEquationTask : Task
// This class contains the data of the differential equation to be solved.
...

public class DifferentialEquationResult : Result
// This class contains the the result.
...

Therefore, the client should instantiate a new object DifferentialEquationTask and pass it to the method of the second service:

DifferentialEquationTask myTask = new DifferentialEquationTask(...); 
...
Result result = executeTask(myTask); // called by basic application
// The second service receives myTask as a Task object.
// This Task object also contains the destination plugin, so myTask is send
// to the correct plugin, which converts it to DifferentialEquationTask
...
myResult = result as DifferentialEquationResult;
// received by the client

Moreover, each plugin should have a version for the application server and a version for the client application.

An alternative would be to include the service in the plugin itself: in this way, a new plugin should implement a new functionality and expose it via an additional service. In summary, I thought the following two alternatives:

  1. a main service to ask the server if it has a plugin or not, and a second service to deliver tasks at the correct plugin;
  2. a main service to ask if the server has a plugin or not, and various additional services (an additional service for each plugin installed).

In order to choose the best approach, I could use the following requirements:

Being a novice, I was wondering if there was a better approach...

Thanks a lot!

Upvotes: 0

Views: 236

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 134065

It seems like the main service could maintain a dictionary of plugins, indexed by name. Then for a client to see if the server provides a particular service, all the main service has to do is look up the name in the dictionary. And to process, the service just has to call a method on the object that's in the value portion of the dictionary entry. An example:

You have three abstract classes: Service, ServiceResult, and ServiceTask. The contents of ServiceTask and ServiceResult aren't really important for this discussion. Service must have a parameterless constructor and a method called Process that takes a ServiceTask as its sole parameter. So your differential equation solver would look like:

public class DiffeqSolver : Service
{
    public DiffeqSolver()
    {
        // do any required initialization here
    }

    public ServiceResult Process(ServiceTask task)
    {
        DiffeqTask dtask = task as DiffeqTask;
        if (dtask == null)
        {
            // Error. User didn't pass a DiffeqTask.
            // Somehow communicate error back to client.
        }

        // Here, solve the diff eq and return the result.
    }
}

The main service is somehow notified of existing plugins. It maintains a dictionary:

Dictionary<string, Service> Services = new Dictionary<string, Service>();

I assume you have some idea how you're going to load the plugins. What you want, in effect, is for the dictionary to contain:

Key = "DiffeqSolver", Value = new DiffeqSolver();
Key = "ServiceType1", Value = new ServiceType1();
etc., etc.

You can then have two methods for the main service: ServiceIsSupported and Process:

bool ServiceIsSupported(string serviceName)
{
    return Services.ContainsKey(serviceName);
}

ServiceResult Process(string serviceName, ServiceTask task)
{
    Service srv;
    if (Services.TryGetValue(serviceName, out srv))
    {
        return srv.Process(task);
    }
    else
    {
        // The service isn't supported.
        // Return a failure result
        return FailedServiceResult;
    }
}

I've simplified that to some extent. In particular, I'm using a Dictionary, which is not thread safe. You'd want to use a ConcurrentDictionary, or use locks to synchronize access to your dictionary.

The more difficult part, I think, will be loading the plugins. But there are many available examples of creating a plugin architecture. I think you can find what you need.

Upvotes: 1

Related Questions