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