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