/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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 org.drools.compiler.osgi;

import org.drools.compiler.builder.impl.KnowledgeBuilderFactoryServiceImpl;
import org.drools.compiler.compiler.BPMN2ProcessProvider;
import org.drools.compiler.compiler.DecisionTableProvider;
import org.drools.core.marshalling.impl.ProcessMarshallerFactoryService;
import org.drools.core.runtime.process.ProcessRuntimeFactoryService;
import org.kie.api.Service;
import org.kie.api.builder.KieScannerFactoryService;
import org.kie.api.osgi.Activator.BundleContextInstantiator;
import org.kie.internal.builder.KnowledgeBuilderFactoryService;
import org.kie.internal.utils.ClassLoaderResolver;
import org.kie.internal.utils.ServiceRegistryImpl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Dictionary;
import java.util.Hashtable;

public class Activator
    implements
    BundleActivator {

    protected static final transient Logger logger = LoggerFactory.getLogger(Activator.class);

    private ServiceRegistration kbuilderReg;

    private ServiceTracker      dtableTracker;
    private ServiceTracker      bpmn2Tracker;
    private ServiceTracker      processRuntimeTracker;
    private ServiceTracker      processMarshallerTracker;
    private ServiceTracker      scannerTracker;
    private ServiceTracker      classResolverTracker;

    public void start(BundleContext bc) throws Exception {
        logger.info( "registering compiler services" );
        this.kbuilderReg = bc.registerService( new String[]{KnowledgeBuilderFactoryService.class.getName(), Service.class.getName()},
                                               new KnowledgeBuilderFactoryServiceImpl(),
                                               new Hashtable() );

        this.dtableTracker = new ServiceTracker( bc,
                                                 bc.createFilter( "(|(" + 
                                                                  Constants.OBJECTCLASS + "=" + 
                                                                  DecisionTableProvider.class.getName() + ")(" +
                                                                  Constants.OBJECTCLASS + "=" + 
                                                                  BPMN2ProcessProvider.class.getName() +") )"),
                                                 new DroolsServiceTracker( bc,
                                                                           this ) );
        this.dtableTracker.open();

        this.bpmn2Tracker = new ServiceTracker( bc,
                                                BPMN2ProcessProvider.class.getName(),
                                                new DroolsServiceTracker( bc,
                                                                          this ) );
        this.bpmn2Tracker.open();
        
        this.processRuntimeTracker = new ServiceTracker( bc,
                                                         ProcessRuntimeFactoryService.class.getName(),
                                                         new DroolsServiceTracker( bc,
                                                                                   this ) );
        this.processRuntimeTracker.open();

        this.processMarshallerTracker = new ServiceTracker( bc,
                                                            ProcessMarshallerFactoryService.class.getName(),
                                                            new DroolsServiceTracker( bc,
                                                                                      this ) );
        this.processRuntimeTracker.open();

        this.scannerTracker = new ServiceTracker( bc,
                                                  KieScannerFactoryService.class.getName(),
                                                  new DroolsServiceTracker( bc, this ) );
        this.scannerTracker.open();

        this.classResolverTracker = new ServiceTracker( bc,
                                                        ClassLoaderResolver.class.getName(),
                                                        new DroolsServiceTracker( bc, this ) );
        this.classResolverTracker.open();

        logger.info( "compiler services registered" );
    }

    public void stop(BundleContext bc) throws Exception {
        this.kbuilderReg.unregister();
        this.dtableTracker.close();
        this.bpmn2Tracker.close();
        this.processRuntimeTracker.close();
        this.processMarshallerTracker.close();
        this.scannerTracker.close();
        this.classResolverTracker.close();
    }

    public static class DroolsServiceTracker
        implements
        ServiceTrackerCustomizer {
        private final BundleContext bc;
        private final Activator     activator;
        private final Class         serviceClass;

        public DroolsServiceTracker(BundleContext bc, Activator activator) {
            this(bc, activator, null);
        }

        public DroolsServiceTracker(BundleContext bc, Activator activator, Class serviceClass) {
            this.bc = bc;
            this.activator = activator;
            this.serviceClass = serviceClass;
        }

        public Object addingService(ServiceReference ref) {
            Service service = (Service) this.bc.getService( ref );
            logger.info( "registering compiler : " + service + " : " + service.getClass().getInterfaces()[0] );

            Dictionary dic = new Hashtable();
            ServiceReference regServiceRef = this.activator.kbuilderReg.getReference();
            for ( String key : regServiceRef.getPropertyKeys() ) {
                dic.put( key,
                         regServiceRef.getProperty( key ) );
            }
            dic.put( service.getClass().getInterfaces()[0].getName(),
                     "true" );
            activator.kbuilderReg.setProperties( dic );

            ServiceRegistryImpl.getInstance().registerLocator( serviceClass != null ? serviceClass : service.getClass().getInterfaces()[0],
                                                               new BundleContextInstantiator( this.bc,
                                                                                              ref ) );
            return service;
        }

        public void modifiedService(ServiceReference arg0,
                                    Object arg1) {

        }

        public void removedService(ServiceReference ref,
                                   Object arg1) {
            Service service = (Service) bc.getService( ref );
            ServiceRegistryImpl.getInstance().unregisterLocator( service.getClass().getInterfaces()[0] );
            logger.info( "unregistering compiler : " + service + " : " + service.getClass().getInterfaces()[0] );
        }
    }

}

@@ -1070,69 +1070,8 @@
 ce;%0A
-import org.kie.api.osgi.Activator.BundleContextInstantiator;%0A
 impo
@@ -1658,16 +1658,54 @@
 shtable;
+%0Aimport java.util.concurrent.Callable;
 %0A%0Apublic
@@ -7670,10 +7670,463 @@
 %0A    %7D%0A%0A
+    public static class BundleContextInstantiator%3CV%3E implements Callable%3CV%3E %7B%0A        private BundleContext bc;%0A        private ServiceReference ref;%0A%0A        public BundleContextInstantiator(BundleContext bc,%0A                                         ServiceReference ref) %7B%0A            this.bc = bc;%0A            this.ref = ref;%0A        %7D%0A%0A        public V call() throws Exception %7B%0A            return (V) this.bc.getService(this.ref);%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Move BundleContextInstantiator class from kie-api