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.artifact.ArtifactHandler;
019 import griffon.core.artifact.ArtifactManager;
020 import griffon.core.artifact.GriffonArtifact;
021 import griffon.core.artifact.GriffonClass;
022 import griffon.core.injection.Injector;
023 import griffon.exceptions.ArtifactHandlerNotFoundException;
024 import griffon.exceptions.ArtifactNotFoundException;
025 import org.slf4j.Logger;
026 import org.slf4j.LoggerFactory;
027
028 import javax.annotation.Nonnull;
029 import javax.annotation.Nullable;
030 import javax.inject.Inject;
031 import javax.inject.Provider;
032 import java.util.ArrayList;
033 import java.util.Collections;
034 import java.util.List;
035 import java.util.Map;
036 import java.util.Set;
037 import java.util.concurrent.ConcurrentHashMap;
038
039 import static griffon.util.GriffonNameUtils.requireNonBlank;
040 import static java.util.Arrays.asList;
041 import static java.util.Objects.requireNonNull;
042
043 /**
044 * Base implementation of the {@code ArtifactManager} interface.
045 *
046 * @author Andres Almiray
047 * @since 2.0.0
048 */
049 @SuppressWarnings("rawtypes")
050 public abstract class AbstractArtifactManager implements ArtifactManager {
051 protected static final String ERROR_ARTIFACT_HANDLER_NULL = "Argument 'artifactHandler' must not be null";
052 private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
053 private static final String ERROR_TYPE_BLANK = "Argument 'type' must not be blank";
054 private static final String ERROR_CLASS_NULL = "Argument 'clazz' must not be null";
055 private static final String ERROR_ARTIFACT_NULL = "Argument 'artifact' must not be null";
056 private static final String ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK = "Argument 'fqClassName' must not be blank";
057 private static final Logger LOG = LoggerFactory.getLogger(AbstractArtifactManager.class);
058 private final Map<String, Class<? extends GriffonArtifact>[]> artifacts = new ConcurrentHashMap<>();
059 private final Map<String, ArtifactHandler> artifactHandlers = new ConcurrentHashMap<>();
060 private final Object lock = new Object[0];
061
062 @Inject
063 private Provider<Injector> injectorProvider;
064
065 @Nonnull
066 protected Map<String, ArtifactHandler> getArtifactHandlers() {
067 return artifactHandlers;
068 }
069
070 @SuppressWarnings("unchecked")
071 public final void loadArtifactMetadata() {
072 Map<String, List<Class<? extends GriffonArtifact>>> loadedArtifacts = doLoadArtifactMetadata();
073
074 synchronized (lock) {
075 for (Map.Entry<String, List<Class<? extends GriffonArtifact>>> artifactsEntry : loadedArtifacts.entrySet()) {
076 String type = artifactsEntry.getKey();
077 ArtifactHandler handler = artifactHandlers.get(type);
078 if (handler == null) {
079 throw new ArtifactHandlerNotFoundException(type);
080 }
081 List<Class<? extends GriffonArtifact>> list = artifactsEntry.getValue();
082 artifacts.put(type, list.toArray(new Class[list.size()]));
083 handler.initialize(artifacts.get(type));
084 }
085 }
086 }
087
088 @Nonnull
089 @Override
090 public Set<String> getAllTypes() {
091 return Collections.unmodifiableSet(artifactHandlers.keySet());
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 (A) injectorProvider.get().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 synchronized (lock) {
169 return findGriffonClass(artifact.getClass());
170 }
171 }
172
173 @Nullable
174 @SuppressWarnings({"unchecked", "rawtypes"})
175 public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz) {
176 requireNonNull(clazz, ERROR_CLASS_NULL);
177 LOG.debug("Searching for griffonClass of {}", clazz.getName());
178 synchronized (lock) {
179 for (ArtifactHandler handler : artifactHandlers.values()) {
180 GriffonClass griffonClass = handler.getClassFor(clazz);
181 if (griffonClass != null) return griffonClass;
182 }
183 }
184 return null;
185 }
186
187 @Nullable
188 public GriffonClass findGriffonClass(@Nonnull String fqClassName) {
189 requireNonBlank(fqClassName, ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK);
190 LOG.debug("Searching for griffonClass of {}", fqClassName);
191 synchronized (lock) {
192 for (ArtifactHandler handler : artifactHandlers.values()) {
193 GriffonClass griffonClass = handler.getClassFor(fqClassName);
194 if (griffonClass != null) return griffonClass;
195 }
196 }
197 return null;
198 }
199
200 @Nonnull
201 public List<GriffonClass> getClassesOfType(@Nonnull String type) {
202 requireNonBlank(type, ERROR_TYPE_BLANK);
203 synchronized (lock) {
204 if (artifacts.containsKey(type)) {
205 return asList(artifactHandlers.get(type).getClasses());
206 }
207 }
208 return EMPTY_GRIFFON_CLASS_LIST;
209 }
210
211 @Nonnull
212 public List<GriffonClass> getAllClasses() {
213 List<GriffonClass> all = new ArrayList<>();
214 synchronized (lock) {
215 for (ArtifactHandler handler : artifactHandlers.values()) {
216 all.addAll(asList(handler.getClasses()));
217 }
218 }
219 return Collections.unmodifiableList(all);
220 }
221
222 protected <A extends GriffonArtifact> boolean isClassOfType(@Nonnull String type, @Nonnull Class<A> clazz) {
223 for (Class<? extends GriffonArtifact> klass : artifacts.get(type)) {
224 if (klass.getName().equals(clazz.getName())) {
225 return true;
226 }
227 }
228 return false;
229 }
230 }
|