/* * Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.client; import com.hazelcast.client.impl.ListenerManager; import com.hazelcast.config.Config; import com.hazelcast.config.GroupConfig; import com.hazelcast.core.*; import com.hazelcast.logging.ILogger; import com.hazelcast.logging.Logger; import com.hazelcast.logging.LoggingService; import com.hazelcast.partition.PartitionService; import com.hazelcast.security.UsernamePasswordCredentials; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import static com.hazelcast.core.LifecycleEvent.LifecycleState.STARTED; import static com.hazelcast.core.LifecycleEvent.LifecycleState.STARTING; /** * Hazelcast Client enables you to do all Hazelcast operations without * being a member of the cluster. It connects to one of the * cluster members and delegates all cluster wide operations to it. * When the connected cluster member dies, client will * automatically switch to another live member. */ public class HazelcastClient implements HazelcastInstance { private final static AtomicInteger clientIdCounter = new AtomicInteger(); private final static List<HazelcastClient> lsClients = new CopyOnWriteArrayList<HazelcastClient>(); final Map<Long, Call> calls = new ConcurrentHashMap<Long, Call>(100); final ListenerManager listenerManager; final OutRunnable out; final InRunnable in; final ConnectionManager connectionManager; final Map<Object, Object> mapProxies = new ConcurrentHashMap<Object, Object>(100); final ConcurrentMap<String, ExecutorServiceClientProxy> mapExecutors = new ConcurrentHashMap<String, ExecutorServiceClientProxy>(2); final ClusterClientProxy clusterClientProxy; final PartitionClientProxy partitionClientProxy; final LifecycleServiceClientImpl lifecycleService; final static ILogger logger = Logger.getLogger(HazelcastClient.class.getName()); final int id; private final ClientConfig config; private final AtomicBoolean active = new AtomicBoolean(true); private HazelcastClient(ClientConfig config) { if (config.getAddressList().size() == 0) { config.addAddress("localhost"); } if (config.getCredentials() == null) { config.setCredentials(new UsernamePasswordCredentials(config.getGroupConfig().getName(), config.getGroupConfig().getPassword())); } this.config = config; this.id = clientIdCounter.incrementAndGet(); lifecycleService = new LifecycleServiceClientImpl(this); lifecycleService.fireLifecycleEvent(STARTING); //empty check connectionManager = new ConnectionManager(this, config, lifecycleService); connectionManager.setBinder(new DefaultClientBinder(this)); out = new OutRunnable(this, calls, new PacketWriter()); in = new InRunnable(this, out, calls, new PacketReader()); listenerManager = new ListenerManager(this); try { final Connection c = connectionManager.getInitConnection(); if (c == null) { connectionManager.shutdown(); throw new IllegalStateException("Unable to connect to cluster"); } } catch (IOException e) { connectionManager.shutdown(); throw new ClusterClientException(e.getMessage(), e); } final String prefix = "hz.client." + this.id + "."; new Thread(out, prefix + "OutThread").start(); new Thread(in, prefix + "InThread").start(); new Thread(listenerManager, prefix + "Listener").start(); clusterClientProxy = new ClusterClientProxy(this); partitionClientProxy = new PartitionClientProxy(this); if (config.isUpdateAutomatic()) { this.getCluster().addMembershipListener(connectionManager); connectionManager.updateMembers(); } lifecycleService.fireLifecycleEvent(STARTED); connectionManager.scheduleHeartbeatTimerTask(); lsClients.add(HazelcastClient.this); } GroupConfig groupConfig() { return config.getGroupConfig(); } public InRunnable getInRunnable() { return in; } public OutRunnable getOutRunnable() { return out; } ListenerManager getListenerManager() { return listenerManager; } /** * @param config * @return */ public static HazelcastClient newHazelcastClient(ClientConfig config) { if (config == null) config = new ClientConfig(); return new HazelcastClient(config); } public Config getConfig() { throw new UnsupportedOperationException(); } public PartitionService getPartitionService() { return partitionClientProxy; } public ClientService getClientService() { return null; } public LoggingService getLoggingService() { throw new UnsupportedOperationException(); } public <K, V> IMap<K, V> getMap(String name) { return (IMap<K, V>) getClientProxy(Prefix.MAP + name); } public <K, V, E> Object getClientProxy(Object o) { Object proxy = mapProxies.get(o); if (proxy == null) { synchronized (mapProxies) { proxy = mapProxies.get(o); if (proxy == null) { if (o instanceof String) { String name = (String) o; if (name.startsWith(Prefix.MAP)) { proxy = new MapClientProxy<K, V>(this, name); } else if (name.startsWith(Prefix.AS_LIST)) { proxy = new ListClientProxy<E>(this, name); } else if (name.startsWith(Prefix.SET)) { proxy = new SetClientProxy<E>(this, name); } else if (name.startsWith(Prefix.QUEUE)) { proxy = new QueueClientProxy<E>(this, name); } else if (name.startsWith(Prefix.TOPIC)) { proxy = new TopicClientProxy<E>(this, name); } else if (name.startsWith(Prefix.ATOMIC_NUMBER)) { proxy = new AtomicNumberClientProxy(this, name); } else if (name.startsWith(Prefix.COUNT_DOWN_LATCH)) { proxy = new CountDownLatchClientProxy(this, name); } else if (name.startsWith(Prefix.IDGEN)) { proxy = new IdGeneratorClientProxy(this, name); } else if (name.startsWith(Prefix.MULTIMAP)) { proxy = new MultiMapClientProxy(this, name); } else if (name.startsWith(Prefix.SEMAPHORE)) { proxy = new SemaphoreClientProxy(this, name); } else { proxy = new LockClientProxy(o, this); } } else { proxy = new LockClientProxy(o, this); } mapProxies.put(o, proxy); } } } return mapProxies.get(o); } public com.hazelcast.core.Transaction getTransaction() { ClientThreadContext trc = ClientThreadContext.get(); TransactionClientProxy proxy = (TransactionClientProxy) trc.getTransaction(this); return proxy; } public ConnectionManager getConnectionManager() { return connectionManager; } public void addInstanceListener(InstanceListener instanceListener) { clusterClientProxy.addInstanceListener(instanceListener); } public Cluster getCluster() { return clusterClientProxy; } public ExecutorService getExecutorService() { return getExecutorService("default"); } public ExecutorService getExecutorService(String name) { if (name == null) throw new IllegalArgumentException("ExecutorService name cannot be null"); // name = Prefix.EXECUTOR_SERVICE + name; ExecutorServiceClientProxy executorServiceProxy = mapExecutors.get(name); if (executorServiceProxy == null) { executorServiceProxy = new ExecutorServiceClientProxy(this, name); ExecutorServiceClientProxy old = mapExecutors.putIfAbsent(name, executorServiceProxy); if (old != null) { executorServiceProxy = old; } } return executorServiceProxy; } public IdGenerator getIdGenerator(String name) { return (IdGenerator) getClientProxy(Prefix.IDGEN + name); } public AtomicNumber getAtomicNumber(String name) { return (AtomicNumber) getClientProxy(Prefix.ATOMIC_NUMBER + name); } public ICountDownLatch getCountDownLatch(String name) { return (ICountDownLatch) getClientProxy(Prefix.COUNT_DOWN_LATCH + name); } public ISemaphore getSemaphore(String name) { return (ISemaphore) getClientProxy(Prefix.SEMAPHORE + name); } public Collection<Instance> getInstances() { return clusterClientProxy.getInstances(); } public <E> IList<E> getList(String name) { return (IList<E>) getClientProxy(Prefix.AS_LIST + name); } public ILock getLock(Object obj) { return new LockClientProxy(obj, this); } public <K, V> MultiMap<K, V> getMultiMap(String name) { return (MultiMap<K, V>) getClientProxy(Prefix.MULTIMAP + name); } public String getName() { return config.getGroupConfig().getName(); } public <E> IQueue<E> getQueue(String name) { return (IQueue<E>) getClientProxy(Prefix.QUEUE + name); } public <E> ISet<E> getSet(String name) { return (ISet<E>) getClientProxy(Prefix.SET + name); } public <E> ITopic<E> getTopic(String name) { return (ITopic) getClientProxy(Prefix.TOPIC + name); } public void removeInstanceListener(InstanceListener instanceListener) { clusterClientProxy.removeInstanceListener(instanceListener); } public static void shutdownAll() { for (HazelcastClient hazelcastClient : lsClients) { try { hazelcastClient.shutdown(); } catch (Exception ignored) { } } lsClients.clear(); } public void shutdown() { lifecycleService.shutdown(); } void doShutdown() { if (active.compareAndSet(true, false)) { logger.log(Level.INFO, "HazelcastClient[" + this.id + "] is shutting down."); connectionManager.shutdown(); out.shutdown(); in.shutdown(); listenerManager.shutdown(); ClientThreadContext.shutdown(); lsClients.remove(HazelcastClient.this); } } public boolean isActive() { return active.get(); } protected void destroy(String proxyName) { mapProxies.remove(proxyName); } public void restart() { lifecycleService.restart(); } public LifecycleService getLifecycleService() { return lifecycleService; } static void runAsyncAndWait(final Runnable runnable) { callAsyncAndWait(new Callable<Boolean>() { public Boolean call() throws Exception { runnable.run(); return true; } }); } static <V> V callAsyncAndWait(final Callable<V> callable) { final ExecutorService es = Executors.newSingleThreadExecutor(); try { Future<V> future = es.submit(callable); try { return future.get(); } catch (Throwable e) { logger.log(Level.WARNING, e.getMessage(), e); return null; } } finally { es.shutdown(); } } public ClientConfig getClientConfig() { return config; } }