001 /* 
002  * Copyright 2008-2017 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(@Nonnull final 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.getTypeClass()); 
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 }
    
    |