001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.monitoring.configuration;
018    
019    import org.apache.commons.monitoring.MonitoringException;
020    import org.apache.commons.monitoring.util.ClassLoaders;
021    
022    import java.io.File;
023    import java.io.FileInputStream;
024    import java.io.FileNotFoundException;
025    import java.io.InputStream;
026    import java.lang.annotation.ElementType;
027    import java.lang.annotation.Retention;
028    import java.lang.annotation.RetentionPolicy;
029    import java.lang.annotation.Target;
030    import java.lang.reflect.Method;
031    import java.util.ArrayList;
032    import java.util.Collection;
033    import java.util.Properties;
034    import java.util.logging.Level;
035    import java.util.logging.Logger;
036    
037    public final class Configuration {
038        private static final Logger LOGGER = Logger.getLogger(Configuration.class.getName());
039    
040        private static final Collection<ToDestroy> INSTANCES = new ArrayList<ToDestroy>();
041    
042        public static final String COMMONS_MONITORING_PREFIX = "org.apache.commons.monitoring.";
043        private static final String DEFAULT_CONFIGURATION_FILE = "commons-monitoring.properties";
044    
045        private static Thread shutdownHook = null;
046    
047        private static final Properties PROPERTIES = new Properties(System.getProperties());
048        static {
049            try {
050                final InputStream is = findConfiguration();
051                if (is != null) {
052                    PROPERTIES.load(is);
053                }
054            } catch (final Exception e) {
055                LOGGER.log(Level.SEVERE, e.getMessage(), e);
056            }
057        }
058        private static InputStream findConfiguration() throws FileNotFoundException {
059            final String filename = System.getProperty(COMMONS_MONITORING_PREFIX + "configuration", DEFAULT_CONFIGURATION_FILE);
060            if (new File(filename).exists()) {
061                return new FileInputStream(filename);
062            }
063    
064            return ClassLoaders.current().getResourceAsStream(filename);
065        }
066    
067        public static synchronized <T> T newInstance(final Class<T> clazz) {
068            try {
069                String config = PROPERTIES.getProperty(clazz.getName());
070                if (config == null) {
071                    config = clazz.getPackage().getName() + ".Default" + clazz.getSimpleName();
072                }
073    
074                Class<?> loadedClass;
075                try {
076                    loadedClass = ClassLoaders.current().loadClass(config);
077                } catch (final Throwable throwable) { // NoClassDefFoundError or Exception
078                    loadedClass = clazz;
079                }
080    
081                final Object instance = loadedClass.newInstance();
082                for (final Method m : loadedClass.getMethods()) {
083                    if (m.getAnnotation(Created.class) != null) {
084                        m.invoke(instance);
085                    } else if (m.getAnnotation(Destroying.class) != null) {
086                        if (shutdownHook == null == is(COMMONS_MONITORING_PREFIX + "shutdown.hook", true)) {
087                            shutdownHook = new Thread() {
088                                @Override
089                                public void run() {
090                                    shutdown();
091                                }
092                            };
093                            Runtime.getRuntime().addShutdownHook(shutdownHook);
094                        }
095                        INSTANCES.add(new ToDestroy(m, instance));
096                    }
097                }
098    
099                return clazz.cast(instance);
100            } catch (final Exception e) {
101                throw new MonitoringException(e);
102            }
103        }
104    
105        public static boolean is(final String key, final boolean defaultValue) {
106            return Boolean.parseBoolean(getProperty(key, Boolean.toString(defaultValue)));
107        }
108    
109        public static int getInteger(final String key, final int defaultValue) {
110            return Integer.parseInt(getProperty(key, Integer.toString(defaultValue)));
111        }
112    
113        public static String getProperty(final String key, final String defaultValue) {
114            return PROPERTIES.getProperty(key, defaultValue);
115        }
116    
117        public static void shutdown() {
118            for (final ToDestroy c : INSTANCES) {
119                c.destroy();
120            }
121            INSTANCES.clear();
122        }
123    
124        private Configuration() {
125            // no-op
126        }
127    
128        @Retention(RetentionPolicy.RUNTIME)
129        @Target(ElementType.METHOD)
130        public static @interface Created {
131        }
132    
133        @Retention(RetentionPolicy.RUNTIME)
134        @Target(ElementType.METHOD)
135        public static @interface Destroying {
136        }
137    
138        private static class ToDestroy {
139            private final Method method;
140            private final Object target;
141    
142            public ToDestroy(final Method m, final Object instance) {
143                this.method = m;
144                this.target = instance;
145            }
146    
147            public void destroy() {
148                try {
149                    method.invoke(target);
150                } catch (final Exception e) {
151                    // no-op
152                }
153            }
154        }
155    }