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

org.fabric3.binding.zeromq.runtime.context.ContextManagerImpl Maven / Gradle / Ivy

The newest version!
/*
 * Fabric3
 * Copyright (c) 2009-2015 Metaform Systems
 *
 * 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.
 * Portions originally based on Apache Tuscany 2007
 * licensed under the Apache 2.0 license.
 */
package org.fabric3.binding.zeromq.runtime.context;

import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

import org.fabric3.api.host.runtime.HostInfo;
import org.oasisopen.sca.annotation.Destroy;
import org.oasisopen.sca.annotation.EagerInit;
import org.oasisopen.sca.annotation.Init;
import org.oasisopen.sca.annotation.Reference;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;

/**
 *
 */
@EagerInit
public class ContextManagerImpl implements ContextManager {
    private static final byte[] EMPTY_BYTES = new byte[0];

    private Context context;
    private ZMQ.Socket controlSocket;

    // client leases
    private Set leases = new ConcurrentSkipListSet<>();

    // object monitor used as a sync for closing the ZeroMQ context after all open sockets have been closed
    private final Object termMonitor = new Object();

    @Reference
    protected HostInfo hostInfo;

    public Context getContext() {
        return context;
    }

    public ZMQ.Socket createControlSocket() {
        ZMQ.Socket controlSocket = context.socket(ZMQ.SUB);
        controlSocket.setLinger(0);
        controlSocket.subscribe(EMPTY_BYTES);
        controlSocket.connect("inproc://fabric3");
        return controlSocket;
    }

    public void reserve(String id) {
        leases.add(id);
    }

    public void release(String id) {
        synchronized (termMonitor) {
            leases.remove(id);
            termMonitor.notifyAll();
        }
    }

    @Init
    public void init() {
        // Windows requires the ZMQ library to be loaded as the JZMQ library is linked to it and Windows is unable to resolve it relative to the JZMQ library
        // System.loadLibrary("zmq");
        loadLibrary(hostInfo);

        context = ZMQ.context(1);

        controlSocket = context.socket(ZMQ.PUB);
        controlSocket.bind("inproc://fabric3");
    }

    /**
     * Closes the ZeroMQ context after all socket clients have released their locks. This guarantees the context will not be closed prior to all sockets being
     * closed. Note that ZeroMQ requires sockets to be open, accessed and closed by the same thread.
     */
    @Destroy
    public void destroy() {
        if (controlSocket != null) {
            // send message for all listening sockets to close
            controlSocket.send(new byte[0], 0);
        }
        while (!leases.isEmpty()) {
            synchronized (termMonitor) {
                if (leases.isEmpty()) {
                    break;
                }
                try {
                    termMonitor.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        if (controlSocket != null) {
            controlSocket.close();
        }
        context.term();
    }

    /**
     * Uses the OperatingSystem information of the HostInfo to decide what library to load. On Windows the library name is "libzmq". On Linux the library
     * name is "zmq".
     *
     * @param hostInfo Based on the OperatingSystem member the needed Library will be loaded.
     */
    protected void loadLibrary(HostInfo hostInfo) {
        if (hostInfo == null) {
            return;
        }
        // don't load native lib for jeromq profile
        if (getClass().getClassLoader().getResource("org/codehaus/fabric3/jeromq") != null) {
            return;
        }
        String osName = hostInfo.getOperatingSystem().getName().toLowerCase();
        if (osName == null) {
            return;
        }

        for (ZMQLibraryInitializer lib : ZMQLibraryInitializer.values()) {
            if (osName.toLowerCase().contains(lib.name().toLowerCase())) {
                lib.loadLibrary();
                return;
            }
        }
    }

    /**
     * Initializes the ZeroMQ library on Windows and Linux. If the ZeroMQ Library is not initialized before the Context is created the loading of the library is
     * delegated to the Operating System. This causes problems since F3 can't control where to load the libraries from. To work around this problem we
     * initialize ZeroMQ base library prior to JZMQ (which happens when a Context is created).
     */
    protected enum ZMQLibraryInitializer {
        WINDOWS("libzmq-v120-mt-3_2_4"), LINUX("zmq"), OTHER("");

        private String libName;

        private ZMQLibraryInitializer(String libName) {
            this.libName = libName;
        }

        private void loadLibrary() {
            if (!this.equals(OTHER)) {
                System.loadLibrary(libName);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy