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