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