AbstractMVCGroup.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.artifact.GriffonController;
022 import griffon.core.artifact.GriffonControllerClass;
023 import griffon.core.artifact.GriffonModel;
024 import griffon.core.artifact.GriffonModelClass;
025 import griffon.core.artifact.GriffonMvcArtifact;
026 import griffon.core.artifact.GriffonView;
027 import griffon.core.artifact.GriffonViewClass;
028 import griffon.core.mvc.MVCFunction;
029 import griffon.core.mvc.MVCGroup;
030 import griffon.core.mvc.MVCGroupConfiguration;
031 import griffon.core.mvc.MVCGroupFunction;
032 import griffon.core.mvc.MVCGroupManager;
033 import griffon.core.mvc.TypedMVCGroup;
034 import griffon.core.mvc.TypedMVCGroupFunction;
035 
036 import javax.annotation.Nonnull;
037 import javax.annotation.Nullable;
038 import java.util.ArrayList;
039 import java.util.Collections;
040 import java.util.LinkedHashMap;
041 import java.util.List;
042 import java.util.Map;
043 import java.util.UUID;
044 
045 import static griffon.util.GriffonClassUtils.requireState;
046 import static griffon.util.GriffonClassUtils.setPropertyOrFieldValue;
047 import static griffon.util.GriffonNameUtils.isBlank;
048 import static griffon.util.GriffonNameUtils.requireNonBlank;
049 import static java.util.Collections.unmodifiableMap;
050 import static java.util.Objects.requireNonNull;
051 
052 /**
053  * Base implementation of the {@code MVCGroup} interface
054  *
055  @author Andres Almiray
056  @since 2.0.0
057  */
058 public abstract class AbstractMVCGroup extends AbstractMVCHandler implements MVCGroup {
059     protected final MVCGroupConfiguration configuration;
060     protected final String mvcId;
061     protected final Context context;
062     protected final Map<String, Object> members = new LinkedHashMap<>();
063     protected final Map<String, MVCGroup> children = new LinkedHashMap<>();
064     private final Object[] lock = new Object[0];
065     protected MVCGroup parentGroup;
066     private boolean alive;
067     private final List<Object> injectedInstances = new ArrayList<>();
068 
069     public AbstractMVCGroup(@Nonnull MVCGroupManager mvcGroupManager, @Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> members, @Nullable MVCGroup parentGroup) {
070         super(mvcGroupManager);
071         this.configuration = requireNonNull(configuration, "Argument 'configuration' must not be null");
072         this.mvcId = isBlank(mvcId? configuration.getMvcType() "-" + UUID.randomUUID().toString() : mvcId;
073         this.members.putAll(requireNonNull(members, "Argument 'members' must not be null"));
074         this.alive = true;
075         this.parentGroup = parentGroup;
076         this.context = mvcGroupManager.newContext(parentGroup);
077 
078         for (Object o : this.members.values()) {
079             if (instanceof GriffonMvcArtifact) {
080                 setPropertyOrFieldValue(o, "mvcGroup"this);
081             }
082         }
083     }
084 
085     @Nonnull
086     public List<Object> getInjectedInstances() {
087         return injectedInstances;
088     }
089 
090     @Nonnull
091     @Override
092     public Context getContext() {
093         return context;
094     }
095 
096     @Nullable
097     @Override
098     public MVCGroup getParentGroup() {
099         return parentGroup;
100     }
101 
102     @Nonnull
103     @Override
104     public MVCGroupConfiguration getConfiguration() {
105         return configuration;
106     }
107 
108     @Nonnull
109     @Override
110     public String getMvcType() {
111         return configuration.getMvcType();
112     }
113 
114     @Nonnull
115     @Override
116     public String getMvcId() {
117         return mvcId;
118     }
119 
120     @Nullable
121     @Override
122     public GriffonModel getModel() {
123         return (GriffonModelgetMember(GriffonModelClass.TYPE);
124     }
125 
126     @Nullable
127     @Override
128     public GriffonView getView() {
129         return (GriffonViewgetMember(GriffonViewClass.TYPE);
130     }
131 
132     @Nullable
133     @Override
134     public GriffonController getController() {
135         return (GriffonControllergetMember(GriffonControllerClass.TYPE);
136     }
137 
138     @Nullable
139     @Override
140     public Object getMember(@Nonnull String name) {
141         requireNonBlank(name, "Argument 'name' must not be blank");
142         checkIfAlive();
143         return members.get(name);
144     }
145 
146     @Nonnull
147     @Override
148     public Map<String, Object> getMembers() {
149         checkIfAlive();
150         return unmodifiableMap(members);
151     }
152 
153     @Override
154     public void destroy() {
155         if (isAlive()) {
156             List<String> childrenIds = new ArrayList<>(children.keySet());
157             Collections.reverse(childrenIds);
158             for (String id : childrenIds) {
159                 getMvcGroupManager().destroyMVCGroup(id);
160             }
161             getMvcGroupManager().destroyMVCGroup(mvcId);
162             members.clear();
163             children.clear();
164             if (parentGroup != null) {
165                 parentGroup.notifyMVCGroupDestroyed(mvcId);
166             }
167             parentGroup = null;
168             context.destroy();
169             synchronized (lock) {
170                 alive = false;
171             }
172         }
173     }
174 
175     @Override
176     public void notifyMVCGroupDestroyed(@Nonnull String mvcId) {
177         requireNonBlank(mvcId, "Argument 'mvcId' must not be blank");
178         children.remove(mvcId);
179     }
180 
181     @Override
182     public boolean isAlive() {
183         synchronized (lock) {
184             return alive;
185         }
186     }
187 
188     protected void checkIfAlive() {
189         requireState(isAlive()"Group " + getMvcType() ":" + mvcId + " has been destroyed already.");
190     }
191 
192 
193     @Nonnull
194     @Override
195     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
196         return manageChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup()));
197     }
198 
199     @Nonnull
200     @Override
201     public MVCGroup createMVCGroup(@Nonnull String mvcType) {
202         return manageChildGroup(super.createMVCGroup(mvcType, injectParentGroup()));
203     }
204 
205     @Nonnull
206     @Override
207     public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
208         return manageChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType));
209     }
210 
211     @Nonnull
212     @Override
213     public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
214         return manageChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType, mvcId));
215     }
216 
217     @Nonnull
218     @Override
219     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
220         return manageChildGroup(super.createMVCGroup(mvcType, injectParentGroup(args)));
221     }
222 
223     @Nonnull
224     @Override
225     public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
226         return manageChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup(args)));
227     }
228 
229     @Nonnull
230     @Override
231     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
232         return manageTypedChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup()));
233     }
234 
235     @Nonnull
236     @Override
237     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType) {
238         return manageTypedChildGroup(super.createMVCGroup(mvcType, injectParentGroup()));
239     }
240 
241     @Nonnull
242     @Override
243     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType) {
244         return manageTypedChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType));
245     }
246 
247     @Nonnull
248     @Override
249     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
250         return manageTypedChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType, mvcId));
251     }
252 
253     @Nonnull
254     @Override
255     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args) {
256         return manageTypedChildGroup(super.createMVCGroup(mvcType, injectParentGroup(args)));
257     }
258 
259     @Nonnull
260     @Override
261     public <MVC extends TypedMVCGroup> MVC createMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
262         return manageTypedChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup(args)));
263     }
264 
265     @Nonnull
266     @Override
267     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId) {
268         return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup()));
269     }
270 
271     @Nonnull
272     @Override
273     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType) {
274         return manageChildGroup(super.createMVC(mvcType, injectParentGroup()));
275     }
276 
277     @Nonnull
278     @Override
279     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
280         return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType));
281     }
282 
283     @Nonnull
284     @Override
285     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
286         return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType, mvcId));
287     }
288 
289     @Nonnull
290     @Override
291     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
292         return manageChildGroup(super.createMVC(mvcType, injectParentGroup(args)));
293     }
294 
295     @Nonnull
296     @Override
297     public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
298         return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup(args)));
299     }
300 
301     @Nonnull
302     @Override
303     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
304         return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup()));
305     }
306 
307     @Nonnull
308     @Override
309     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType) {
310         return manageChildGroup(super.createMVC(mvcType, injectParentGroup()));
311     }
312 
313     @Nonnull
314     @Override
315     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType) {
316         return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType));
317     }
318 
319     @Nonnull
320     @Override
321     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId) {
322         return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType, mvcId));
323     }
324 
325     @Nonnull
326     @Override
327     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args) {
328         return manageChildGroup(super.createMVC(mvcType, injectParentGroup(args)));
329     }
330 
331     @Nonnull
332     @Override
333     public <MVC extends TypedMVCGroup> List<? extends GriffonMvcArtifact> createMVC(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
334         return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup(args)));
335     }
336 
337     @Override
338     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) {
339         super.withMVC(injectParentGroup(args), mvcType, new MVCFunctionDecorator<>(handler));
340     }
341 
342     @Override
343     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) {
344         super.withMVC(injectParentGroup(args), mvcType, mvcId, new MVCFunctionDecorator<>(handler));
345     }
346 
347     @Override
348     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) {
349         super.withMVC(mvcType, injectParentGroup(args)new MVCFunctionDecorator<>(handler));
350     }
351 
352     @Override
353     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) {
354         super.withMVC(mvcType, mvcId, injectParentGroup(args)new MVCFunctionDecorator<>(handler));
355     }
356 
357     @Override
358     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull MVCFunction<M, V, C> handler) {
359         super.withMVC(mvcType, injectParentGroup()new MVCFunctionDecorator<>(handler));
360     }
361 
362     @Override
363     public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
364         super.withMVC(mvcType, mvcId, injectParentGroup()new MVCFunctionDecorator<>(handler));
365     }
366 
367     @Override
368     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) {
369         super.withMVC(injectParentGroup(args), mvcType, new MVCFunctionDecorator<>(handler));
370     }
371 
372     @Override
373     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) {
374         super.withMVC(injectParentGroup(args), mvcType, mvcId, new MVCFunctionDecorator<>(handler));
375     }
376 
377     @Override
378     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) {
379         super.withMVC(mvcType, injectParentGroup(args)new MVCFunctionDecorator<>(handler));
380     }
381 
382     @Override
383     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) {
384         super.withMVC(mvcType, mvcId, injectParentGroup(args)new MVCFunctionDecorator<>(handler));
385     }
386 
387     @Override
388     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) {
389         super.withMVC(mvcType, injectParentGroup()new MVCFunctionDecorator<>(handler));
390     }
391 
392     @Override
393     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) {
394         super.withMVC(mvcType, mvcId, injectParentGroup()new MVCFunctionDecorator<>(handler));
395     }
396 
397     @Override
398     public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
399         super.withMVCGroup(injectParentGroup(args), mvcType, new MVCGroupFunctionDecorator(handler));
400     }
401 
402     @Override
403     public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
404         super.withMVCGroup(injectParentGroup(args), mvcType, mvcId, new MVCGroupFunctionDecorator(handler));
405     }
406 
407     @Override
408     public void withMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
409         super.withMVCGroup(mvcType, injectParentGroup(args)new MVCGroupFunctionDecorator(handler));
410     }
411 
412     @Override
413     public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
414         super.withMVCGroup(mvcType, mvcId, injectParentGroup(args)new MVCGroupFunctionDecorator(handler));
415     }
416 
417     @Override
418     public void withMVCGroup(@Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
419         super.withMVCGroup(mvcType, injectParentGroup()new MVCGroupFunctionDecorator(handler));
420     }
421 
422     @Override
423     public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull final MVCGroupFunction handler) {
424         super.withMVCGroup(mvcType, mvcId, injectParentGroup()new MVCGroupFunctionDecorator(handler));
425     }
426 
427     @Override
428     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull TypedMVCGroupFunction<MVC> handler) {
429         super.withMVCGroup(injectParentGroup(args), mvcType, new TypedMVCGroupFunctionDecorator<>(handler));
430     }
431 
432     @Override
433     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull TypedMVCGroupFunction<MVC> handler) {
434         super.withMVCGroup(injectParentGroup(args), mvcType, mvcId, new TypedMVCGroupFunctionDecorator<>(handler));
435     }
436 
437     @Override
438     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull Map<String, Object> args, @Nonnull TypedMVCGroupFunction<MVC> handler) {
439         super.withMVCGroup(mvcType, injectParentGroup(args)new TypedMVCGroupFunctionDecorator<>(handler));
440     }
441 
442     @Override
443     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull TypedMVCGroupFunction<MVC> handler) {
444         super.withMVCGroup(mvcType, mvcId, injectParentGroup(args)new TypedMVCGroupFunctionDecorator<>(handler));
445     }
446 
447     @Override
448     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull TypedMVCGroupFunction<MVC> handler) {
449         super.withMVCGroup(mvcType, injectParentGroup()new TypedMVCGroupFunctionDecorator<>(handler));
450     }
451 
452     @Override
453     public <MVC extends TypedMVCGroup> void withMVCGroup(@Nonnull Class<? extends MVC> mvcType, @Nonnull String mvcId, @Nonnull final TypedMVCGroupFunction<MVC> handler) {
454         super.withMVCGroup(mvcType, mvcId, injectParentGroup()new TypedMVCGroupFunctionDecorator<>(handler));
455     }
456 
457     @Nonnull
458     private MVCGroup manageChildGroup(@Nonnull MVCGroup group) {
459         children.put(group.getMvcId(), group);
460         return group;
461     }
462 
463     @Nonnull
464     private <MVC extends TypedMVCGroup> MVC manageTypedChildGroup(@Nonnull MVC group) {
465         children.put(group.getMvcId(), group);
466         return group;
467     }
468 
469     @Nonnull
470     private List<? extends GriffonMvcArtifact> manageChildGroup(@Nonnull List<? extends GriffonMvcArtifact> artifacts) {
471         MVCGroup group = null;
472         for (GriffonMvcArtifact artifact : artifacts) {
473             if (artifact != null) {
474                 group = artifact.getMvcGroup();
475                 break;
476             }
477         }
478         if (group != null) {
479             children.put(group.getMvcId(), group);
480         }
481         return artifacts;
482     }
483 
484     @Nonnull
485     @Override
486     public Map<String, MVCGroup> getChildrenGroups() {
487         return unmodifiableMap(children);
488     }
489 
490     @Nonnull
491     private Map<String, Object> injectParentGroup() {
492         return injectParentGroup(new LinkedHashMap<String, Object>());
493     }
494 
495     @Nonnull
496     private Map<String, Object> injectParentGroup(@Nonnull Map<String, Object> args) {
497         Map<String, Object> map = new LinkedHashMap<>();
498         map.put("parentGroup"this);
499         map.putAll(args);
500         return map;
501     }
502 
503     private final class MVCFunctionDecorator<M extends GriffonModel, V extends GriffonView, C extends GriffonController> implements MVCFunction<M, V, C> {
504         private final MVCFunction<M, V, C> delegate;
505 
506         private MVCFunctionDecorator(MVCFunction<M, V, C> delegate) {
507             this.delegate = delegate;
508         }
509 
510         @Override
511         public void apply(@Nullable M model, @Nullable V view, @Nullable C controller) {
512             MVCGroup group = null;
513             if (model != null) { group = model.getMvcGroup()}
514             if (view != null) { group = view.getMvcGroup()}
515             if (controller != null) { group = controller.getMvcGroup()}
516 
517             if (group != null) { children.put(group.getMvcId(), group)}
518             delegate.apply(model, view, controller);
519             if (group != null) { children.remove(group.getMvcId())}
520         }
521     }
522 
523     private final class MVCGroupFunctionDecorator implements MVCGroupFunction {
524         private final MVCGroupFunction delegate;
525 
526         private MVCGroupFunctionDecorator(MVCGroupFunction delegate) {
527             this.delegate = delegate;
528         }
529 
530         @Override
531         public void apply(@Nonnull MVCGroup group) {
532             children.put(group.getMvcId(), group);
533             delegate.apply(group);
534             children.remove(group.getMvcId());
535         }
536     }
537 
538     private final class TypedMVCGroupFunctionDecorator<MVC extends TypedMVCGroup> implements TypedMVCGroupFunction<MVC> {
539         private final TypedMVCGroupFunction<MVC> delegate;
540 
541         private TypedMVCGroupFunctionDecorator(TypedMVCGroupFunction<MVC> delegate) {
542             this.delegate = delegate;
543         }
544 
545         @Override
546         public void apply(@Nonnull MVC group) {
547             children.put(group.getMvcId(), group);
548             delegate.apply(group);
549             children.remove(group.getMvcId());
550         }
551     }
552 }