001 /*
002 * Copyright 2009-2013 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.exceptions.NewInstanceCreationException;
021 import griffon.util.ApplicationHolder;
022 import groovy.lang.MetaClass;
023 import groovy.lang.MetaProperty;
024 import org.codehaus.groovy.runtime.InvokerHelper;
025 import org.slf4j.Logger;
026 import org.slf4j.LoggerFactory;
027
028 import java.lang.reflect.InvocationTargetException;
029 import java.util.Collections;
030 import java.util.Map;
031 import java.util.concurrent.ConcurrentHashMap;
032
033 import static griffon.util.ConfigUtils.getConfigValueAsBoolean;
034 import static griffon.util.GriffonExceptionHandler.sanitize;
035 import static java.util.Arrays.asList;
036
037 /**
038 * Handler for 'Service' artifacts.
039 *
040 * @author Andres Almiray
041 * @since 0.9.1
042 */
043 public class ServiceArtifactHandler extends ArtifactHandlerAdapter {
044 private static final Logger LOG = LoggerFactory.getLogger(ServiceArtifactHandler.class);
045 private final DefaultServiceManager serviceManager;
046
047 private class DefaultServiceManager extends AbstractServiceManager {
048 private final Map<String, GriffonService> serviceInstances = new ConcurrentHashMap<String, GriffonService>();
049
050 public DefaultServiceManager(GriffonApplication app) {
051 super(app);
052 }
053
054 public Map<String, GriffonService> getServices() {
055 return Collections.unmodifiableMap(serviceInstances);
056 }
057
058 protected GriffonService doFindService(String name) {
059 return serviceInstances.get(name);
060 }
061
062 protected GriffonService doInstantiateService(String name) {
063 return doInstantiateService0(name, true);
064 }
065
066 private GriffonService doInstantiateService0(String name, boolean triggerEvent) {
067 GriffonService serviceInstance = null;
068 GriffonClass griffonClass = findClassFor(name);
069 if (griffonClass != null) {
070 serviceInstance = instantiateService(griffonClass);
071 serviceInstances.put(name, serviceInstance);
072 getApp().addApplicationEventListener(serviceInstance);
073 if (triggerEvent) {
074 getApp().event(GriffonApplication.Event.NEW_INSTANCE.getName(),
075 asList(griffonClass.getClazz(), GriffonServiceClass.TYPE, serviceInstance));
076 }
077 }
078 return serviceInstance;
079 }
080
081 private GriffonService instantiateService(GriffonClass griffonClass) {
082 try {
083 GriffonService serviceInstance = (GriffonService) griffonClass.getClazz().newInstance();
084 InvokerHelper.setProperty(serviceInstance, "app", getApp());
085 return serviceInstance;
086 } catch (Exception e) {
087 Throwable targetException = null;
088 if (e instanceof InvocationTargetException) {
089 targetException = ((InvocationTargetException) e).getTargetException();
090 } else {
091 targetException = e;
092 }
093 throw new NewInstanceCreationException("Could not create a new instance of class " + griffonClass.getClazz().getName(), sanitize(targetException));
094 }
095 }
096 }
097
098 public ServiceArtifactHandler(GriffonApplication app) {
099 super(app, GriffonServiceClass.TYPE, GriffonServiceClass.TRAILING);
100 serviceManager = new DefaultServiceManager(app);
101 if (LOG.isDebugEnabled()) {
102 LOG.debug("Registering " + serviceManager + " as ServiceManager.");
103 }
104 InvokerHelper.setProperty(app, "serviceManager", serviceManager);
105 }
106
107 protected GriffonClass newGriffonClassInstance(Class clazz) {
108 return new DefaultGriffonServiceClass(getApp(), clazz);
109 }
110
111 public void initialize(ArtifactInfo[] artifacts) {
112 super.initialize(artifacts);
113 if (isBasicInjectionDisabled()) return;
114 getApp().addApplicationEventListener(this);
115 if (isEagerInstantiationEnabled()) {
116 if (LOG.isDebugEnabled()) {
117 LOG.debug("Instantiating service instances eagerly");
118 }
119 for (ArtifactInfo artifactInfo : artifacts) {
120 GriffonClass griffonClass = getClassFor(artifactInfo.getClazz());
121 serviceManager.doInstantiateService0(griffonClass.getPropertyName(), false);
122 }
123 for (ArtifactInfo artifactInfo : artifacts) {
124 GriffonClass griffonClass = getClassFor(artifactInfo.getClazz());
125 GriffonService serviceInstance = serviceManager.findService(griffonClass.getPropertyName());
126 getApp().event(GriffonApplication.Event.NEW_INSTANCE.getName(),
127 asList(griffonClass.getClazz(), GriffonServiceClass.TYPE, serviceInstance));
128 }
129 }
130 }
131
132 /**
133 * Application event listener.<p>
134 * Lazily injects services instances if {@code app.config.griffon.basic_injection.disable}
135 * is not set to true
136 */
137 public void onNewInstance(Class klass, String t, Object instance) {
138 if (isBasicInjectionDisabled()) return;
139 MetaClass metaClass = InvokerHelper.getMetaClass(instance);
140 for (MetaProperty property : metaClass.getProperties()) {
141 String propertyName = property.getName();
142 if (!propertyName.endsWith(getTrailing())) continue;
143 GriffonService serviceInstance = serviceManager.findService(propertyName);
144
145 if (serviceInstance != null) {
146 if (LOG.isDebugEnabled()) {
147 LOG.debug("Injecting service " + serviceInstance + " on " + instance + " using property '" + propertyName + "'");
148 }
149 InvokerHelper.setProperty(instance, propertyName, serviceInstance);
150 }
151 }
152 }
153
154 public static boolean isBasicInjectionDisabled() {
155 return getConfigValueAsBoolean(ApplicationHolder.getApplication().getConfig(), "griffon.services.basic.disabled", false);
156 }
157
158 private boolean isEagerInstantiationEnabled() {
159 return getConfigValueAsBoolean(getApp().getConfig(), "griffon.services.eager.instantiation", false);
160 }
161 }
|