/**
 *  Copyright 2005-2016 Red Hat, Inc.
 *
 *  Red Hat licenses this file to you 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 io.fabric8.core.mxbean;

import io.fabric8.api.mxbean.ProfileManagement;
import io.fabric8.api.scr.AbstractComponent;
import io.fabric8.api.scr.ValidatingReference;

import javax.management.InstanceAlreadyExistsException;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.StandardMBean;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A provider of system MXBeans
 */
@Component(policy = ConfigurationPolicy.IGNORE, immediate = true)
@Service(MXBeansProvider.class)
public final class MXBeansProvider extends AbstractComponent {

    public static Logger LOGGER = LoggerFactory.getLogger(MXBeansProvider.class);

    @Reference(referenceInterface = MBeanServer.class)
    private final ValidatingReference<MBeanServer> mbeanServer = new ValidatingReference<>();

    private BundleContext context;
    private ServiceTracker<MBeanServerConnection, MBeanServerConnection> tracker;

    @Activate
    void activate(BundleContext context) throws InvalidSyntaxException {
        this.context = context;
        activateInternal();
        activateComponent();
    }

    @Deactivate
    void deactivate() {
        deactivateComponent();
        deactivateInternal();
    }

    private void activateInternal() throws InvalidSyntaxException {
        this.tracker = new ServiceTracker<>(context, context.createFilter("(&(objectClass=javax.management.MBeanServerConnection)(guarded=true))"),
                new ServiceTrackerCustomizer<MBeanServerConnection, MBeanServerConnection>() {
            @Override
            public MBeanServerConnection addingService(ServiceReference<MBeanServerConnection> reference) {
                MBeanServerConnection server = MXBeansProvider.this.context.getService(reference);
                registerGuardedMBeanServer(server);
                return server;
            }

            @Override
            public void modifiedService(ServiceReference<MBeanServerConnection> reference, MBeanServerConnection service) {
                MBeanServerConnection server = MXBeansProvider.this.context.getService(reference);
                registerGuardedMBeanServer(null);
                registerGuardedMBeanServer(server);
            }

            @Override
            public void removedService(ServiceReference<MBeanServerConnection> reference, MBeanServerConnection service) {
                registerGuardedMBeanServer(null);
                MXBeansProvider.this.context.ungetService(reference);
            }
        });
        this.tracker.open();

        MBeanServer server = mbeanServer.get();
        try {
            ProfileManagement profileMXBean = new ProfileManagementImpl();
            server.registerMBean(new StandardMBean(profileMXBean, ProfileManagement.class, true), new ObjectName(ProfileManagement.OBJECT_NAME));
        } catch (JMException ex) {
            throw new IllegalStateException(ex);
        }
    }

    private void deactivateInternal() {
        try {
            if (this.tracker != null) {
                this.tracker.close();
            }
            MBeanServer server = mbeanServer.get();
            server.unregisterMBean(new ObjectName(ProfileManagement.OBJECT_NAME));
        } catch (JMException ex) {
            throw new IllegalStateException(ex);
        }
    }

    /**
     * (Un)Registers guarded {@link MBeanServer} in JMX to be used by Jolokia
     * @param server
     */
    private void registerGuardedMBeanServer(MBeanServerConnection server) {
        if (server != null) {
            try {
                ObjectName jolokiaServerName = new ObjectName("jolokia:type=MBeanServer");
                if (!mbeanServer.get().isRegistered(jolokiaServerName)) {
                    mbeanServer.get().registerMBean(new JolokiaMBeanHolder((MBeanServer) server), jolokiaServerName);
                }
            } catch (InstanceAlreadyExistsException e) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(e.getMessage());
                }
            } catch (Exception e) {
                LOGGER.warn(e.getMessage(), e);
            }
        } else {
            try {
                ObjectName jolokiaServerName = new ObjectName("jolokia:type=MBeanServer");
                mbeanServer.get().unregisterMBean(jolokiaServerName);
            } catch (Throwable t) {
                LOGGER.warn("Error while unregistering \"jolokia:type=MBeanServer\"");
            }
        }
    }

    void bindMbeanServer(MBeanServer service) {
        this.mbeanServer.bind(service);
    }

    void unbindMbeanServer(MBeanServer service) {
        this.mbeanServer.unbind(service);
    }

}

@@ -940,55 +940,8 @@
 er;%0A
-import javax.management.MBeanServerConnection;%0A
 impo
@@ -2123,34 +2123,24 @@
 %3CMBeanServer
-Connection
 , MBeanServe
@@ -2140,26 +2140,16 @@
 anServer
-Connection
 %3E tracke
@@ -2629,26 +2629,16 @@
 anServer
-Connection
 )(guarde
@@ -2705,26 +2705,16 @@
 anServer
-Connection
 , MBeanS
@@ -2718,26 +2718,16 @@
 anServer
-Connection
 %3E() %7B%0A  
@@ -2776,26 +2776,16 @@
 anServer
-Connection
  addingS
@@ -2815,34 +2815,24 @@
 %3CMBeanServer
-Connection
 %3E reference)
@@ -2857,34 +2857,24 @@
  MBeanServer
-Connection
  server = MX
@@ -3107,34 +3107,24 @@
 %3CMBeanServer
-Connection
 %3E reference,
@@ -3131,34 +3131,24 @@
  MBeanServer
-Connection
  service) %7B%0A
@@ -3170,34 +3170,24 @@
  MBeanServer
-Connection
  server = MX
@@ -3442,26 +3442,16 @@
 anServer
-Connection
 %3E refere
@@ -3462,34 +3462,24 @@
  MBeanServer
-Connection
  service) %7B%0A
@@ -4594,18 +4594,8 @@
 rver
-Connection
  ser
@@ -4893,22 +4893,8 @@
 der(
-(MBeanServer) 
 serv

Revert "[ENTESB-5219] Expose proxied MBeanServer as MBeanServerConnection interface to keep aries.jmx.core happy"