001 /*
002 * Copyright 2008-2014 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 package org.codehaus.griffon.runtime.core.artifact;
017
018 import griffon.core.GriffonApplication;
019 import griffon.core.artifact.ArtifactHandler;
020 import griffon.core.artifact.ArtifactManager;
021 import griffon.core.artifact.GriffonArtifact;
022 import griffon.core.artifact.GriffonClass;
023 import griffon.core.injection.Binding;
024 import griffon.core.injection.Injector;
025 import griffon.exceptions.ArtifactHandlerNotFoundException;
026 import griffon.exceptions.ArtifactNotFoundException;
027 import org.slf4j.Logger;
028 import org.slf4j.LoggerFactory;
029
030 import javax.annotation.Nonnull;
031 import javax.annotation.Nullable;
032 import java.util.*;
033 import java.util.concurrent.ConcurrentHashMap;
034
035 import static griffon.util.GriffonNameUtils.requireNonBlank;
036 import static java.util.Arrays.asList;
037 import static java.util.Objects.requireNonNull;
038
039 /**
040 * Base implementation of the {@code ArtifactManager} interface.
041 *
042 * @author Andres Almiray
043 * @since 2.0.0
044 */
045 @SuppressWarnings("rawtypes")
046 public abstract class AbstractArtifactManager implements ArtifactManager {
047 protected static final String ERROR_ARTIFACT_HANDLER_NULL = "Argument 'artifactHandler' must not be null";
048 private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
049 private static final String ERROR_TYPE_BLANK = "Argument 'type' must not be blank";
050 private static final String ERROR_CLASS_NULL = "Argument 'clazz' must not be null";
051 private static final String ERROR_ARTIFACT_NULL = "Argument 'artifact' must not be null";
052 private static final String ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK = "Argument 'fqClassName' must not be blank";
053 private final Map<String, Class<? extends GriffonArtifact>[]> artifacts = new ConcurrentHashMap<>();
054 private final Map<String, ArtifactHandler> artifactHandlers = new ConcurrentHashMap<>();
055 private final Object lock = new Object[0];
056 private Injector<?> artifactInjector;
057
058 private static final Logger LOG = LoggerFactory.getLogger(AbstractArtifactManager.class);
059
060 @Nonnull
061 protected Map<String, ArtifactHandler> getArtifactHandlers() {
062 return artifactHandlers;
063 }
064
065 @SuppressWarnings("unchecked")
066 public final void loadArtifactMetadata(@Nonnull Injector<?> injector) {
067 requireNonNull(injector, "Argument 'injector' must not be null");
068 Map<String, List<Class<? extends GriffonArtifact>>> loadedArtifacts = doLoadArtifactMetadata();
069
070 Collection<Binding<?>> bindings = new ArrayList<>();
071 synchronized (lock) {
072 for (Map.Entry<String, List<Class<? extends GriffonArtifact>>> artifactsEntry : loadedArtifacts.entrySet()) {
073 String type = artifactsEntry.getKey();
074 ArtifactHandler handler = artifactHandlers.get(type);
075 if (handler == null) {
076 throw new ArtifactHandlerNotFoundException(type);
077 }
078 List<Class<? extends GriffonArtifact>> list = artifactsEntry.getValue();
079 artifacts.put(type, list.toArray(new Class[list.size()]));
080 //noinspection unchecked
081 bindings.addAll(handler.initialize(artifacts.get(type)));
082 }
083 }
084
085 if (LOG.isTraceEnabled()) {
086 for (Binding<?> binding : bindings) {
087 LOG.trace(binding.toString());
088 }
089 }
090
091 artifactInjector = injector.createNestedInjector("artifactInjector", bindings);
092 }
093
094 @Override
095 @Nonnull
096 @SuppressWarnings("unchecked")
097 public <A extends GriffonArtifact> A newInstance(@Nonnull GriffonClass griffonClass) {
098 try {
099 requireNonNull(griffonClass, "Argument 'griffonClass' must not be null");
100 } catch (RuntimeException re) {
101 throw new ArtifactNotFoundException(re);
102 }
103
104 return newInstance((Class<A>) griffonClass.getClazz());
105 }
106
107 @Override
108 @Nonnull
109 @SuppressWarnings("unchecked")
110 public <A extends GriffonArtifact> A newInstance(@Nonnull Class<A> clazz) {
111 if (findGriffonClass(clazz) == null) {
112 throw new ArtifactNotFoundException(clazz);
113 }
114
115 return artifactInjector.getInstance(clazz);
116 }
117
118 @Nonnull
119 protected abstract Map<String, List<Class<? extends GriffonArtifact>>> doLoadArtifactMetadata();
120
121 public void registerArtifactHandler(@Nonnull ArtifactHandler artifactHandler) {
122 requireNonNull(artifactHandler, ERROR_ARTIFACT_HANDLER_NULL);
123 LOG.debug("Registering artifact handler for type '{}': {}", artifactHandler.getType(), artifactHandler);
124 synchronized (lock) {
125 artifactHandlers.put(artifactHandler.getType(), artifactHandler);
126 }
127 }
128
129 public void unregisterArtifactHandler(@Nonnull ArtifactHandler artifactHandler) {
130 requireNonNull(artifactHandler, ERROR_ARTIFACT_HANDLER_NULL);
131 LOG.debug("Removing artifact handler for type '{}': {}", artifactHandler.getType(), artifactHandler);
132 synchronized (lock) {
133 artifactHandlers.remove(artifactHandler.getType());
134 }
135 }
136
137 protected boolean isArtifactTypeSupported(@Nonnull String type) {
138 requireNonBlank(type, ERROR_TYPE_BLANK);
139 return artifactHandlers.get(type) != null;
140 }
141
142 @Nullable
143 public GriffonClass findGriffonClass(@Nonnull String name, @Nonnull String type) {
144 requireNonBlank(name, ERROR_NAME_BLANK);
145 requireNonBlank(type, ERROR_TYPE_BLANK);
146 LOG.debug("Searching for griffonClass of {}:{}", type, name);
147 synchronized (lock) {
148 ArtifactHandler handler = artifactHandlers.get(type);
149 return handler != null ? handler.findClassFor(name) : null;
150 }
151 }
152
153 @Nullable
154 @SuppressWarnings({"unchecked", "rawtypes"})
155 public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz, @Nonnull String type) {
156 requireNonNull(clazz, ERROR_CLASS_NULL);
157 requireNonBlank(type, ERROR_TYPE_BLANK);
158 LOG.debug("Searching for griffonClass of {}:{}", type, clazz.getName());
159 synchronized (lock) {
160 ArtifactHandler handler = artifactHandlers.get(type);
161 return handler != null ? handler.getClassFor(clazz) : null;
162 }
163 }
164
165 @Nullable
166 public <A extends GriffonArtifact> GriffonClass findGriffonClass(@Nonnull A artifact) {
167 requireNonNull(artifact, ERROR_ARTIFACT_NULL);
168 LOG.debug("Searching for griffonClass of {}", artifact);
169 synchronized (lock) {
170 return findGriffonClass(artifact.getClass());
171 }
172 }
173
174 @Nullable
175 @SuppressWarnings({"unchecked", "rawtypes"})
176 public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz) {
177 requireNonNull(clazz, ERROR_CLASS_NULL);
178 LOG.debug("Searching for griffonClass of {}", clazz.getName());
179 synchronized (lock) {
180 for (ArtifactHandler handler : artifactHandlers.values()) {
181 GriffonClass griffonClass = handler.getClassFor(clazz);
182 if (griffonClass != null) return griffonClass;
183 }
184 }
185 return null;
186 }
187
188 @Nullable
189 public GriffonClass findGriffonClass(@Nonnull String fqClassName) {
190 requireNonBlank(fqClassName, ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK);
191 LOG.debug("Searching for griffonClass of {}", fqClassName);
192 synchronized (lock) {
193 for (ArtifactHandler handler : artifactHandlers.values()) {
194 GriffonClass griffonClass = handler.getClassFor(fqClassName);
195 if (griffonClass != null) return griffonClass;
196 }
197 }
198 return null;
199 }
200
201 @Nonnull
202 public List<GriffonClass> getClassesOfType(@Nonnull String type) {
203 requireNonBlank(type, ERROR_TYPE_BLANK);
204 synchronized (lock) {
205 if (artifacts.containsKey(type)) {
206 return asList(artifactHandlers.get(type).getClasses());
207 }
208 }
209 return EMPTY_GRIFFON_CLASS_LIST;
210 }
211
212 @Nonnull
213 public List<GriffonClass> getAllClasses() {
214 List<GriffonClass> all = new ArrayList<>();
215 synchronized (lock) {
216 for (ArtifactHandler handler : artifactHandlers.values()) {
217 all.addAll(asList(handler.getClasses()));
218 }
219 }
220 return Collections.unmodifiableList(all);
221 }
222
223 @Override
224 public boolean canShutdown(@Nonnull GriffonApplication application) {
225 return true;
226 }
227
228 @Override
229 public void onShutdown(@Nonnull GriffonApplication application) {
230 artifactInjector.close();
231 }
232
233 protected <A extends GriffonArtifact> boolean isClassOfType(@Nonnull String type, @Nonnull Class<A> clazz) {
234 for (Class<? extends GriffonArtifact> klass : artifacts.get(type)) {
235 if (klass.getName().equals(clazz.getName())) {
236 return true;
237 }
238 }
239 return false;
240 }
241 }
|