/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.agent;
import com.google.common.collect.Maps;
import com.griddynamics.jagger.coordinator.*;
import com.griddynamics.jagger.coordinator.async.AsyncCallback;
import com.griddynamics.jagger.coordinator.async.AsyncRunner;
import com.griddynamics.jagger.coordinator.http.NodeNotFound;
import com.griddynamics.jagger.coordinator.http.PackResponse;
import com.griddynamics.jagger.coordinator.http.client.ExchangeClient;
import com.griddynamics.jagger.exception.TechnicalException;
import com.griddynamics.jagger.util.ConfigurableExecutor;
import com.griddynamics.jagger.util.TimeUtils;
import org.apache.http.client.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Starter for agent
*
* @author Alexey Kiselyov
* Date: 16.05.11
*/
public class Agent {
private static final Logger log = LoggerFactory.getLogger(Agent.class);
private Worker worker;
private NodeContext nodeContext;
private AtomicBoolean underManagement = new AtomicBoolean(false);
private ExchangeClient exchangeClient;
private ConfigurableExecutor executor;
private ExchangerThread exchangerThread = new ExchangerThread();
private long pollRate;
private String urlBase;
private String urlExchangePack;
private String urlRegistration;
private HttpClient httpClient;
@Required
public void setUrlBase(String urlBase) {
this.urlBase = urlBase;
}
@Required
public void setUrlExchangePack(String urlExchangePack) {
this.urlExchangePack = urlExchangePack;
}
@Required
public void setUrlRegistration(String urlRegistration) {
this.urlRegistration = urlRegistration;
}
@Required
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
public Worker getWorker() {
return this.worker;
}
public void setWorker(Worker worker) {
this.worker = worker;
}
public StatusChangeListener changeListener = new StatusChangeListener() {
@Override
public void onNodeStatusChanged(NodeId nodeId, NodeStatus status) {
log.debug("{} {}", nodeId, status);
}
@Override
public void onCoordinatorDisconnected() {
log.debug("Coordinator disconnected");
}
@Override
public void onCoordinatorConnected() {
log.debug("Coordinator connected");
}
};
public StatusChangeListener getStatusChangeListener() {
return this.changeListener;
}
public void setNodeContext(NodeContext nodeContext) {
this.nodeContext = nodeContext;
}
public NodeContext getNodeContext() {
return this.nodeContext;
}
public boolean isUnderManagement() {
return this.underManagement.get();
}
public void markAsUnderManagement() {
this.underManagement.set(true);
}
public void unmarkAsUnderManagement() {
this.underManagement.set(false);
}
public ExchangeClient getExchangeClient() {
return exchangeClient;
}
public void setExecutor(ConfigurableExecutor executor) {
this.executor = executor;
}
public ConfigurableExecutor getExecutor() {
return executor;
}
@Required
public void setPollRate(long pollRate) {
this.pollRate = pollRate;
}
public void init() {
final Map<Qualifier, CommandExecutor> commandsRunner = Maps.newHashMap();
for (CommandExecutor commandExecutor : worker.getExecutors()) {
commandsRunner.put(commandExecutor.getQualifier(), commandExecutor);
}
AsyncRunner<Command<Serializable>, Serializable> incomingCommandRunner =
new AsyncRunner<Command<Serializable>, Serializable>() {
@Override
public void run(final Command<Serializable> command, final AsyncCallback<Serializable> callback) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
Serializable result = commandsRunner.get(Qualifier.of(command)).execute(command, nodeContext);
callback.onSuccess(result);
} catch (Throwable e) {
callback.onFailure(e);
}
}
});
}
};
exchangeClient = new ExchangeClient(executor, incomingCommandRunner, nodeContext);
exchangeClient.setNodeContext(nodeContext);
exchangeClient.setHttpClient(httpClient);
exchangeClient.setUrlBase(urlBase);
exchangeClient.setUrlExchangePack(urlExchangePack);
exchangeClient.setUrlRegistration(urlRegistration);
}
public void start() {
exchangerThread.alive = true;
executor.execute(exchangerThread);
}
public void stop() {
exchangerThread.alive = false;
}
public class ExchangerThread implements Runnable {
private volatile boolean alive;
public ExchangerThread() {
this.alive = true;
}
@Override
public void run() {
while (alive) {
try {
PackResponse packResponse = exchangeClient.exchange();
long newPollRate = packResponse != null ? packResponse.getNewPollRate() : 0;
if (newPollRate > 0 && pollRate != newPollRate) {
log.info("Poll rate {} changed to {} ms", pollRate, newPollRate);
pollRate = newPollRate;
}
} catch (IOException e) {
log.error("Error in exchange client", e);
throw new TechnicalException("IOException", e);
} catch (NodeNotFound e) {
log.warn("Agent {} didn't registered on current coordinator! Reset agent registration.", nodeContext.getId());
exchangeClient.getPackExchanger().clean();
AgentStarter.resetAgent(Agent.this);
} catch (Throwable e) {
alive = false;
log.error("Agent "+nodeContext.getId()+" got an exception from coordinator", e);
}
log.debug("Pack exchange completed. Poll rate on agent {} is {} ms", nodeContext.getId(), pollRate);
TimeUtils.sleepMillis(pollRate);
}
}
}
}