/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.agent.server.impl;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.agent.server.AgentRegistry;
import org.eclipse.che.api.agent.server.exception.AgentException;
import org.eclipse.che.api.agent.shared.model.impl.AgentKeyImpl;
import org.eclipse.che.api.agent.shared.model.Agent;
import org.eclipse.che.api.agent.shared.model.AgentKey;
import org.eclipse.che.commons.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* Sort agents respecting dependencies between them.
*
* @author Anatolii Bazko
*/
@Singleton
public class AgentSorter {
private final AgentRegistry agentRegistry;
@Inject
public AgentSorter(AgentRegistry agentRegistry) {
this.agentRegistry = agentRegistry;
}
/**
* Sort agents respecting dependencies between them.
* Handles circular dependencies.
*
* @see AgentKey
* @see Agent#getDependencies()
* @see AgentRegistry#getAgent(AgentKey)
*
* @param agentKeys list of agents to sort
* @return list of created agents in proper order
*
* @throws AgentException
* if circular dependency found or agent creation failed or other unexpected error
*/
public List<AgentKey> sort(@Nullable List<String> agentKeys) throws AgentException {
List<AgentKey> sorted = new ArrayList<>();
Set<String> pending = new HashSet<>();
if (agentKeys != null) {
for (String agentKey : agentKeys) {
if (agentKey != null) {
doSort(AgentKeyImpl.parse(agentKey), sorted, pending);
}
}
}
return sorted;
}
private void doSort(AgentKey agentKey, List<AgentKey> sorted, Set<String> pending) throws AgentException {
String agentId = agentKey.getId();
Optional<AgentKey> alreadySorted = sorted.stream().filter(k -> k.getId().equals(agentId)).findFirst();
if (alreadySorted.isPresent()) {
return;
}
pending.add(agentId);
Agent agent = agentRegistry.getAgent(agentKey);
for (String dependency : agent.getDependencies()) {
if (pending.contains(dependency)) {
throw new AgentException(
String.format("Agents circular dependency found between '%s' and '%s'", dependency, agentId));
}
doSort(AgentKeyImpl.parse(dependency), sorted, pending);
}
sorted.add(agentKey);
pending.remove(agentId);
}
}