/* * Copyright 2008-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.griffon.runtime.core.addon; import griffon.core.ApplicationEvent; import griffon.core.GriffonApplication; import griffon.core.addon.AddonManager; import griffon.core.addon.GriffonAddon; import griffon.core.mvc.MVCGroupConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.inject.Inject; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static griffon.util.AnnotationUtils.sortByDependencies; import static griffon.util.CollectionUtils.reverse; import static griffon.util.GriffonNameUtils.getPropertyName; import static griffon.util.GriffonNameUtils.requireNonBlank; import static java.util.Arrays.asList; import static java.util.Objects.requireNonNull; /** * Base implementation of the {@code AddonManager} interface. * * @author Andres Almiray * @since 2.0.0 */ public abstract class AbstractAddonManager implements AddonManager { private static final Logger LOG = LoggerFactory.getLogger(AbstractAddonManager.class); private static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank"; private final Map<String, GriffonAddon> addons = new LinkedHashMap<>(); private final Object lock = new Object[0]; @GuardedBy("lock") private boolean initialized; private final GriffonApplication application; @Inject public AbstractAddonManager(@Nonnull GriffonApplication application) { this.application = requireNonNull(application, "Argument 'application' must not be null"); } @Nonnull public GriffonApplication getApplication() { return application; } @Nonnull public Map<String, GriffonAddon> getAddons() { return Collections.unmodifiableMap(addons); } @Nullable public GriffonAddon findAddon(@Nonnull String name) { requireNonBlank(name, ERROR_NAME_BLANK); if (name.endsWith(GriffonAddon.SUFFIX)) { name = name.substring(0, name.length() - 12); } return addons.get(getPropertyName(name)); } public final void initialize() { synchronized (lock) { if (!initialized) { doInitialize(); initialized = true; } } } protected void doInitialize() { LOG.debug("Loading addons [START]"); Map<String, GriffonAddon> addons = preloadAddons(); event(ApplicationEvent.LOAD_ADDONS_START); for (Map.Entry<String, GriffonAddon> entry : addons.entrySet()) { String name = entry.getKey(); GriffonAddon addon = entry.getValue(); LOG.debug("Loading addon {} with class {}", name, addon.getClass().getName()); event(ApplicationEvent.LOAD_ADDON_START, asList(getApplication(), name, addon)); getApplication().getEventRouter().addEventListener(addon); addMVCGroups(addon); addon.init(getApplication()); this.addons.put(name, addon); event(ApplicationEvent.LOAD_ADDON_END, asList(getApplication(), name, addon)); LOG.debug("Loaded addon {}", name); } for (GriffonAddon addon : reverse(addons.values())) { getApplication().addShutdownHandler(addon); } LOG.debug("Loading addons [END]"); event(ApplicationEvent.LOAD_ADDONS_END); } @Nonnull protected Map<String, GriffonAddon> preloadAddons() { Collection<GriffonAddon> addonInstances = getApplication().getInjector().getInstances(GriffonAddon.class); return sortByDependencies(addonInstances, GriffonAddon.SUFFIX, "addon"); } @SuppressWarnings("unchecked") protected void addMVCGroups(@Nonnull GriffonAddon addon) { for (Map.Entry<String, Map<String, Object>> groupEntry : addon.getMvcGroups().entrySet()) { String type = groupEntry.getKey(); LOG.debug("Adding MVC group {}", type); Map<String, Object> members = groupEntry.getValue(); Map<String, Object> configMap = new LinkedHashMap<>(); Map<String, String> membersCopy = new LinkedHashMap<>(); for (Map.Entry<String, Object> entry : members.entrySet()) { String key = String.valueOf(entry.getKey()); if ("config".equals(key) && entry.getValue() instanceof Map) { configMap = (Map<String, Object>) entry.getValue(); } else { membersCopy.put(key, String.valueOf(entry.getValue())); } } MVCGroupConfiguration configuration = getApplication().getMvcGroupManager().newMVCGroupConfiguration(type, membersCopy, configMap); getApplication().getMvcGroupManager().addConfiguration(configuration); } } @Nonnull protected Map<String, GriffonAddon> getAddonsInternal() { return addons; } protected void event(@Nonnull ApplicationEvent evt) { event(evt, asList(getApplication())); } protected void event(@Nonnull ApplicationEvent evt, @Nonnull List<?> args) { getApplication().getEventRouter().publishEvent(evt.getName(), args); } }