package io.quarkus.arc.impl;

import io.quarkus.arc.Arc;
import io.quarkus.arc.InjectableBean;
import io.quarkus.arc.InjectableContext;
import io.quarkus.arc.InstanceHandle;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import org.jboss.logging.Logger;

abstract class AbstractInstanceHandle<T> implements InstanceHandle<T> {

    private static final Logger LOGGER = Logger.getLogger(AbstractInstanceHandle.class.getName());

    private final InjectableBean<T> bean;
    private final CreationalContext<T> creationalContext;
    private final CreationalContext<?> parentCreationalContext;
    private final AtomicBoolean destroyed;
    private final Consumer<T> destroyLogic;

    AbstractInstanceHandle(InjectableBean<T> bean, CreationalContext<T> creationalContext,
            CreationalContext<?> parentCreationalContext, Consumer<T> destroyLogic) {
        this.bean = bean;
        this.creationalContext = creationalContext;
        this.parentCreationalContext = parentCreationalContext;
        this.destroyed = new AtomicBoolean(false);
        this.destroyLogic = destroyLogic;
    }

    @Override
    public T get() {
        if (destroyed.get()) {
            throw new IllegalStateException("Instance already destroyed");
        }
        return instanceInternal();
    }

    @Override
    public InjectableBean<T> getBean() {
        return bean;
    }

    protected abstract boolean isInstanceCreated();

    protected abstract T instanceInternal();

    @Override
    public void destroy() {
        if (isInstanceCreated() && destroyed.compareAndSet(false, true)) {
            if (destroyLogic != null) {
                destroyLogic.accept(instanceInternal());
            } else {
                if (bean.getScope().equals(Dependent.class)) {
                    destroyInternal();
                } else {
                    InjectableContext context = Arc.container().getActiveContext(bean.getScope());
                    if (context == null) {
                        throw new ContextNotActiveException(
                                "Cannot destroy instance of " + bean + " - no active context found for: " + bean.getScope());
                    }
                    context.destroy(bean);
                }
            }
        }
    }

    protected void destroyInternal() {
        if (parentCreationalContext != null) {
            parentCreationalContext.release();
        } else {
            try {
                bean.destroy(instanceInternal(), creationalContext);
            } catch (Throwable t) {
                String msg = "Error occurred while destroying instance of bean [%s]";
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.errorf(t, msg, bean.getClass().getName());
                } else {
                    LOGGER.errorf(msg + ": %s", bean.getClass().getName(), t);
                }
            }
        }
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + " [bean=" + bean + ", destroyed=" + destroyed.get() + "]";
    }

}

@@ -208,23 +208,35 @@
 c.Atomic
-Boolean
+IntegerFieldUpdater
 ;%0Aimport
@@ -625,24 +625,248 @@
 etName());%0A%0A
+    @SuppressWarnings(%22rawtypes%22)%0A    private static final AtomicIntegerFieldUpdater%3CAbstractInstanceHandle%3E DESTROYED_UPDATER = AtomicIntegerFieldUpdater%0A            .newUpdater(AbstractInstanceHandle.class, %22destroyed%22);%0A%0A
     private 
@@ -1021,51 +1021,8 @@
 xt;%0A
-    private final AtomicBoolean destroyed;%0A
     
@@ -1062,16 +1062,101 @@
 Logic;%0A%0A
+    // values: 0=%22not destroyed%22, 1=%22destroyed%22%0A    private volatile int destroyed;%0A%0A
     Abst
@@ -1470,59 +1470,8 @@
 xt;%0A
-        this.destroyed = new AtomicBoolean(false);%0A
     
@@ -1571,22 +1571,21 @@
 estroyed
-.get()
+ != 0
 ) %7B%0A    
@@ -1966,25 +1966,33 @@
 ed() && 
-destroyed
+DESTROYED_UPDATER
 .compare
@@ -2002,19 +2002,18 @@
 Set(
-false, true
+this, 0, 1
 )) %7B
@@ -3455,16 +3455,17 @@
 yed=%22 + 
+(
 destroye
@@ -3469,13 +3469,13 @@
 oyed
-.get(
+ != 0
 ) + 

Replace AtomicBoolean usage in Arc with AtomicIntegerFieldUpdater