/* * Copyright (c) 2010-2015 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.model.impl.scripting.actions; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.ReferenceDelta; import com.evolveum.midpoint.prism.query.AndFilter; import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.*; /** * @author mederly */ @Component public class DiscoverConnectorsExecutor extends BaseActionExecutor { private static final Trace LOGGER = TraceManager.getTrace(DiscoverConnectorsExecutor.class); private static final String NAME = "discover-connectors"; private static final String PARAM_REBIND_RESOURCES = "rebindResources"; @PostConstruct public void init() { scriptingExpressionEvaluator.registerActionExecutor(NAME, this); } @Override public Data execute(ActionExpressionType expression, Data input, ExecutionContext context, OperationResult result) throws ScriptExecutionException { boolean rebind = expressionHelper.getArgumentAsBoolean(expression.getParameter(), PARAM_REBIND_RESOURCES, input, context, false, PARAM_REBIND_RESOURCES, result); Data output = Data.createEmpty(); for (PrismValue value: input.getData()) { context.checkTaskStop(); if (value instanceof PrismObjectValue && ((PrismObjectValue) value).asObjectable() instanceof ConnectorHostType) { PrismObject<ConnectorHostType> connectorHostTypePrismObject = ((PrismObjectValue) value).asPrismObject(); Set<ConnectorType> newConnectors; long started = operationsHelper.recordStart(context, connectorHostTypePrismObject.asObjectable()); Throwable exception = null; try { newConnectors = modelService.discoverConnectors(connectorHostTypePrismObject.asObjectable(), context.getTask(), result); operationsHelper.recordEnd(context, connectorHostTypePrismObject.asObjectable(), started, null); } catch (CommunicationException | SecurityViolationException | SchemaException | ConfigurationException | ObjectNotFoundException | RuntimeException e) { operationsHelper.recordEnd(context, connectorHostTypePrismObject.asObjectable(), started, e); exception = processActionException(e, NAME, value, context); newConnectors = Collections.emptySet(); } context.println((exception != null ? "Attempted to discover " : "Discovered " + newConnectors.size()) + " new connector(s) from " + connectorHostTypePrismObject + exceptionSuffix(exception)); for (ConnectorType connectorType : newConnectors) { output.addItem(connectorType.asPrismObject()); } try { if (rebind) { rebindConnectors(newConnectors, context, result); } } catch (ScriptExecutionException e) { //noinspection ThrowableNotThrown processActionException(e, NAME, value, context); // TODO better message } } else { //noinspection ThrowableNotThrown processActionException(new ScriptExecutionException("Input item is not a PrismObject<ConnectorHost>"), NAME, value, context); } } return output; } private void rebindConnectors(Set<ConnectorType> newConnectors, ExecutionContext context, OperationResult result) throws ScriptExecutionException { Map<String,String> rebindMap = new HashMap<>(); for (ConnectorType connectorType : newConnectors) { determineConnectorMappings(rebindMap, connectorType, context, result); } LOGGER.trace("Connector rebind map: {}", rebindMap); rebindResources(rebindMap, context, result); } private void rebindResources(Map<String, String> rebindMap, ExecutionContext context, OperationResult result) throws ScriptExecutionException { List<PrismObject<ResourceType>> resources; try { resources = modelService.searchObjects(ResourceType.class, null, null, null, result); } catch (SchemaException|ConfigurationException|ObjectNotFoundException|CommunicationException|SecurityViolationException e) { throw new ScriptExecutionException("Couldn't list resources: " + e.getMessage(), e); } for (PrismObject<ResourceType> resource : resources) { if (resource.asObjectable().getConnectorRef() != null) { String connectorOid = resource.asObjectable().getConnectorRef().getOid(); String newOid = rebindMap.get(connectorOid); if (newOid != null) { String msg = "resource " + resource + " from connector " + connectorOid + " to new one: " + newOid; LOGGER.info("Rebinding " + msg); ReferenceDelta refDelta = ReferenceDelta.createModificationReplace(ResourceType.F_CONNECTOR_REF, resource.getDefinition(), newOid); ObjectDelta<ResourceType> objDelta = ObjectDelta.createModifyDelta(resource.getOid(), refDelta, ResourceType.class, prismContext); operationsHelper.applyDelta(objDelta, context, result); context.println("Rebound " + msg); } } } } private void determineConnectorMappings(Map<String,String> rebindMap, ConnectorType connectorType, ExecutionContext context, OperationResult result) throws ScriptExecutionException { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Finding obsolete versions for connector: {}", connectorType.asPrismObject().debugDump()); } ObjectQuery query = QueryBuilder.queryFor(ConnectorType.class, prismContext) .item(SchemaConstants.C_CONNECTOR_FRAMEWORK).eq(connectorType.getFramework()) .and().item(SchemaConstants.C_CONNECTOR_CONNECTOR_TYPE).eq(connectorType.getConnectorType()) .build(); List<PrismObject<ConnectorType>> foundConnectors; try { foundConnectors = modelService.searchObjects(ConnectorType.class, query, null, null, result); } catch (SchemaException|ConfigurationException|ObjectNotFoundException|CommunicationException|SecurityViolationException e) { throw new ScriptExecutionException("Couldn't get connectors of type: " + connectorType.getConnectorType() + ": " + e.getMessage(), e); } for (PrismObject<ConnectorType> foundConnector : foundConnectors) { ConnectorType foundConnectorType = foundConnector.asObjectable(); // TODO temporary hack. fix it after MID-3355 is implemented. if (connectorType.getConnectorHost() != null) { if (foundConnectorType.getConnectorHost() == null) { connectorType.setConnectorHostRef(ObjectTypeUtil.createObjectRef(connectorType.getConnectorHost().getOid(), ObjectTypes.CONNECTOR_HOST)); connectorType.setConnectorHost(null); } } if (connectorType.getConnectorHostRef().equals(foundConnectorType.getConnectorHostRef()) && foundConnectorType.getConnectorVersion() != null && !foundConnectorType.getConnectorVersion().equals(connectorType.getConnectorVersion())) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Found obsolete connector: {}", foundConnectorType.asPrismObject().debugDump()); } rebindMap.put(foundConnectorType.getOid(), connectorType.getOid()); } } } }