// Path: cicomponents-api/src/main/java/org/cicomponents/Resource.java
// public interface Resource extends AutoCloseable {
//     default void acquire() {}
//     default void release() {}
//     default void close() {
//         release();
//     }
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceEmitter.java
// public interface ResourceEmitter<T extends Resource> {
//     void addResourceListener(ResourceListener<T> listener);
//     void removeResourceListener(ResourceListener<T> listener);
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceHolder.java
// public interface ResourceHolder<T extends Resource> {
//     T acquire();
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceListener.java
// @FunctionalInterface
// public interface ResourceListener<T extends Resource> {
//     void onEmittedResource(ResourceHolder<T> holder,
//                            ResourceEmitter<T> emitter);
// 
//     default boolean isMatchingListener(Class klass) {
//         for (Type type : getClass().getGenericInterfaces()) {
//             if (type instanceof ParameterizedType &&
//                     ((ParameterizedType) type).getRawType() == ResourceListener.class) {
//                 ParameterizedType parameterizedType = (ParameterizedType) type;
//                 Type target = parameterizedType.getActualTypeArguments()[0];
//                 if (target == klass) {
//                     return true;
//                 }
//             }
//         }
//         return false;
//     }
// }


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cicomponents.Resource;
import org.cicomponents.ResourceEmitter;
import org.cicomponents.ResourceHolder;
import org.cicomponents.ResourceListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.cicomponents.common;



@Slf4j
public class AbstractResourceEmitter<T extends Resource> implements ResourceEmitter<T> {
    @Getter
    private Collection<ResourceListener<T>> listeners = new ArrayList<>();

    private static final ExecutorService executor = Executors.newCachedThreadPool(
            new ThreadFactoryBuilder().setNameFormat("resource-emitter-%d").build()
    );

    @Override public void addResourceListener(ResourceListener<T> listener) {
        listeners.add(listener);
    }

// Path: cicomponents-api/src/main/java/org/cicomponents/Resource.java
// public interface Resource extends AutoCloseable {
//     default void acquire() {}
//     default void release() {}
//     default void close() {
//         release();
//     }
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceEmitter.java
// public interface ResourceEmitter<T extends Resource> {
//     void addResourceListener(ResourceListener<T> listener);
//     void removeResourceListener(ResourceListener<T> listener);
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceHolder.java
// public interface ResourceHolder<T extends Resource> {
//     T acquire();
// }
// 
// Path: cicomponents-api/src/main/java/org/cicomponents/ResourceListener.java
// @FunctionalInterface
// public interface ResourceListener<T extends Resource> {
//     void onEmittedResource(ResourceHolder<T> holder,
//                            ResourceEmitter<T> emitter);
// 
//     default boolean isMatchingListener(Class klass) {
//         for (Type type : getClass().getGenericInterfaces()) {
//             if (type instanceof ParameterizedType &&
//                     ((ParameterizedType) type).getRawType() == ResourceListener.class) {
//                 ParameterizedType parameterizedType = (ParameterizedType) type;
//                 Type target = parameterizedType.getActualTypeArguments()[0];
//                 if (target == klass) {
//                     return true;
//                 }
//             }
//         }
//         return false;
//     }
// }


// Path: cicomponents-common/src/main/java/org/cicomponents/common/AbstractResourceEmitter.java
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cicomponents.Resource;
import org.cicomponents.ResourceEmitter;
import org.cicomponents.ResourceHolder;
import org.cicomponents.ResourceListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.cicomponents.common;



@Slf4j
public class AbstractResourceEmitter<T extends Resource> implements ResourceEmitter<T> {
    @Getter
    private Collection<ResourceListener<T>> listeners = new ArrayList<>();

    private static final ExecutorService executor = Executors.newCachedThreadPool(
            new ThreadFactoryBuilder().setNameFormat("resource-emitter-%d").build()
    );

    @Override public void addResourceListener(ResourceListener<T> listener) {
        listeners.add(listener);
    }

    @Override public void removeResourceListener(ResourceListener<T> listener) {