AbstractMVCGroupManager.java
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.mvc;
017 
018 import griffon.core.Context;
019 import griffon.core.ContextFactory;
020 import griffon.core.GriffonApplication;
021 import griffon.core.artifact.GriffonController;
022 import griffon.core.artifact.GriffonModel;
023 import griffon.core.artifact.GriffonMvcArtifact;
024 import griffon.core.artifact.GriffonView;
025 import griffon.core.mvc.MVCFunction;
026 import griffon.core.mvc.MVCGroup;
027 import griffon.core.mvc.MVCGroupConfiguration;
028 import griffon.core.mvc.MVCGroupConfigurationFactory;
029 import griffon.core.mvc.MVCGroupFactory;
030 import griffon.core.mvc.MVCGroupFunction;
031 import griffon.core.mvc.MVCGroupManager;
032 import griffon.core.mvc.TypedMVCGroup;
033 import griffon.core.mvc.TypedMVCGroupFunction;
034 import griffon.exceptions.ArtifactNotFoundException;
035 import griffon.exceptions.MVCGroupConfigurationException;
036 import griffon.exceptions.MVCGroupInstantiationException;
037 import griffon.util.AnnotationUtils;
038 import org.slf4j.Logger;
039 import org.slf4j.LoggerFactory;
040 
041 import javax.annotation.Nonnull;
042 import javax.annotation.Nullable;
043 import javax.inject.Inject;
044 import java.lang.reflect.Constructor;
045 import java.util.Collections;
046 import java.util.LinkedHashMap;
047 import java.util.List;
048 import java.util.Map;
049 
050 import static griffon.core.GriffonExceptionHandler.sanitize;
051 import static griffon.util.GriffonNameUtils.isBlank;
052 import static griffon.util.GriffonNameUtils.requireNonBlank;
053 import static java.util.Arrays.asList;
054 import static java.util.Collections.unmodifiableMap;
055 import static java.util.Objects.requireNonNull;
056 
057 /**
058  * Base implementation of the {@code MVCGroupManager} interface.
059  *
060  @author Andres Almiray
061  @since 2.0.0
062  */
063 public abstract class AbstractMVCGroupManager implements MVCGroupManager {
064     protected static final String ERROR_MVCTYPE_BLANK = "Argument 'mvcType' must not be blank";
065     protected static final String ERROR_MVCID_BLANK = "Argument 'mvcId' must not be blank";
066     protected static final String ERROR_CONFIGURATION_NULL = "Argument 'configuration' must not be null";
067     protected static final String ERROR_GROUP_NULL = "Argument 'group' must not be null";
068     protected static final String ERROR_CONFIG_NULL = "Argument 'config' must not be null";
069     protected static final String ERROR_ARGS_NULL = "Argument 'args' must not be null";
070     protected static final String ERROR_NAME_BLANK = "Argument 'name' cannot be blank";
071     protected static final String ERROR_TYPE_NULL = "Argument 'type' cannot be null";
072     private static final Logger LOG = LoggerFactory.getLogger(AbstractMVCGroupManager.class);
073     private final GriffonApplication application;
074 
075     private final Map<String, MVCGroupConfiguration> configurations = new LinkedHashMap<>();
076     private final Map<String, MVCGroup> groups = new LinkedHashMap<>();
077     private final Object lock = new Object[0];
078     private boolean initialized;
079 
080     @Inject
081     private MVCGroupConfigurationFactory mvcGroupConfigurationFactory;
082 
083     @Inject
084     private MVCGroupFactory mvcGroupFactory;
085 
086     @Inject
087     private ContextFactory contextFactory;
088 
089     @Inject
090     public AbstractMVCGroupManager(@Nonnull GriffonApplication application) {
091         this.application = requireNonNull(application, "Argument 'application' must not be null");
092     }
093 
094     @Override
095     public GriffonApplication getApplication() {
096         return application;
097     }
098 
099     @Nonnull
100     public MVCGroupConfiguration newMVCGroupConfiguration(@Nonnull String mvcType, @Nonnull Map<String, String> members, @Nonnull Map<String, Object> config) {
101         return mvcGroupConfigurationFactory.create(mvcType, members, config);
102     }
103 
104     @Nonnull
105     public MVCGroup newMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> members, @Nullable MVCGroup parentGroup) {
106         return mvcGroupFactory.create(configuration, mvcId, members, parentGroup);
107     }
108 
109     @Nonnull
110     @Override
111     public Context newContext(@Nullable MVCGroup parentGroup) {
112         Context parentContext = parentGroup != null ? parentGroup.getContext() : getApplication().getContext();
113         return contextFactory.create(parentContext);
114     }
115 
116     @Nonnull
117     public Map<String, MVCGroupConfiguration> getConfigurations() {
118         synchronized (lock) {
119             return unmodifiableMap(configurations);
120         }
121     }
122 
123     @Nonnull
124     public Map<String, MVCGroup> getGroups() {
125         synchronized (lock) {
126             return unmodifiableMap(groups);
127         }
128     }
129 
130     @Nonnull
131     public MVCGroupConfiguration findConfiguration(@Nonnull String mvcType) {
132         requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
133         MVCGroupConfiguration configuration;
134         synchronized (lock) {
135             configuration = configurations.get(mvcType);
136         }
137 
138         if (configuration == null) {
139             throw new MVCGroupConfigurationException("Unknown MVC type '" + mvcType + "'. Known types are " + configurations.keySet(), mvcType);
140         }
141         return configuration;
142     }
143 
144     @Nullable
145     public MVCGroup findGroup(@Nonnull String mvcId) {
146         requireNonBlank(mvcId, ERROR_MVCID_BLANK);
147         synchronized (lock) {
148             LOG.debug("Searching group {}", mvcId);
149             return groups.get(mvcId);
150         }
151     }
152 
153     @Nullable
154     public MVCGroup getAt(@Nonnull String mvcId) {
155         return findGroup(mvcId);
156     }
157 
158     public final void initialize(@Nonnull Map<String, MVCGroupConfiguration> configurations) {
159         requireNonNull(configurations, "Argument 'configurations' must not be null");
160         if (configurations.isEmpty()) { return}
161         synchronized (lock) {
162             if (!initialized) {
163                 doInitialize(configurations);
164                 initialized = true;
165             }
166         }
167     }
168 
169     public void addConfiguration(@Nonnull MVCGroupConfiguration configuration) {
170         requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
171         synchronized (lock) {
172             if (initialized && configurations.get(configuration.getMvcType()) != null) {
173                 return;
174             }
175             configurations.put(configuration.getMvcType(), configuration);
176         }
177     }
178 
179     public void removeConfiguration(@Nonnull MVCGroupConfiguration configuration) {
180         requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
181         removeConfiguration(configuration.getMvcType());
182     }
183 
184     public void removeConfiguration(@Nonnull String name) {
185         requireNonBlank(name, "Argument 'name' must not be blank");
186         if (!isBlank(name)) {
187             synchronized (lock) {
188                 configurations.remove(name);
189             }
190         }
191     }
192 
193     protected void addGroup(@Nonnull MVCGroup group) {
194         requireNonNull(group, ERROR_GROUP_NULL);
195         synchronized (lock) {
196             LOG.debug("Adding group {}:{}", group.getMvcId(), group);
197             groups.put(group.getMvcId(), group);
198         }
199     }
200 
201     protected void removeGroup(@Nonnull MVCGroup group) {
202         requireNonNull(group, ERROR_GROUP_NULL);
203         synchronized (lock) {
204             LOG.debug("Removing group {}:{}", group.getMvcId(), group);
205             groups.remove(group.getMvcId());
206         }
207     }
208 
209     @Nonnull
210     public final Map<String, ? extends GriffonModel> getModels() {
211         Map<String, GriffonModel> models = new LinkedHashMap<>();
212         synchronized (lock) {
213             for (MVCGroup group : groups.values()) {
214                 GriffonModel model = group.getModel();
215                 if (model != null) {
216                     models.put(group.getMvcId(), model);
217                 }
218             }
219         }
220         return unmodifiableMap(models);
221     }
222 
223     @Nonnull
224     public final Map<String, ? extends GriffonView> getViews() {
225         Map<String, GriffonView> views = new LinkedHashMap<>();
226         synchronized (lock) {
227             for (MVCGroup group : groups.values()) {
228                 GriffonView view = group.getView();
229                 if (view != null) {
230                     views.put(group.getMvcId(), view);
231                 }
232             }
233         }
234         return unmodifiableMap(views);
235     }
236 
237     @Nonnull
238     public final Map<String, ? extends GriffonController> getControllers() {
239         Map<String, GriffonController> controllers = new LinkedHashMap<>();
240         synchronized (lock) {
241             for (MVCGroup group : groups.values()) {
242                 GriffonController controller = group.getController();
243                 if (controller != null) {
244                     controllers.put(group.getMvcId(), controller);
245                 }
246             }
247         }
248         return unmodifiableMap(controllers);
249     }
250 
251     @Nonnull
252     @Override
253     public MVCGroupConfiguration cloneMVCGroupConfiguration(@Nonnull String mvcType, @Nonnull Map<String, Object> config) {
254         requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
255         requireNonNull(config, ERROR_CONFIG_NULL);
256         MVCGroupConfiguration configuration = findConfiguration(mvcType);
257         Map<String, Object> configCopy = new LinkedHashMap<>();
258         configCopy.putAll(configuration.getConfig());
259         configCopy.putAll(config);
260         return newMVCGroupConfiguration(mvcType, configuration.getMembers(), configCopy);
261     }
262 
263     @Nonnull
264     protected List<? extends GriffonMvcArtifact> createMVC(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args) {
265         MVCGroup group = createMVCGroup(findConfiguration(configuration.getMvcType()), mvcId, args);
266         return asList(group.getModel(), group.getView(), group.getController());
267     }
268 
269     @SuppressWarnings("unchecked")
270     protected <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCFunction<M, V, C> handler) {
271         MVCGroup group = null;
272         try {
273             group = createMVCGroup(configuration, mvcId, args);
274             handler.apply((Mgroup.getModel()(Vgroup.getView()(Cgroup.getController());
275         finally {
276             try {
277                 if (group != null) {
278                     destroyMVCGroup(group.getMvcId());
279                 }
280             catch (Exception x) {
281                 LOG.warn("Could not destroy group [{}] of type {}", mvcId, configuration.getMvcType(), sanitize(x));
282             }
283         }
284     }
285 
286     @SuppressWarnings("unchecked")
287     protected void withMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
288         MVCGroup group = null;
289         try {
290             group = createMVCGroup(configuration, mvcId, args);
291             handler.apply(group);
292         finally {
293             try {
294                 if (group != null) {
295                     destroyMVCGroup(group.getMvcId());
296                 }
297             catch (Exception x) {
298                 LOG.warn("Could not destroy group [{}] of type {}", mvcId, configuration.getMvcType(), sanitize(x));
299             }
300         }
301     }
302 
303     @Nonnull
304     protected abstract MVCGroup createMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args);
305 
306     protected abstract void doInitialize(@Nonnull Map<String, MVCGroupConfiguration> configurations);
307 
308     @Nonnull
309     @Override
310     public MVCGroup createMVCGroup(@Nonnull String mvcType) {
311         return createMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
312     }
313 
314     @Nonnull
315     @Override
316     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
317         return createMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
318     }
319 
320     @Nonnull
321     @Override
322     public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
323         return createMVCGroup(findConfiguration(mvcType), null, args);
324     }
325 
326     @Nonnull
327     @Override
328     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
329         return createMVCGroup(findConfiguration(mvcType), null, args);
330     }
331 
332     @Nonnull
333     @Override
334     public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
335         return createMVCGroup(findConfiguration(mvcType), mvcId, args);
336     }
337 
338     @Nonnull
339     @Override
340     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
341         return createMVCGroup(findConfiguration(mvcType), mvcId, args);
342     }
343 
344     @Nonnull
345     @Override
346     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType) {
347         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), null, Collections.<String, Object>emptyMap()));
348     }
349 
350     @Nonnull
351     @Override
352     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
353         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, Collections.<String, Object>emptyMap()));
354     }
355 
356     @Nonnull
357     @Override
358     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType) {
359         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), null, args));
360     }
361 
362     @Nonnull
363     @Override
364     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args) {
365         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), null, args));
366     }
367 
368     @Nonnull
369     @Override
370     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
371         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, args));
372     }
373 
374     @Nonnull
375     @Override
376     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
377         return typedMvcGroup(mvcType, createMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, args));
378     }
379 
380     @Nonnull
381     @Override
382     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType) {
383         return createMVC(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
384     }
385 
386     @Nonnull
387     @Override
388     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
389         return createMVC(findConfiguration(mvcType), null, args);
390     }
391 
392     @Nonnull
393     @Override
394     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
395         return createMVC(findConfiguration(mvcType), null, args);
396     }
397 
398     @Nonnull
399     @Override
400     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId) {
401         return createMVC(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
402     }
403 
404     @Nonnull
405     @Override
406     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
407         return createMVC(findConfiguration(mvcType), mvcId, args);
408     }
409 
410     @Nonnull
411     @Override
412     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
413         return createMVC(findConfiguration(mvcType), mvcId, args);
414     }
415 
416     @Nonnull
417     @Override
418     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType) {
419         return createMVC(findConfiguration(nameOf(mvcType)), null, Collections.<String, Object>emptyMap());
420     }
421 
422     @Nonnull
423     @Override
424     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType) {
425         return createMVC(findConfiguration(nameOf(mvcType)), null, args);
426     }
427 
428     @Nonnull
429     @Override
430     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args) {
431         return createMVC(findConfiguration(nameOf(mvcType)), null, args);
432     }
433 
434     @Nonnull
435     @Override
436     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
437         return createMVC(findConfiguration(nameOf(mvcType)), mvcId, Collections.<String, Object>emptyMap());
438     }
439 
440     @Nonnull
441     @Override
442     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
443         return createMVC(findConfiguration(nameOf(mvcType)), mvcId, args);
444     }
445 
446     @Nonnull
447     @Override
448     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
449         return createMVC(findConfiguration(nameOf(mvcType)), mvcId, args);
450     }
451 
452     @Override
453     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull MVCFunction<M, V, C> handler) {
454         withMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap(), handler);
455     }
456 
457     @Override
458     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
459         withMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap(), handler);
460     }
461 
462     @Override
463     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCFunction<M, V, C> handler) {
464         withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
465     }
466 
467     @Override
468     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
469         withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
470     }
471 
472     @Override
473     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCFunction<M, V, C> handler) {
474         withMVCGroup(findConfiguration(mvcType), null, args, handler);
475     }
476 
477     @Override
478     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCFunction<M, V, C> handler) {
479         withMVCGroup(findConfiguration(mvcType), null, args, handler);
480     }
481 
482     @Override
483     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull MVCFunction<M, V, C> handler) {
484         withMVCGroup(findConfiguration(nameOf(mvcType)), null, Collections.<String, Object>emptyMap(), handler);
485     }
486 
487     @Override
488     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
489         withMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, Collections.<String, Object>emptyMap(), handler);
490     }
491 
492     @Override
493     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCFunction<M, V, C> handler) {
494         withMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, args, handler);
495     }
496 
497     @Override
498     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
499         withMVCGroup(findConfiguration(nameOf(mvcType)), mvcId, args, handler);
500     }
501 
502     @Override
503     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCFunction<M, V, C> handler) {
504         withMVCGroup(findConfiguration(nameOf(mvcType)), null, args, handler);
505     }
506 
507     @Override
508     public <MVC extends TypedMVCGroup, M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull MVCFunction<M, V, C> handler) {
509         withMVCGroup(findConfiguration(nameOf(mvcType)), null, args, handler);
510     }
511 
512     @Override
513     public void withMVCGroup(@Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
514         withMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap(), handler);
515     }
516 
517     @Override
518     public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
519         withMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap(), handler);
520     }
521 
522     @Override
523     public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
524         withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
525     }
526 
527     @Override
528     public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
529         withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
530     }
531 
532     @Override
533     public void withMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
534         withMVCGroup(findConfiguration(mvcType), null, args, handler);
535     }
536 
537     @Override
538     public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
539         withMVCGroup(findConfiguration(mvcType), null, args, handler);
540     }
541 
542     @Override
543     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull TypedMVCGroupFunction<MVC> handler) {
544         withMVCGroup(mvcType, null, Collections.<String, Object>emptyMap(), handler);
545     }
546 
547     @Override
548     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull TypedMVCGroupFunction<MVC> handler) {
549         withMVCGroup(mvcType, mvcId, Collections.<String, Object>emptyMap(), handler);
550     }
551 
552     @Override
553     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull TypedMVCGroupFunction<MVC> handler) {
554         MVC group = null;
555         try {
556             group = createMVCGroup(mvcType, mvcId, args);
557             handler.apply(group);
558         finally {
559             try {
560                 if (group != null) {
561                     destroyMVCGroup(group.getMvcId());
562                 }
563             catch (Exception x) {
564                 LOG.warn("Could not destroy group [{}] of type {}", mvcId, nameOf(mvcType), sanitize(x));
565             }
566         }
567     }
568 
569     @Override
570     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull TypedMVCGroupFunction<MVC> handler) {
571         withMVCGroup(mvcType, mvcId, args, handler);
572     }
573 
574     @Override
575     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args, @Nonnull TypedMVCGroupFunction<MVC> handler) {
576         withMVCGroup(mvcType, null, args, handler);
577     }
578 
579     @Override
580     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull TypedMVCGroupFunction<MVC> handler) {
581         withMVCGroup(mvcType, null, args, handler);
582     }
583 
584     @Nonnull
585     @Override
586     public <C extends GriffonController> C getController(@Nonnull String name, @Nonnull Class<C> typethrows ArtifactNotFoundException {
587         requireNonBlank(name, ERROR_NAME_BLANK);
588         requireNonNull(type, ERROR_TYPE_NULL);
589         GriffonController controller = getControllers().get(name);
590         if (controller != null) {
591             return type.cast(controller);
592         }
593         throw new ArtifactNotFoundException(type, name);
594     }
595 
596     @Nonnull
597     @Override
598     public <M extends GriffonModel> M getModel(@Nonnull String name, @Nonnull Class<M> typethrows ArtifactNotFoundException {
599         requireNonBlank(name, ERROR_NAME_BLANK);
600         requireNonNull(type, ERROR_TYPE_NULL);
601         GriffonModel model = getModels().get(name);
602         if (model != null) {
603             return type.cast(model);
604         }
605         throw new ArtifactNotFoundException(type, name);
606     }
607 
608     @Nonnull
609     @Override
610     public <V extends GriffonView> V getView(@Nonnull String name, @Nonnull Class<V> typethrows ArtifactNotFoundException {
611         requireNonBlank(name, ERROR_NAME_BLANK);
612         requireNonNull(type, ERROR_TYPE_NULL);
613         GriffonView view = getViews().get(name);
614         if (view != null) {
615             return type.cast(view);
616         }
617         throw new ArtifactNotFoundException(type, name);
618     }
619 
620     @Nullable
621     @Override
622     public <C extends GriffonController> C findController(@Nonnull String name, @Nonnull Class<C> type) {
623         try {
624             return getController(name, type);
625         catch (ArtifactNotFoundException anfe) {
626             return null;
627         }
628     }
629 
630     @Nullable
631     @Override
632     public <M extends GriffonModel> M findModel(@Nonnull String name, @Nonnull Class<M> type) {
633         try {
634             return getModel(name, type);
635         catch (ArtifactNotFoundException anfe) {
636             return null;
637         }
638     }
639 
640     @Nullable
641     @Override
642     public <V extends GriffonView> V findView(@Nonnull String name, @Nonnull Class<V> type) {
643         try {
644             return getView(name, type);
645         catch (ArtifactNotFoundException anfe) {
646             return null;
647         }
648     }
649 
650     @Nonnull
651     protected <MVC extends TypedMVCGroup> String nameOf(@Nonnull Class<? extends MVC> mvcType) {
652         return AnnotationUtils.nameFor(mvcType, true);
653     }
654 
655     @Nonnull
656     protected <MVC extends TypedMVCGroup> MVC typedMvcGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull MVCGroup mvcGroup) {
657         try {
658             Constructor<? extends MVC> constructor = mvcType.getDeclaredConstructor(MVCGroup.class);
659             return constructor.newInstance(mvcGroup);
660         catch (Exception e) {
661             throw new MVCGroupInstantiationException("Unexpected error", mvcGroup.getMvcType(), mvcGroup.getMvcId(), e);
662         }
663     }
664 }