001    
002    /*
003     * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004     *
005     * $Id: ContextMainClass.java 19 2011-02-16 14:42:52Z archie.cobbs $
006     */
007    
008    package org.dellroad.stuff.main;
009    
010    import org.springframework.context.support.ClassPathXmlApplicationContext;
011    
012    /**
013     * Support superclass for {@link MainClass} implementations that wish to execute
014     * with an associated Spring application context.
015     */
016    public abstract class ContextMainClass extends MainClass {
017    
018        protected ClassPathXmlApplicationContext context;
019    
020        private void openContext() {
021            String path = getContextLocation();
022            this.log.info("opening application context " + path);
023            this.context = new ClassPathXmlApplicationContext(path, getClass());
024        }
025    
026        private void closeContext() {
027            this.log.info("closing application context");
028            this.context.close();
029            this.context = null;
030        }
031    
032        /**
033         * Get the classpath location of this instance's associated XML application context.
034         * The returned string will resolved on the classpath relative to this instance's class.
035         *
036         * <p>
037         * The implementation in {@link ContextMainClass} returns {@code getClass().getSimpleName() + ".xml"},
038         * which will locate an XML file in the same package and with the same name.
039         */
040        protected String getContextLocation() {
041            return getClass().getSimpleName() + ".xml";
042        }
043    
044        /**
045         * Autowire this instance using its associated application context.
046         * This may be invoked by {@link #runInContext} to autowire this bean using its associated context.
047         *
048         * <p>
049         * For this to work, the application context must have autowiring enabled, e.g., via
050         * {@code <context:annotation-config/>}.
051         */
052        protected void autowire() {
053            this.log.info("autowiring instance of " + this.getClass() + " using " + this.context.getAutowireCapableBeanFactory());
054            this.context.getAutowireCapableBeanFactory().autowireBean(this);
055        }
056    
057        @Override
058        public final int run(final String[] args) throws Exception {
059    
060            // Open context
061            openContext();
062    
063            // Invoke subclass
064            try {
065                return this.runInContext(args);
066            } catch (Exception e) {
067                this.log.error("caught exception during execution", e);
068                throw e;
069            } finally {
070                closeContext();
071            }
072        }
073    
074        /**
075         * Execute the main method. The application context will be open when this method is invoked.
076         */
077        protected abstract int runInContext(String[] args) throws Exception;
078    }
079