001    /*
002     * $Id: Environment.java,v 1.26 2014/04/21 16:04:52 oboehm Exp $
003     *
004     * Copyright (c) 2010 by Oliver Boehm
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     *
018     * (c)reated 01.02.2010 by oliver (ob@oasd.de)
019     */
020    
021    package patterntesting.runtime.util;
022    
023    import java.io.*;
024    import java.net.*;
025    import java.util.Map.Entry;
026    import java.util.*;
027    import java.util.jar.*;
028    
029    import org.slf4j.*;
030    
031    import patterntesting.runtime.io.FileHelper;
032    import patterntesting.runtime.monitor.ClasspathMonitor;
033    
034    /**
035     * This class provides some utilities for the access to the environment
036     * (e.g. the system properties).
037     * <br/>
038     * TODO: Use common.lang.SystemUtils for OS_NAME or other system properties
039     *
040     * @author oliver
041     * @since 1.0 (01.02.2010)
042     */
043    public final class Environment {
044    
045        private static final Logger log = LoggerFactory.getLogger(Environment.class);
046    
047        /** operating system (e.g. "Mac OS X"). */
048        public static final String OS_NAME = System.getProperty("os.name", "unknown");
049        /** architecture (e.g. "x86_64"). */
050        public static final String OS_ARCH = System.getProperty("os.arch", "unknown");
051        /** os version (e.g. "10.6.2"). */
052        public static final String OS_VERSION = System.getProperty("os.version", "unknown");
053        /** JDK version (e.g. "1.6.0_17"). */
054        public static final String JAVA_VERSION = System.getProperty("java.version");
055        /** Java vendor (e.g. "Apple Inc."). */
056        public static final String JAVA_VENDOR = System.getProperty("java.vendor");
057        /** User (e.g. "oliver") */
058        public static final String USER_NAME = System.getProperty("user.name");
059        /** System property to disable multithreading. */
060        public static final String DISABLE_THREADS = "patterntesting.disableThreads";
061        /** System property to enable integration tests */
062        public static final String INTEGRATION_TEST = "patterntesting.integrationTest";
063        /** System property for annotation RunTestsParallel. */
064        public static final String RUN_TESTS_PARALLEL = "patterntesting.runTestsParallel";
065        /** System property for annotation SmokeTest. */
066        public static final String RUN_SMOKE_TESTS = "patterntesting.runSmokeTests";
067        /** True if property for integration test is set. */
068        public static final boolean integrationTestEnabled = Environment
069                .isPropertyEnabled(Environment.INTEGRATION_TEST);
070        /** True if SmokeTest property is set. */
071        public static final boolean smokeTestEnabled = Environment
072                .isPropertyEnabled(Environment.RUN_SMOKE_TESTS);
073    
074        /** to avoid instantiation of this (static) utility class. */
075        private Environment() {}
076    
077        /**
078         * The name of an environment is derived from the classloader.
079         * I.e. on a Tomcat server the name is "org.apache.catalina".
080         *
081         * @return e.g. "com.google.apphosting" for Google App Enginge
082         */
083        public static String getName() {
084            String name = getClassLoader().getClass().getName();
085            String[] packages = name.split("\\.|\\$", 4);
086            return packages[0] + "." + packages[1] + "." + packages[2];
087        }
088    
089        /**
090         * @{link "http://www.odi.ch/prog/design/newbies.php#23"}
091         * @return a valid classloader
092         */
093        public static ClassLoader getClassLoader() {
094            ClassLoader cloader = Thread.currentThread().getContextClassLoader();
095            if (cloader == null) {
096                cloader = Environment.class.getClassLoader();
097                log.warn("no ContextClassLoader found - using " + cloader);
098            }
099            return cloader;
100        }
101    
102        /**
103         * Looks if one of the given properties matches a system property.
104         * If one system property is found and this system property is not
105         * "false" true is returned.
106         *
107         * @param props the properties to be checked
108         * @return true if one of the given properties exist (and are not "false")
109         */
110        public static boolean matchesOneOf(final String[] props) {
111            for (int i = 0; i < props.length; i++) {
112                if (props[i].contains("*") || props[i].contains("?")) {
113                    log.warn("Wildcard in property \"" + props[i] + "\" is not supported!");
114                }
115                String prop = System.getProperty(props[i]);
116                if ((prop != null) && !"false".equalsIgnoreCase(prop)) {
117                    return true;
118                }
119            }
120            return false;
121        }
122    
123        /**
124         * Returns true if the given property is set as System property and the
125         * value of it is not false.
126         *
127         * @param key e.g. "patterntesting.runTestsParallel"
128         * @return true if property is set
129         */
130        public static boolean isPropertyEnabled(final String key) {
131            String prop = System.getProperty(key, "false");
132            return !prop.equalsIgnoreCase("false");
133        }
134    
135        /**
136         * Loads the properties from the classpath and provides them as system
137         * properties.
138         *
139         * @param resource the name of the classpath resource
140         * @return the loaded properties
141         * @throws IOException if properties can't be loaded
142         * @see #loadProperties(InputStream)
143         */
144        public static Properties loadProperties(final String resource)
145                throws IOException {
146            ClassLoader cloader = getClassLoader();
147            InputStream istream = cloader.getResourceAsStream(resource);
148            if ((istream == null) && resource.startsWith("/")) {
149                istream = cloader.getResourceAsStream(resource.substring(1));
150            }
151            if (istream == null) {
152                log.debug("using Environment.class to get " + resource + "...");
153                istream = Environment.class.getResourceAsStream(resource);
154            }
155            Properties props = loadProperties(istream);
156            istream.close();
157            return props;
158        }
159    
160        /**
161         * Loads the properties from the given InputStream and provides them as
162         * system properties.
163         * </br>
164         * Note: Setting it as system property is not guaranteed to run in a
165         * cluster or cloud. E.g. on Google's App Engine this seems not to work.
166         *
167         * @param istream from here the properties are loaded
168         * @return the loaded properties
169         * @throws IOException if properties can't be loaded
170         */
171        public static Properties loadProperties(final InputStream istream)
172                throws IOException {
173            Properties props = new Properties();
174            props.load(istream);
175            Properties systemProps = System.getProperties();
176            for (Entry<Object, Object>entry : props.entrySet()) {
177                systemProps.setProperty((String) entry.getKey(), (String) entry
178                        .getValue());
179            }
180            if (log.isDebugEnabled()) {
181                log.debug(props.size() + " properties loaded from " + istream);
182            }
183            return props;
184        }
185    
186        /**
187         * In some JEE environment like Google's App Engine (GAE) it is not allowed
188         * to use multi threading. But you can also disable multi threading by
189         * setting the system property {@link #DISABLE_THREADS}.
190         *
191         * @return normally true
192         */
193        public static boolean areThreadsAllowed() {
194            if (isGoogleAppEngine() || isPropertyEnabled(DISABLE_THREADS)) {
195                return false;
196            }
197            return true;
198        }
199    
200        /**
201         * If we are in a Google App Engine (GAE) environment we will return true
202         * here.
203         *
204         * @return true if application runs on GAE
205         */
206        public static boolean isGoogleAppEngine() {
207            return System.getProperty("com.google.appengine.runtime.version") != null;
208        }
209    
210        /**
211         * If we are inside a Weblogic Server (WLS) we will return true here.
212         * We look only for the system property "weblogic.Name" here.
213         * Another possibility (not realized) would be to look at the classloader.
214         *
215         * @return true inside Weblogic Server
216         */
217        public static boolean isWeblogicServer() {
218            return System.getProperty("weblogic.Name") != null;
219        }
220    
221        /**
222         * Normally you'll find the local Maven repository at ~/.m2/repository.
223         * But on cloudbees it is the local .repository directory. So we try to
224         * find out here which one we should use.
225         *
226         * @return the root dir of the local Maven repository
227         * @throws IOException Signals that an I/O exception has occurred.
228         */
229        public static File getLocalMavenRepositoryDir() throws IOException {
230            File[] repoDirs = { new File(FileHelper.getHomeDir(), ".m2/repository"),
231                    new File(".repository").getAbsoluteFile(),
232                    new File("../.repository").getAbsoluteFile() };
233            for (int i = 0; i < repoDirs.length; i++) {
234                if (repoDirs[i].exists() && repoDirs[i].isDirectory()) {
235                    return repoDirs[i];
236                }
237            }
238            throw new IOException("local maven repository not found in " + Converter.toString(repoDirs));
239        }
240    
241        /**
242         * It is only tested for Jamon 2.4 and 2.7 so we look for it
243         *
244         * @return true if Jamon 2.4 or 2.7 (or greater) was found
245         */
246        public static boolean isJamonAvailable() {
247            String resource = "/com/jamonapi/MonitorFactory.class";
248            try {
249                URL classURL = Environment.class.getResource(resource);
250                URI jarURI = ClasspathHelper.getParent(classURL.toURI(), resource);
251                JarFile jarfile = ClasspathMonitor.whichResourceJar(jarURI);
252                Manifest manifest = jarfile.getManifest();
253                Attributes attributes = manifest.getMainAttributes();
254                String version = attributes.getValue("version");
255                if (version.equalsIgnoreCase("JAMon 2.4") || (version.compareTo("JAMon 2.7") >= 0)) {
256                    log.info("{} available for profiling.", version);
257                    return true;
258                } else {
259                    log.info(version
260                       + " not supported (only JAMon 2.4 and 2.7 or higher), using simple profiling.");
261                }
262            } catch (RuntimeException e) {
263                // if JAMon is not in classpath we come with a NPE to here
264                log.debug("JAMon not available, using simple profiling");
265            } catch (IOException ioe) {
266                log.info("Manifest for JAMon not found, using simple profiling", ioe);
267            } catch (URISyntaxException use) {
268                log.info(resource + " not available as URI, using simple profiling", use);
269            }
270            return false;
271        }
272    
273    }
274