/**
* Copyright (c) 2017 Evolveum
*
* 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 com.evolveum.midpoint.provisioning.ucf.api.connectors;
import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.List;
import javax.xml.namespace.QName;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.schema.PrismSchema;
import com.evolveum.midpoint.provisioning.ucf.api.ConfigurationProperty;
import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance;
import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException;
import com.evolveum.midpoint.provisioning.ucf.api.ManagedConnectorConfiguration;
import com.evolveum.midpoint.provisioning.ucf.api.UcfUtil;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
/**
* @author semancik
*
*/
public abstract class AbstractManagedConnectorInstance implements ConnectorInstance {
private ConnectorType connectorObject;
private PrismSchema connectorConfigurationSchema;
private String resourceSchemaNamespace;
private PrismContext prismContext;
private PrismContainerValue<?> connectorConfiguration;
private ResourceSchema resourceSchema = null;
private Collection<Object> capabilities = null;
public ConnectorType getConnectorObject() {
return connectorObject;
}
public void setConnectorObject(ConnectorType connectorObject) {
this.connectorObject = connectorObject;
}
public PrismSchema getConnectorConfigurationSchema() {
return connectorConfigurationSchema;
}
public void setConnectorConfigurationSchema(PrismSchema connectorConfigurationSchema) {
this.connectorConfigurationSchema = connectorConfigurationSchema;
}
public PrismContainerValue<?> getConnectorConfiguration() {
return connectorConfiguration;
}
public void setConnectorConfiguration(PrismContainerValue<?> connectorConfiguration) {
this.connectorConfiguration = connectorConfiguration;
}
public String getResourceSchemaNamespace() {
return resourceSchemaNamespace;
}
public void setResourceSchemaNamespace(String resourceSchemaNamespace) {
this.resourceSchemaNamespace = resourceSchemaNamespace;
}
public PrismContext getPrismContext() {
return prismContext;
}
public void setPrismContext(PrismContext prismContext) {
this.prismContext = prismContext;
}
protected ResourceSchema getResourceSchema() {
return resourceSchema;
}
protected void setResourceSchema(ResourceSchema resourceSchema) {
this.resourceSchema = resourceSchema;
}
protected Collection<Object> getCapabilities() {
return capabilities;
}
protected void setCapabilities(Collection<Object> capabilities) {
this.capabilities = capabilities;
}
@Override
public void configure(PrismContainerValue<?> configuration, OperationResult parentResult)
throws CommunicationException, GenericFrameworkException, SchemaException,
ConfigurationException {
OperationResult result = parentResult.createSubresult(ConnectorInstance.OPERATION_CONFIGURE);
result.addParam("configuration", configuration);
boolean immutable = configuration.isImmutable();
try {
if (immutable) {
configuration.setImmutable(false);
}
configuration.applyDefinition(getConfigurationContainerDefinition());
} finally {
if (immutable) {
configuration.setImmutable(true);
}
}
setConnectorConfiguration(configuration);
applyConfigurationToConfigurationClass(configuration);
// TODO: transform configuration in a subclass
result.recordSuccessIfUnknown();
}
@Override
public void initialize(ResourceSchema resourceSchema, Collection<Object> capabilities,
boolean caseIgnoreAttributeNames, OperationResult parentResult)
throws CommunicationException, GenericFrameworkException, ConfigurationException {
OperationResult result = parentResult.createSubresult(ConnectorInstance.OPERATION_INITIALIZE);
result.addContext("connector", getConnectorObject());
result.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, this.getClass());
setResourceSchema(resourceSchema);
setCapabilities(capabilities);
connect(result);
result.recordSuccessIfUnknown();
}
protected abstract void connect(OperationResult result);
protected PrismContainerDefinition<?> getConfigurationContainerDefinition() throws SchemaException {
QName configContainerQName = new QName(getConnectorObject().getNamespace(),
ResourceType.F_CONNECTOR_CONFIGURATION.getLocalPart());
PrismContainerDefinition<?> configContainerDef = getConnectorConfigurationSchema()
.findContainerDefinitionByElementName(configContainerQName);
if (configContainerDef == null) {
throw new SchemaException("No definition of container " + configContainerQName
+ " in configuration schema for connector " + this);
}
return configContainerDef;
}
private void applyConfigurationToConfigurationClass(PrismContainerValue<?> configurationContainer) throws ConfigurationException {
BeanWrapper connectorBean = new BeanWrapperImpl(this);
PropertyDescriptor connectorConfigurationProp = UcfUtil.findAnnotatedProperty(connectorBean, ManagedConnectorConfiguration.class);
if (connectorConfigurationProp == null) {
return;
}
Class<?> configurationClass = connectorConfigurationProp.getPropertyType();
Object configurationObject;
try {
configurationObject = configurationClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new ConfigurationException("Cannot instantiate configuration "+configurationClass);
}
BeanWrapper configurationClassBean = new BeanWrapperImpl(configurationObject);
for (Item<?, ?> configurationItem: configurationContainer.getItems()) {
if (! (configurationItem instanceof PrismProperty<?>)) {
throw new ConfigurationException("Only properties are supported for now");
}
PrismProperty<?> configurationProperty = (PrismProperty<?>)configurationItem;
Object realValue = configurationProperty.getRealValue();
configurationClassBean.setPropertyValue(configurationProperty.getElementName().getLocalPart(), realValue);
}
connectorBean.setPropertyValue(connectorConfigurationProp.getName(), configurationObject);
}
}