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.MVCCallable;
024 import griffon.core.mvc.MVCGroup;
025 import griffon.core.mvc.MVCGroupConfiguration;
026 import griffon.core.mvc.MVCGroupManager;
027 import griffon.exceptions.MVCGroupConfigurationException;
028 import org.slf4j.Logger;
029 import org.slf4j.LoggerFactory;
030
031 import javax.annotation.Nonnull;
032 import javax.annotation.Nullable;
033 import javax.inject.Inject;
034 import java.util.Collections;
035 import java.util.LinkedHashMap;
036 import java.util.List;
037 import java.util.Map;
038
039 import static griffon.core.GriffonExceptionHandler.sanitize;
040 import static griffon.util.GriffonNameUtils.isBlank;
041 import static griffon.util.GriffonNameUtils.requireNonBlank;
042 import static java.util.Arrays.asList;
043 import static java.util.Collections.unmodifiableMap;
044 import static java.util.Objects.requireNonNull;
045
046 /**
047 * Base implementation of the {@code MVCGroupManager} interface.
048 *
049 * @author Andres Almiray
050 * @since 2.0.0
051 */
052 public abstract class AbstractMVCGroupManager implements MVCGroupManager {
053 private static final Logger LOG = LoggerFactory.getLogger(AbstractMVCGroupManager.class);
054 protected static final String ERROR_MVCTYPE_BLANK = "Argument 'mvcType' must not be blank";
055 protected static final String ERROR_MVCID_BLANK = "Argument 'mvcId' must not be blank";
056 protected static final String ERROR_CONFIGURATION_NULL = "Argument 'configuration' must not be null";
057 protected static final String ERROR_GROUP_NULL = "Argument 'group' must not be null";
058 protected static final String ERROR_CONFIG_NULL = "Argument 'config' must not be null";
059 protected static final String ERROR_ARGS_NULL = "Argument 'args' must not be null";
060
061 private final GriffonApplication application;
062
063 private final Map<String, MVCGroupConfiguration> configurations = new LinkedHashMap<>();
064 private final Map<String, MVCGroup> groups = new LinkedHashMap<>();
065 private final Object lock = new Object[0];
066 private boolean initialized;
067
068 @Inject
069 public AbstractMVCGroupManager(@Nonnull GriffonApplication application) {
070 this.application = requireNonNull(application, "Argument 'application' must not be null");
071 }
072
073 @Override
074 public GriffonApplication getApplication() {
075 return application;
076 }
077
078 @Nonnull
079 public Map<String, MVCGroupConfiguration> getConfigurations() {
080 synchronized (lock) {
081 return unmodifiableMap(configurations);
082 }
083 }
084
085 @Nonnull
086 public Map<String, MVCGroup> getGroups() {
087 synchronized (lock) {
088 return unmodifiableMap(groups);
089 }
090 }
091
092 @Nonnull
093 public MVCGroupConfiguration findConfiguration(@Nonnull String mvcType) {
094 requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
095 MVCGroupConfiguration configuration;
096 synchronized (lock) {
097 configuration = configurations.get(mvcType);
098 }
099
100 if (configuration == null) {
101 throw new MVCGroupConfigurationException("Unknown MVC type '" + mvcType + "'. Known types are " + configurations.keySet(), mvcType);
102 }
103 return configuration;
104 }
105
106 @Nullable
107 public MVCGroup findGroup(@Nonnull String mvcId) {
108 requireNonBlank(mvcId, ERROR_MVCID_BLANK);
109 synchronized (lock) {
110 LOG.debug("Searching group {}", mvcId);
111 return groups.get(mvcId);
112 }
113 }
114
115 @Nullable
116 public MVCGroup getAt(@Nonnull String mvcId) {
117 return findGroup(mvcId);
118 }
119
120 public final void initialize(@Nonnull Map<String, MVCGroupConfiguration> configurations) {
121 requireNonNull(configurations, "Argument 'configurations' must not be null");
122 if (configurations.isEmpty()) return;
123 synchronized (lock) {
124 if (!initialized) {
125 doInitialize(configurations);
126 initialized = true;
127 }
128 }
129 }
130
131 public void addConfiguration(@Nonnull MVCGroupConfiguration configuration) {
132 requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
133 synchronized (lock) {
134 if (initialized && configurations.get(configuration.getMvcType()) != null) {
135 return;
136 }
137 configurations.put(configuration.getMvcType(), configuration);
138 }
139 }
140
141 public void removeConfiguration(@Nonnull MVCGroupConfiguration configuration) {
142 requireNonNull(configuration, ERROR_CONFIGURATION_NULL);
143 removeConfiguration(configuration.getMvcType());
144 }
145
146 public void removeConfiguration(@Nonnull String name) {
147 requireNonBlank(name, "Argument 'name' must not be blank");
148 if (!isBlank(name)) {
149 synchronized (lock) {
150 configurations.remove(name);
151 }
152 }
153 }
154
155 protected void addGroup(@Nonnull MVCGroup group) {
156 requireNonNull(group, ERROR_GROUP_NULL);
157 synchronized (lock) {
158 LOG.debug("Adding group {}:{}", group.getMvcId(), group);
159 groups.put(group.getMvcId(), group);
160 }
161 }
162
163 protected void removeGroup(@Nonnull MVCGroup group) {
164 requireNonNull(group, ERROR_GROUP_NULL);
165 synchronized (lock) {
166 LOG.debug("Removing group {}:{}", group.getMvcId(), group);
167 groups.remove(group.getMvcId());
168 }
169 }
170
171 @Nonnull
172 public final Map<String, ? extends GriffonModel> getModels() {
173 Map<String, GriffonModel> models = new LinkedHashMap<>();
174 synchronized (lock) {
175 for (MVCGroup group : groups.values()) {
176 GriffonModel model = group.getModel();
177 if (model != null) {
178 models.put(group.getMvcId(), model);
179 }
180 }
181 }
182 return unmodifiableMap(models);
183 }
184
185 @Nonnull
186 public final Map<String, ? extends GriffonView> getViews() {
187 Map<String, GriffonView> views = new LinkedHashMap<>();
188 synchronized (lock) {
189 for (MVCGroup group : groups.values()) {
190 GriffonView view = group.getView();
191 if (view != null) {
192 views.put(group.getMvcId(), view);
193 }
194 }
195 }
196 return unmodifiableMap(views);
197 }
198
199 @Nonnull
200 public final Map<String, ? extends GriffonController> getControllers() {
201 Map<String, GriffonController> controllers = new LinkedHashMap<>();
202 synchronized (lock) {
203 for (MVCGroup group : groups.values()) {
204 GriffonController controller = group.getController();
205 if (controller != null) {
206 controllers.put(group.getMvcId(), controller);
207 }
208 }
209 }
210 return unmodifiableMap(controllers);
211 }
212
213 @Nonnull
214 @Override
215 public MVCGroupConfiguration cloneMVCGroupConfiguration(@Nonnull String mvcType, @Nonnull Map<String, Object> config) {
216 requireNonBlank(mvcType, ERROR_MVCTYPE_BLANK);
217 requireNonNull(config, ERROR_CONFIG_NULL);
218 MVCGroupConfiguration configuration = findConfiguration(mvcType);
219 Map<String, Object> configCopy = new LinkedHashMap<>();
220 configCopy.putAll(configuration.getConfig());
221 configCopy.putAll(config);
222 return newMVCGroupConfiguration(mvcType, configuration.getMembers(), configCopy);
223 }
224
225 @Nonnull
226 protected List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args) {
227 MVCGroup group = buildMVCGroup(findConfiguration(configuration.getMvcType()), mvcId, args);
228 return asList(group.getModel(), group.getView(), group.getController());
229 }
230
231 @SuppressWarnings("unchecked")
232 protected <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCCallable<M, V, C> handler) {
233 MVCGroup group = null;
234 try {
235 group = buildMVCGroup(configuration, mvcId, args);
236 handler.call((M) group.getModel(), (V) group.getView(), (C) group.getController());
237 } finally {
238 try {
239 if (group != null) {
240 destroyMVCGroup(group.getMvcId());
241 }
242 } catch (Exception x) {
243 LOG.warn("Could not destroy group [{}] of type {}", mvcId, configuration.getMvcType(), sanitize(x));
244
245 }
246 }
247 }
248
249 @Nonnull
250 protected abstract MVCGroup buildMVCGroup(@Nonnull MVCGroupConfiguration configuration, @Nullable String mvcId, @Nonnull Map<String, Object> args);
251
252 protected abstract void doInitialize(@Nonnull Map<String, MVCGroupConfiguration> configurations);
253
254 @Nonnull
255 @Override
256 public MVCGroup buildMVCGroup(@Nonnull String mvcType) {
257 return buildMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
258 }
259
260 @Nonnull
261 @Override
262 public MVCGroup buildMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
263 return buildMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
264 }
265
266 @Nonnull
267 @Override
268 public MVCGroup buildMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
269 return buildMVCGroup(findConfiguration(mvcType), null, args);
270 }
271
272 @Nonnull
273 @Override
274 public MVCGroup buildMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
275 return buildMVCGroup(findConfiguration(mvcType), null, args);
276 }
277
278 @Nonnull
279 @Override
280 public MVCGroup buildMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
281 return buildMVCGroup(findConfiguration(mvcType), mvcId, args);
282 }
283
284 @Nonnull
285 @Override
286 public MVCGroup buildMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
287 return buildMVCGroup(findConfiguration(mvcType), mvcId, args);
288 }
289
290 @Nonnull
291 @Override
292 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull String mvcType) {
293 return createMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap());
294 }
295
296 @Nonnull
297 @Override
298 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType) {
299 return createMVCGroup(findConfiguration(mvcType), null, args);
300 }
301
302 @Nonnull
303 @Override
304 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args) {
305 return createMVCGroup(findConfiguration(mvcType), null, args);
306 }
307
308 @Nonnull
309 @Override
310 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId) {
311 return createMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap());
312 }
313
314 @Nonnull
315 @Override
316 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId) {
317 return createMVCGroup(findConfiguration(mvcType), mvcId, args);
318 }
319
320 @Nonnull
321 @Override
322 public List<? extends GriffonMvcArtifact> createMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args) {
323 return createMVCGroup(findConfiguration(mvcType), mvcId, args);
324 }
325
326 @Override
327 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull String mvcType, @Nonnull MVCCallable<M, V, C> handler) {
328 withMVCGroup(findConfiguration(mvcType), null, Collections.<String, Object>emptyMap(), handler);
329 }
330
331 @Override
332 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCCallable<M, V, C> handler) {
333 withMVCGroup(findConfiguration(mvcType), mvcId, Collections.<String, Object>emptyMap(), handler);
334 }
335
336 @Override
337 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull String mvcType, @Nonnull String mvcId, @Nonnull Map<String, Object> args, @Nonnull MVCCallable<M, V, C> handler) {
338 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
339 }
340
341 @Override
342 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull String mvcId, @Nonnull MVCCallable<M, V, C> handler) {
343 withMVCGroup(findConfiguration(mvcType), mvcId, args, handler);
344 }
345
346 @Override
347 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull String mvcType, @Nonnull Map<String, Object> args, @Nonnull MVCCallable<M, V, C> handler) {
348 withMVCGroup(findConfiguration(mvcType), null, args, handler);
349 }
350
351 @Override
352 public <M extends GriffonModel, V extends GriffonView, C extends GriffonController> void withMVCGroup(@Nonnull Map<String, Object> args, @Nonnull String mvcType, @Nonnull MVCCallable<M, V, C> handler) {
353 withMVCGroup(findConfiguration(mvcType), null, args, handler);
354 }
355 }
|