AbstractArtifactManager.java
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 (AinjectorProvider.get().getInstance(clazz);
126                 }
127             });
128         }
129 
130         return (AinjectorProvider.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(namenull;
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(clazznull;
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 != nullreturn 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 != nullreturn 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 }