001 /*
002 * Copyright 2008-2016 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.artifact.GriffonController;
020 import griffon.core.artifact.GriffonControllerClass;
021 import griffon.core.artifact.GriffonModel;
022 import griffon.core.artifact.GriffonModelClass;
023 import griffon.core.artifact.GriffonMvcArtifact;
024 import griffon.core.artifact.GriffonView;
025 import griffon.core.artifact.GriffonViewClass;
026 import griffon.core.mvc.MVCFunction;
027 import griffon.core.mvc.MVCGroup;
028 import griffon.core.mvc.MVCGroupConfiguration;
029 import griffon.core.mvc.MVCGroupFunction;
030 import griffon.core.mvc.MVCGroupManager;
031
032 import javax.annotation.Nonnull;
033 import javax.annotation.Nullable;
034 import java.util.ArrayList;
035 import java.util.Collections;
036 import java.util.LinkedHashMap;
037 import java.util.List;
038 import java.util.Map;
039 import java.util.UUID;
040
041 import static griffon.util.GriffonClassUtils.requireState;
042 import static griffon.util.GriffonClassUtils.setPropertyOrFieldValue;
043 import static griffon.util.GriffonNameUtils.isBlank;
044 import static griffon.util.GriffonNameUtils.requireNonBlank;
045 import static java.util.Collections.unmodifiableMap;
046 import static java.util.Objects.requireNonNull;
047
048 /**
049 * Base implementation of the {@code MVCGroup} interface
050 *
051 * @author Andres Almiray
052 * @since 2.0.0
053 */
054 public abstract class AbstractMVCGroup extends AbstractMVCHandler implements MVCGroup {
055 protected final MVCGroupConfiguration configuration;
056 protected final String mvcId;
057 protected final Context context;
058 protected final Map<String, Object> members = new LinkedHashMap<>();
059 protected final Map<String, MVCGroup> children = new LinkedHashMap<>();
060 private final Object[] lock = new Object[0];
061 protected MVCGroup parentGroup;
062 private boolean alive;
063 private final List<Object> injectedInstances = new ArrayList<>();
064
065 public AbstractMVCGroup(@Nonnull MVCGroupManager mvcGroupManager, @Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> members, @Nullable MVCGroup parentGroup) {
066 super(mvcGroupManager);
067 this.configuration = requireNonNull(configuration, "Argument 'configuration' must not be null");
068 this.mvcId = isBlank(mvcId) ? configuration.getMvcType() + "-" + UUID.randomUUID().toString() : mvcId;
069 this.members.putAll(requireNonNull(members, "Argument 'members' must not be null"));
070 this.alive = true;
071 this.parentGroup = parentGroup;
072 this.context = mvcGroupManager.newContext(parentGroup);
073
074 for (Object o : this.members.values()) {
075 if (o instanceof GriffonMvcArtifact) {
076 setPropertyOrFieldValue(o, "mvcGroup", this);
077 }
078 }
079 }
080
081 @Nonnull
082 public List<Object> getInjectedInstances() {
083 return injectedInstances;
084 }
085
086 @Nonnull
087 @Override
088 public Context getContext() {
089 return context;
090 }
091
092 @Nullable
093 @Override
094 public MVCGroup getParentGroup() {
095 return parentGroup;
096 }
097
098 @Nonnull
099 @Override
100 public MVCGroupConfiguration getConfiguration() {
101 return configuration;
102 }
103
104 @Nonnull
105 @Override
106 public String getMvcType() {
107 return configuration.getMvcType();
108 }
109
110 @Nonnull
111 @Override
112 public String getMvcId() {
113 return mvcId;
114 }
115
116 @Nullable
117 @Override
118 public GriffonModel getModel() {
119 return (GriffonModel) getMember(GriffonModelClass.TYPE);
120 }
121
122 @Nullable
123 @Override
124 public GriffonView getView() {
125 return (GriffonView) getMember(GriffonViewClass.TYPE);
126 }
127
128 @Nullable
129 @Override
130 public GriffonController getController() {
131 return (GriffonController) getMember(GriffonControllerClass.TYPE);
132 }
133
134 @Nullable
135 @Override
136 public Object getMember(@Nonnull String name) {
137 requireNonBlank(name, "Argument 'name' must not be blank");
138 checkIfAlive();
139 return members.get(name);
140 }
141
142 @Nonnull
143 @Override
144 public Map<String, Object> getMembers() {
145 checkIfAlive();
146 return unmodifiableMap(members);
147 }
148
149 @Override
150 public void destroy() {
151 if (isAlive()) {
152 List<String> childrenIds = new ArrayList<>(children.keySet());
153 Collections.reverse(childrenIds);
154 for (String id : childrenIds) {
155 getMvcGroupManager().destroyMVCGroup(id);
156 }
157 getMvcGroupManager().destroyMVCGroup(mvcId);
158 members.clear();
159 children.clear();
160 if (parentGroup != null) {
161 parentGroup.notifyMVCGroupDestroyed(mvcId);
162 }
163 parentGroup = null;
164 context.destroy();
165 synchronized (lock) {
166 alive = false;
167 }
168 }
169 }
170
171 @Override
172 public void notifyMVCGroupDestroyed(@Nonnull String mvcId) {
173 requireNonBlank(mvcId, "Argument 'mvcId' must not be blank");
174 children.remove(mvcId);
175 }
176
177 @Override
178 public boolean isAlive() {
179 synchronized (lock) {
180 return alive;
181 }
182 }
183
184 protected void checkIfAlive() {
185 requireState(isAlive(), "Group " + getMvcType() + ":" + mvcId + " has been destroyed already.");
186 }
187
188 @Nonnull
189 @Override
190 public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
191 return manageChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType));
192 }
193
194 @Nonnull
195 @Override
196 public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
197 return manageChildGroup(super.createMVCGroup(injectParentGroup(args), mvcType, mvcId));
198 }
199
200 @Nonnull
201 @Override
202 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
203 return manageChildGroup(super.createMVCGroup(mvcType, injectParentGroup(args)));
204 }
205
206 @Nonnull
207 @Override
208 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
209 return manageChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup(args)));
210 }
211
212 @Nonnull
213 @Override
214 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
215 return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType));
216 }
217
218 @Nonnull
219 @Override
220 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
221 return manageChildGroup(super.createMVC(injectParentGroup(args), mvcType, mvcId));
222 }
223
224 @Nonnull
225 @Override
226 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
227 return manageChildGroup(super.createMVC(mvcType, injectParentGroup(args)));
228 }
229
230 @Nonnull
231 @Override
232 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
233 return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup(args)));
234 }
235
236 @Override
237 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) {
238 super.withMVC(injectParentGroup(args), mvcType, new MVCFunctionDecorator<>(handler));
239 }
240
241 @Override
242 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) {
243 super.withMVC(injectParentGroup(args), mvcType, mvcId, new MVCFunctionDecorator<>(handler));
244 }
245
246 @Override
247 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) {
248 super.withMVC(mvcType, injectParentGroup(args), new MVCFunctionDecorator<>(handler));
249 }
250
251 @Override
252 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) {
253 super.withMVC(mvcType, mvcId, injectParentGroup(args), new MVCFunctionDecorator<>(handler));
254 }
255
256 @Override
257 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull MVCFunction<M, V, C> handler) {
258 super.withMVC(mvcType, injectParentGroup(), new MVCFunctionDecorator<>(handler));
259 }
260
261 @Override
262 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
263 super.withMVC(mvcType, mvcId, injectParentGroup(), new MVCFunctionDecorator<>(handler));
264 }
265
266 @Override
267 public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
268 super.withMVCGroup(injectParentGroup(args), mvcType, new MVCGroupFunctionDecorator(handler));
269 }
270
271 @Override
272 public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
273 super.withMVCGroup(injectParentGroup(args), mvcType, mvcId, new MVCGroupFunctionDecorator(handler));
274 }
275
276 @Override
277 public void withMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
278 super.withMVCGroup(mvcType, injectParentGroup(args), new MVCGroupFunctionDecorator(handler));
279 }
280
281 @Override
282 public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
283 super.withMVCGroup(mvcType, mvcId, injectParentGroup(args), new MVCGroupFunctionDecorator(handler));
284 }
285
286 @Override
287 public void withMVCGroup(@Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
288 super.withMVCGroup(mvcType, injectParentGroup(), new MVCGroupFunctionDecorator(handler));
289 }
290
291 @Override
292 public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, final @Nonnull MVCGroupFunction handler) {
293 super.withMVCGroup(mvcType, mvcId, injectParentGroup(), new MVCGroupFunctionDecorator(handler));
294 }
295
296 @Nonnull
297 @Override
298 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId) {
299 return manageChildGroup(super.createMVC(mvcType, mvcId, injectParentGroup()));
300 }
301
302 @Nonnull
303 @Override
304 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType) {
305 return manageChildGroup(super.createMVC(mvcType, injectParentGroup()));
306 }
307
308 @Nonnull
309 @Override
310 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
311 return manageChildGroup(super.createMVCGroup(mvcType, mvcId, injectParentGroup()));
312 }
313
314 @Nonnull
315 @Override
316 public MVCGroup createMVCGroup(@Nonnull String mvcType) {
317 return manageChildGroup(super.createMVCGroup(mvcType, injectParentGroup()));
318 }
319
320 @Nonnull
321 private MVCGroup manageChildGroup(@Nonnull MVCGroup group) {
322 children.put(group.getMvcId(), group);
323 return group;
324 }
325
326 @Nonnull
327 private List<? extends GriffonMvcArtifact> manageChildGroup(@Nonnull List<? extends GriffonMvcArtifact> artifacts) {
328 MVCGroup group = null;
329 for (GriffonMvcArtifact artifact : artifacts) {
330 if (artifact != null) {
331 group = artifact.getMvcGroup();
332 break;
333 }
334 }
335 if (group != null) {
336 children.put(group.getMvcId(), group);
337 }
338 return artifacts;
339 }
340
341 @Nonnull
342 @Override
343 public Map<String, MVCGroup> getChildrenGroups() {
344 return unmodifiableMap(children);
345 }
346
347 @Nonnull
348 private Map<String, Object> injectParentGroup() {
349 return injectParentGroup(new LinkedHashMap<String, Object>());
350 }
351
352 @Nonnull
353 private Map<String, Object> injectParentGroup(@Nonnull Map<String, Object> args) {
354 Map<String, Object> map = new LinkedHashMap<>();
355 map.put("parentGroup", this);
356 map.putAll(args);
357 return map;
358 }
359
360 private final class MVCFunctionDecorator<M extends GriffonModel, V extends GriffonView, C extends GriffonController> implements MVCFunction<M, V, C> {
361 private final MVCFunction<M, V, C> delegate;
362
363 private MVCFunctionDecorator(MVCFunction<M, V, C> delegate) {
364 this.delegate = delegate;
365 }
366
367 @Override
368 public void apply(@Nullable M model, @Nullable V view, @Nullable C controller) {
369 MVCGroup group = null;
370 if (model != null) group = model.getMvcGroup();
371 if (view != null) group = view.getMvcGroup();
372 if (controller != null) group = controller.getMvcGroup();
373
374 if (group != null) children.put(group.getMvcId(), group);
375 delegate.apply(model, view, controller);
376 if (group != null) children.remove(group.getMvcId());
377 }
378 }
379
380 private final class MVCGroupFunctionDecorator implements MVCGroupFunction {
381 private final MVCGroupFunction delegate;
382
383 private MVCGroupFunctionDecorator(MVCGroupFunction delegate) {
384 this.delegate = delegate;
385 }
386
387 @Override
388 public void apply(@Nullable MVCGroup group) {
389 children.put(group.getMvcId(), group);
390 delegate.apply(group);
391 children.remove(group.getMvcId());
392 }
393 }
394 }
|