/*
* Jopr Management Platform
* Copyright (C) 2005-2009 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.plugins.jbossas5.serviceBinding;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.deployers.spi.management.ManagementView;
import org.jboss.managed.api.ManagedComponent;
import org.jboss.managed.api.ManagedProperty;
import org.jboss.managed.api.RunState;
import org.jboss.metatype.api.types.CollectionMetaType;
import org.jboss.metatype.api.types.ImmutableCompositeMetaType;
import org.jboss.metatype.api.types.MetaType;
import org.jboss.metatype.api.values.CollectionValue;
import org.jboss.metatype.api.values.CollectionValueSupport;
import org.jboss.metatype.api.values.CompositeValue;
import org.jboss.metatype.api.values.MapCompositeValueSupport;
import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.SimpleValue;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.resource.CreateResourceStatus;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet;
import org.rhq.core.pluginapi.inventory.CreateResourceReport;
import org.rhq.plugins.jbossas5.ManagedComponentComponent;
import org.rhq.plugins.jbossas5.serviceBinding.Util.PropertyDefinition;
/**
* Manager component for the Service Binding Manager.
*
* @author Heiko W. Rupp
* @author Lukas Krejci
*/
public class ManagerComponent extends ManagedComponentComponent implements CreateChildResourceFacet {
private final Log log = LogFactory.getLog(this.getClass());
private static final String BINDING_PROPERTY = "binding";
private static final String BINDING_SET_SERVICE_NAME = "Service Binding Set";
private static final String RESOURCE_KEY_SEPARATOR = "!)@(#*";
@Override
protected AvailabilityType getAvailabilityForRunState(RunState runState) {
// This is a workaround for a bug where the binding manager MO will return a run state of UNKNOWN even when it's
// happily running.
return (runState == RunState.RUNNING || runState == RunState.UNKNOWN) ?
AvailabilityType.UP : AvailabilityType.DOWN;
}
// ConfigurationFacet -----------------------------
@Override
public Configuration loadResourceConfiguration() {
ManagedComponent bindingManagerComponent = getBindingManager();
Configuration configuration = new Configuration();
String activeBindingSetName = Util.getValue((SimpleValue) bindingManagerComponent.getProperty(
Util.ACTIVE_BINDING_SET_NAME_PROPERTY).getValue(), String.class);
configuration.put(new PropertySimple(Util.ACTIVE_BINDING_SET_NAME_PROPERTY, activeBindingSetName));
CollectionValue standardBindings = (CollectionValue) bindingManagerComponent.getProperty(
Util.STANDARD_BINDINGS_PROPERTY).getValue();
PropertyList bindings = new PropertyList(Util.STANDARD_BINDINGS_PROPERTY);
configuration.put(bindings);
for (MetaValue b : standardBindings.getElements()) {
CompositeValue binding = (CompositeValue) b;
PropertyMap bindingMap = new PropertyMap(BINDING_PROPERTY);
bindings.add(bindingMap);
for (PropertySimple prop : Util.getProperties(Arrays.asList(Util.STANDARD_BINDING_PROPERTIES), binding)) {
bindingMap.put(prop);
}
}
return configuration;
}
@Override
public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) {
try {
Configuration updatedConfiguration = configurationUpdateReport.getConfiguration();
ManagedComponent bindingManagerComponent = getBindingManager();
//check that provided active binding set name is valid
ManagedProperty bindingSetsProperty = bindingManagerComponent.getProperty(Util.BINDING_SETS_PROPERTY);
CollectionValue bindingSets = (CollectionValue) bindingSetsProperty.getValue();
String updatedActiveBindingSetName = updatedConfiguration.getSimpleValue(
Util.ACTIVE_BINDING_SET_NAME_PROPERTY, null);
if (updatedActiveBindingSetName == null || updatedActiveBindingSetName.trim().length() == 0) {
configurationUpdateReport.setErrorMessage("Active binding set name must be set.");
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.FAILURE);
}
boolean found = false;
for (MetaValue bindingSet : bindingSets) {
CompositeValue bindingSetComposite = (CompositeValue)bindingSet;
String bindingSetName = Util.getValue(bindingSetComposite, "name", String.class);
if (updatedActiveBindingSetName.equals(bindingSetName)) {
found = true;
break;
}
}
if (!found) {
configurationUpdateReport
.setErrorMessage("A binding set with the provided name does not exist - cannot set it as active.");
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.FAILURE);
return;
}
bindingManagerComponent.getProperty(Util.ACTIVE_BINDING_SET_NAME_PROPERTY).setValue(
Util.wrap(updatedConfiguration.getSimple(Util.ACTIVE_BINDING_SET_NAME_PROPERTY), String.class));
PropertyList standardBindingsList = updatedConfiguration.getList(Util.STANDARD_BINDINGS_PROPERTY);
MetaValue[] standarBindingsArray = new MetaValue[standardBindingsList.getList().size()];
CollectionValueSupport standardBindingsValue = new CollectionValueSupport(
(CollectionMetaType) bindingManagerComponent.getProperty(Util.STANDARD_BINDINGS_PROPERTY).getMetaType());
standardBindingsValue.setElements(standarBindingsArray);
ImmutableCompositeMetaType bindingMetaType = (ImmutableCompositeMetaType) standardBindingsValue
.getMetaType().getElementType();
int i = 0;
for (Property p : standardBindingsList.getList()) {
PropertyMap standardBindingMap = (PropertyMap) p;
MapCompositeValueSupport binding = new MapCompositeValueSupport(bindingMetaType);
for (PropertyDefinition def : Util.STANDARD_BINDING_PROPERTIES) {
binding.put(def.propertyName, Util.wrap(standardBindingMap.getSimple(def.propertyName),
def.propertyType));
}
standarBindingsArray[i++] = binding;
}
bindingManagerComponent.getProperty(Util.STANDARD_BINDINGS_PROPERTY).setValue(standardBindingsValue);
updateBindingManager(bindingManagerComponent);
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.SUCCESS);
} catch (Exception e) {
log.warn("Failed to update SBM configuration.", e);
configurationUpdateReport.setErrorMessageFromThrowable(e);
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.FAILURE);
}
}
// CreateChildResourceFacet ----------------------------------------------
public CreateResourceReport createResource(CreateResourceReport report) {
try {
ManagedComponent bindingManagerComponent = getBindingManager();
if (BINDING_SET_SERVICE_NAME.equals(report.getResourceType().getName())) {
Configuration bindingConfiguration = report.getResourceConfiguration();
checkValidity(bindingConfiguration);
CompositeValue newBindingSet = Util.getBindingSetFromConfiguration(
getBindingSetValueMetaType(bindingManagerComponent), bindingConfiguration);
//ok, now we can update the bindingSets property with the update set of binding sets
ManagedProperty bindingSetsProperty = bindingManagerComponent.getProperty(Util.BINDING_SETS_PROPERTY);
//check that the provided binding set name is unique
CollectionValue bindingSets = (CollectionValue) bindingSetsProperty.getValue();
String newBindingSetName = Util.getValue(newBindingSet, "name", String.class);
for (MetaValue bindingSet : bindingSets) {
CompositeValue bindingSetComposite = (CompositeValue)bindingSet;
String bindingSetName = Util.getValue(bindingSetComposite, "name", String.class);
if (newBindingSetName.equals(bindingSetName)) {
report.setErrorMessage("A binding set with the provided name already exists.");
report.setStatus(CreateResourceStatus.FAILURE);
return report;
}
}
// Create a new array that's one element larger than the original array.
MetaValue[] newBindingSets = new MetaValue[bindingSets.getSize() + 1];
// Copy the original array into the new array.
System.arraycopy(bindingSets.getElements(), 0, newBindingSets, 0, bindingSets.getSize());
// Add the new one as the last element of the new array.
newBindingSets[bindingSets.getSize()] = newBindingSet;
CollectionValueSupport newBindingSetsValue = new CollectionValueSupport(bindingSets.getMetaType());
newBindingSetsValue.setElements(newBindingSets);
bindingSetsProperty.setValue(newBindingSetsValue);
updateBindingManager(bindingManagerComponent);
report.setResourceKey(getBindingSetResourceKey(newBindingSetName));
report.setResourceName(newBindingSetName);
report.setStatus(CreateResourceStatus.SUCCESS);
}
} catch (Exception e) {
log.warn("Failed to create service " + report.getResourceType().getName(), e);
report.setException(e);
report.setStatus(CreateResourceStatus.FAILURE);
}
return report;
}
public MetaType getBindingSetValueMetaType(ManagedComponent bindingManager) {
CollectionMetaType bindingSetsMetaType = (CollectionMetaType) bindingManager.getProperty(
Util.BINDING_SETS_PROPERTY).getMetaType();
return bindingSetsMetaType.getElementType();
}
public ManagedComponent getBindingManager() {
return getManagedComponent();
}
public void updateBindingManager(ManagedComponent bindingManagerComponent) throws Exception {
ManagementView managementView = getConnection().getManagementView();
managementView.updateComponent(bindingManagerComponent);
managementView.load();
}
public String getBindingSetResourceKey(String bindingSetName) {
return getResourceContext().getResourceKey() + RESOURCE_KEY_SEPARATOR + bindingSetName;
}
public String getBindingSetNameFromResourceKey(String resourceKey) {
int separatorIdx = resourceKey.lastIndexOf(RESOURCE_KEY_SEPARATOR);
return resourceKey.substring(separatorIdx + RESOURCE_KEY_SEPARATOR.length());
}
/**
* Checks the validity of the binding set configuration before it is submitted to the
* Profile Service.
*
* This is to work around JOPR-372.
*
* @param bindingSetConfiguration
*
* @throws IllegalArgumentException if some of the required properties is null or empty
* @throws UnknownHostException if default host name is invalid
*/
public void checkValidity(Configuration bindingSetConfiguration) throws IllegalArgumentException, UnknownHostException {
String name = bindingSetConfiguration.getSimpleValue(Util.NAME_PROPERTY, null);
if (name == null || name.trim().length() == 0) {
throw new IllegalArgumentException("Name of the binding set must not be empty.");
}
String defaultHostName = bindingSetConfiguration.getSimpleValue(Util.DEFAULT_HOST_NAME_PROPERTY, null);
if (defaultHostName == null || defaultHostName.trim().length() == 0) {
throw new IllegalArgumentException("The default host name of the binding set must not be empty.");
}
//check that the hostname is valid
InetAddress.getByName(defaultHostName);
}
}