/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.framework.vertx;

import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.SLF4JLogDelegateFactory;
import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager;
import org.apache.felix.ipojo.annotations.*;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.wisdom.api.configuration.Configuration;

import java.io.File;
import java.util.Hashtable;
import java.util.concurrent.CountDownLatch;

/**
 * Exposes the Vert.X instance as a service.
 * It used the default vertx factory, and expose the instance as it is.
 */
@Component
@Instantiate
public class VertxSingleton {

    @Context
    protected BundleContext context;

    @Requires(optional = true, filter = "(configuration.path=vertx)", nullable = false, proxy = false)
    Configuration configuration;

    private Vertx vertx;
    private ServiceRegistration<Vertx> vertxRegistration;
    private ServiceRegistration<EventBus> busRegistration;

    //TODO Use services to retrieve the cluster manager

    /**
     * Creates and exposed the instance of Vert.X.
     */
    @Validate
    public void start() {
        String log = System.getProperty("org.vertx.logger-delegate-factory-class-name");
        if (log == null) {
            // No logging backend configured, set one:
            System.setProperty("org.vertx.logger-delegate-factory-class-name",
                    SLF4JLogDelegateFactory.class.getName());
        }

        VertxOptions options = new VertxOptions();
        boolean clustered = false;
        if (configuration != null) {
            clustered = configuration.getBoolean("clustered");
            options = new VertxOptions(new JsonObject(configuration.asMap()));

            if (clustered) {
                options
                        .setClustered(true)
                        .setClusterHost(configuration.getOrDie("cluster-host"));
                // Identify port and configuration file
                String clusterConfig = configuration.getWithDefault("cluster-config", "conf/cluster.xml");
                System.setProperty("hazelcast.config", new File(clusterConfig).getAbsolutePath());
            }
        }

        // To setup the logging backend, Vert.x needs a TTCL.
        final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());

            Hashtable<String, Object> properties = new Hashtable<>();
            if (clustered) {
                options.setClusterManager(new HazelcastClusterManager());
                String host = options.getClusterHost();
                properties.put("eventbus.host", host);
                Vertx.clusteredVertx(options, ar -> {
                    if (ar.failed()) {
                        throw new IllegalStateException("Cannot join cluster", ar.cause());
                    }
                    vertx = ar.result();
                    vertxRegistration = context.registerService(Vertx.class, vertx, properties);
                    busRegistration = context.registerService(EventBus.class, vertx.eventBus(), properties);
                });
            } else {
                // Not a clustered environment
                vertx = Vertx.vertx(options);
                vertxRegistration = context.registerService(Vertx.class, vertx, properties);
                busRegistration = context.registerService(EventBus.class, vertx.eventBus(), properties);
            }
        } finally {
            Thread.currentThread().setContextClassLoader(tccl);
        }
    }

    /**
     * Unregisters and shuts down the Vert.X singleton.
     */
    @Invalidate
    public void stop() throws InterruptedException {
        unregisterQuietly(vertxRegistration);
        unregisterQuietly(busRegistration);
        CountDownLatch latch = new CountDownLatch(1);
        vertx.close(v -> latch.countDown());
        latch.await();
        vertx = null;
    }

    private static void unregisterQuietly(ServiceRegistration reg) {
        if (reg != null) {
            try {
                reg.unregister();
            } catch (IllegalStateException e) {
                // Ignore it.
            }
        }
    }
}

@@ -2393,16 +2393,27 @@
 tBoolean
+WithDefault
 (%22cluste
@@ -2416,16 +2416,23 @@
 ustered%22
+, false
 );%0A     

Fix potential NPE