`AbstractGriffonApplication.java`
`001 /* 002 * Copyright 2008-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 org.codehaus.griffon.runtime.core; 018 019 import griffon.core.*; 020 import griffon.util.ApplicationHolder; 021 import griffon.util.ConfigUtils; 022 import griffon.util.Metadata; 023 import griffon.util.RunnableWithArgs; 024 import groovy.lang.Binding; 025 import groovy.lang.Closure; 026 import groovy.util.ConfigObject; 027 import groovy.util.FactoryBuilderSupport; 028 import org.codehaus.griffon.runtime.util.GriffonApplicationHelper; 029 import org.codehaus.griffon.runtime.util.MVCGroupExceptionHandler; 030 import org.slf4j.Logger; 031 import org.slf4j.LoggerFactory; 032 033 import java.io.InputStream; 034 import java.net.URL; 035 import java.util.*; 036 import java.util.concurrent.Callable; 037 import java.util.concurrent.CountDownLatch; 038 import java.util.concurrent.ExecutorService; 039 import java.util.concurrent.Future; 040 041 import static java.util.Arrays.asList; 042 043 /** 044 * Implements the basics for a skeleton GriffonApplication.<p> 045 * 046 * @author Danno Ferrin 047 * @author Andres Almiray 048 */ 049 public abstract class AbstractGriffonApplication extends AbstractObservable implements GriffonApplication { 050 private Binding bindings = new Binding(); 051 private ConfigObject config; 052 private ConfigObject builderConfig; 053 private Object eventsConfig; 054 private AddonManager addonManager; 055 private ArtifactManager artifactManager; 056 private MVCGroupManager mvcGroupManager; 057 private ServiceManager serviceManager; 058 059 private Locale locale = Locale.getDefault(); 060 public static final String[] EMPTY_ARGS = new String[0]; 061 protected final Object lock = new Object(); 062 private ApplicationPhase phase = ApplicationPhase.INITIALIZE; 063 064 private final EventRouter eventRouter = new EventRouter(); 065 private final ResourceLocator resourceLocator = new ResourceLocator(); 066 private final List<ShutdownHandler> shutdownHandlers = new ArrayList<ShutdownHandler>(); 067 private final String[] startupArgs; 068 private final Object shutdownLock = new Object(); 069 private final Logger log; 070 071 public AbstractGriffonApplication() { 072 this(EMPTY_ARGS); 073 } 074 075 public AbstractGriffonApplication(String[] args) { 076 startupArgs = new String[args.length]; 077 System.arraycopy(args, 0, startupArgs, 0, args.length); 078 ApplicationHolder.setApplication(this); 079 log = LoggerFactory.getLogger(getClass()); 080 MVCGroupExceptionHandler.registerWith(this); 081 } 082 083 public Binding getBindings() { 084 return bindings; 085 } 086 087 public void setBindings(Binding bindings) { 088 this.bindings = bindings; 089 } 090 091 public ConfigObject getConfig() { 092 return config; 093 } 094 095 public void setConfig(ConfigObject config) { 096 this.config = config; 097 } 098 099 public ConfigObject getBuilderConfig() { 100 return builderConfig; 101 } 102 103 public void setBuilderConfig(ConfigObject builderConfig) { 104 this.builderConfig = builderConfig; 105 } 106 107 public Object getEventsConfig() { 108 return eventsConfig; 109 } 110 111 public void setEventsConfig(Object eventsConfig) { 112 this.eventsConfig = eventsConfig; 113 } 114 115 public Map<String, ? extends GriffonModel> getModels() { 116 return getMvcGroupManager().getModels(); 117 } 118 119 public Map<String, ? extends GriffonView> getViews() { 120 return getMvcGroupManager().getViews(); 121 } 122 123 public Map<String, ? extends GriffonController> getControllers() { 124 return getMvcGroupManager().getControllers(); 125 } 126 127 public Map<String, ? extends FactoryBuilderSupport> getBuilders() { 128 return getMvcGroupManager().getBuilders(); 129 } 130 131 public Map<String, MVCGroup> getGroups() { 132 return getMvcGroupManager().getGroups(); 133 } 134 135 public AddonManager getAddonManager() { 136 return addonManager; 137 } 138 139 public void setAddonManager(AddonManager addonManager) { 140 this.addonManager = addonManager; 141 } 142 143 public ArtifactManager getArtifactManager() { 144 return artifactManager; 145 } 146 147 public void setArtifactManager(ArtifactManager artifactManager) { 148 this.artifactManager = artifactManager; 149 } 150 151 public MVCGroupManager getMvcGroupManager() { 152 return mvcGroupManager; 153 } 154 155 public void setMvcGroupManager(MVCGroupManager mvcGroupManager) { 156 this.mvcGroupManager = mvcGroupManager; 157 } 158 159 public ServiceManager getServiceManager() { 160 return serviceManager; 161 } 162 163 public void setServiceManager(ServiceManager serviceManager) { 164 this.serviceManager = serviceManager; 165 } 166 167 public Map<String, ? extends GriffonService> getServices() { 168 return serviceManager.getServices(); 169 } 170 171 public Locale getLocale() { 172 return locale; 173 } 174 175 public String[] getStartupArgs() { 176 return startupArgs; 177 } 178 179 public Logger getLog() { 180 return log; 181 } 182 183 public void setLocale(Locale locale) { 184 firePropertyChange("locale", this.locale, this.locale = locale); 185 } 186 187 public Metadata getMetadata() { 188 return Metadata.getCurrent(); 189 } 190 191 public Class getAppConfigClass() { 192 return loadClass(GriffonApplication.Configuration.APPLICATION.getName()); 193 } 194 195 public Class getConfigClass() { 196 return loadClass(GriffonApplication.Configuration.CONFIG.getName()); 197 } 198 199 public Class getBuilderClass() { 200 return loadClass(GriffonApplication.Configuration.BUILDER.getName()); 201 } 202 203 public Class getEventsClass() { 204 return loadClass(GriffonApplication.Configuration.EVENTS.getName()); 205 } 206 207 public void initialize() { 208 if (phase == ApplicationPhase.INITIALIZE) { 209 GriffonApplicationHelper.prepare(this); 210 } 211 } 212 213 public void ready() { 214 if (phase != ApplicationPhase.STARTUP) return; 215 216 phase = ApplicationPhase.READY; 217 event(GriffonApplication.Event.READY_START.getName(), asList(this)); 218 GriffonApplicationHelper.runLifecycleHandler(GriffonApplication.Lifecycle.READY.getName(), this); 219 event(GriffonApplication.Event.READY_END.getName(), asList(this)); 220 phase = ApplicationPhase.MAIN; 221 } 222 223 public boolean canShutdown() { 224 event(GriffonApplication.Event.SHUTDOWN_REQUESTED.getName(), asList(this)); 225 synchronized (shutdownLock) { 226 for (ShutdownHandler handler : shutdownHandlers) { 227 if (!handler.canShutdown(this)) { 228 event(GriffonApplication.Event.SHUTDOWN_ABORTED.getName(), asList(this)); 229 if (log.isDebugEnabled()) { 230 try { 231 log.debug("Shutdown aborted by " + handler); 232 } catch (UnsupportedOperationException uoe) { 233 log.debug("Shutdown aborted by a handler"); 234 } 235 } 236 return false; 237 } 238 } 239 } 240 return true; 241 } 242 243 public boolean shutdown() { 244 // avoids reentrant calls to shutdown() 245 // once permission to quit has been granted 246 if (phase == ApplicationPhase.SHUTDOWN) return false; 247 248 if (!canShutdown()) return false; 249 log.info("Shutdown is in process"); 250 251 // signal that shutdown is in process 252 phase = ApplicationPhase.SHUTDOWN; 253 254 // stage 1 - alert all app event handlers 255 // wait for all handlers to complete before proceeding 256 // with stage #2 if and only if the current thread is 257 // the ui thread 258 log.debug("Shutdown stage 1: notify all event listeners"); 259 if (isEventPublishingEnabled()) { 260 final CountDownLatch latch = new CountDownLatch(isUIThread() ? 1 : 0); 261 addApplicationEventListener(GriffonApplication.Event.SHUTDOWN_START.getName(), new RunnableWithArgs() { 262 @Override 263 public void run(Object[] args) { 264 latch.countDown(); 265 } 266 }); 267 event(GriffonApplication.Event.SHUTDOWN_START.getName(), asList(this)); 268 try { 269 latch.await(); 270 } catch (InterruptedException e) { 271 // ignore 272 } 273 } 274 275 // stage 2 - alert all shutdown handlers 276 log.debug("Shutdown stage 2: notify all shutdown handlers"); 277 synchronized (shutdownLock) { 278 for (ShutdownHandler handler : shutdownHandlers) { 279 handler.onShutdown(this); 280 } 281 } 282 283 // stage 3 - destroy all mvc groups 284 log.debug("Shutdown stage 3: destroy all MVC groups"); 285 List<String> mvcNames = new ArrayList<String>(); 286 if (getMvcGroupManager() != null) { 287 mvcNames.addAll(getMvcGroupManager().getGroups().keySet()); 288 for (String name : mvcNames) { 289 destroyMVCGroup(name); 290 } 291 } 292 293 // stage 4 - call shutdown script 294 log.debug("Shutdown stage 4: execute Shutdown script"); 295 GriffonApplicationHelper.runLifecycleHandler(GriffonApplication.Lifecycle.SHUTDOWN.getName(), this); 296 297 return true; 298 } 299 300 public void startup() { 301 if (phase != ApplicationPhase.INITIALIZE) return; 302 303 phase = ApplicationPhase.STARTUP; 304 event(GriffonApplication.Event.STARTUP_START.getName(), asList(this)); 305 306 Object startupGroups = ConfigUtils.getConfigValue(getConfig(), "application.startupGroups"); 307 if (startupGroups instanceof List) { 308 if (log.isInfoEnabled()) { 309 log.info("Initializing all startup groups: " + startupGroups); 310 } 311 312 for (String groupName : (List<String>) startupGroups) { 313 createMVCGroup(groupName); 314 } 315 } else if (startupGroups != null && startupGroups.getClass().isArray()) { 316 Object[] groups = (Object[]) startupGroups; 317 if (log.isInfoEnabled()) { 318 log.info("Initializing all startup groups: " + Arrays.toString(groups)); 319 } 320 321 for (Object groupName : groups) { 322 createMVCGroup(String.valueOf(groupName)); 323 } 324 } 325 326 GriffonApplicationHelper.runLifecycleHandler(GriffonApplication.Lifecycle.STARTUP.getName(), this); 327 328 event(GriffonApplication.Event.STARTUP_END.getName(), asList(this)); 329 } 330 331 public void event(String eventName) { 332 eventRouter.publish(eventName, Collections.emptyList()); 333 } 334 335 public void event(String eventName, List params) { 336 eventRouter.publish(eventName, params); 337 } 338 339 // TODO @deprecated - remove before 1.0 340 public void eventOutside(String eventName) { 341 eventOutsideUI(eventName, Collections.emptyList()); 342 } 343 344 // TODO @deprecated - remove before 1.0 345 public void eventOutside(String eventName, List params) { 346 eventOutsideUI(eventName, params); 347 } 348 349 public void eventOutsideUI(String eventName) { 350 eventRouter.publishOutsideUI(eventName, Collections.emptyList()); 351 } 352 353 public void eventOutsideUI(String eventName, List params) { 354 eventRouter.publishOutsideUI(eventName, params); 355 } 356 357 public void eventAsync(String eventName) { 358 eventRouter.publishAsync(eventName, Collections.emptyList()); 359 } 360 361 public void eventAsync(String eventName, List params) { 362 eventRouter.publishAsync(eventName, params); 363 } 364 365 public void addApplicationEventListener(Object listener) { 366 eventRouter.addEventListener(listener); 367 } 368 369 public void removeApplicationEventListener(Object listener) { 370 eventRouter.removeEventListener(listener); 371 } 372 373 public void addApplicationEventListener(String eventName, Closure listener) { 374 eventRouter.addEventListener(eventName, listener); 375 } 376 377 public void removeApplicationEventListener(String eventName, Closure listener) { 378 eventRouter.removeEventListener(eventName, listener); 379 } 380 381 public void addApplicationEventListener(String eventName, RunnableWithArgs listener) { 382 eventRouter.addEventListener(eventName, listener); 383 } 384 385 public void removeApplicationEventListener(String eventName, RunnableWithArgs listener) { 386 eventRouter.removeEventListener(eventName, listener); 387 } 388 389 public boolean isEventPublishingEnabled() { 390 return eventRouter.isEnabled(); 391 } 392 393 public void setEventPublishingEnabled(boolean enabled) { 394 eventRouter.setEnabled(enabled); 395 } 396 397 public Object createApplicationContainer() { 398 return null; 399 } 400 401 public void addShutdownHandler(ShutdownHandler handler) { 402 if (handler != null && !shutdownHandlers.contains(handler)) shutdownHandlers.add(handler); 403 } 404 405 public void removeShutdownHandler(ShutdownHandler handler) { 406 if (handler != null) shutdownHandlers.remove(handler); 407 } 408 409 public ApplicationPhase getPhase() { 410 synchronized (lock) { 411 return this.phase; 412 } 413 } 414 415 protected void setPhase(ApplicationPhase phase) { 416 synchronized (lock) { 417 this.phase = phase; 418 } 419 } 420 421 // ----------------------- 422 423 public boolean isUIThread() { 424 return UIThreadManager.getInstance().isUIThread(); 425 } 426 427 // TODO @deprecated - remove before 1.0 428 public void execAsync(Runnable runnable) { 429 execInsideUIAsync(runnable); 430 } 431 432 // TODO @deprecated - remove before 1.0 433 public void execSync(Runnable runnable) { 434 execInsideUIAsync(runnable); 435 } 436 437 // TODO @deprecated - remove before 1.0 438 public void execOutside(Runnable runnable) { 439 execOutsideUI(runnable); 440 } 441 442 public void execInsideUIAsync(Runnable runnable) { 443 UIThreadManager.getInstance().executeAsync(runnable); 444 } 445 446 public void execInsideUISync(Runnable runnable) { 447 UIThreadManager.getInstance().executeSync(runnable); 448 } 449 450 public void execOutsideUI(Runnable runnable) { 451 UIThreadManager.getInstance().executeOutside(runnable); 452 } 453 454 public Future execFuture(ExecutorService executorService, Closure closure) { 455 return UIThreadManager.getInstance().executeFuture(executorService, closure); 456 } 457 458 public Future execFuture(Closure closure) { 459 return UIThreadManager.getInstance().executeFuture(closure); 460 } 461 462 public Future execFuture(ExecutorService executorService, Callable callable) { 463 return UIThreadManager.getInstance().executeFuture(executorService, callable); 464 } 465 466 public Future execFuture(Callable callable) { 467 return UIThreadManager.getInstance().executeFuture(callable); 468 } 469 470 public Object newInstance(Class clazz, String type) { 471 return GriffonApplicationHelper.newInstance(this, clazz, type); 472 } 473 474 public MVCGroup buildMVCGroup(String mvcType) { 475 return getMvcGroupManager().buildMVCGroup(mvcType, null, Collections.<String, Object>emptyMap()); 476 } 477 478 public MVCGroup buildMVCGroup(String mvcType, String mvcName) { 479 return getMvcGroupManager().buildMVCGroup(mvcType, mvcName, Collections.<String, Object>emptyMap()); 480 } 481 482 public MVCGroup buildMVCGroup(Map<String, Object> args, String mvcType) { 483 return getMvcGroupManager().buildMVCGroup(mvcType, null, args); 484 } 485 486 public MVCGroup buildMVCGroup(String mvcType, Map<String, Object> args) { 487 return getMvcGroupManager().buildMVCGroup(mvcType, null, args); 488 } 489 490 public MVCGroup buildMVCGroup(Map<String, Object> args, String mvcType, String mvcName) { 491 return getMvcGroupManager().buildMVCGroup(mvcType, mvcName, args); 492 } 493 494 public MVCGroup buildMVCGroup(String mvcType, String mvcName, Map<String, Object> args) { 495 return getMvcGroupManager().buildMVCGroup(mvcType, mvcName, args); 496 } 497 498 public List<? extends GriffonMvcArtifact> createMVCGroup(String mvcType) { 499 return getMvcGroupManager().createMVCGroup(mvcType, null, Collections.<String, Object>emptyMap()); 500 } 501 502 public List<? extends GriffonMvcArtifact> createMVCGroup(Map<String, Object> args, String mvcType) { 503 return getMvcGroupManager().createMVCGroup(mvcType, null, args); 504 } 505 506 public List<? extends GriffonMvcArtifact> createMVCGroup(String mvcType, Map<String, Object> args) { 507 return getMvcGroupManager().createMVCGroup(mvcType, null, args); 508 } 509 510 public List<? extends GriffonMvcArtifact> createMVCGroup(String mvcType, String mvcName) { 511 return getMvcGroupManager().createMVCGroup(mvcType, mvcName, Collections.<String, Object>emptyMap()); 512 } 513 514 public List<? extends GriffonMvcArtifact> createMVCGroup(Map<String, Object> args, String mvcType, String mvcName) { 515 return getMvcGroupManager().createMVCGroup(mvcType, mvcName, args); 516 } 517 518 public List<? extends GriffonMvcArtifact> createMVCGroup(String mvcType, String mvcName, Map<String, Object> args) { 519 return getMvcGroupManager().createMVCGroup(mvcType, mvcName, args); 520 } 521 522 public void destroyMVCGroup(String mvcName) { 523 getMvcGroupManager().destroyMVCGroup(mvcName); 524 } 525 526 public void withMVCGroup(String mvcType, Closure handler) { 527 getMvcGroupManager().withMVCGroup(mvcType, null, Collections.<String, Object>emptyMap(), handler); 528 } 529 530 public void withMVCGroup(String mvcType, String mvcName, Closure handler) { 531 getMvcGroupManager().withMVCGroup(mvcType, mvcName, Collections.<String, Object>emptyMap(), handler); 532 } 533 534 public void withMVCGroup(String mvcType, Map<String, Object> args, Closure handler) { 535 getMvcGroupManager().withMVCGroup(mvcType, null, args, handler); 536 } 537 538 public void withMVCGroup(Map<String, Object> args, String mvcType, Closure handler) { 539 getMvcGroupManager().withMVCGroup(mvcType, null, args, handler); 540 } 541 542 public void withMVCGroup(String mvcType, String mvcName, Map<String, Object> args, Closure handler) { 543 getMvcGroupManager().withMVCGroup(mvcType, mvcName, args, handler); 544 } 545 546 public void withMVCGroup(Map<String, Object> args, String mvcType, String mvcName, Closure handler) { 547 getMvcGroupManager().withMVCGroup(mvcType, mvcName, args, handler); 548 } 549 550 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(String mvcType, MVCClosure<M, V, C> handler) { 551 getMvcGroupManager().withMVCGroup(mvcType, null, Collections.<String, Object>emptyMap(), handler); 552 } 553 554 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(String mvcType, String mvcName, MVCClosure<M, V, C> handler) { 555 getMvcGroupManager().withMVCGroup(mvcType, mvcName, Collections.<String, Object>emptyMap(), handler); 556 } 557 558 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(String mvcType, Map<String, Object> args, MVCClosure<M, V, C> handler) { 559 getMvcGroupManager().withMVCGroup(mvcType, null, args, handler); 560 } 561 562 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(Map<String, Object> args, String mvcType, MVCClosure<M, V, C> handler) { 563 getMvcGroupManager().withMVCGroup(mvcType, null, args, handler); 564 } 565 566 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(String mvcType, String mvcName, Map<String, Object> args, MVCClosure<M, V, C> handler) { 567 getMvcGroupManager().withMVCGroup(mvcType, mvcName, args, handler); 568 } 569 570 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(Map<String, Object> args, String mvcType, String mvcName, MVCClosure<M, V, C> handler) { 571 getMvcGroupManager().withMVCGroup(mvcType, mvcName, args, handler); 572 } 573 574 private Class loadClass(String className) { 575 try { 576 return getClass().getClassLoader().loadClass(className); 577 } catch (ClassNotFoundException e) { 578 // ignored 579 } 580 return null; 581 } 582 583 public InputStream getResourceAsStream(String name) { 584 return resourceLocator.getResourceAsStream(name); 585 } 586 587 public URL getResourceAsURL(String name) { 588 return resourceLocator.getResourceAsURL(name); 589 } 590 591 public List<URL> getResources(String name) { 592 return resourceLocator.getResources(name); 593 } 594 }`