How to write client proxy for SPI and what the difference between client and server proxies?

556 views Asked by At

I have developed own idGenerator based on Hazelcast IdGenerator class (with storing each last_used_id into db). Now I want to run hazelcast cluster as a single java application and my web-application as other app (web-application restart shouldn't move id values to next block). I move MyIdGeneratorProxy and MyIdGeneratorService to new application, run it, run web-application as a hazelcast-client and get

IllegalArgumentException: No factory registered for service: ecs:impl:idGeneratorService

It was okay when client and server were the same application.

It seems it's unable to process without some clientProxy. I have compared IdGeneratorProxy and ClientIdGeneratorProxy and it looks the same. What is the idea? How to write client proxy for services? I have found no documentation yet. Is direction of investigations correct? I thought it is possible to divide hazelcast inner services (like a id generator service) and my business-processes. Should I store custom ClientProxy (for custom spi) in my web-application?

1

There are 1 answers

2
wener On BEST ANSWER

This is a demo how to create a client proxy, the missing part CustomClientProxy function call, is quit complicated(more like a server proxy,here is called ReadRequest, the server is called Operation), you can find a how AtomicLong implement.For every client proxy method you have to make a request.

@Test
public void client() throws InterruptedException, IOException
{
    ClientConfig cfg = new XmlClientConfigBuilder("hazelcast-client.xml").build();
    ServiceConfig serviceConfig = new ServiceConfig();
    serviceConfig.setName(ConnectorService.NAME)
                 .setClassName(ConnectorService.class.getCanonicalName())
                 .setEnabled(true);
    ProxyFactoryConfig proxyFactoryConfig = new ProxyFactoryConfig();
    proxyFactoryConfig.setService(ConnectorService.NAME);
    proxyFactoryConfig.setClassName(CustomProxyFactory.class.getName());
    cfg.addProxyFactoryConfig(proxyFactoryConfig);
    HazelcastInstance hz = HazelcastClient.newHazelcastClient(cfg);

    Thread.sleep(1000);
    for (int i = 0; i < 10; i++)
    {
        Connector c = hz.getDistributedObject(ConnectorService.NAME, "Connector:" + ThreadLocalRandom.current()
                                                                                                     .nextInt(10000));
        System.out.println(c.snapshot());
    }
}

private static class CustomProxyFactory implements ClientProxyFactory
{

    @Override
    public ClientProxy create(String id)
    {
        return new CustomClientProxy(ConnectorService.NAME, id);
    }
}

private static class CustomClientProxy extends ClientProxy implements Connector
{
    protected CustomClientProxy(String serviceName, String objectName)
    {
        super(serviceName, objectName);
    }

    @Override
    public ConnectorState snapshot()
    {
        return null;
    }

    @Override
    public void loadState(ConnectorState state)
    {

    }

    @Override
    public boolean reconnect(HostNode node)
    {
        return false;
    }

    @Override
    public boolean connect()
    {
        return false;
    }

}

EDIT

In hazelcast the IdGenerate is implemented as a wrapper for AtomicLong, you should implement you IdGenerate by you own, instead of extend IdGenerate.

So you have to implement these(more like a todo list XD):

API
interface MyIdGenerate
Server
MyIdGenerateService
MyIdGenerateProxy
MyIdGenerateXXXOperation
Client
ClientMyIdGenerateFactory
ClientMyIdGenerateProxy
MyIdGenerateXXXRequest

I also made a sequence(same as IdGenerate) here, this is backed by zookeeper or redis,also it's easy to add a db backend,too.I will integrate to hazelcast if I got time.