| 
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.addon;
 017
 018 import griffon.core.ApplicationEvent;
 019 import griffon.core.GriffonApplication;
 020 import griffon.core.addon.AddonManager;
 021 import griffon.core.addon.GriffonAddon;
 022 import griffon.core.mvc.MVCGroupConfiguration;
 023 import org.slf4j.Logger;
 024 import org.slf4j.LoggerFactory;
 025
 026 import javax.annotation.Nonnull;
 027 import javax.annotation.Nullable;
 028 import javax.annotation.concurrent.GuardedBy;
 029 import javax.inject.Inject;
 030 import java.util.Collection;
 031 import java.util.Collections;
 032 import java.util.LinkedHashMap;
 033 import java.util.List;
 034 import java.util.Map;
 035
 036 import static griffon.util.AnnotationUtils.sortByDependencies;
 037 import static griffon.util.CollectionUtils.reverse;
 038 import static griffon.util.GriffonNameUtils.getPropertyName;
 039 import static griffon.util.GriffonNameUtils.requireNonBlank;
 040 import static java.util.Arrays.asList;
 041 import static java.util.Objects.requireNonNull;
 042
 043 /**
 044  * Base implementation of the {@code AddonManager} interface.
 045  *
 046  * @author Andres Almiray
 047  * @since 2.0.0
 048  */
 049 public abstract class AbstractAddonManager implements AddonManager {
 050     private static final Logger LOG = LoggerFactory.getLogger(AbstractAddonManager.class);
 051
 052     private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
 053     private final Map<String, GriffonAddon> addons = new LinkedHashMap<>();
 054     private final Object lock = new Object[0];
 055     @GuardedBy("lock")
 056     private boolean initialized;
 057
 058     private final GriffonApplication application;
 059
 060     @Inject
 061     public AbstractAddonManager(@Nonnull GriffonApplication application) {
 062         this.application = requireNonNull(application, "Argument 'application' must not be null");
 063     }
 064
 065     @Nonnull
 066     public GriffonApplication getApplication() {
 067         return application;
 068     }
 069
 070     @Nonnull
 071     public Map<String, GriffonAddon> getAddons() {
 072         return Collections.unmodifiableMap(addons);
 073     }
 074
 075     @Nullable
 076     public GriffonAddon findAddon(@Nonnull String name) {
 077         requireNonBlank(name, ERROR_NAME_BLANK);
 078         if (name.endsWith(GriffonAddon.SUFFIX)) {
 079             name = name.substring(0, name.length() - 12);
 080         }
 081         return addons.get(getPropertyName(name));
 082     }
 083
 084     public final void initialize() {
 085         synchronized (lock) {
 086             if (!initialized) {
 087                 doInitialize();
 088                 initialized = true;
 089             }
 090         }
 091     }
 092
 093     protected void doInitialize() {
 094         LOG.debug("Loading addons [START]");
 095
 096         Map<String, GriffonAddon> addons = preloadAddons();
 097         event(ApplicationEvent.LOAD_ADDONS_START);
 098
 099         for (Map.Entry<String, GriffonAddon> entry : addons.entrySet()) {
 100             String name = entry.getKey();
 101             GriffonAddon addon = entry.getValue();
 102             LOG.debug("Loading addon {} with class {}", name, addon.getClass().getName());
 103             event(ApplicationEvent.LOAD_ADDON_START, asList(getApplication(), name, addon));
 104
 105             getApplication().getEventRouter().addEventListener(addon);
 106             addMVCGroups(addon);
 107             addon.init(getApplication());
 108
 109             this.addons.put(name, addon);
 110             event(ApplicationEvent.LOAD_ADDON_END, asList(getApplication(), name, addon));
 111             LOG.debug("Loaded addon {}", name);
 112         }
 113
 114         for (GriffonAddon addon : reverse(addons.values())) {
 115             getApplication().addShutdownHandler(addon);
 116         }
 117
 118         LOG.debug("Loading addons [END]");
 119         event(ApplicationEvent.LOAD_ADDONS_END);
 120     }
 121
 122     @Nonnull
 123     protected Map<String, GriffonAddon> preloadAddons() {
 124         Collection<GriffonAddon> addonInstances = getApplication().getInjector().getInstances(GriffonAddon.class);
 125         return sortByDependencies(addonInstances, GriffonAddon.SUFFIX, "addon");
 126     }
 127
 128     @SuppressWarnings("unchecked")
 129     protected void addMVCGroups(@Nonnull GriffonAddon addon) {
 130         for (Map.Entry<String, Map<String, Object>> groupEntry : addon.getMvcGroups().entrySet()) {
 131             String type = groupEntry.getKey();
 132             LOG.debug("Adding MVC group {}", type);
 133             Map<String, Object> members = groupEntry.getValue();
 134             Map<String, Object> configMap = new LinkedHashMap<>();
 135             Map<String, String> membersCopy = new LinkedHashMap<>();
 136             for (Map.Entry<String, Object> entry : members.entrySet()) {
 137                 String key = String.valueOf(entry.getKey());
 138                 if ("config".equals(key) && entry.getValue() instanceof Map) {
 139                     configMap = (Map<String, Object>) entry.getValue();
 140                 } else {
 141                     membersCopy.put(key, String.valueOf(entry.getValue()));
 142                 }
 143             }
 144             MVCGroupConfiguration configuration = getApplication().getMvcGroupManager().newMVCGroupConfiguration(type, membersCopy, configMap);
 145             getApplication().getMvcGroupManager().addConfiguration(configuration);
 146         }
 147     }
 148
 149     @Nonnull
 150     protected Map<String, GriffonAddon> getAddonsInternal() {
 151         return addons;
 152     }
 153
 154     protected void event(@Nonnull ApplicationEvent evt) {
 155         event(evt, asList(getApplication()));
 156     }
 157
 158     protected void event(@Nonnull ApplicationEvent evt, @Nonnull List<?> args) {
 159         getApplication().getEventRouter().publishEvent(evt.getName(), args);
 160     }
 161 }
 |