/**
* Copyright (c) 1997, 2015 by ProSyst Software GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.automation.internal.core.provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.Condition;
import org.eclipse.smarthome.automation.Trigger;
import org.eclipse.smarthome.automation.internal.core.provider.i18n.ModuleI18nUtil;
import org.eclipse.smarthome.automation.internal.core.provider.i18n.ModuleTypeI18nUtil;
import org.eclipse.smarthome.automation.parser.Parser;
import org.eclipse.smarthome.automation.type.ActionType;
import org.eclipse.smarthome.automation.type.CompositeActionType;
import org.eclipse.smarthome.automation.type.CompositeConditionType;
import org.eclipse.smarthome.automation.type.CompositeTriggerType;
import org.eclipse.smarthome.automation.type.ConditionType;
import org.eclipse.smarthome.automation.type.Input;
import org.eclipse.smarthome.automation.type.ModuleType;
import org.eclipse.smarthome.automation.type.ModuleTypeProvider;
import org.eclipse.smarthome.automation.type.ModuleTypeRegistry;
import org.eclipse.smarthome.automation.type.Output;
import org.eclipse.smarthome.automation.type.TriggerType;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.osgi.framework.Bundle;
/**
* This class is implementation of {@link ModuleTypeProvider}. It serves for providing {@link ModuleType}s by loading
* bundle resources. It extends functionality of {@link AbstractResourceBundleProvider} by specifying:
* <ul>
* <li>the path to resources, corresponding to the {@link ModuleType}s - root directory
* {@link AbstractResourceBundleProvider#PATH} with sub-directory "moduletypes".
* <li>type of the {@link Parser}s, corresponding to the {@link ModuleType}s - {@link Parser#PARSER_MODULE_TYPE}
* <li>specific functionality for loading the {@link ModuleType}s
* <li>tracking the managing service of the {@link ModuleType}s.
* </ul>
*
* @author Ana Dimova - Initial Contribution
* @author Kai Kreuzer - refactored (managed) provider and registry implementation
* @author Yordan Mihaylov - updates related to api changes
*/
public class ModuleTypeResourceBundleProvider extends AbstractResourceBundleProvider<ModuleType>
implements ModuleTypeProvider {
protected ModuleTypeRegistry moduleTypeRegistry;
/**
* This constructor is responsible for initializing the path to resources and tracking the
* {@link ModuleTypeRegistry}.
*
* @param context is the {@code BundleContext}, used for creating a tracker for {@link Parser} services.
*/
public ModuleTypeResourceBundleProvider() {
listeners = new LinkedList<ProviderChangeListener<ModuleType>>();
path = PATH + "/moduletypes/";
}
@Override
public Collection<ModuleType> getAll() {
return providedObjectsHolder.values();
}
@Override
public void addProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
@Override
public void removeProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
/**
* @see ModuleTypeProvider#getModuleType(java.lang.String, java.util.Locale)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends ModuleType> T getModuleType(String UID, Locale locale) {
return (T) getPerLocale(providedObjectsHolder.get(UID), locale);
}
/**
* @see ModuleTypeProvider#getModuleTypes(java.util.Locale)
*/
@Override
public Collection<ModuleType> getModuleTypes(Locale locale) {
List<ModuleType> moduleTypesList = new ArrayList<ModuleType>();
for (ModuleType mt : providedObjectsHolder.values()) {
moduleTypesList.add(getPerLocale(mt, locale));
}
return moduleTypesList;
}
protected void setModuleTypeRegistry(ModuleTypeRegistry moduleTypeRegistry) {
this.moduleTypeRegistry = moduleTypeRegistry;
}
protected void removeModuleTypeRegistry(ModuleTypeRegistry moduleTypeRegistry) {
this.moduleTypeRegistry = null;
}
/**
* This method is responsible for checking the existence of {@link ModuleType}s with the same UIDs before these
* objects to be added in the system.
*
* @param uid UID of the newly created {@link ModuleType}, which to be checked.
* @return {@code true} if {@link ModuleType} with the same UID exists or {@code false} in the opposite case.
*/
@Override
protected boolean checkExistence(String uid) {
if (moduleTypeRegistry.get(uid) != null) {
logger.error("Module Type with UID \"{}\" already exists! Failed to create a second with the same UID!",
uid, new IllegalArgumentException());
return true;
}
return false;
}
@Override
protected String getUID(ModuleType parsedObject) {
return parsedObject.getUID();
}
/**
* This method is used to localize the {@link ModuleType}s.
*
* @param element is the {@link ModuleType} that must be localized.
* @param locale represents a specific geographical, political, or cultural region.
* @return the localized {@link ModuleType}.
*/
private ModuleType getPerLocale(ModuleType defModuleType, Locale locale) {
if (locale == null || defModuleType == null || i18nProvider == null) {
return defModuleType;
}
String uid = defModuleType.getUID();
Bundle bundle = getBundle(uid);
String llabel = ModuleTypeI18nUtil.getLocalizedModuleTypeLabel(i18nProvider, bundle, uid,
defModuleType.getLabel(), locale);
String ldescription = ModuleTypeI18nUtil.getLocalizedModuleTypeDescription(i18nProvider, bundle, uid,
defModuleType.getDescription(), locale);
List<ConfigDescriptionParameter> lconfigDescriptions = getLocalizedConfigurationDescription(i18nProvider,
defModuleType.getConfigurationDescriptions(), bundle, uid, ModuleTypeI18nUtil.MODULE_TYPE, locale);
if (defModuleType instanceof ActionType) {
return createLocalizedActionType((ActionType) defModuleType, bundle, uid, locale, lconfigDescriptions,
llabel, ldescription);
}
if (defModuleType instanceof ConditionType) {
return createLocalizedConditionType((ConditionType) defModuleType, bundle, uid, locale, lconfigDescriptions,
llabel, ldescription);
}
if (defModuleType instanceof TriggerType) {
return createLocalizedTriggerType((TriggerType) defModuleType, bundle, uid, locale, lconfigDescriptions,
llabel, ldescription);
}
return null;
}
/**
* Utility method for localization of ActionTypes.
*
* @param at is an ActionType for localization.
* @param bundle the bundle providing localization resources.
* @param moduleTypeUID is an ActionType uid.
* @param locale represents a specific geographical, political, or cultural region.
* @param lconfigDescriptions are ActionType localized config descriptions.
* @param llabel is an ActionType localized label.
* @param ldescription is an ActionType localized description.
* @return localized ActionType.
*/
private ActionType createLocalizedActionType(ActionType at, Bundle bundle, String moduleTypeUID, Locale locale,
List<ConfigDescriptionParameter> lconfigDescriptions, String llabel, String ldescription) {
List<Input> inputs = ModuleTypeI18nUtil.getLocalizedInputs(i18nProvider, at.getInputs(), bundle, moduleTypeUID,
locale);
List<Output> outputs = ModuleTypeI18nUtil.getLocalizedOutputs(i18nProvider, at.getOutputs(), bundle,
moduleTypeUID, locale);
ActionType lat = null;
if (at instanceof CompositeActionType) {
List<Action> modules = ModuleI18nUtil.getLocalizedModules(i18nProvider,
((CompositeActionType) at).getChildren(), bundle, moduleTypeUID, ModuleTypeI18nUtil.MODULE_TYPE,
locale);
lat = new CompositeActionType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, at.getTags(),
at.getVisibility(), inputs, outputs, modules);
} else {
lat = new ActionType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, at.getTags(),
at.getVisibility(), inputs, outputs);
}
return lat;
}
/**
* Utility method for localization of ConditionTypes.
*
* @param ct is a ConditionType for localization.
* @param bundle the bundle providing localization resources.
* @param moduleTypeUID is a ConditionType uid.
* @param locale represents a specific geographical, political, or cultural region.
* @param lconfigDescriptions are ConditionType localized config descriptions.
* @param llabel is a ConditionType localized label.
* @param ldescription is a ConditionType localized description.
* @return localized ConditionType.
*/
private ConditionType createLocalizedConditionType(ConditionType ct, Bundle bundle, String moduleTypeUID,
Locale locale, List<ConfigDescriptionParameter> lconfigDescriptions, String llabel, String ldescription) {
List<Input> inputs = ModuleTypeI18nUtil.getLocalizedInputs(i18nProvider, ct.getInputs(), bundle, moduleTypeUID,
locale);
ConditionType lct = null;
if (ct instanceof CompositeConditionType) {
List<Condition> modules = ModuleI18nUtil.getLocalizedModules(i18nProvider,
((CompositeConditionType) ct).getChildren(), bundle, moduleTypeUID, ModuleTypeI18nUtil.MODULE_TYPE,
locale);
lct = new CompositeConditionType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, ct.getTags(),
ct.getVisibility(), inputs, modules);
} else {
lct = new ConditionType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, ct.getTags(),
ct.getVisibility(), inputs);
}
return lct;
}
/**
* Utility method for localization of TriggerTypes.
*
* @param ct is a TriggerType for localization.
* @param bundle the bundle providing localization resources.
* @param moduleTypeUID is a TriggerType uid.
* @param locale represents a specific geographical, political, or cultural region.
* @param lconfigDescriptions are TriggerType localized config descriptions.
* @param llabel is a TriggerType localized label.
* @param ldescription is a TriggerType localized description.
* @return localized TriggerType.
*/
private TriggerType createLocalizedTriggerType(TriggerType tt, Bundle bundle, String moduleTypeUID, Locale locale,
List<ConfigDescriptionParameter> lconfigDescriptions, String llabel, String ldescription) {
List<Output> outputs = ModuleTypeI18nUtil.getLocalizedOutputs(i18nProvider, tt.getOutputs(), bundle,
moduleTypeUID, locale);
TriggerType ltt = null;
if (tt instanceof CompositeTriggerType) {
List<Trigger> modules = ModuleI18nUtil.getLocalizedModules(i18nProvider,
((CompositeTriggerType) tt).getChildren(), bundle, moduleTypeUID, ModuleTypeI18nUtil.MODULE_TYPE,
locale);
ltt = new CompositeTriggerType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, tt.getTags(),
tt.getVisibility(), outputs, modules);
} else {
ltt = new TriggerType(moduleTypeUID, lconfigDescriptions, llabel, ldescription, tt.getTags(),
tt.getVisibility(), outputs);
}
return ltt;
}
}