/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.component.workflow.update.internal; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; import org.codehaus.jackson.node.ArrayNode; import org.codehaus.jackson.node.JsonNodeFactory; import org.codehaus.jackson.node.ObjectNode; import org.codehaus.jackson.node.TextNode; import de.rcenvironment.core.communication.api.PlatformService; import de.rcenvironment.core.communication.common.LogicalNodeId; import de.rcenvironment.core.communication.common.NodeIdentifierUtils; import de.rcenvironment.core.component.api.ComponentConstants; import de.rcenvironment.core.component.api.DistributedComponentKnowledge; import de.rcenvironment.core.component.api.DistributedComponentKnowledgeService; import de.rcenvironment.core.component.model.api.ComponentInstallation; import de.rcenvironment.core.component.model.api.ComponentInterface; import de.rcenvironment.core.component.update.api.DistributedPersistentComponentDescriptionUpdateService; import de.rcenvironment.core.component.update.api.PersistentComponentDescription; import de.rcenvironment.core.component.update.api.PersistentDescriptionFormatVersion; import de.rcenvironment.core.component.workflow.api.WorkflowConstants; import de.rcenvironment.core.component.workflow.update.api.PersistentWorkflowDescription; import de.rcenvironment.core.component.workflow.update.api.PersistentWorkflowDescriptionUpdateService; import de.rcenvironment.core.utils.common.JsonUtils; import de.rcenvironment.core.utils.common.StringUtils; /** * {@link PersistentWorkflowDescriptionUpdateService}. * * @author Doreen Seider * @author Sascha Zur * @author Robert Mischke (8.0.0 id adaptations) */ public class PersistentWorkflowDescriptionUpdateServiceImpl implements PersistentWorkflowDescriptionUpdateService { private static final String WORKFLOW_VERSION = "workflowVersion"; private static final String DYNAMIC_OUTPUTS = "dynamicOutputs"; private static final String DYNAMIC_INPUTS = "dynamicInputs"; private static final String DATATYPE = "datatype"; private static final String SHORT_TEXT = "ShortText"; private static final String STATIC_INPUTS = "staticInputs"; private static final String STATIC_OUTPUTS = "staticOutputs"; private static final String CURRENT_VERSION = String.valueOf(WorkflowConstants.CURRENT_WORKFLOW_VERSION_NUMBER); private static final String VERSION_3 = "3"; private static final String NAME = "name"; private static final String INPUT = "input"; private static final String OUTPUT = "output"; private static final String IDENTIFIER = "identifier"; private static final String TARGET = "target"; private static final String SOURCE = "source"; private static final String CONFIGURATION = "configuration"; @SuppressWarnings("serial") private static final Map<String, String> OLD_TO_NEW_TYPES = new HashMap<String, String>() { { put("java.lang.String", SHORT_TEXT); put("java.lang.Double", "Float"); put("java.lang.Integer", "Integer"); put("java.lang.Float", "Float"); put("java.lang.Long", "Integer"); put("java.lang.Boolean", "Boolean"); put("de.rcenvironment.commons.channel.DataManagementFileReference", "FileReference"); put("de.rcenvironment.commons.channel.VariantArray", "SmallTable"); } }; private static final String BENDPOINTS = "bendpoints"; private static final String CONNECTIONS = "connections"; private static final String NODES = "nodes"; private static final Log LOGGER = LogFactory.getLog(PersistentWorkflowDescriptionUpdateServiceImpl.class); private DistributedPersistentComponentDescriptionUpdateService componentUpdateService; private DistributedComponentKnowledgeService componentKnowledgeService; private LogicalNodeId localLogicalNodeId; @Override public boolean isUpdateForWorkflowDescriptionAvailable(PersistentWorkflowDescription description, boolean silent) { if (!silent) { if (description.getWorkflowVersion().compareTo(VERSION_3) < 0) { return true; } } else { if (description.getWorkflowVersion().compareTo(CURRENT_VERSION) < 0) { return true; } } if (componentUpdateService.getFormatVersionsAffectedByUpdate(description.getComponentDescriptions(), silent) != PersistentDescriptionFormatVersion.NONE) { return true; } return false; } @Override public PersistentWorkflowDescription performWorkflowDescriptionUpdate(PersistentWorkflowDescription persistentDescription) throws IOException { PersistentWorkflowDescription description = persistentDescription; Set<String> endpoints = getEndpoints(description); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.BEFORE_VERSON_THREE, description, true); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.BEFORE_VERSON_THREE, description, false); String workflowVersion = description.getWorkflowVersion(); description = checkForWorkflowDescriptionUpdateAndPerformOnDemand(description, workflowVersion); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.FOR_VERSION_THREE, description, true); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.FOR_VERSION_THREE, description, false); description = checkForConnectionDescriptionUpdateAndPerformOnDemand(description, workflowVersion); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.AFTER_VERSION_THREE, description, true); description = performComponentDescriptionUpdates(PersistentDescriptionFormatVersion.AFTER_VERSION_THREE, description, false); endpoints.removeAll(getEndpoints(description)); description = removeConnectionsRelatedToRemovedEndpoints(description, endpoints); description = updateWorkflowToCurrentVersion(description); return description; } private Set<String> getEndpoints(PersistentWorkflowDescription persWfDescription) throws JsonProcessingException, IOException { Set<String> endpoints = new HashSet<>(); for (PersistentComponentDescription persCompDesc : persWfDescription.getComponentDescriptions()) { ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNode node = mapper.readTree(persCompDesc.getComponentDescriptionAsString()); endpoints.addAll(getEndpointsOfGroup(node, STATIC_INPUTS)); endpoints.addAll(getEndpointsOfGroup(node, STATIC_OUTPUTS)); endpoints.addAll(getEndpointsOfGroup(node, DYNAMIC_INPUTS)); endpoints.addAll(getEndpointsOfGroup(node, DYNAMIC_OUTPUTS)); } return endpoints; } private Set<String> getEndpointsOfGroup(JsonNode node, String endpointGroup) throws JsonProcessingException, IOException { Set<String> endpoints = new HashSet<>(); if (node.has(endpointGroup)) { Iterator<JsonNode> outputJsonNodes = node.get(endpointGroup).getElements(); while (outputJsonNodes.hasNext()) { endpoints.add(outputJsonNodes.next().get(IDENTIFIER).getTextValue()); } } return endpoints; } private PersistentWorkflowDescription removeConnectionsRelatedToRemovedEndpoints(PersistentWorkflowDescription persWfDescription, Set<String> endpointsRemoved) throws JsonProcessingException, IOException { ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNode workflowDescriptionAsTree = mapper.readTree(persWfDescription.getWorkflowDescriptionAsString()); for (String endpointRemoved : endpointsRemoved) { if (workflowDescriptionAsTree.has(CONNECTIONS)) { ArrayNode connectionsJsonNode = (ArrayNode) workflowDescriptionAsTree.get(CONNECTIONS); Iterator<JsonNode> connectionJsonNodes = connectionsJsonNode.getElements(); while (connectionJsonNodes.hasNext()) { JsonNode connectionJsonNode = connectionJsonNodes.next(); if (connectionJsonNode.get("input").getTextValue().equals(endpointRemoved) || connectionJsonNode.get("output").getTextValue().equals(endpointRemoved)) { connectionJsonNodes.remove(); } } } } ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); return new PersistentWorkflowDescription(persWfDescription.getComponentDescriptions(), writer.writeValueAsString(workflowDescriptionAsTree)); } private PersistentWorkflowDescription updateWorkflowToCurrentVersion(PersistentWorkflowDescription description) { ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); try { JsonNode workflowDescriptionAsTree = mapper.readTree(description.getWorkflowDescriptionAsString()); ((ObjectNode) workflowDescriptionAsTree).put(WORKFLOW_VERSION, TextNode.valueOf(CURRENT_VERSION)); ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); JsonNode nodes = workflowDescriptionAsTree.get(NODES); return new PersistentWorkflowDescription(createComponentDescriptions(nodes), writer.writeValueAsString(workflowDescriptionAsTree)); } catch (JsonProcessingException e) { LOGGER.error(e.getStackTrace()); } catch (IOException e) { LOGGER.error(e.getStackTrace()); } return null; } private PersistentWorkflowDescription checkForWorkflowDescriptionUpdateAndPerformOnDemand(PersistentWorkflowDescription description, String version) throws IOException { if (version.compareTo(VERSION_3) < 0) { description = performWorkflowDescriptionUpdateVersionOneToTwo(description); } return description; } private PersistentWorkflowDescription checkForConnectionDescriptionUpdateAndPerformOnDemand(PersistentWorkflowDescription description, String version) throws IOException { if (version.compareTo(VERSION_3) < 0) { description = performWorkflowDescriptionUpdateVersionOneToTwoForConnections(description); } return description; } private PersistentWorkflowDescription performComponentDescriptionUpdates(int formatVersion, PersistentWorkflowDescription description, boolean silent) throws IOException { List<PersistentComponentDescription> componentDescriptions = componentUpdateService .performComponentDescriptionUpdates(formatVersion, description.getComponentDescriptions(), silent); ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNodeFactory jsonFactory = JsonNodeFactory.instance; try { ObjectNode workflowDescriptionAsTree = (ObjectNode) mapper.readTree(description.getWorkflowDescriptionAsString()); ArrayNode componentNodes = new ArrayNode(jsonFactory); if (componentDescriptions.size() > 0) { for (PersistentComponentDescription pcd : componentDescriptions) { JsonNode component = mapper.readTree(pcd.getComponentDescriptionAsString()); componentNodes.add(component); } JsonNode connections = workflowDescriptionAsTree.remove(CONNECTIONS); JsonNode bendpoints = workflowDescriptionAsTree.remove(BENDPOINTS); workflowDescriptionAsTree.remove(NODES); workflowDescriptionAsTree.put(NODES, componentNodes); if (connections != null) { workflowDescriptionAsTree.put(CONNECTIONS, connections); } if (bendpoints != null) { workflowDescriptionAsTree.put(BENDPOINTS, bendpoints); } } ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); return new PersistentWorkflowDescription(componentDescriptions, writer.writeValueAsString(workflowDescriptionAsTree)); } catch (JsonProcessingException e) { LOGGER.error(e); } catch (IOException e) { LOGGER.error(e); } return null; } private PersistentWorkflowDescription performWorkflowDescriptionUpdateVersionOneToTwoForConnections( PersistentWorkflowDescription description) throws IOException { JsonNodeFactory jsonFactory = JsonNodeFactory.instance; ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNode workflowDescriptionAsTree = mapper.readTree(description.getWorkflowDescriptionAsString()); JsonNode nodes = workflowDescriptionAsTree.get(NODES); JsonNode connections = workflowDescriptionAsTree.get(CONNECTIONS); connections = updateConnectionsToVersion3(connections, nodes, jsonFactory); ((ObjectNode) workflowDescriptionAsTree).remove(CONNECTIONS); if (connections != null) { ((ObjectNode) workflowDescriptionAsTree).put(CONNECTIONS, connections); } ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); return new PersistentWorkflowDescription(createComponentDescriptions(nodes), writer.writeValueAsString(workflowDescriptionAsTree)); } private PersistentWorkflowDescription performWorkflowDescriptionUpdateVersionOneToTwo(PersistentWorkflowDescription description) throws IOException { JsonNodeFactory jsonFactory = JsonNodeFactory.instance; ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNode workflowDescriptionAsTree = mapper.readTree(description.getWorkflowDescriptionAsString()); JsonNode nodes = workflowDescriptionAsTree.get(NODES); if (nodes != null) { nodes = updateNodesToVersion3(nodes, jsonFactory); } ((ObjectNode) workflowDescriptionAsTree).remove(NODES); ((ObjectNode) workflowDescriptionAsTree).remove(WORKFLOW_VERSION); ((ObjectNode) workflowDescriptionAsTree).put(WORKFLOW_VERSION, TextNode.valueOf(VERSION_3)); if (nodes != null) { ((ObjectNode) workflowDescriptionAsTree).put(NODES, nodes); } ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); return new PersistentWorkflowDescription(createComponentDescriptions(nodes), writer.writeValueAsString(workflowDescriptionAsTree)); } private static JsonNode updateNodesToVersion3(JsonNode nodes, JsonNodeFactory jsonFactory) { ArrayNode newNodes = jsonFactory.arrayNode(); for (JsonNode componentNode : nodes) { ObjectNode newComponentNode = (ObjectNode) componentNode; updateDynamicEndpoints("Output", jsonFactory, componentNode, newComponentNode); updateDynamicEndpoints("Input", jsonFactory, componentNode, newComponentNode); updateConfiguration(jsonFactory, componentNode, newComponentNode); newNodes.add(newComponentNode); } return newNodes; } private static JsonNode updateConnectionsToVersion3(JsonNode connections, JsonNode nodes, JsonNodeFactory jsonFactory) { ArrayNode newConnectionsArrayNode = jsonFactory.arrayNode(); if (connections != null) { for (JsonNode connection : ((ArrayNode) connections)) { ObjectNode connectionObject = (ObjectNode) connection; ObjectNode newConnectionsObjectNode = jsonFactory.objectNode(); newConnectionsObjectNode.put(SOURCE, connectionObject.get(SOURCE)); String sourceOutput = connectionObject.get(OUTPUT).getTextValue(); for (JsonNode component : nodes) { if (((ObjectNode) component).get(IDENTIFIER).getTextValue().equals(connectionObject.get(SOURCE).getTextValue())) { boolean foundOutput = false; if (((ObjectNode) component).get(DYNAMIC_OUTPUTS) != null) { for (JsonNode endpoint : ((ObjectNode) component).get(DYNAMIC_OUTPUTS)) { if (((ObjectNode) endpoint).get(NAME).getTextValue().equals(sourceOutput)) { newConnectionsObjectNode.put(OUTPUT, ((ObjectNode) endpoint).get(IDENTIFIER)); foundOutput = true; } } } if (((ObjectNode) component).get(STATIC_OUTPUTS) != null) { for (JsonNode endpoint : ((ObjectNode) component).get(STATIC_OUTPUTS)) { if (((ObjectNode) endpoint).get(NAME).getTextValue().equals(sourceOutput)) { newConnectionsObjectNode.put(OUTPUT, ((ObjectNode) endpoint).get(IDENTIFIER)); foundOutput = true; } } } if (!foundOutput) { ArrayNode staticOutputs = (ArrayNode) component.get(STATIC_OUTPUTS); if (staticOutputs == null) { staticOutputs = JsonNodeFactory.instance.arrayNode(); ((ObjectNode) component).put(STATIC_OUTPUTS, staticOutputs); } ObjectNode newStaticOutput = JsonNodeFactory.instance.objectNode(); newStaticOutput.put(NAME, sourceOutput); newStaticOutput.put(IDENTIFIER, UUID.randomUUID().toString()); newStaticOutput.put(DATATYPE, SHORT_TEXT); staticOutputs.add(newStaticOutput); newConnectionsObjectNode.put(OUTPUT, newStaticOutput.get(IDENTIFIER)); } } } newConnectionsObjectNode.put(TARGET, connectionObject.get(TARGET)); String targetInput = connectionObject.get(INPUT).getTextValue(); for (JsonNode component : nodes) { if (((ObjectNode) component).get(IDENTIFIER).getTextValue().equals(connectionObject.get(TARGET).getTextValue())) { boolean foundInput = false; if (((ObjectNode) component).get(DYNAMIC_INPUTS) != null) { for (JsonNode endpoint : ((ObjectNode) component).get(DYNAMIC_INPUTS)) { if (((ObjectNode) endpoint).get(NAME).getTextValue().equals(targetInput)) { newConnectionsObjectNode.put(INPUT, ((ObjectNode) endpoint).get(IDENTIFIER)); foundInput = true; } } } if (((ObjectNode) component).get(STATIC_INPUTS) != null) { for (JsonNode endpoint : ((ObjectNode) component).get(STATIC_INPUTS)) { if (((ObjectNode) endpoint).get(NAME).getTextValue().equals(targetInput)) { newConnectionsObjectNode.put(INPUT, ((ObjectNode) endpoint).get(IDENTIFIER)); foundInput = true; } } } if (!foundInput) { ArrayNode staticInputs = (ArrayNode) component.get(STATIC_INPUTS); if (staticInputs == null) { staticInputs = JsonNodeFactory.instance.arrayNode(); ((ObjectNode) component).put(STATIC_INPUTS, staticInputs); } ObjectNode newStaticInput = JsonNodeFactory.instance.objectNode(); newStaticInput.put(NAME, targetInput); newStaticInput.put(IDENTIFIER, UUID.randomUUID().toString()); newStaticInput.put(DATATYPE, SHORT_TEXT); staticInputs.add(newStaticInput); newConnectionsObjectNode.put(INPUT, newStaticInput.get(IDENTIFIER)); } } } newConnectionsArrayNode.add(newConnectionsObjectNode); } } return newConnectionsArrayNode; } private static void updateConfiguration(JsonNodeFactory jsonFactory, JsonNode componentNode, ObjectNode newComponentNode) { ObjectNode newConfigNode = jsonFactory.objectNode(); ArrayNode oldConfigNode = (ArrayNode) componentNode.get(CONFIGURATION); if (oldConfigNode != null) { for (JsonNode config : oldConfigNode) { String[] splitted = StringUtils.splitAndUnescape(config.getTextValue()); if (splitted.length > 2) { newConfigNode.put(splitted[0], TextNode.valueOf(splitted[2])); } else { newConfigNode.put(splitted[0], jsonFactory.textNode("")); } } } newComponentNode.put(CONFIGURATION, newConfigNode); } private static void updateDynamicEndpoints(String type, JsonNodeFactory jsonFactory, JsonNode componentNode, ObjectNode newComponentNode) { ArrayNode newEndpointList = jsonFactory.arrayNode(); ArrayNode oldEndpointList = (ArrayNode) componentNode.get("add" + type); JsonNode metadata = componentNode.get(type.toLowerCase() + "MetaData"); if (oldEndpointList != null) { for (JsonNode endpoint : oldEndpointList) { ObjectNode newEndpoint = jsonFactory.objectNode(); String oldEndpoint = endpoint.getTextValue(); newEndpoint.put(IDENTIFIER, UUID.randomUUID().toString()); newEndpoint.put("epIdentifier", jsonFactory.nullNode()); String[] splittedEndpoint = StringUtils.splitAndUnescape(oldEndpoint); newEndpoint.put(NAME, splittedEndpoint[0]); newEndpoint.put(DATATYPE, OLD_TO_NEW_TYPES.get(splittedEndpoint[1])); if (splittedEndpoint.length > 2) { newEndpoint.put("value", splittedEndpoint[2]); } else { newEndpoint.put("value", ""); } if (metadata != null && metadata.get(splittedEndpoint[0]) != null) { ObjectNode newMetadata = jsonFactory.objectNode(); for (JsonNode metaDatum : metadata.get(splittedEndpoint[0])) { String metadataText = metaDatum.getTextValue(); String[] splittedMetaDatum = StringUtils.splitAndUnescape(metadataText); if (splittedMetaDatum[0].equals("usage")) { if (splittedMetaDatum[2].equals("init")) { splittedMetaDatum[2] = "initial"; } else if (splittedMetaDatum[2].equals("Required")) { splittedMetaDatum[2] = "required"; } else if (splittedMetaDatum[2].equals("Optional")) { splittedMetaDatum[2] = "optional"; } } newMetadata.put(splittedMetaDatum[0], splittedMetaDatum[2]); } newEndpoint.put("metadata", newMetadata); } newEndpointList.add(newEndpoint); } } newComponentNode.remove("add" + type); newComponentNode.remove(type.toLowerCase() + "MetaData"); newComponentNode.put("dynamic" + type + "s", newEndpointList); } @Override public PersistentWorkflowDescription createPersistentWorkflowDescription(String persistentWorkflowDescriptionString) throws JsonParseException, IOException { try (JsonParser jsonParser = new JsonFactory().createJsonParser(persistentWorkflowDescriptionString)) { ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); JsonNode node = mapper.readTree(jsonParser); List<PersistentComponentDescription> nodeDescriptionList = new ArrayList<PersistentComponentDescription>(); JsonNode componentNodes = node.get(NODES); if (componentNodes != null) { nodeDescriptionList = createComponentDescriptions(componentNodes); } ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); String workflowDescriptionString = writer.writeValueAsString(node); return new PersistentWorkflowDescription(nodeDescriptionList, workflowDescriptionString); } } private List<PersistentComponentDescription> createComponentDescriptions(JsonNode nodes) throws JsonGenerationException, JsonMappingException, IOException { List<PersistentComponentDescription> componentDescriptions = new LinkedList<PersistentComponentDescription>(); if (nodes != null) { Iterator<JsonNode> nodeIterator = nodes.getElements(); while (nodeIterator.hasNext()) { JsonNode component = nodeIterator.next(); ObjectMapper mapper = JsonUtils.getDefaultObjectMapper(); ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); componentDescriptions.add(new PersistentComponentDescription(writer.writeValueAsString(component))); } DistributedComponentKnowledge compKnowledge = componentKnowledgeService.getCurrentComponentKnowledge(); for (PersistentComponentDescription componentDescription : componentDescriptions) { checkAndSetNodeIdentifier(componentDescription, compKnowledge.getAllInstallations()); } } return componentDescriptions; } protected PersistentComponentDescription checkAndSetNodeIdentifier(PersistentComponentDescription compDesc, Collection<ComponentInstallation> collection) { ComponentInstallation exactlyMatchingComponent = null; List<ComponentInstallation> matchingComponents = new ArrayList<ComponentInstallation>(); // for all registered components which match the persistent one (identifiers are equal and version of persistent one is greater or // equal of registered one) decide: // if the platform is equal as well, the component is registered on the node where it was when workflow was created, the update // check can be directly done on the given node, the description can be returned as it is and this method is done otherwise add the // basically matching component to the list of matching components which will be considered later on for (ComponentInstallation compInst : collection) { ComponentInterface compInterface = compInst.getComponentRevision().getComponentInterface(); String compId = compInterface.getIdentifier(); if (compId.contains(ComponentConstants.ID_SEPARATOR)) { compId = compInterface.getIdentifier().split(ComponentConstants.ID_SEPARATOR)[0]; } if (compId.equals(compDesc.getComponentIdentifier()) && (compDesc.getComponentVersion().equals("") || compInterface.getVersion().compareTo(compDesc.getComponentVersion()) >= 0)) { if (compInst.getNodeId() == null || compInst.getNodeId().equals(localLogicalNodeId.getLogicalNodeIdString())) { compDesc.setNodeIdentifier(localLogicalNodeId); return compDesc; } else if (compInst.getNodeId() != null && compDesc.getComponentNodeIdentifier() != null && compInst.getNodeId().equals(compDesc.getComponentNodeIdentifier().getLogicalNodeIdString())) { exactlyMatchingComponent = compInst; } else { matchingComponents.add(compInst); } } } // if there is not local component, take the exactly matching remote component if there is one if (exactlyMatchingComponent != null) { compDesc .setNodeIdentifier(NodeIdentifierUtils .parseArbitraryIdStringToLogicalNodeIdWithExceptionWrapping(exactlyMatchingComponent.getNodeId())); return compDesc; } // a matching component on the originally registered node was not found. thus set the node // identifier of any matching component if there is at least one found if (matchingComponents.size() > 0) { compDesc.setNodeIdentifier(NodeIdentifierUtils.parseArbitraryIdStringToLogicalNodeIdWithExceptionWrapping(matchingComponents .get(0).getNodeId())); return compDesc; } // if there is no matching component found in the RCE network set the node identifier to // local, thus the local update service will be requested and will return that it has no // updater registered for the component as it is not registered at all compDesc.setNodeIdentifier(localLogicalNodeId); return compDesc; } /** * OSGi bind method. This bind method is set to public for tests of this class. * * @param updateService to bind. */ public void bindComponentDescriptionUpdateService(DistributedPersistentComponentDescriptionUpdateService updateService) { this.componentUpdateService = updateService; } protected void bindDistributedComponentKnowledgeService(DistributedComponentKnowledgeService service) { this.componentKnowledgeService = service; } protected void bindPlatformService(PlatformService platformService) { localLogicalNodeId = platformService.getLocalDefaultLogicalNodeId(); } }