1 /* 2 * Copyright 2004-2005 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package grails.util; 17 18 import groovy.lang.Closure; 19 import groovy.lang.GroovyObjectSupport; 20 import groovy.lang.MissingMethodException; 21 22 import java.util.HashMap; 23 import java.util.Locale; 24 import java.util.Map; 25 26 import org.springframework.util.StringUtils; 27 28 /** 29 * An enum that represents the current environment 30 * 31 * @author Graeme Rocher 32 * @since 1.1 33 * <p/> 34 * Created: Dec 12, 2008 35 */ 36 @SuppressWarnings("serial") 37 public enum Environment { 38 39 /** The development environment */ 40 DEVELOPMENT, 41 42 /** The production environment */ 43 PRODUCTION, 44 45 /** The test environment */ 46 TEST, 47 48 /** 49 * For the application data source, primarly for backward compatability for those applications 50 * that use ApplicationDataSource.groovy. 51 */ 52 APPLICATION, 53 54 /** A custom environment */ 55 CUSTOM; 56 57 /** 58 * Constant used to resolve the environment via System.getProperty(Environment.KEY) 59 */ 60 public static String KEY = "grails.env"; 61 62 /** 63 * Specify whether reloading is enabled for this environment 64 */ 65 public static String RELOAD_ENABLED = "grails.reload.enabled"; 66 67 /** 68 * The location where to reload resources from 69 */ 70 public static final String RELOAD_LOCATION = "grails.reload.location"; 71 72 /** 73 * Constants that indicates whether this GrailsApplication is running in the default environment 74 */ 75 public static final String DEFAULT = "grails.env.default"; 76 77 private static final String PRODUCTION_ENV_SHORT_NAME = "prod"; 78 private static final String DEVELOPMENT_ENVIRONMENT_SHORT_NAME = "dev"; 79 80 private static final String TEST_ENVIRONMENT_SHORT_NAME = "test"; 81 private static Map<String, String> envNameMappings = new HashMap<String, String>() {{ 82 put(DEVELOPMENT_ENVIRONMENT_SHORT_NAME, Environment.DEVELOPMENT.getName()); 83 put(PRODUCTION_ENV_SHORT_NAME, Environment.PRODUCTION.getName()); 84 put(TEST_ENVIRONMENT_SHORT_NAME, Environment.TEST.getName()); 85 }}; 86 87 /** 88 * Returns the current environment which is typcally either DEVELOPMENT, PRODUCTION or TEST. 89 * For custom environments CUSTOM type is returned. 90 * 91 * @return The current environment. 92 */ getCurrent()93 public static Environment getCurrent() { 94 95 String envName = System.getProperty(Environment.KEY); 96 Metadata metadata = Metadata.getCurrent(); 97 if (metadata!=null && isBlank(envName)) { 98 envName = metadata.getEnvironment(); 99 } 100 101 if (isBlank(envName)) { 102 return DEVELOPMENT; 103 } 104 105 Environment env = getEnvironment(envName); 106 if (env == null) { 107 try { 108 env = Environment.valueOf(envName.toUpperCase()); 109 } 110 catch (IllegalArgumentException e) { 111 // ignore 112 } 113 } 114 if (env == null) { 115 env = Environment.CUSTOM; 116 env.setName(envName); 117 } 118 return env; 119 } 120 121 /** 122 * @see #getCurrent() 123 * @return the current environment 124 */ getCurrentEnvironment()125 public static Environment getCurrentEnvironment() { 126 return getCurrent(); 127 } 128 129 /** 130 * Returns true if the application is running in development mode (within grails run-app) 131 * @return True if the application is running in development mode 132 */ isDevelopmentMode()133 public static boolean isDevelopmentMode() { 134 return getCurrent() == DEVELOPMENT && !(Metadata.getCurrent().isWarDeployed()) && 135 System.getProperty("grails.home") != null; 136 } 137 138 /** 139 * @return Return true if the environment has been set as a Systme property 140 */ isSystemSet()141 public static boolean isSystemSet() { 142 return System.getProperty(KEY) != null; 143 } 144 145 /** 146 * Returns the environment for the given short name 147 * @param shortName The short name 148 * @return The Environment or null if not known 149 */ getEnvironment(String shortName)150 public static Environment getEnvironment(String shortName) { 151 final String envName = envNameMappings.get(shortName); 152 if (envName != null) { 153 return Environment.valueOf(envName.toUpperCase()); 154 } 155 return null; 156 } 157 158 /** 159 * Takes an environment specific DSL block like: 160 * 161 * <code> 162 * environments { 163 * development {} 164 * production {} 165 * } 166 * </code> 167 * 168 * And returns the closure that relates to the current environment 169 * 170 * @param closure The top level closure 171 * @return The environment specific block or null if non exists 172 */ getEnvironmentSpecificBlock(Closure closure)173 public static Closure getEnvironmentSpecificBlock(Closure closure) { 174 final Environment env = getCurrent(); 175 return getEnvironmentSpecificBlock(env, closure); 176 } 177 178 /** 179 * Takes an environment specific DSL block like: 180 * 181 * <code> 182 * environments { 183 * development {} 184 * production {} 185 * } 186 * </code> 187 * 188 * And returns the closure that relates to the specified 189 * 190 * @param env The environment to use 191 * @param closure The top level closure 192 * @return The environment specific block or null if non exists 193 */ getEnvironmentSpecificBlock(Environment env, Closure closure)194 public static Closure getEnvironmentSpecificBlock(Environment env, Closure closure) { 195 if (closure == null) { 196 return null; 197 } 198 199 final EnvironmentBlockEvaluator evaluator = evaluateEnvironmentSpecificBlock(env, closure); 200 return evaluator.getCallable(); 201 } 202 203 /** 204 * Takes an environment specific DSL block like: 205 * 206 * <code> 207 * environments { 208 * development {} 209 * production {} 210 * } 211 * </code> 212 * 213 * And executes the closure that relates to the current environment 214 * 215 * @param closure The top level closure 216 * @return The result of the closure execution 217 */ executeForCurrentEnvironment(Closure closure)218 public static Object executeForCurrentEnvironment(Closure closure) { 219 final Environment env = getCurrent(); 220 return executeForEnvironment(env, closure); 221 } 222 223 /** 224 * Takes an environment specific DSL block like: 225 * 226 * <code> 227 * environments { 228 * development {} 229 * production {} 230 * } 231 * </code> 232 * 233 * And executes the closure that relates to the specified environment 234 * 235 * @param env The environment to use 236 * @param closure The top level closure 237 * @return The result of the closure execution 238 */ executeForEnvironment(Environment env, Closure closure)239 public static Object executeForEnvironment(Environment env, Closure closure) { 240 if (closure == null) { 241 return null; 242 } 243 244 final EnvironmentBlockEvaluator evaluator = evaluateEnvironmentSpecificBlock(env, closure); 245 return evaluator.execute(); 246 } 247 evaluateEnvironmentSpecificBlock(Environment environment, Closure closure)248 private static EnvironmentBlockEvaluator evaluateEnvironmentSpecificBlock(Environment environment, Closure closure) { 249 final EnvironmentBlockEvaluator evaluator = new EnvironmentBlockEvaluator(environment); 250 closure.setDelegate(evaluator); 251 closure.call(); 252 return evaluator; 253 } 254 255 private static class EnvironmentBlockEvaluator extends GroovyObjectSupport { 256 private Environment current; 257 private Closure callable; 258 getCallable()259 public Closure getCallable() { 260 return callable; 261 } 262 execute()263 Object execute() { 264 return callable == null ? null : callable.call(); 265 } 266 EnvironmentBlockEvaluator(Environment e)267 private EnvironmentBlockEvaluator(Environment e) { 268 this.current = e; 269 } 270 271 @SuppressWarnings("unused") environments(Closure c)272 public void environments(Closure c) { 273 if (c != null) { 274 c.setDelegate(this); 275 c.call(); 276 } 277 } 278 @SuppressWarnings("unused") production(Closure c)279 public void production(Closure c) { 280 if (current == Environment.PRODUCTION) { 281 this.callable = c; 282 } 283 } 284 @SuppressWarnings("unused") development(Closure c)285 public void development(Closure c) { 286 if (current == Environment.DEVELOPMENT) { 287 this.callable = c; 288 } 289 } 290 @SuppressWarnings("unused") test(Closure c)291 public void test(Closure c) { 292 if (current == Environment.TEST) { 293 this.callable = c; 294 } 295 } 296 297 @SuppressWarnings("unused") methodMissing(String name, Object args)298 public Object methodMissing(String name, Object args) { 299 Object[] argsArray = (Object[])args; 300 if (args != null && argsArray.length > 0 && (argsArray[0] instanceof Closure)) { 301 if (current == Environment.CUSTOM && current.getName().equals(name)) { 302 this.callable = (Closure) argsArray[0]; 303 } 304 return null; 305 } 306 throw new MissingMethodException(name, Environment.class, argsArray); 307 } 308 } 309 isBlank(String value)310 private static boolean isBlank(String value) { 311 return value == null || value.trim().length() == 0; 312 } 313 314 private String name; 315 316 /** 317 * @return the name of the environment 318 */ getName()319 public String getName() { 320 if (name == null) { 321 return this.toString().toLowerCase(Locale.getDefault()); 322 } 323 return name; 324 } 325 326 /** 327 * Set the name. 328 * @param name the name 329 */ setName(String name)330 public void setName(String name) { 331 this.name = name; 332 } 333 334 /** 335 * @return Returns whether reload is enabled for the environment 336 */ isReloadEnabled()337 public boolean isReloadEnabled() { 338 final boolean reloadOverride = Boolean.getBoolean(RELOAD_ENABLED); 339 340 final String reloadLocation = getReloadLocationInternal(); 341 final boolean reloadLocationSpecified = StringUtils.hasLength(reloadLocation); 342 return this == DEVELOPMENT && reloadLocationSpecified && !Metadata.getCurrent().isWarDeployed() || 343 reloadOverride && reloadLocationSpecified; 344 } 345 346 /** 347 * @return Obtains the location to reload resources from 348 */ getReloadLocation()349 public String getReloadLocation() { 350 String location = getReloadLocationInternal(); 351 if (StringUtils.hasLength(location)) { 352 return location; 353 } 354 return "."; // default to the current directory 355 } 356 357 /** 358 * @return Whether a reload location is specified 359 */ hasReloadLocation()360 public boolean hasReloadLocation() { 361 return StringUtils.hasLength(getReloadLocationInternal()); 362 } 363 getReloadLocationInternal()364 private String getReloadLocationInternal() { 365 String location = System.getProperty(RELOAD_LOCATION); 366 if (!StringUtils.hasLength(location)) location = System.getProperty(BuildSettings.APP_BASE_DIR); 367 if (!StringUtils.hasLength(location)) { 368 BuildSettings settings = BuildSettingsHolder.getSettings(); 369 if (settings != null) { 370 location = settings.getBaseDir().getAbsolutePath(); 371 } 372 } 373 return location; 374 } 375 } 376