AbstractArtifactManager.java
001 /*
002  * Copyright 2008-2014 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.*;
033 import java.util.concurrent.ConcurrentHashMap;
034 
035 import static griffon.util.GriffonNameUtils.requireNonBlank;
036 import static java.util.Arrays.asList;
037 import static java.util.Objects.requireNonNull;
038 
039 /**
040  * Base implementation of the {@code ArtifactManager} interface.
041  *
042  @author Andres Almiray
043  @since 2.0.0
044  */
045 @SuppressWarnings("rawtypes")
046 public abstract class AbstractArtifactManager implements ArtifactManager {
047     protected static final String ERROR_ARTIFACT_HANDLER_NULL = "Argument 'artifactHandler' must not be null";
048     private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
049     private static final String ERROR_TYPE_BLANK = "Argument 'type' must not be blank";
050     private static final String ERROR_CLASS_NULL = "Argument 'clazz' must not be null";
051     private static final String ERROR_ARTIFACT_NULL = "Argument 'artifact' must not be null";
052     private static final String ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK = "Argument 'fqClassName' must not be blank";
053     private final Map<String, Class<? extends GriffonArtifact>[]> artifacts = new ConcurrentHashMap<>();
054     private final Map<String, ArtifactHandler> artifactHandlers = new ConcurrentHashMap<>();
055     private final Object lock = new Object[0];
056     private Injector<?> artifactInjector;
057 
058     private static final Logger LOG = LoggerFactory.getLogger(AbstractArtifactManager.class);
059 
060     @Nonnull
061     protected Map<String, ArtifactHandler> getArtifactHandlers() {
062         return artifactHandlers;
063     }
064 
065     @SuppressWarnings("unchecked")
066     public final void loadArtifactMetadata(@Nonnull Injector<?> injector) {
067         requireNonNull(injector, "Argument 'injector' must not be null");
068         Map<String, List<Class<? extends GriffonArtifact>>> loadedArtifacts = doLoadArtifactMetadata();
069 
070         Collection<Binding<?>> bindings = new ArrayList<>();
071         synchronized (lock) {
072             for (Map.Entry<String, List<Class<? extends GriffonArtifact>>> artifactsEntry : loadedArtifacts.entrySet()) {
073                 String type = artifactsEntry.getKey();
074                 ArtifactHandler handler = artifactHandlers.get(type);
075                 if (handler == null) {
076                     throw new ArtifactHandlerNotFoundException(type);
077                 }
078                 List<Class<? extends GriffonArtifact>> list = artifactsEntry.getValue();
079                 artifacts.put(type, list.toArray(new Class[list.size()]));
080                 //noinspection unchecked
081                 bindings.addAll(handler.initialize(artifacts.get(type)));
082             }
083         }
084 
085         if (LOG.isTraceEnabled()) {
086             for (Binding<?> binding : bindings) {
087                 LOG.trace(binding.toString());
088             }
089         }
090 
091         artifactInjector = injector.createNestedInjector("artifactInjector", bindings);
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 artifactInjector.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(namenull;
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(clazznull;
162         }
163     }
164 
165     @Nullable
166     public <A extends GriffonArtifact> GriffonClass findGriffonClass(@Nonnull A artifact) {
167         requireNonNull(artifact, ERROR_ARTIFACT_NULL);
168         LOG.debug("Searching for griffonClass of {}", artifact);
169         synchronized (lock) {
170             return findGriffonClass(artifact.getClass());
171         }
172     }
173 
174     @Nullable
175     @SuppressWarnings({"unchecked""rawtypes"})
176     public GriffonClass findGriffonClass(@Nonnull Class<? extends GriffonArtifact> clazz) {
177         requireNonNull(clazz, ERROR_CLASS_NULL);
178         LOG.debug("Searching for griffonClass of {}", clazz.getName());
179         synchronized (lock) {
180             for (ArtifactHandler handler : artifactHandlers.values()) {
181                 GriffonClass griffonClass = handler.getClassFor(clazz);
182                 if (griffonClass != nullreturn griffonClass;
183             }
184         }
185         return null;
186     }
187 
188     @Nullable
189     public GriffonClass findGriffonClass(@Nonnull String fqClassName) {
190         requireNonBlank(fqClassName, ERROR_FULLY_QUALIFIED_CLASSNAME_BLANK);
191         LOG.debug("Searching for griffonClass of {}", fqClassName);
192         synchronized (lock) {
193             for (ArtifactHandler handler : artifactHandlers.values()) {
194                 GriffonClass griffonClass = handler.getClassFor(fqClassName);
195                 if (griffonClass != nullreturn griffonClass;
196             }
197         }
198         return null;
199     }
200 
201     @Nonnull
202     public List<GriffonClass> getClassesOfType(@Nonnull String type) {
203         requireNonBlank(type, ERROR_TYPE_BLANK);
204         synchronized (lock) {
205             if (artifacts.containsKey(type)) {
206                 return asList(artifactHandlers.get(type).getClasses());
207             }
208         }
209         return EMPTY_GRIFFON_CLASS_LIST;
210     }
211 
212     @Nonnull
213     public List<GriffonClass> getAllClasses() {
214         List<GriffonClass> all = new ArrayList<>();
215         synchronized (lock) {
216             for (ArtifactHandler handler : artifactHandlers.values()) {
217                 all.addAll(asList(handler.getClasses()));
218             }
219         }
220         return Collections.unmodifiableList(all);
221     }
222 
223     @Override
224     public boolean canShutdown(@Nonnull GriffonApplication application) {
225         return true;
226     }
227 
228     @Override
229     public void onShutdown(@Nonnull GriffonApplication application) {
230         artifactInjector.close();
231     }
232 
233     protected <A extends GriffonArtifact> boolean isClassOfType(@Nonnull String type, @Nonnull Class<A> clazz) {
234         for (Class<? extends GriffonArtifact> klass : artifacts.get(type)) {
235             if (klass.getName().equals(clazz.getName())) {
236                 return true;
237             }
238         }
239         return false;
240     }
241 }