001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.codehaus.griffon.runtime.core.artifact;
019
020 import griffon.core.artifact.ArtifactHandler;
021 import griffon.core.artifact.ArtifactManager;
022 import griffon.core.artifact.GriffonArtifact;
023 import griffon.core.artifact.GriffonClass;
024 import griffon.core.artifact.GriffonView;
025 import griffon.core.injection.Injector;
026 import griffon.core.threading.UIThreadManager;
027 import griffon.exceptions.ArtifactHandlerNotFoundException;
028 import griffon.exceptions.ArtifactNotFoundException;
029 import org.slf4j.Logger;
030 import org.slf4j.LoggerFactory;
031
032 import javax.annotation.Nonnull;
033 import javax.annotation.Nullable;
034 import javax.inject.Inject;
035 import javax.inject.Provider;
036 import java.util.ArrayList;
037 import java.util.Collections;
038 import java.util.List;
039 import java.util.Map;
040 import java.util.Set;
041 import java.util.concurrent.Callable;
042 import java.util.concurrent.ConcurrentHashMap;
043
044 import static griffon.util.GriffonNameUtils.requireNonBlank;
045 import static java.util.Arrays.asList;
046 import static java.util.Objects.requireNonNull;
047
048 /**
049 * Base implementation of the {@code ArtifactManager} interface.
050 *
051 * @author Andres Almiray
052 * @since 2.0.0
053 */
054 @SuppressWarnings("rawtypes")
055 public abstract class AbstractArtifactManager implements ArtifactManager {
056 protected static final String ERROR_ARTIFACT_HANDLER_NULL = "Argument 'artifactHandler' must not be null";
057 private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
058 private static final String ERROR_TYPE_BLANK = "Argument 'type' must not be blank";
059 private static final String ERROR_CLASS_NULL = "Argument 'clazz' must not be null";
060 private static final String ERROR_ARTIFACT_NULL = "Argument 'artifact' must not be null";
061 private static final String ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK = "Argument 'fqClassName' must not be blank";
062 private static final Logger LOG = LoggerFactory.getLogger(AbstractArtifactManager.class);
063 private final Map<String, Class<? extends GriffonArtifact>[]> artifacts = new ConcurrentHashMap<>();
064 private final Map<String, ArtifactHandler> artifactHandlers = new ConcurrentHashMap<>();
065 private final Object lock = new Object[0];
066
067 @Inject
068 private Provider<Injector> injectorProvider;
069
070 @Inject
071 private UIThreadManager uiThreadManager;
072
073 @Nonnull
074 protected Map<String, ArtifactHandler> getArtifactHandlers() {
075 return artifactHandlers;
076 }
077
078 @SuppressWarnings("unchecked")
079 public final void loadArtifactMetadata() {
080 Map<String, List<Class<? extends GriffonArtifact>>> loadedArtifacts = doLoadArtifactMetadata();
081
082 synchronized (lock) {
083 for (Map.Entry<String, List<Class<? extends GriffonArtifact>>> artifactsEntry : loadedArtifacts.entrySet()) {
084 String type = artifactsEntry.getKey();
085 ArtifactHandler handler = artifactHandlers.get(type);
086 if (handler == null) {
087 throw new ArtifactHandlerNotFoundException(type);
088 }
089 List<Class<? extends GriffonArtifact>> list = artifactsEntry.getValue();
090 artifacts.put(type, list.toArray(new Class[list.size()]));
091 handler.initialize(artifacts.get(type));
092 }
093 }
094 }
095
096 @Nonnull
097 @Override
098 public Set<String> getAllTypes() {
099 return Collections.unmodifiableSet(artifactHandlers.keySet());
100 }
101
102 @Override
103 @Nonnull
104 @SuppressWarnings("unchecked")
105 public <A extends GriffonArtifact> A newInstance(@Nonnull GriffonClass griffonClass) {
106 try {
107 requireNonNull(griffonClass, "Argument 'griffonClass' must not be null");
108 } catch (RuntimeException re) {
109 throw new ArtifactNotFoundException(re);
110 }
111
112 return newInstance((Class<A>) griffonClass.getClazz());
113 }
114
115 @Override
116 @Nonnull
117 @SuppressWarnings("unchecked")
118 public <A extends GriffonArtifact> A newInstance(@Nonnull final Class<A> clazz) {
119 if (findGriffonClass(clazz) == null) {
120 throw new ArtifactNotFoundException(clazz);
121 }
122
123 if (GriffonView.class.isAssignableFrom(clazz)) {
124 return uiThreadManager.runInsideUISync(new Callable<A>() {
125 @Override
126 public A call() throws Exception {
127 return (A) injectorProvider.get().getInstance(clazz);
128 }
129 });
130 }
131
132 return (A) injectorProvider.get().getInstance(clazz);
133 }
134
135 @Nonnull
136 protected abstract Map<String, List<Class<? extends GriffonArtifact>>> doLoadArtifactMetadata();
137
138 public void registerArtifactHandler(@Nonnull ArtifactHandler artifactHandler) {
139 requireNonNull(artifactHandler, ERROR_ARTIFACT_HANDLER_NULL);
140 LOG.debug("Registering artifact handler for type '{}': {}", artifactHandler.getType(), artifactHandler);
141 synchronized (lock) {
142 artifactHandlers.put(artifactHandler.getType(), artifactHandler);
143 }
144 }
145
146 public void unregisterArtifactHandler(@Nonnull ArtifactHandler artifactHandler) {
147 requireNonNull(artifactHandler, ERROR_ARTIFACT_HANDLER_NULL);
148 LOG.debug("Removing artifact handler for type '{}': {}", artifactHandler.getType(), artifactHandler);
149 synchronized (lock) {
150 artifactHandlers.remove(artifactHandler.getType());
151 }
152 }
153
154 protected boolean isArtifactTypeSupported(@Nonnull String type) {
155 requireNonBlank(type, ERROR_TYPE_BLANK);
156 return artifactHandlers.get(type) != null;
157 }
158
159 @Nullable
160 public GriffonClass findGriffonClass(@Nonnull String name, @Nonnull String type) {
161 requireNonBlank(name, ERROR_NAME_BLANK);
162 requireNonBlank(type, ERROR_TYPE_BLANK);
163 LOG.debug("Searching for griffonClass of {}:{}", type, name);
164 synchronized (lock) {
165 ArtifactHandler handler = artifactHandlers.get(type);
166 return handler != null ? handler.findClassFor(name) : null;
167 }
168 }
169
170 @Nullable
171 @SuppressWarnings({"unchecked", "rawtypes"})
172 public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz, @Nonnull String type) {
173 requireNonNull(clazz, ERROR_CLASS_NULL);
174 requireNonBlank(type, ERROR_TYPE_BLANK);
175 LOG.debug("Searching for griffonClass of {}:{}", type, clazz.getName());
176 synchronized (lock) {
177 ArtifactHandler handler = artifactHandlers.get(type);
178 return handler != null ? handler.getClassFor(clazz) : null;
179 }
180 }
181
182 @Nullable
183 public <A extends GriffonArtifact> GriffonClass findGriffonClass(@Nonnull A artifact) {
184 requireNonNull(artifact, ERROR_ARTIFACT_NULL);
185 synchronized (lock) {
186 return findGriffonClass(artifact.getTypeClass());
187 }
188 }
189
190 @Nullable
191 @SuppressWarnings({"unchecked", "rawtypes"})
192 public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz) {
193 requireNonNull(clazz, ERROR_CLASS_NULL);
194 LOG.debug("Searching for griffonClass of {}", clazz.getName());
195 synchronized (lock) {
196 for (ArtifactHandler handler : artifactHandlers.values()) {
197 GriffonClass griffonClass = handler.getClassFor(clazz);
198 if (griffonClass != null) return griffonClass;
199 }
200 }
201 return null;
202 }
203
204 @Nullable
205 public GriffonClass findGriffonClass(@Nonnull String fqClassName) {
206 requireNonBlank(fqClassName, ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK);
207 LOG.debug("Searching for griffonClass of {}", fqClassName);
208 synchronized (lock) {
209 for (ArtifactHandler handler : artifactHandlers.values()) {
210 GriffonClass griffonClass = handler.getClassFor(fqClassName);
211 if (griffonClass != null) return griffonClass;
212 }
213 }
214 return null;
215 }
216
217 @Nonnull
218 public List<GriffonClass> getClassesOfType(@Nonnull String type) {
219 requireNonBlank(type, ERROR_TYPE_BLANK);
220 synchronized (lock) {
221 if (artifacts.containsKey(type)) {
222 return asList(artifactHandlers.get(type).getClasses());
223 }
224 }
225 return EMPTY_GRIFFON_CLASS_LIST;
226 }
227
228 @Nonnull
229 public List<GriffonClass> getAllClasses() {
230 List<GriffonClass> all = new ArrayList<>();
231 synchronized (lock) {
232 for (ArtifactHandler handler : artifactHandlers.values()) {
233 all.addAll(asList(handler.getClasses()));
234 }
235 }
236 return Collections.unmodifiableList(all);
237 }
238
239 protected <A extends GriffonArtifact> boolean isClassOfType(@Nonnull String type, @Nonnull Class<A> clazz) {
240 for (Class<? extends GriffonArtifact> klass : artifacts.get(type)) {
241 if (klass.getName().equals(clazz.getName())) {
242 return true;
243 }
244 }
245 return false;
246 }
247 }
|