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