All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.paralleluniverse.actors.ActorRegistry Maven / Gradle / Ivy

There is a newer version: 0.8.0
Show newest version
/*
 * Quasar: lightweight threads and actors for the JVM.
 * Copyright (C) 2013, Parallel Universe Software Co. All rights reserved.
 * 
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *  
 *   or (per the licensee's choosing)
 *  
 * under the terms of the GNU Lesser General Public License version 3.0
 * as published by the Free Software Foundation.
 */
package co.paralleluniverse.actors;

import co.paralleluniverse.common.util.Exceptions;
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.common.util.ServiceUtil;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import jsr166e.ConcurrentHashMapV8;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author pron
 */
public class ActorRegistry {
    // TODO: there are probably race conditions here
    private static final Logger LOG = LoggerFactory.getLogger(ActorRegistry.class);
    private static final ConcurrentMap registeredActors = new ConcurrentHashMapV8();
    private static final GlobalRegistry globalRegistry = ServiceUtil.loadSingletonServiceOrNull(GlobalRegistry.class);

    static {
        LOG.info("Global registry is {}", globalRegistry);
    }

    static Object register(Actor actor) {
        final String name = actor.getName();
        if (name == null)
            throw new IllegalArgumentException("name is null");

        // atomically register
        final ActorRef ref = actor.ref();
        final Entry old = registeredActors.get(name);
        if (old != null && old.actor == actor.ref())
            return old.globalId;

        if (old != null && LocalActorUtil.isLocal(old.actor) && !LocalActorUtil.isDone(old.actor))
            throw new RegistrationException("Actor " + old + " is not dead and is already registered under " + name);

        if (old != null)
            LOG.info("Re-registering {}: old was {}", name, old);

        if (old != null && !registeredActors.remove(name, old))
            throw new RegistrationException("Concurrent registration under the name " + name);
        
        final Entry entry = new Entry(null, ref);
        if (registeredActors.putIfAbsent(name, entry) != null)
            throw new RegistrationException("Concurrent registration under the name " + name);

        LOG.info("Registering {}: {}", name, actor);

        final Object globalId = globalRegistry != null ? registerGlobal(actor.ref()) : name;
        entry.globalId = globalId;
        
        actor.monitor();

        return globalId;
    }

    static private Object registerGlobal(final ActorRef actor) {
        try {
            return new Fiber() {
                @Override
                protected Object run() throws SuspendExecution, InterruptedException {
                    return globalRegistry.register(actor);
                }
            }.start().get();
        } catch (ExecutionException e) {
            throw Exceptions.rethrow(e.getCause());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    static void unregister(final String name) {
        LOG.info("Unregistering actor: {}", name);

        if (globalRegistry != null) {
            // TODO: will only work if called from a fiber
            try {
                new Fiber() {
                    @Override
                    protected Void run() throws SuspendExecution, InterruptedException {
                        globalRegistry.unregister(registeredActors.get(name).actor);
                        return null;
                    }
                }.start().join();
            } catch (ExecutionException e) {
                throw Exceptions.rethrow(e.getCause());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        registeredActors.remove(name);
    }

    public static  ActorRef getActor(final String name) {
        Entry entry = registeredActors.get(name);
        ActorRef actor = entry != null ? (ActorRef)entry.actor : null;

        if (actor == null && globalRegistry != null) {
            // TODO: will only work if called from a fiber
            try {
                actor = new Fiber>() {
                    @Override
                    protected ActorRef run() throws SuspendExecution, InterruptedException {
                        return globalRegistry.getActor(name);
                    }
                }.start().get();
            } catch (ExecutionException e) {
                throw Exceptions.rethrow(e.getCause());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        return actor;
    }

    public static boolean hasGlobalRegistry() {
        return globalRegistry != null;
    }
    
    private static class Entry {
        Object globalId;
        final ActorRef actor;

        public Entry(Object globalId, ActorRef actor) {
            this.globalId = globalId;
            this.actor = actor;
        }
    }
}