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