/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ambari.server.state;
import java.io.File;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.stack.Validable;
import org.apache.ambari.server.state.stack.MetricDefinition;
import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.annotate.JsonFilter;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
@XmlAccessorType(XmlAccessType.FIELD)
@JsonFilter("propertiesfilter")
public class ServiceInfo implements Validable{
public static final AbstractMap.SimpleEntry<String, String> DEFAULT_SERVICE_INSTALLABLE_PROPERTY = new AbstractMap.SimpleEntry<>("installable", "true");
public static final AbstractMap.SimpleEntry<String, String> DEFAULT_SERVICE_MANAGED_PROPERTY = new AbstractMap.SimpleEntry<>("managed", "true");
public static final AbstractMap.SimpleEntry<String, String> DEFAULT_SERVICE_MONITORED_PROPERTY = new AbstractMap.SimpleEntry<>("monitored", "true");
/**
* Format version. Added at schema ver 2
*/
@XmlTransient
private String schemaVersion;
private String name;
private String displayName;
private String version;
private String comment;
private String serviceType;
private Selection selection;
@XmlTransient
private List<PropertyInfo> properties;
@XmlElementWrapper(name="components")
@XmlElements(@XmlElement(name="component"))
private List<ComponentInfo> components;
@XmlElement(name="deleted")
private boolean isDeleted = false;
@XmlElement(name="supportDeleteViaUI")
private Boolean supportDeleteViaUIField;
private boolean supportDeleteViaUIInternal = true;
@JsonIgnore
@XmlTransient
private volatile Map<String, Set<String>> configLayout = null;
@XmlElementWrapper(name="configuration-dependencies")
@XmlElement(name="config-type")
private List<String> configDependencies;
@XmlElementWrapper(name="excluded-config-types")
@XmlElement(name="config-type")
private Set<String> excludedConfigTypes = new HashSet<>();
@XmlTransient
private Map<String, Map<String, Map<String, String>>> configTypes;
@JsonIgnore
private Boolean monitoringService;
@JsonIgnore
@XmlElement(name = "restartRequiredAfterChange")
private Boolean restartRequiredAfterChange;
@JsonIgnore
@XmlElement(name = "restartRequiredAfterRackChange")
private Boolean restartRequiredAfterRackChange;
@XmlElement(name = "extends")
private String parent;
@XmlElement(name = "widgetsFileName")
private String widgetsFileName = AmbariMetaInfo.WIDGETS_DESCRIPTOR_FILE_NAME;
@XmlElement(name = "metricsFileName")
private String metricsFileName = AmbariMetaInfo.SERVICE_METRIC_FILE_NAME;
@XmlTransient
private volatile Map<String, PropertyInfo> requiredProperties;
/**
* Credential store information
*/
@XmlElements(@XmlElement(name = "credential-store"))
private CredentialStoreInfo credentialStoreInfo;
public Boolean isRestartRequiredAfterChange() {
return restartRequiredAfterChange;
}
public void setRestartRequiredAfterChange(Boolean restartRequiredAfterChange) {
this.restartRequiredAfterChange = restartRequiredAfterChange;
}
@XmlTransient
private File metricsFile = null;
@XmlTransient
private Map<String, Map<String, List<MetricDefinition>>> metrics = null;
@XmlTransient
private File advisorFile = null;
@XmlTransient
private String advisorName = null;
@XmlTransient
private File alertsFile = null;
@XmlTransient
private File kerberosDescriptorFile = null;
@XmlTransient
private File widgetsDescriptorFile = null;
private StackRoleCommandOrder roleCommandOrder;
@XmlTransient
private boolean valid = true;
@XmlElementWrapper(name = "properties")
@XmlElement(name="property")
private List<ServicePropertyInfo> servicePropertyList = Lists.newArrayList();
@XmlTransient
private Map<String, String> servicePropertyMap = ImmutableMap.copyOf(ensureMandatoryServiceProperties(Maps.<String, String>newHashMap()));
/**
*
* @return valid xml flag
*/
@Override
public boolean isValid() {
return valid;
}
/**
*
* @param valid set validity flag
*/
@Override
public void setValid(boolean valid) {
this.valid = valid;
}
@XmlTransient
private Set<String> errorSet = new HashSet<>();
@Override
public void addError(String error) {
errorSet.add(error);
}
@Override
public Collection<String> getErrors() {
return errorSet;
}
@Override
public void addErrors(Collection<String> errors) {
this.errorSet.addAll(errors);
}
/**
* Internal list of os-specific details (loaded from xml). Added at schema ver 2
*/
@JsonIgnore
@XmlElementWrapper(name="osSpecifics")
@XmlElements(@XmlElement(name="osSpecific"))
private List<ServiceOsSpecific> serviceOsSpecifics;
@JsonIgnore
@XmlElement(name="configuration-dir")
private String configDir = AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME;
@JsonIgnore
@XmlElement(name = "themes-dir")
private String themesDir = AmbariMetaInfo.SERVICE_THEMES_FOLDER_NAME;
@JsonIgnore
@XmlElementWrapper(name = "themes")
@XmlElements(@XmlElement(name = "theme"))
private List<ThemeInfo> themes;
@XmlTransient
private volatile Map<String, ThemeInfo> themesMap;
@JsonIgnore
@XmlElement(name = "quickLinksConfigurations-dir")
private String quickLinksConfigurationsDir = AmbariMetaInfo.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME;
@JsonIgnore
@XmlElementWrapper(name = "quickLinksConfigurations")
@XmlElements(@XmlElement(name = "quickLinksConfiguration"))
private List<QuickLinksConfigurationInfo> quickLinksConfigurations;
@XmlTransient
private volatile Map<String, QuickLinksConfigurationInfo> quickLinksConfigurationsMap;
/**
* Map of of os-specific details that is exposed (and initialised from list)
* at getter.
* Added at schema ver 2
*/
private volatile Map<String, ServiceOsSpecific> serviceOsSpecificsMap;
/**
* This is used to add service check actions for services.
* Added at schema ver 2
*/
private CommandScriptDefinition commandScript;
/**
* Added at schema ver 2
*/
@XmlElementWrapper(name="customCommands")
@XmlElements(@XmlElement(name="customCommand"))
private List<CustomCommandDefinition> customCommands;
@XmlElementWrapper(name="requiredServices")
@XmlElement(name="service")
private List<String> requiredServices = new ArrayList<>();
/**
* Meaning: stores subpath from stack root to exact directory, that contains
* service scripts and templates. Since schema ver 2,
* we may have multiple service metadata inside folder.
* Added at schema ver 2
*/
@XmlTransient
private String servicePackageFolder;
/**
* Stores the path to the upgrades folder which contains the upgrade xmls for the given service.
*/
@XmlTransient
private File serviceUpgradesFolder;
/**
* Stores the path to the checks folder which contains prereq check jars for the given service.
*/
@XmlTransient
private File checksFolder;
public boolean isDeleted() {
return isDeleted;
}
public void setDeleted(boolean deleted) {
isDeleted = deleted;
}
public Boolean getSupportDeleteViaUIField(){
return supportDeleteViaUIField;
}
public void setSupportDeleteViaUIField(Boolean supportDeleteViaUIField) {
this.supportDeleteViaUIField = supportDeleteViaUIField;
}
public boolean isSupportDeleteViaUI() {
if (null != supportDeleteViaUIField) {
return supportDeleteViaUIField.booleanValue();
}
// If set to null and has a parent, then the value would have already been resolved and set.
// Otherwise, return the default value (true).
return this.supportDeleteViaUIInternal;
}
public void setSupportDeleteViaUI(boolean supportDeleteViaUI){
this.supportDeleteViaUIInternal = supportDeleteViaUI;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getServiceType() {
return serviceType;
}
public void setServiceType(String serviceType) {
this.serviceType = serviceType;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Selection getSelection() {
if (selection == null) {
return Selection.DEFAULT;
}
return selection;
}
public void setSelection(Selection selection) {
this.selection = selection;
}
/**
* Check if selection was presented in xml. We need this for proper stack inheritance, because {@link ServiceInfo#getSelection}
* by default returns {@link Selection#DEFAULT}, even if no value found in metainfo.xml.
* @return true, if selection not defined in metainfo.xml
*/
public boolean isSelectionEmpty() {
return selection == null;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public List<String> getRequiredServices() {
return requiredServices;
}
public String getWidgetsFileName() {
return widgetsFileName;
}
public void setWidgetsFileName(String widgetsFileName) {
this.widgetsFileName = widgetsFileName;
}
public String getMetricsFileName() {
return metricsFileName;
}
public void setMetricsFileName(String metricsFileName) {
this.metricsFileName = metricsFileName;
}
public void setRequiredServices(List<String> requiredServices) {
this.requiredServices = requiredServices;
}
public List<PropertyInfo> getProperties() {
if (properties == null) properties = new ArrayList<>();
return properties;
}
public void setProperties(List properties) {
this.properties = properties;
}
public List<ComponentInfo> getComponents() {
if (components == null) components = new ArrayList<>();
return components;
}
/**
* Finds ComponentInfo by component name
* @param componentName name of the component
* @return ComponentInfo componentName or null
*/
public ComponentInfo getComponentByName(String componentName){
for(ComponentInfo componentInfo : getComponents()) {
if(componentInfo.getName().equals(componentName)){
return componentInfo;
}
}
return null;
}
public boolean isClientOnlyService() {
if (components == null || components.isEmpty()) {
return false;
}
for (ComponentInfo compInfo : components) {
if (!compInfo.isClient()) {
return false;
}
}
return true;
}
public ComponentInfo getClientComponent() {
ComponentInfo client = null;
if (components != null) {
for (ComponentInfo compInfo : components) {
if (compInfo.isClient()) {
client = compInfo;
break;
}
}
}
return client;
}
public File getAdvisorFile() {
return advisorFile;
}
public void setAdvisorFile(File advisorFile) {
this.advisorFile = advisorFile;
}
public String getAdvisorName() {
return advisorName;
}
public void setAdvisorName(String advisorName) {
this.advisorName = advisorName;
}
/**
* Indicates if this service supports credential store.
* False, it was not specified.
*
* @return true or false
*/
public boolean isCredentialStoreSupported() {
if (credentialStoreInfo != null) {
if (credentialStoreInfo.isSupported() != null) {
return credentialStoreInfo.isSupported();
}
}
return false;
}
/**
* Set a value indicating if this service supports credential store.
* @param credentialStoreSupported
*/
public void setCredentialStoreSupported(boolean credentialStoreSupported) {
if (credentialStoreInfo == null) {
credentialStoreInfo = new CredentialStoreInfo();
}
credentialStoreInfo.setSupported(credentialStoreSupported);
}
/**
* Indicates if this service is requires credential store.
* False if it was not specified.
*
* @return true or false
*/
public boolean isCredentialStoreRequired() {
if (credentialStoreInfo != null) {
if (credentialStoreInfo.isRequired() != null) {
return credentialStoreInfo.isRequired();
}
}
return false;
}
/**
* Set a value indicating if this service requires credential store.
* @param credentialStoreRequired
*/
public void setCredentialStoreRequired(boolean credentialStoreRequired) {
if (credentialStoreInfo == null) {
credentialStoreInfo = new CredentialStoreInfo();
}
credentialStoreInfo.setRequired(credentialStoreRequired);
}
/**
* Indicates if this service is enabled for credential store use.
* False if it was not specified.
*
* @return true or false
*/
public boolean isCredentialStoreEnabled() {
if (credentialStoreInfo != null) {
if (credentialStoreInfo.isEnabled() != null) {
return credentialStoreInfo.isEnabled();
}
}
return false;
}
/**
* Set a value indicating if this service is enabled for credential store use.
* @param credentialStoreEnabled
*/
public void setCredentialStoreEnabled(boolean credentialStoreEnabled) {
if (credentialStoreInfo == null) {
credentialStoreInfo = new CredentialStoreInfo();
}
credentialStoreInfo.setEnabled(credentialStoreEnabled);
}
/**
* Get the credential store information object.
*
* @return
*/
public CredentialStoreInfo getCredentialStoreInfo() {
return credentialStoreInfo;
}
/**
* Set a new value for the credential store information.
*
* @param credentialStoreInfo
*/
public void setCredentialStoreInfo(CredentialStoreInfo credentialStoreInfo) {
this.credentialStoreInfo = credentialStoreInfo;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service name:");
sb.append(name);
sb.append("\nService type:");
sb.append(serviceType);
sb.append("\nversion:");
sb.append(version);
sb.append("\ncomment:");
sb.append(comment);
//for (PropertyInfo property : getProperties()) {
// sb.append("\tProperty name=" + property.getName() +
//"\nproperty value=" + property.getValue() + "\ndescription=" + property.getDescription());
//}
for (ComponentInfo component : getComponents()) {
sb.append("\n\n\nComponent:\n");
sb.append("name=");
sb.append(component.getName());
sb.append("\tcategory=");
sb.append(component.getCategory());
}
return sb.toString();
}
/**
* Obtain the config types associated with this service.
* The returned map is an unmodifiable view.
* @return unmodifiable map of config types associated with this service
*/
public synchronized Map<String, Map<String, Map<String, String>>> getConfigTypeAttributes() {
Map<String, Map<String, Map<String, String>>> tmpConfigTypes = configTypes == null ?
new HashMap<String, Map<String, Map<String, String>>>() : configTypes;
for(String excludedtype : excludedConfigTypes){
tmpConfigTypes.remove(excludedtype);
}
return Collections.unmodifiableMap(tmpConfigTypes);
}
/**
* Add the given type and set it's attributes.
* If the type is marked for exclusion, it will not be added.
*
* @param type configuration type
* @param typeAttributes attributes associated with the type
*/
public synchronized void setTypeAttributes(String type, Map<String, Map<String, String>> typeAttributes) {
if (this.configTypes == null) {
configTypes = new HashMap<>();
}
configTypes.put(type, typeAttributes);
}
/**
* Set all types and associated attributes. Any previously existing types and
* attributes are removed prior to setting the new values.
*
* @param types map of type attributes
*/
public synchronized void setAllConfigAttributes(Map<String, Map<String, Map<String, String>>> types) {
configTypes = new HashMap<>();
for (Map.Entry<String, Map<String, Map<String, String>>> entry : types.entrySet()) {
setTypeAttributes(entry.getKey(), entry.getValue());
}
}
/**
* Determine of the service has a dependency on the provided configuration type.
* @param type the config type
* @return <code>true</code> if the service defines a dependency on the provided type
*/
public boolean hasConfigDependency(String type) {
return configDependencies != null && configDependencies.contains(type);
}
/**
* Determine if the service contains the specified config type
* @param type config type to check
* @return true if the service has the specified config type; false otherwise
*/
public boolean hasConfigType(String type) {
return configTypes != null && configTypes.containsKey(type)
&& !excludedConfigTypes.contains(type);
}
/**
* Determine if the service has a dependency on the provided type and contains any of the provided properties.
* This can be used in determining if a property is stale.
* @param type the config type
* @param keyNames the names of all the config keys for the given type
* @return <code>true</code> if the config is stale
*/
public boolean hasDependencyAndPropertyFor(String type, Collection<String> keyNames) {
if (!hasConfigDependency(type))
return false;
buildConfigLayout();
Set<String> keys = configLayout.get(type);
for (String staleCheck : keyNames) {
if (keys != null && keys.contains(staleCheck))
return true;
}
return false;
}
/**
* Builds the config map specific to this service.
*/
private void buildConfigLayout() {
if (null == configLayout) {
synchronized(this) {
if (null == configLayout) {
configLayout = new HashMap<>();
for (PropertyInfo pi : getProperties()) {
String type = pi.getFilename();
int idx = type.indexOf(".xml");
type = type.substring(0, idx);
if (!configLayout.containsKey(type))
configLayout.put(type, new HashSet<String>());
configLayout.get(type).add(pi.getName());
}
}
}
}
}
public List<String> getConfigDependencies() {
return configDependencies;
}
public List<String> getConfigDependenciesWithComponents(){
List<String> retVal = new ArrayList<>();
if(configDependencies != null){
retVal.addAll(configDependencies);
}
if(components != null){
for (ComponentInfo c : components) {
if(c.getConfigDependencies() != null){
retVal.addAll(c.getConfigDependencies());
}
}
}
return retVal.size() == 0 ? (configDependencies == null ? null : configDependencies) : retVal;
}
public void setConfigDependencies(List<String> configDependencies) {
this.configDependencies = configDependencies;
}
public String getSchemaVersion() {
if (schemaVersion == null) {
return AmbariMetaInfo.SCHEMA_VERSION_2;
} else {
return schemaVersion;
}
}
public void setSchemaVersion(String schemaVersion) {
this.schemaVersion = schemaVersion;
}
public String getServicePackageFolder() {
return servicePackageFolder;
}
public void setServicePackageFolder(String servicePackageFolder) {
this.servicePackageFolder = servicePackageFolder;
}
public File getServiceUpgradesFolder() {
return serviceUpgradesFolder;
}
public void setServiceUpgradesFolder(File serviceUpgradesFolder) {
this.serviceUpgradesFolder = serviceUpgradesFolder;
}
public File getChecksFolder() {
return checksFolder;
}
public void setChecksFolder(File checksFolder) {
this.checksFolder = checksFolder;
}
/**
* Exposes (and initializes on first use) map of os-specific details.
* @return map of OS specific details keyed by family
*/
public Map<String, ServiceOsSpecific> getOsSpecifics() {
if (serviceOsSpecificsMap == null) {
synchronized (this) { // Double-checked locking pattern
if (serviceOsSpecificsMap == null) {
Map<String, ServiceOsSpecific> tmpMap =
new TreeMap<>();
if (serviceOsSpecifics != null) {
for (ServiceOsSpecific osSpecific : serviceOsSpecifics) {
tmpMap.put(osSpecific.getOsFamily(), osSpecific);
}
}
serviceOsSpecificsMap = tmpMap;
}
}
}
return serviceOsSpecificsMap;
}
public void setOsSpecifics(Map<String, ServiceOsSpecific> serviceOsSpecificsMap) {
this.serviceOsSpecificsMap = serviceOsSpecificsMap;
}
public List<CustomCommandDefinition> getCustomCommands() {
if (customCommands == null) {
customCommands = new ArrayList<>();
}
return customCommands;
}
public void setCustomCommands(List<CustomCommandDefinition> customCommands) {
this.customCommands = customCommands;
}
public CommandScriptDefinition getCommandScript() {
return commandScript;
}
public void setCommandScript(CommandScriptDefinition commandScript) {
this.commandScript = commandScript;
}
/**
* @param file the file containing the metrics definitions
*/
public void setMetricsFile(File file) {
metricsFile = file;
}
/**
* @return the metrics file, or <code>null</code> if none exists
*/
public File getMetricsFile() {
return metricsFile;
}
/**
* @return the metrics defined for this service
*/
public Map<String, Map<String, List<MetricDefinition>>> getMetrics() {
return metrics;
}
/**
* @param map the metrics for this service
*/
public void setMetrics(Map<String, Map<String, List<MetricDefinition>>> map) {
metrics = map;
}
/**
* @return the configuration directory name
*/
public String getConfigDir() {
return configDir;
}
/**
* @return whether the service is a monitoring service
*/
public Boolean isMonitoringService() {
return monitoringService;
}
/**
* @param monitoringService whether the service is a monitoring service
*/
public void setMonitoringService(Boolean monitoringService) {
this.monitoringService = monitoringService;
}
/**
* @param file the file containing the alert definitions
*/
public void setAlertsFile(File file) {
alertsFile = file;
}
/**
* @return the alerts file, or <code>null</code> if none exists
*/
public File getAlertsFile() {
return alertsFile;
}
/**
* @param file the file containing the alert definitions
*/
public void setKerberosDescriptorFile(File file) {
kerberosDescriptorFile = file;
}
/**
* @return the kerberos descriptor file, or <code>null</code> if none exists
*/
public File getKerberosDescriptorFile() {
return kerberosDescriptorFile;
}
/**
* @return the widgets descriptor file, or <code>null</code> if none exists
*/
public File getWidgetsDescriptorFile() {
return widgetsDescriptorFile;
}
public void setWidgetsDescriptorFile(File widgetsDescriptorFile) {
this.widgetsDescriptorFile = widgetsDescriptorFile;
}
public StackRoleCommandOrder getRoleCommandOrder() {
return roleCommandOrder;
}
public void setRoleCommandOrder(StackRoleCommandOrder roleCommandOrder) {
this.roleCommandOrder = roleCommandOrder;
}
/**
* @return config types this service contains configuration for, but which are primarily related to another service
*/
public Set<String> getExcludedConfigTypes() {
return excludedConfigTypes;
}
public void setExcludedConfigTypes(Set<String> excludedConfigTypes) {
this.excludedConfigTypes = excludedConfigTypes;
}
//todo: ensure that required properties are never modified...
public Map<String, PropertyInfo> getRequiredProperties() {
Map<String, PropertyInfo> result = requiredProperties;
if (result == null) {
synchronized(this) {
result = requiredProperties;
if (result == null) {
requiredProperties = result = new HashMap<>();
List<PropertyInfo> properties = getProperties();
for (PropertyInfo propertyInfo : properties) {
if (propertyInfo.isRequireInput()) {
result.put(propertyInfo.getName(), propertyInfo);
}
}
}
}
}
return result;
}
/**
* Determine whether or not a restart is required for this service after a host rack info change.
*
* @return true if a restart is required
*/
public Boolean isRestartRequiredAfterRackChange() {
return restartRequiredAfterRackChange;
}
/**
* Set indicator for required restart after a host rack info change.
*
* @param restartRequiredAfterRackChange true if a restart is required
*/
public void setRestartRequiredAfterRackChange(Boolean restartRequiredAfterRackChange) {
this.restartRequiredAfterRackChange = restartRequiredAfterRackChange;
}
public String getThemesDir() {
return themesDir;
}
public void setThemesDir(String themesDir) {
this.themesDir = themesDir;
}
public List<ThemeInfo> getThemes() {
return themes;
}
public void setThemes(List<ThemeInfo> themes) {
this.themes = themes;
}
public Map<String, ThemeInfo> getThemesMap() {
if (themesMap == null) {
Map<String, ThemeInfo> tmp = new TreeMap<>();
if (themes != null) {
for (ThemeInfo theme : themes) {
tmp.put(theme.getFileName(), theme);
}
}
themesMap = tmp;
}
return themesMap;
}
public void setThemesMap(Map<String, ThemeInfo> themesMap) {
this.themesMap = themesMap;
}
//Quick links configurations
public String getQuickLinksConfigurationsDir() {
return quickLinksConfigurationsDir;
}
public void setQuickLinksConfigurationsDir(String quickLinksConfigurationsDir) {
this.quickLinksConfigurationsDir = quickLinksConfigurationsDir;
}
public List<QuickLinksConfigurationInfo> getQuickLinksConfigurations() {
return quickLinksConfigurations;
}
public void setQuickLinksConfigurations(List<QuickLinksConfigurationInfo> quickLinksConfigurations) {
this.quickLinksConfigurations = quickLinksConfigurations;
}
public Map<String, QuickLinksConfigurationInfo> getQuickLinksConfigurationsMap() {
if (quickLinksConfigurationsMap == null) {
Map<String, QuickLinksConfigurationInfo> tmp = new TreeMap<>();
if (quickLinksConfigurations != null) {
for (QuickLinksConfigurationInfo quickLinksConfiguration : quickLinksConfigurations) {
tmp.put(quickLinksConfiguration.getFileName(), quickLinksConfiguration);
}
}
quickLinksConfigurationsMap = tmp;
}
return quickLinksConfigurationsMap;
}
public void setQuickLinksConfigurationsMap(Map<String, QuickLinksConfigurationInfo> quickLinksConfigurationsMap) {
this.quickLinksConfigurationsMap = quickLinksConfigurationsMap;
}
public List<ServicePropertyInfo> getServicePropertyList() {
return servicePropertyList;
}
public void setServicePropertyList(List<ServicePropertyInfo> servicePropertyList) {
this.servicePropertyList = servicePropertyList;
afterServicePropertyListSet();
}
private void afterServicePropertyListSet(){
validateServiceProperties();
buildServiceProperties();
}
/**
* Returns the service properties defined in the xml service definition.
* @return Service property map
*/
public Map<String, String> getServiceProperties() {
return servicePropertyMap;
}
/**
* Constructs the map that stores the service properties defined in the xml service definition.
* The keys are the property names and values the property values.
* It ensures that missing required service properties are added with default values.
*/
private void buildServiceProperties() {
if (isValid()) {
Map<String, String> properties = Maps.newHashMap();
for (ServicePropertyInfo property : getServicePropertyList()) {
properties.put(property.getName(), property.getValue());
}
servicePropertyMap = ImmutableMap.copyOf(ensureMandatoryServiceProperties(properties));
}
else
servicePropertyMap = ImmutableMap.of();
}
private Map<String, String> ensureMandatoryServiceProperties(Map<String, String> properties) {
return ensureVisibilityServiceProperties(properties);
}
private Map<String, String> ensureVisibilityServiceProperties(Map<String, String> properties) {
if (!properties.containsKey(DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey()))
properties.put(DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey(), DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getValue());
if (!properties.containsKey(DEFAULT_SERVICE_MANAGED_PROPERTY.getKey()))
properties.put(DEFAULT_SERVICE_MANAGED_PROPERTY.getKey(), DEFAULT_SERVICE_MANAGED_PROPERTY.getValue());
if (!properties.containsKey(DEFAULT_SERVICE_MONITORED_PROPERTY.getKey()))
properties.put(DEFAULT_SERVICE_MONITORED_PROPERTY.getKey(), DEFAULT_SERVICE_MONITORED_PROPERTY.getValue());
return properties;
}
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
afterServicePropertyListSet();
}
private void validateServiceProperties() {
// Verify if there are duplicate service properties by name
Multimap<String, ServicePropertyInfo> servicePropsByName = Multimaps.index(
getServicePropertyList(),
new Function<ServicePropertyInfo, String>() {
@Override
public String apply(ServicePropertyInfo servicePropertyInfo) {
return servicePropertyInfo.getName();
}
}
);
for (String propertyName: servicePropsByName.keySet()) {
if (servicePropsByName.get(propertyName).size() > 1) {
setValid(false);
addError("Duplicate service property with name '" + propertyName + "' found in " + getName() + ":" + getVersion() + " service definition !");
}
}
for (ComponentInfo component : getComponents()) {
int primaryLogs = 0;
for (LogDefinition log : component.getLogs()) {
primaryLogs += log.isPrimary() ? 1 : 0;
}
if (primaryLogs > 1) {
setValid(false);
addError("More than one primary log exists for the component " + component.getName());
}
}
// validate credential store information
if (credentialStoreInfo != null) {
// if both are specified, supported must be true if enabled is false or true.
if (credentialStoreInfo.isSupported() != null && credentialStoreInfo.isEnabled() != null) {
if (!credentialStoreInfo.isSupported() && credentialStoreInfo.isEnabled()) {
setValid(false);
addError("Credential store cannot be enabled for service " + getName() + " as it does not support it.");
}
}
// Must be specified
if (credentialStoreInfo.isSupported() == null) {
setValid(false);
addError("Credential store supported is not specified for service " + getName());
}
// Must be specified
if (credentialStoreInfo.isEnabled() == null) {
setValid(false);
addError("Credential store enabled is not specified for service " + getName());
}
}
}
public enum Selection {
DEFAULT,
TECH_PREVIEW,
MANDATORY,
DEPRECATED
}
}