package org.jtheque.features.impl;
/*
* Copyright JTheque (Baptiste Wicht)
*
* 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.
*/
import org.jtheque.features.CoreFeature;
import org.jtheque.features.Feature;
import org.jtheque.features.Feature.FeatureType;
import org.jtheque.features.FeatureListener;
import org.jtheque.features.FeatureService;
import org.jtheque.features.Features;
import org.jtheque.features.Menu;
import org.jtheque.i18n.LanguageService;
import org.jtheque.modules.Module;
import org.jtheque.modules.ModuleListener;
import org.jtheque.modules.ModuleResourceCache;
import org.jtheque.modules.ModuleService;
import org.jtheque.utils.StringUtils;
import org.jtheque.utils.annotations.GuardedInternally;
import org.jtheque.utils.annotations.ThreadSafe;
import org.jtheque.utils.collections.CollectionUtils;
import org.jtheque.utils.collections.WeakEventListenerList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
/**
* A Feature manager.
*
* @author Baptiste Wicht
*/
@ThreadSafe
public final class FeatureServiceImpl implements FeatureService, ModuleListener {
@GuardedInternally
private final WeakEventListenerList<FeatureListener> listeners = WeakEventListenerList.create();
@GuardedInternally
//Because it's never modified after creation
private final Map<CoreFeature, Feature> coreFeatures;
@GuardedInternally
private final LanguageService languageService;
@GuardedInternally
private final Collection<Feature> features = CollectionUtils.newConcurrentList();
/**
* Construct a new FeatureServiceImpl.
*
* @param languageService The language service.
* @param moduleService The module service.
*/
public FeatureServiceImpl(LanguageService languageService, ModuleService moduleService) {
super();
this.languageService = languageService;
moduleService.addModuleListener("", this);
coreFeatures = new EnumMap<CoreFeature, Feature>(CoreFeature.class);
coreFeatures.put(CoreFeature.FILE, createAndAddFeature(0, "menu.file"));
coreFeatures.put(CoreFeature.EDIT, createAndAddFeature(1, "menu.edit"));
coreFeatures.put(CoreFeature.ADVANCED, createAndAddFeature(990, "menu.advanced"));
coreFeatures.put(CoreFeature.HELP, createAndAddFeature(1000, "menu.help"));
}
/**
* Create and add the feature.
*
* @param position The position of the feature.
* @param key The i18n key of the feature.
*
* @return The added feature.
*/
private Feature createAndAddFeature(int position, String key) {
Feature feature = Features.newPackFeature(position, key);
features.add(feature);
return feature;
}
@Override
public void addMenu(String moduleId, Menu menu) {
languageService.addInternationalizable(menu);
if (StringUtils.isNotEmpty(moduleId)) {
ModuleResourceCache.addResource(moduleId, Menu.class, menu);
}
for (CoreFeature feature : CoreFeature.values()) {
Collection<Feature> subFeatures = menu.getSubFeatures(feature);
if (!subFeatures.isEmpty()) {
coreFeatures.get(feature).addSubFeatures(subFeatures);
fireFeatureModified(coreFeatures.get(feature));
}
}
addFeatures(menu.getMainFeatures());
menu.refreshText(languageService);
}
/**
* Add the given features into the menu.
*
* @param newFeatures The features to add to the menu.
*/
private void addFeatures(Iterable<Feature> newFeatures) {
for (Feature feature : newFeatures) {
if (feature.getType() != FeatureType.PACK) {
throw new IllegalArgumentException("Can only add feature of type pack directly. ");
}
features.add(feature);
fireFeatureAdded(feature);
}
}
@Override
public Collection<Feature> getFeatures() {
return CollectionUtils.protect(features);
}
@Override
public void addFeatureListener(FeatureListener listener) {
listeners.add(listener);
}
@Override
public void removeFeatureListener(FeatureListener listener) {
listeners.remove(listener);
}
/**
* Avert the listeners thant a feature has been added.
*
* @param feature The feature who's been added.
*/
private void fireFeatureAdded(Feature feature) {
for (FeatureListener listener : listeners) {
if (listener != null) {
listener.featureAdded(feature);
}
}
}
/**
* Avert the listeners thant a feature has been removed.
*
* @param feature The feature who's been removed.
*/
private void fireFeatureRemoved(Feature feature) {
for (FeatureListener listener : listeners) {
if (listener != null) {
listener.featureRemoved(feature);
}
}
}
/**
* Avert the listeners thant a sub feature has been added in a specific feature.
*
* @param feature The feature in which the sub feature has been added.
*/
private void fireFeatureModified(Feature feature) {
for (FeatureListener listener : listeners) {
if (listener != null) {
listener.featureModified(feature);
}
}
}
@Override
public void moduleStopped(Module module) {
Set<Menu> resources = ModuleResourceCache.getResources(module.getId(), Menu.class);
for (Menu menu : resources) {
removeMenu(menu);
}
ModuleResourceCache.removeResourceOfType(module.getId(), Menu.class);
}
/**
* Remove the specified menu.
*
* @param menu The menu to remove.
*/
private void removeMenu(Menu menu) {
for (CoreFeature feature : CoreFeature.values()) {
coreFeatures.get(feature).removeSubFeatures(menu.getSubFeatures(feature));
fireFeatureModified(coreFeatures.get(feature));
}
for (Feature f : menu.getMainFeatures()) {
features.remove(f);
fireFeatureRemoved(f);
}
}
@Override
public void moduleStarted(Module module) {
//Nothing to do here
}
@Override
public void moduleInstalled(Module module) {
//Nothing to do here
}
@Override
public void moduleUninstalled(Module module) {
//Nothing to do here
}
}