// Path: src/main/java/com/adeptj/runtime/common/OSGiUtil.java
// public final class OSGiUtil {
// 
//     private static final String FILTER_AND = "(&(";
// 
//     private static final String EQ = "=";
// 
//     private static final String ASTERISK = "*";
// 
//     private static final String PARENTHESIS_OPEN = "(";
// 
//     private static final String PARENTHESIS_CLOSE = ")";
// 
//     // No instantiation. Utility methods only.
//     private OSGiUtil() {
//     }
// 
//     public static boolean isNotFragment(Bundle bundle) {
//         return bundle.getHeaders().get(FRAGMENT_HOST) == null;
//     }
// 
//     public static boolean isSystemBundleFragment(Bundle bundle) {
//         return StringUtils.contains(bundle.getHeaders().get(FRAGMENT_HOST), EXTENSION_DIRECTIVE);
//     }
// 
//     public static boolean isNotBundle(Manifest manifest) {
//         return manifest != null && StringUtils.isEmpty(manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME));
//     }
// 
//     public static Filter filter(BundleContext context, String objectClassFQN) {
//         try {
//             return context.createFilter(PARENTHESIS_OPEN +
//                     OBJECTCLASS +
//                     EQ +
//                     objectClassFQN +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static Filter filter(BundleContext context, Class<?> objectClass, String filterExpr) {
//         try {
//             return context.createFilter(FILTER_AND +
//                     OBJECTCLASS +
//                     EQ +
//                     objectClass.getName() +
//                     PARENTHESIS_CLOSE +
//                     filterExpr +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static Filter anyServiceFilter(BundleContext context, String filterExpr) {
//         try {
//             return context.createFilter(FILTER_AND +
//                     OBJECTCLASS +
//                     EQ +
//                     ASTERISK +
//                     PARENTHESIS_CLOSE +
//                     filterExpr +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static void unregisterService(ServiceRegistration<?> registration) {
//         Optional.ofNullable(registration).ifPresent(ServiceRegistration::unregister);
//     }
// 
//     public static String getServiceDesc(ServiceReference<?> reference) {
//         return getString(reference, SERVICE_DESCRIPTION);
//     }
// 
//     public static String getString(ServiceReference<?> reference, String key) {
//         return (String) reference.getProperty(key);
//     }
// 
//     public static boolean getBoolean(ServiceReference<?> reference, String key) {
//         return (boolean) reference.getProperty(key);
//     }
// 
//     public static Set<String> arrayToSet(ServiceReference<?> reference, String key) {
//         // Not doing any type check as the property has to be an array type suggested by method name itself.
//         return Stream.of((String[]) reference.getProperty(key))
//                 .filter(StringUtils::isNotBlank)
//                 .map(String::trim)
//                 .collect(Collectors.toSet());
//     }
// }


import com.adeptj.runtime.common.OSGiUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicBoolean;
/*
###############################################################################
#                                                                             #
#    Copyright 2016, AdeptJ (http://www.adeptj.com)                           #
#                                                                             #
#    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 com.adeptj.runtime.osgi;



/**
 * Boilerplate for {@link DispatcherServletTracker} and {@link EventDispatcherTracker}
 *
 * @author Rakesh.Kumar, AdeptJ
 */
public abstract class BridgeServiceTracker<T> extends ServiceTracker<T, T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(BridgeServiceTracker.class);

    private static final String DISPATCHER_SERVICE_FILTER = "(http.felix.dispatcher=*)";

    /**
     * This is to prevent {@link IllegalStateException} : Invalid {@link BundleContext} when service is removed and
     * then added again on framework restart using the stale {@link BundleContext}.
     * <p>
     * This is registered again using the fresh {@link BundleContext} obtained via {@link FrameworkLifecycleListener}
     */
    private final AtomicBoolean serviceRemoved;

    BridgeServiceTracker(BundleContext context, Class<T> objectClass) {
// Path: src/main/java/com/adeptj/runtime/common/OSGiUtil.java
// public final class OSGiUtil {
// 
//     private static final String FILTER_AND = "(&(";
// 
//     private static final String EQ = "=";
// 
//     private static final String ASTERISK = "*";
// 
//     private static final String PARENTHESIS_OPEN = "(";
// 
//     private static final String PARENTHESIS_CLOSE = ")";
// 
//     // No instantiation. Utility methods only.
//     private OSGiUtil() {
//     }
// 
//     public static boolean isNotFragment(Bundle bundle) {
//         return bundle.getHeaders().get(FRAGMENT_HOST) == null;
//     }
// 
//     public static boolean isSystemBundleFragment(Bundle bundle) {
//         return StringUtils.contains(bundle.getHeaders().get(FRAGMENT_HOST), EXTENSION_DIRECTIVE);
//     }
// 
//     public static boolean isNotBundle(Manifest manifest) {
//         return manifest != null && StringUtils.isEmpty(manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME));
//     }
// 
//     public static Filter filter(BundleContext context, String objectClassFQN) {
//         try {
//             return context.createFilter(PARENTHESIS_OPEN +
//                     OBJECTCLASS +
//                     EQ +
//                     objectClassFQN +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static Filter filter(BundleContext context, Class<?> objectClass, String filterExpr) {
//         try {
//             return context.createFilter(FILTER_AND +
//                     OBJECTCLASS +
//                     EQ +
//                     objectClass.getName() +
//                     PARENTHESIS_CLOSE +
//                     filterExpr +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static Filter anyServiceFilter(BundleContext context, String filterExpr) {
//         try {
//             return context.createFilter(FILTER_AND +
//                     OBJECTCLASS +
//                     EQ +
//                     ASTERISK +
//                     PARENTHESIS_CLOSE +
//                     filterExpr +
//                     PARENTHESIS_CLOSE);
//         } catch (InvalidSyntaxException ex) {
//             // Filter expression is malformed, not RFC-1960 based Filter.
//             throw new IllegalArgumentException(ex);
//         }
//     }
// 
//     public static void unregisterService(ServiceRegistration<?> registration) {
//         Optional.ofNullable(registration).ifPresent(ServiceRegistration::unregister);
//     }
// 
//     public static String getServiceDesc(ServiceReference<?> reference) {
//         return getString(reference, SERVICE_DESCRIPTION);
//     }
// 
//     public static String getString(ServiceReference<?> reference, String key) {
//         return (String) reference.getProperty(key);
//     }
// 
//     public static boolean getBoolean(ServiceReference<?> reference, String key) {
//         return (boolean) reference.getProperty(key);
//     }
// 
//     public static Set<String> arrayToSet(ServiceReference<?> reference, String key) {
//         // Not doing any type check as the property has to be an array type suggested by method name itself.
//         return Stream.of((String[]) reference.getProperty(key))
//                 .filter(StringUtils::isNotBlank)
//                 .map(String::trim)
//                 .collect(Collectors.toSet());
//     }
// }


// Path: src/main/java/com/adeptj/runtime/osgi/BridgeServiceTracker.java
import com.adeptj.runtime.common.OSGiUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicBoolean;

/*
###############################################################################
#                                                                             #
#    Copyright 2016, AdeptJ (http://www.adeptj.com)                           #
#                                                                             #
#    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 com.adeptj.runtime.osgi;



/**
 * Boilerplate for {@link DispatcherServletTracker} and {@link EventDispatcherTracker}
 *
 * @author Rakesh.Kumar, AdeptJ
 */
public abstract class BridgeServiceTracker<T> extends ServiceTracker<T, T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(BridgeServiceTracker.class);

    private static final String DISPATCHER_SERVICE_FILTER = "(http.felix.dispatcher=*)";

    /**
     * This is to prevent {@link IllegalStateException} : Invalid {@link BundleContext} when service is removed and
     * then added again on framework restart using the stale {@link BundleContext}.
     * <p>
     * This is registered again using the fresh {@link BundleContext} obtained via {@link FrameworkLifecycleListener}
     */
    private final AtomicBoolean serviceRemoved;

    BridgeServiceTracker(BundleContext context, Class<T> objectClass) {
        super(context, OSGiUtil.filter(context, objectClass, DISPATCHER_SERVICE_FILTER), null);