| 
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.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.MVCGroupConfiguration;
 026 import griffon.core.mvc.MVCGroupFunction;
 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 }
 |