/*
 * JBoss, Home of Professional Open Source
 * Copyright 2014, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * 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.jboss.javaee.mongodb;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AfterTypeDiscovery;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanAttributes;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.InjectionTargetFactory;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.WithAnnotations;


/**
 * This CDI Extension registers a <code>Mongoclient</code>
 * defined by adding a {@link MongoClientDefinition} annotation to any class of the application
 * Registration will be aborted if user defines her own <code>MongoClient</code> bean or producer
 *
 * @author Anttoine Sabot-Durand
 */
public class MongoExtension implements Extension {

    private static final Logger log = Logger.getLogger(MongoExtension.class.getName());
    private MongoClientDefinition mongoDef = null;
    private boolean moreThanOne = false;

    /**
     * Looks for {@link MongoClientDefinition} annotation to capture it.
     * Also Checks if the application contains more than one of these definition
     */
    void detectMongoClientDefinition(
            @Observes @WithAnnotations(MongoClientDefinition.class) ProcessAnnotatedType<?> pat) {
        AnnotatedType at = pat.getAnnotatedType();

        MongoClientDefinition md = at.getAnnotation(MongoClientDefinition.class);
        String name = md.name();

        if (mongoDef != null) {
            moreThanOne = true;
        } else {
            mongoDef = md;
        }
    }

    /**
     * Warns user if there's none onr more than one {@link MongoClientDefinition} in the application
     */
    void checkMongoClientUniqueness(@Observes AfterTypeDiscovery atd) {
        if (mongoDef == null) {
            log.warning("No mongoDB data sources found, mongo CDI extension will do nothing");
        } else if (moreThanOne) {
            log.log(Level.WARNING, "You defined more than one mongoDB data source. Only the one with name %s will be "
                    + "created", mongoDef
                    .name());
        }

    }

    /**
     * If the application has a {@link MongoClientDefinition} register the bean for it unless user has defined a bean or a
     * producer for a <code>MongoClient</code>
     */
    void registerDataSourceBeans(@Observes AfterBeanDiscovery abd, BeanManager bm) {

        if (mongoDef != null) {
            if (bm.getBeans(MongoClient.class, DefaultLiteral.INSTANCE).isEmpty()) {
                log.log(Level.INFO, "Registering bean for MongoDB datasource %s", mongoDef.name());
                MongoClientURI uri = new MongoClientURI(mongoDef.url());
                abd.addBean(bm.createBean(new MongoClientBeanAttributes(bm.createBeanAttributes(bm.createAnnotatedType
                        (MongoClient.class))), MongoClient.class, new MongoClientProducerFactory(uri)));
            } else {
                log.log(Level.INFO, "Application contains a default MongoClient Bean, automatic registration will be disabled");
            }
        }
    }


    private static class MongoClientBeanAttributes implements BeanAttributes<MongoClient> {

        private BeanAttributes<MongoClient> delegate;

        MongoClientBeanAttributes(BeanAttributes<MongoClient> beanAttributes) {
            delegate = beanAttributes;
        }

        @Override
        public String getName() {
            return delegate.getName();
        }

        @Override
        public Set<Annotation> getQualifiers() {
            return delegate.getQualifiers();
        }

        @Override
        public Class<? extends Annotation> getScope() {
            return ApplicationScoped.class;
        }

        @Override
        public Set<Class<? extends Annotation>> getStereotypes() {
            return delegate.getStereotypes();
        }

        @Override
        public Set<Type> getTypes() {
            return delegate.getTypes();
        }

        @Override
        public boolean isAlternative() {
            return delegate.isAlternative();
        }
    }


    private static class MongoClientProducerFactory
            implements InjectionTargetFactory<MongoClient> {

        MongoClientURI uri;

        MongoClientProducerFactory(MongoClientURI uri) {
            this.uri = uri;
        }

        @Override
        public InjectionTarget<MongoClient> createInjectionTarget(Bean<MongoClient> bean) {
            return new InjectionTarget<MongoClient>() {
                @Override
                public void inject(MongoClient instance, CreationalContext<MongoClient> ctx) {
                }

                @Override
                public void postConstruct(MongoClient instance) {
                }

                @Override
                public void preDestroy(MongoClient instance) {
                }

                @Override
                public MongoClient produce(CreationalContext<MongoClient> ctx) {
                    try {
                        return new MongoClient(uri);
                    } catch (UnknownHostException e) {
                        throw new IllegalArgumentException(e);
                    }
                }

                @Override
                public void dispose(MongoClient instance) {
                    instance.close();
                }

                @Override
                public Set<InjectionPoint> getInjectionPoints() {
                    return Collections.EMPTY_SET;
                }
            };
        }
    }
}

@@ -3450,18 +3450,19 @@
 th name 
-%25s
+%7B0%7D
  will be
@@ -4024,10 +4024,11 @@
 rce 
-%25s
+%7B0%7D
 %22, m

Update MongoExtension.java