Environment.java
001 /*
002  * Copyright 2004-2012 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 
017 package griffon.util;
018 
019 import groovy.lang.Closure;
020 import groovy.lang.GroovyObjectSupport;
021 import groovy.lang.MissingMethodException;
022 
023 import java.util.HashMap;
024 import java.util.Locale;
025 import java.util.Map;
026 
027 /**
028  * An enum that represents the current environment
029  *
030  @author Graeme Rocher (Grails 1.1)
031  */
032 public enum Environment {
033     /** The development environment */
034     DEVELOPMENT,
035 
036     /** The production environment */
037     PRODUCTION,
038 
039     /** The test environment */
040     TEST,
041 
042     /** A custom environment */
043     CUSTOM;
044 
045     /**
046      * Constant used to resolve the environment via System.getProperty(Environment.KEY)
047      */
048     public static final String KEY = "griffon.env";
049 
050     /**
051      * Constants that indicates whether this GriffonApplication is running in the default environment
052      */
053     public static final String DEFAULT = "griffon.env.default";
054     private static final String PRODUCTION_ENV_SHORT_NAME = "prod";
055     private static final String DEVELOPMENT_ENVIRONMENT_SHORT_NAME = "dev";
056 
057     private static final String TEST_ENVIRONMENT_SHORT_NAME = "test";
058     private static Map<String, String> envNameMappings = new HashMap<String, String>() {{
059         put(DEVELOPMENT_ENVIRONMENT_SHORT_NAME, Environment.DEVELOPMENT.getName());
060         put(PRODUCTION_ENV_SHORT_NAME, Environment.PRODUCTION.getName());
061         put(TEST_ENVIRONMENT_SHORT_NAME, Environment.TEST.getName());
062     }};
063 
064     /**
065      * Returns the current environment which is typcally either DEVELOPMENT, PRODUCTION or TEST.
066      * For custom environments CUSTOM type is returned.
067      *
068      @return The current environment.
069      */
070     public static Environment getCurrent() {
071         String envName = System.getProperty(Environment.KEY);
072         Metadata metadata = Metadata.getCurrent();
073         if (metadata!=null && isBlank(envName)) {
074             envName = metadata.getEnvironment();
075         }
076 
077         if (isBlank(envName)) {
078             return DEVELOPMENT;
079         }
080 
081         Environment env = getEnvironment(envName);
082         if (env == null) {
083             try {
084                 env = Environment.valueOf(envName.toUpperCase());
085             }
086             catch (IllegalArgumentException e) {
087                 // ignore
088             }
089         }
090         if (env == null) {
091             env = Environment.CUSTOM;
092             env.setName(envName);
093         }
094         return env;
095     }
096 
097     /**
098      @see #getCurrent()
099      @return the current environment
100      */
101     public static Environment getCurrentEnvironment() {
102         return getCurrent();
103     }
104 
105     /**
106      @return Return true if the environment has been set as a System property
107      */
108     public static boolean isSystemSet() {
109         return System.getProperty(KEY!= null;
110     }
111 
112     /**
113      * Returns the environment for the given short name
114      @param shortName The short name
115      @return The Environment or null if not known
116      */
117     public static Environment getEnvironment(String shortName) {
118         final String envName = envNameMappings.get(shortName);
119         if (envName != null) {
120             return Environment.valueOf(envName.toUpperCase());
121         }
122         return null;
123     }
124 
125     /**
126      * Takes an environment specific DSL block like:
127      *
128      <code>
129      * environments {
130      *      development {}
131      *      production {}
132      * }
133      </code>
134      *
135      * And returns the closure that relates to the current environment
136      *
137      @param closure The top level closure
138      @return The environment specific block or null if non exists
139      */
140     public static Closure getEnvironmentSpecificBlock(Closure closure) {
141         final Environment env = getCurrent();
142         return getEnvironmentSpecificBlock(env, closure);
143     }
144 
145     /**
146      * Takes an environment specific DSL block like:
147      *
148      <code>
149      * environments {
150      *      development {}
151      *      production {}
152      * }
153      </code>
154      *
155      * And returns the closure that relates to the specified
156      *
157      @param env The environment to use
158      @param closure The top level closure
159      @return The environment specific block or null if non exists
160      */
161     public static Closure getEnvironmentSpecificBlock(Environment env, Closure closure) {
162         if (closure == null) {
163             return null;
164         }
165 
166         final EnvironmentBlockEvaluator evaluator = evaluateEnvironmentSpecificBlock(env, closure);
167         return evaluator.getCallable();
168     }
169 
170     /**
171      * Takes an environment specific DSL block like:
172      *
173      <code>
174      * environments {
175      *      development {}
176      *      production {}
177      * }
178      </code>
179      *
180      * And executes the closure that relates to the current environment
181      *
182      @param closure The top level closure
183      @return The result of the closure execution
184      */
185     public static Object executeForCurrentEnvironment(Closure closure) {
186         final Environment env = getCurrent();
187         return executeForEnvironment(env, closure);
188     }
189 
190     /**
191      * Takes an environment specific DSL block like:
192      *
193      <code>
194      * environments {
195      *      development {}
196      *      production {}
197      * }
198      </code>
199      *
200      * And executes the closure that relates to the specified environment
201      *
202      @param env The environment to use
203      @param closure The top level closure
204      @return The result of the closure execution
205      */
206     public static Object executeForEnvironment(Environment env, Closure closure) {
207         if (closure == null) {
208             return null;
209         }
210 
211         final EnvironmentBlockEvaluator evaluator = evaluateEnvironmentSpecificBlock(env, closure);
212         return evaluator.execute();
213     }
214 
215     private static EnvironmentBlockEvaluator evaluateEnvironmentSpecificBlock(Environment environment, Closure closure) {
216         final EnvironmentBlockEvaluator evaluator = new EnvironmentBlockEvaluator(environment);
217         closure.setDelegate(evaluator);
218         closure.call();
219         return evaluator;
220     }
221 
222     private static class EnvironmentBlockEvaluator extends GroovyObjectSupport {
223         private Environment current;
224         private Closure callable;
225 
226         public Closure getCallable() {
227             return callable;
228         }
229 
230         Object execute() {
231             return callable == null null : callable.call();
232         }
233 
234         private EnvironmentBlockEvaluator(Environment e) {
235             this.current = e;
236         }
237 
238         @SuppressWarnings("unused")
239         public void environments(Closure c) {
240             if (c != null) {
241                 c.setDelegate(this);
242                 c.call();
243             }
244         }
245         @SuppressWarnings("unused")
246         public void production(Closure c) {
247             if (current == Environment.PRODUCTION) {
248                 this.callable = c;
249             }
250         }
251         @SuppressWarnings("unused")
252         public void development(Closure c) {
253             if (current == Environment.DEVELOPMENT) {
254                 this.callable = c;
255             }
256         }
257         @SuppressWarnings("unused")
258         public void test(Closure c) {
259             if (current == Environment.TEST) {
260                 this.callable = c;
261             }
262         }
263 
264         @SuppressWarnings("unused")
265         public Object methodMissing(String name, Object args) {
266             Object[] argsArray = (Object[])args;
267             if (args != null && argsArray.length > && (argsArray[0instanceof Closure)) {
268                 if (current == Environment.CUSTOM && current.getName().equals(name)) {
269                     this.callable = (ClosureargsArray[0];
270                 }
271                 return null;
272             }
273             throw new MissingMethodException(name, Environment.class, argsArray);
274         }
275     }
276 
277     private static boolean isBlank(String value) {
278         return value == null || value.trim().length() == 0;
279     }
280 
281 
282     private String name;
283 
284     /**
285      @return The name of the environment 
286      */
287     public String getName() {
288         if(name == null) {
289             return this.toString().toLowerCase(Locale.getDefault());
290         }
291         return name;
292     }
293 
294     public void setName(String name) {
295         this.name = name;
296     }
297 }