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.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.exceptions.ArtifactNotFoundException;
033 import griffon.exceptions.MVCGroupConfigurationException;
034 import org.slf4j.Logger;
035 import org.slf4j.LoggerFactory;
036
037 import javax.annotation.Nonnull;
038 import javax.annotation.Nullable;
039 import javax.inject.Inject;
040 import java.util.Collections;
041 import java.util.LinkedHashMap;
042 import java.util.List;
043 import java.util.Map;
044
045 import static griffon.core.GriffonExceptionHandler.sanitize;
046 import static griffon.util.GriffonNameUtils.isBlank;
047 import static griffon.util.GriffonNameUtils.requireNonBlank;
048 import static java.util.Arrays.asList;
049 import static java.util.Collections.unmodifiableMap;
050 import static java.util.Objects.requireNonNull;
051
052 /**
053 * Base implementation of the {@code MVCGroupManager} interface.
054 *
055 * @author Andres Almiray
056 * @since 2.0.0
057 */
058 public abstract class AbstractMVCGroupManager implements MVCGroupManager {
059 protected static final String ERROR_MVCTYPE_BLANK = "Argument 'mvcType' must not be blank";
060 protected static final String ERROR_MVCID_BLANK = "Argument 'mvcId' must not be blank";
061 protected static final String ERROR_CONFIGURATION_NULL = "Argument 'configuration' must not be null";
062 protected static final String ERROR_GROUP_NULL = "Argument 'group' must not be null";
063 protected static final String ERROR_CONFIG_NULL = "Argument 'config' must not be null";
064 protected static final String ERROR_ARGS_NULL = "Argument 'args' must not be null";
065 protected static final String ERROR_NAME_BLANK = "Argument 'name' cannot be blank";
066 protected static final String ERROR_TYPE_NULL = "Argument 'type' cannot be null";
067 private static final Logger LOG = LoggerFactory.getLogger(AbstractMVCGroupManager.class);
068 private final GriffonApplication application;
069
070 private final Map<String, MVCGroupConfiguration> configurations = new LinkedHashMap<>();
071 private final Map<String, MVCGroup> groups = new LinkedHashMap<>();
072 private final Object lock = new Object[0];
073 private boolean initialized;
074
075 @Inject
076 private MVCGroupConfigurationFactory mvcGroupConfigurationFactory;
077
078 @Inject
079 private MVCGroupFactory mvcGroupFactory;
080
081 @Inject
082 private ContextFactory contextFactory;
083
084 @Inject
085 public AbstractMVCGroupManager(@Nonnull GriffonApplication application) {
086 this.application = requireNonNull(application, "Argument 'application' must not be null");
087 }
088
089 @Override
090 public GriffonApplication getApplication() {
091 return application;
092 }
093
094 @Nonnull
095 public MVCGroupConfiguration newMVCGroupConfiguration(@Nonnull String mvcType, @Nonnull Map<String, String> members, @Nonnull Map<String, Object> config) {
096 return mvcGroupConfigurationFactory.create(mvcType, members, config);
097 }
098
099 @Nonnull
100 public MVCGroup newMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> members, @Nullable MVCGroup parentGroup) {
101 return mvcGroupFactory.create(configuration, mvcId, members, parentGroup);
102 }
103
104 @Nonnull
105 @Override
106 public Context newContext(@Nullable MVCGroup parentGroup) {
107 Context parentContext = parentGroup != null ? parentGroup.getContext() : getApplication().getContext();
108 return contextFactory.create(parentContext);
109 }
110
111 @Nonnull
112 public Map<String, MVCGroupConfiguration> getConfigurations() {
113 synchronized (lock) {
114 return unmodifiableMap(configurations);
115 }
116 }
117
118 @Nonnull
119 public Map<String, MVCGroup> getGroups() {
120 synchronized (lock) {
121 return unmodifiableMap(groups);
122 }
123 }
124
125 @Nonnull
126 public MVCGroupConfiguration findConfiguration(@Nonnull String mvcType) {
127 requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
128 MVCGroupConfiguration configuration;
129 synchronized (lock) {
130 configuration = configurations.get(mvcType);
131 }
132
133 if (configuration == null) {
134 throw new MVCGroupConfigurationException("Unknown MVC type '" + mvcType + "'. Known types are " + configurations.keySet(), mvcType);
135 }
136 return configuration;
137 }
138
139 @Nullable
140 public MVCGroup findGroup(@Nonnull String mvcId) {
141 requireNonBlank(mvcId, ERROR_MVCID_BLANK);
142 synchronized (lock) {
143 LOG.debug("Searching group {}", mvcId);
144 return groups.get(mvcId);
145 }
146 }
147
148 @Nullable
149 public MVCGroup getAt(@Nonnull String mvcId) {
150 return findGroup(mvcId);
151 }
152
153 public final void initialize(@Nonnull Map<String, MVCGroupConfiguration> configurations) {
154 requireNonNull(configurations, "Argument 'configurations' must not be null");
155 if (configurations.isEmpty()) return;
156 synchronized (lock) {
157 if (!initialized) {
158 doInitialize(configurations);
159 initialized = true;
160 }
161 }
162 }
163
164 public void addConfiguration(@Nonnull MVCGroupConfiguration configuration) {
165 requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
166 synchronized (lock) {
167 if (initialized && configurations.get(configuration.getMvcType()) != null) {
168 return;
169 }
170 configurations.put(configuration.getMvcType(), configuration);
171 }
172 }
173
174 public void removeConfiguration(@Nonnull MVCGroupConfiguration configuration) {
175 requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
176 removeConfiguration(configuration.getMvcType());
177 }
178
179 public void removeConfiguration(@Nonnull String name) {
180 requireNonBlank(name, "Argument 'name' must not be blank");
181 if (!isBlank(name)) {
182 synchronized (lock) {
183 configurations.remove(name);
184 }
185 }
186 }
187
188 protected void addGroup(@Nonnull MVCGroup group) {
189 requireNonNull(group, ERROR_GROUP_NULL);
190 synchronized (lock) {
191 LOG.debug("Adding group {}:{}", group.getMvcId(), group);
192 groups.put(group.getMvcId(), group);
193 }
194 }
195
196 protected void removeGroup(@Nonnull MVCGroup group) {
197 requireNonNull(group, ERROR_GROUP_NULL);
198 synchronized (lock) {
199 LOG.debug("Removing group {}:{}", group.getMvcId(), group);
200 groups.remove(group.getMvcId());
201 }
202 }
203
204 @Nonnull
205 public final Map<String, ? extends GriffonModel> getModels() {
206 Map<String, GriffonModel> models = new LinkedHashMap<>();
207 synchronized (lock) {
208 for (MVCGroup group : groups.values()) {
209 GriffonModel model = group.getModel();
210 if (model != null) {
211 models.put(group.getMvcId(), model);
212 }
213 }
214 }
215 return unmodifiableMap(models);
216 }
217
218 @Nonnull
219 public final Map<String, ? extends GriffonView> getViews() {
220 Map<String, GriffonView> views = new LinkedHashMap<>();
221 synchronized (lock) {
222 for (MVCGroup group : groups.values()) {
223 GriffonView view = group.getView();
224 if (view != null) {
225 views.put(group.getMvcId(), view);
226 }
227 }
228 }
229 return unmodifiableMap(views);
230 }
231
232 @Nonnull
233 public final Map<String, ? extends GriffonController> getControllers() {
234 Map<String, GriffonController> controllers = new LinkedHashMap<>();
235 synchronized (lock) {
236 for (MVCGroup group : groups.values()) {
237 GriffonController controller = group.getController();
238 if (controller != null) {
239 controllers.put(group.getMvcId(), controller);
240 }
241 }
242 }
243 return unmodifiableMap(controllers);
244 }
245
246 @Nonnull
247 @Override
248 public MVCGroupConfiguration cloneMVCGroupConfiguration(@Nonnull String mvcType, @Nonnull Map<String, Object> config) {
249 requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
250 requireNonNull(config, ERROR_CONFIG_NULL);
251 MVCGroupConfiguration configuration = findConfiguration(mvcType);
252 Map<String, Object> configCopy = new LinkedHashMap<>();
253 configCopy.putAll(configuration.getConfig());
254 configCopy.putAll(config);
255 return newMVCGroupConfiguration(mvcType, configuration.getMembers(), configCopy);
256 }
257
258 @Nonnull
259 protected List<? extends GriffonMvcArtifact> createMVC(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args) {
260 MVCGroup group = createMVCGroup(findConfiguration(configuration.getMvcType()), mvcId, args);
261 return asList(group.getModel(), group.getView(), group.getController());
262 }
263
264 @SuppressWarnings("unchecked")
265 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) {
266 MVCGroup group = null;
267 try {
268 group = createMVCGroup(configuration, mvcId, args);
269 handler.apply((M) group.getModel(), (V) group.getView(), (C) group.getController());
270 } finally {
271 try {
272 if (group != null) {
273 destroyMVCGroup(group.getMvcId());
274 }
275 } catch (Exception x) {
276 LOG.warn("Could not destroy group [{}] of type {}", mvcId, configuration.getMvcType(), sanitize(x));
277 }
278 }
279 }
280
281 @SuppressWarnings("unchecked")
282 protected void withMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
283 MVCGroup group = null;
284 try {
285 group = createMVCGroup(configuration, mvcId, args);
286 handler.apply(group);
287 } finally {
288 try {
289 if (group != null) {
290 destroyMVCGroup(group.getMvcId());
291 }
292 } catch (Exception x) {
293 LOG.warn("Could not destroy group [{}] of type {}", mvcId, configuration.getMvcType(), sanitize(x));
294 }
295 }
296 }
297
298 @Nonnull
299 protected abstract MVCGroup createMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args);
300
301 protected abstract void doInitialize(@Nonnull Map<String, MVCGroupConfiguration> configurations);
302
303 @Nonnull
304 @Override
305 public MVCGroup createMVCGroup(@Nonnull String mvcType) {
306 return createMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
307 }
308
309 @Nonnull
310 @Override
311 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
312 return createMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
313 }
314
315 @Nonnull
316 @Override
317 public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
318 return createMVCGroup(findConfiguration(mvcType), null, args);
319 }
320
321 @Nonnull
322 @Override
323 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
324 return createMVCGroup(findConfiguration(mvcType), null, args);
325 }
326
327 @Nonnull
328 @Override
329 public MVCGroup createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
330 return createMVCGroup(findConfiguration(mvcType), mvcId, args);
331 }
332
333 @Nonnull
334 @Override
335 public MVCGroup createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
336 return createMVCGroup(findConfiguration(mvcType), mvcId, args);
337 }
338
339 @Nonnull
340 @Override
341 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType) {
342 return createMVC(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
343 }
344
345 @Nonnull
346 @Override
347 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
348 return createMVC(findConfiguration(mvcType), null, args);
349 }
350
351 @Nonnull
352 @Override
353 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
354 return createMVC(findConfiguration(mvcType), null, args);
355 }
356
357 @Nonnull
358 @Override
359 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId) {
360 return createMVC(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
361 }
362
363 @Nonnull
364 @Override
365 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
366 return createMVC(findConfiguration(mvcType), mvcId, args);
367 }
368
369 @Nonnull
370 @Override
371 public List<? extends GriffonMvcArtifact> createMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
372 return createMVC(findConfiguration(mvcType), mvcId, args);
373 }
374
375 @Override
376 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull MVCFunction<M, V, C> handler) {
377 withMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap(), handler);
378 }
379
380 @Override
381 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVC(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCFunction<M, V, C> handler) {
382 withMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap(), handler);
383 }
384
385 @Override
386 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) {
387 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
388 }
389
390 @Override
391 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) {
392 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
393 }
394
395 @Override
396 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) {
397 withMVCGroup(findConfiguration(mvcType), null, args, handler);
398 }
399
400 @Override
401 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) {
402 withMVCGroup(findConfiguration(mvcType), null, args, handler);
403 }
404
405 @Override
406 public void withMVCGroup(@Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
407 withMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap(), handler);
408 }
409
410 @Override
411 public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
412 withMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap(), handler);
413 }
414
415 @Override
416 public void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
417 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
418 }
419
420 @Override
421 public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCGroupFunction handler) {
422 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
423 }
424
425 @Override
426 public void withMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCGroupFunction handler) {
427 withMVCGroup(findConfiguration(mvcType), null, args, handler);
428 }
429
430 @Override
431 public void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCGroupFunction handler) {
432 withMVCGroup(findConfiguration(mvcType), null, args, handler);
433 }
434
435 @Nonnull
436 @Override
437 public <C extends GriffonController> C getController(@Nonnull String name, @Nonnull Class<C> type) throws ArtifactNotFoundException {
438 requireNonBlank(name, ERROR_NAME_BLANK);
439 requireNonNull(type, ERROR_TYPE_NULL);
440 GriffonController controller = getControllers().get(name);
441 if (controller != null) {
442 return type.cast(controller);
443 }
444 throw new ArtifactNotFoundException(type, name);
445 }
446
447 @Nonnull
448 @Override
449 public <M extends GriffonModel> M getModel(@Nonnull String name, @Nonnull Class<M> type) throws ArtifactNotFoundException {
450 requireNonBlank(name, ERROR_NAME_BLANK);
451 requireNonNull(type, ERROR_TYPE_NULL);
452 GriffonModel model = getModels().get(name);
453 if (model != null) {
454 return type.cast(model);
455 }
456 throw new ArtifactNotFoundException(type, name);
457 }
458
459 @Nonnull
460 @Override
461 public <V extends GriffonView> V getView(@Nonnull String name, @Nonnull Class<V> type) throws ArtifactNotFoundException {
462 requireNonBlank(name, ERROR_NAME_BLANK);
463 requireNonNull(type, ERROR_TYPE_NULL);
464 GriffonView view = getViews().get(name);
465 if (view != null) {
466 return type.cast(view);
467 }
468 throw new ArtifactNotFoundException(type, name);
469 }
470
471 @Nullable
472 @Override
473 public <C extends GriffonController> C findController(@Nonnull String name, @Nonnull Class<C> type) {
474 try {
475 return getController(name, type);
476 } catch (ArtifactNotFoundException anfe) {
477 return null;
478 }
479 }
480
481 @Nullable
482 @Override
483 public <M extends GriffonModel> M findModel(@Nonnull String name, @Nonnull Class<M> type) {
484 try {
485 return getModel(name, type);
486 } catch (ArtifactNotFoundException anfe) {
487 return null;
488 }
489 }
490
491 @Nullable
492 @Override
493 public <V extends GriffonView> V findView(@Nonnull String name, @Nonnull Class<V> type) {
494 try {
495 return getView(name, type);
496 } catch (ArtifactNotFoundException anfe) {
497 return null;
498 }
499 }
500 }
|