So the next thing I wanted to do was to tie into the shutdown of the Weld framework, and the way to do that is via an javax.enterprise.inject.spi.Extension implementation. The default way to add an Extension is to use the META-INF/services mechanism, but since the custom startup class had access to the Weld instance, and this has an addExtension method, I leveraged that along with a couple of new annotations to have the custom startup handle all of the details. The new classes are:

 

package com.si.weld;


import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;


import javax.enterprise.inject.spi.Extension;
import javax.enterprise.util.AnnotationLiteral;
import java.lang.annotation.Annotation;


/**
 * A weld startup class for use in Java SE environment
 *
 * @author Scott Stark
 * @version $Revision:$
 */
public class CustomWeldStartMain {


    /**
     * The entry point to the weld initialization
     * @param args - the
     *             [0] = the class name of WeldMain class to bootstrap
     *             [1..n] = the args to pass to the WeldMain.main(String...) method
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // Need at least one arg giving the WeldMain implementation class name
        if(args.length == 0) {
            throw new IllegalStateException("Non-zero arguments required, first argument must be main class name");
        }
        // Load the class to use as the main class
        String mainClassName = args[0];
        Class<?> mainClass = CustomWeldStartMain.class.getClassLoader().loadClass(mainClassName);
        if(WeldMain.class.isAssignableFrom(mainClass) == false) {
            throw new IllegalStateException(mainClassName+"does not implement WeldMain");
        }
        Class<WeldMain> weldMainClass = (Class<WeldMain>) mainClass;
        Weld weld = new Weld();
        // See if there is a main class extension
        Extension mainExtension = loadExtension(weldMainClass, weld);
        if(mainExtension instanceof DefaultWeldMainExtension) {
            // This is a hack to tie into extension to know which WeldMain impl was used
            DefaultWeldMainExtension tme = (DefaultWeldMainExtension) mainExtension;
            tme.setWeldMainClass(weldMainClass);
        }
        // Standard Weld bootstrap from org.jboss.weld.environment.se.StartMain
        WeldContainer weldContainer = weld.initialize();
        Annotation qualifier = new AnnotationLiteral<WeldMainType>() {};
        WeldMain main = weldContainer.instance().select(weldMainClass, qualifier).get();


        // Add the SE shutdown hook
        Runtime.getRuntime().addShutdownHook(new ShutdownHook(weld));
        // Call the WeldMain.main() entry point
        String[] subargs = new String[args.length-1];
        System.arraycopy(args, 1, subargs, 0, args.length-1);
        main.main(subargs);
    }


    /**
     * Look for an Extension implementation via a WeldMainExtension on the weldMainClass
     * @param weldMainClass
     * @param weld
     */
    private static Extension loadExtension(Class<WeldMain> weldMainClass, Weld weld) {
        Extension extension = null;
        WeldMainExtension extensionType = weldMainClass.getAnnotation(WeldMainExtension.class);
        if(extensionType != null) {
            try {
                Class<? extends Extension> c = extensionType.value();
                extension = c.newInstance();
                weld.addExtension(extension);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return extension;
    }


    static class ShutdownHook extends Thread {
        private final Weld weld;


        ShutdownHook(final Weld weld) {
            this.weld = weld;
        }


        public void run() {
            weld.shutdown();
        }
    }
}

package com.si.weld;


/**
 * A simple interface defining the Weld post bootstrap main entry point.
 *
 * @author Scott Stark
 * @version $Revision:$
 */
public interface WeldMain {
    public void main(String[] args) throws Exception;
    public void shutdown();
}

package com.si.weld;


import javax.enterprise.inject.spi.Extension;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;


/**
 * A WeldMainExtension qualifier
 * @author Scott Stark
 * @version $Revision:$
 */
@Qualifier
@Target({TYPE})
@Retention(RUNTIME)
public @interface WeldMainExtension {
    Class<? extends Extension> value();
}

package com.si.weld;


import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;


/**
 * A WeldMain qualifier used to identify which WeldMain bean was used
 * @author Scott Stark
 * @version $Revision:$
 */
@Qualifier
@Target({TYPE})
@Retention(RUNTIME)
public @interface WeldMainType {
}

package com.si.weld;


import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.util.AnnotationLiteral;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;


/**
 * A Weld Extension that marks the ManagedBean used as the WeldMain instance with a
 * WeldMainType qualifier to allow it to be selected during shutdown, and its WeldMain.shutdown
 * method called.
 * @author Scott Stark
 * @version $Revision:$
 */
public class DefaultWeldMainExtension implements Extension {
    private Class<WeldMain> weldMainClass;
    private HashSet<WeldMainAnnotatedType> weldMainTypes = new HashSet<WeldMainAnnotatedType>();


    <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) {
        AnnotatedType<T> atype = pat.getAnnotatedType();
        if(WeldMain.class.isAssignableFrom(atype.getJavaClass())) {
            //System.out.printf("TestMainExtension: scanning type: %s\n", atype.getJavaClass().getName());
            // If this is a WeldMain, add a wrapper to later hold a WeldMainType qualifier
            if(atype.getJavaClass().equals(weldMainClass)) {
                WeldMainAnnotatedType wrapped = new WeldMainAnnotatedType(atype);
                weldMainTypes.add(wrapped);
                pat.setAnnotatedType(wrapped);
            }
        }
    }
    void beforeShutdown(@Observes BeforeShutdown shutdown, final BeanManager beanManager){
        // Find the WeldMain to invoke shutdown on
        Annotation qualifier = new AnnotationLiteral<WeldMainType>() {};
        WeldMain main = getInstanceByType(beanManager, WeldMain.class, qualifier);
        main.shutdown();
    }


    protected <T> T getInstanceByType(BeanManager manager, Class<T> type, Annotation... bindings) {
        Set<Bean<?>> beans = manager.getBeans(type, bindings);
        final Bean<?> bean = manager.resolve(beans);
        if (bean == null) {
            throw new UnsatisfiedResolutionException("Unable to resolve a bean for " + type + " with bindings " + Arrays.asList(bindings));
        }
        CreationalContext<?> cc = manager.createCreationalContext(bean);
        return type.cast(manager.getReference(bean, type, cc));
    }


    public void setWeldMainClass(Class<WeldMain> weldMainClass) {
        this.weldMainClass = weldMainClass;
    }


    private static class WeldMainAnnotatedType<T> implements AnnotatedType<T> {
        private final AnnotatedType<T> type;
        private boolean markAsWeldMainType = true;
        WeldMainAnnotatedType(AnnotatedType<T> type){
            this.type = type;
        }


        @Override
        public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
           return annotationType.equals(WeldMainType.class) ?
                   markAsWeldMainType : type.isAnnotationPresent(annotationType);
        }


        @Override
        public Set<AnnotatedConstructor<T>> getConstructors() {
            return type.getConstructors();
        }


        @Override
        public Set<AnnotatedField<? super T>> getFields() {
            return type.getFields();
        }


        @Override
        public Class<T> getJavaClass() {
            return type.getJavaClass();
        }


        @Override
        public Set<AnnotatedMethod<? super T>> getMethods() {
            return type.getMethods();
        }


        @Override
        public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
            return type.getAnnotation(annotationType);
        }


        @Override
        public Set<Annotation> getAnnotations() {
            HashSet<Annotation> annotations = new HashSet<Annotation>(type.getAnnotations());
            if(markAsWeldMainType) {
                annotations.add(new AnnotationLiteral<WeldMainType>() {});
            }
            return annotations;
        }


        @Override
        public Type getBaseType() {
            return type.getBaseType();
        }


        @Override
        public Set<Type> getTypeClosure() {
            return type.getTypeClosure();
        }
    }


}

 

The new sample TestMain becomes:

 

package test.com.si.weld;

import com.si.weld.DefaultWeldMainExtension;
import com.si.weld.WeldMain;
import com.si.weld.WeldMainExtension;

import javax.enterprise.inject.Default;
import javax.inject.Singleton;
import java.util.Arrays;


/**
 * A minimalist WeldMain implementation
 *
 * @author Scott Stark
 * @version $Revision:$
 */
@Singleton
@Default
@WeldMainExtension(DefaultWeldMainExtension.class)
public class TestMain2 implements WeldMain {
    public TestMain2() {
    }


    public void main(String[] args) {
        System.out.printf("TestMain2.main(%s)\n", Arrays.asList(args));
    }


    @Override
    public void shutdown() {
        System.out.printf("TestMain2.shutdown()\n");
    }
}

 

 

Which when run using the CustomWeldStartMain main entry point produces:

 

/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -Didea.launcher.port=7537 "..." com.intellij.rt.execution.application.AppMain com.si.weld.CustomWeldStartMain test.com.si.weld.TestMain2 arg2 arg3
34 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.9 (Final)
296 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
TestMain2.main([arg2, arg3])
TestMain2.shutdown()


Process finished with exit code 0

 

 

 

It was a whole lot more code just to add support for the invocation of the WeldMain.shutdown method, and most of that had to do with getting a qualifier on the ManagedBean that was used as the WeldMain implementation. Perhaps there is an easier way.