/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
*
* 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.remote;
import static java.lang.String.format;
import com.thoughtworks.go.domain.JobIdentifier;
import com.thoughtworks.go.domain.JobResult;
import com.thoughtworks.go.domain.JobState;
import com.thoughtworks.go.server.service.AgentRuntimeInfo;
import com.thoughtworks.go.server.service.AgentService;
import com.thoughtworks.go.server.service.BuildRepositoryService;
import com.thoughtworks.go.server.service.AgentWithDuplicateUUIDException;
import com.thoughtworks.go.server.messaging.JobStatusMessage;
import com.thoughtworks.go.server.messaging.JobStatusTopic;
import org.apache.log4j.Logger;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BuildRepositoryRemoteImpl {
private static final Logger LOGGER = Logger.getLogger(BuildRepositoryRemoteImpl.class);
private AgentService agentService;
private BuildRepositoryService buildRepositoryService;
private JobStatusTopic jobStatusTopic;
@Autowired
BuildRepositoryRemoteImpl(BuildRepositoryService buildRepositoryService, AgentService agentService, JobStatusTopic jobStatusTopic) {
this.buildRepositoryService = buildRepositoryService;
this.agentService = agentService;
this.jobStatusTopic = jobStatusTopic;
}
public AgentInstruction ping(AgentRuntimeInfo info) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(info + " ping received.");
}
try {
agentService.updateRuntimeInfo(info);
return new AgentInstruction(agentService.findAgentAndRefreshStatus(info.getUUId()).isCancelled());
} catch (AgentWithDuplicateUUIDException agentException) {
throw wrappedException(agentException);
} catch (Exception e) {
LOGGER.error("Error occurred in " + info + " ping.", e);
throw wrappedException(e);
}
}
public void reportCurrentStatus(final AgentRuntimeInfo agentRuntimeInfo, final JobIdentifier jobIdentifier, final JobState state) {
handleFailuresDuringReporting(agentRuntimeInfo, jobIdentifier, "status", state.toString(), new ReportingAction() {
@Override public void call() throws Exception {
//TODO: may be i don't belong here, ping already updates agent runtime info
agentService.updateRuntimeInfo(agentRuntimeInfo);
buildRepositoryService.updateStatusFromAgent(jobIdentifier, state, agentRuntimeInfo.getUUId());
jobStatusTopic.post(new JobStatusMessage(jobIdentifier, state, agentRuntimeInfo.getUUId()));
}
});
}
public void reportCompleting(final AgentRuntimeInfo agentRuntimeInfo, final JobIdentifier jobIdentifier, final JobResult result) {
handleFailuresDuringReporting(agentRuntimeInfo, jobIdentifier, "result", result.toString(), new ReportingAction() {
@Override public void call() throws Exception {
//TODO: may be i don't belong here, ping already updates agent runtime info
agentService.updateRuntimeInfo(agentRuntimeInfo);
buildRepositoryService.completing(jobIdentifier, result, agentRuntimeInfo.getUUId());
}
});
}
public void reportCompleted(final AgentRuntimeInfo agentRuntimeInfo, final JobIdentifier jobIdentifier, final JobResult result) {
final JobState state = JobState.Completed;
handleFailuresDuringReporting(agentRuntimeInfo, jobIdentifier, "status and result", String.format("%s, %s",state, result), new ReportingAction() {
@Override public void call() throws Exception {
//TODO: may be i don't belong here, ping already updates agent runtime info
agentService.updateRuntimeInfo(agentRuntimeInfo);
buildRepositoryService.completing(jobIdentifier, result, agentRuntimeInfo.getUUId());
buildRepositoryService.updateStatusFromAgent(jobIdentifier, state, agentRuntimeInfo.getUUId());
jobStatusTopic.post(new JobStatusMessage(jobIdentifier, state, agentRuntimeInfo.getUUId()));
}
});
}
private void handleFailuresDuringReporting(AgentRuntimeInfo agentRuntimeInfo, JobIdentifier jobIdentifier, final String thingBeingReported, String changedValue, ReportingAction action) {
String agentDebugString = agentRuntimeInfo.agentInfoDebugString();
LOGGER.info(format("[%s] is reporting %s [%s] for [%s]", agentDebugString, thingBeingReported, changedValue, jobIdentifier.toFullString()));
try {
action.call();
} catch (AgentWithDuplicateUUIDException agentException) {
throw wrappedException(agentException);
} catch (Exception e) {
LOGGER.error(format("Exception occurred when [%s] tries to report " + thingBeingReported + " [%s] for [%s]",
agentDebugString, changedValue, jobIdentifier.toFullString()), e);
throw wrappedException(e);
}
}
public boolean isIgnored(JobIdentifier jobIdentifier) {
try {
return buildRepositoryService.isCancelledOrRescheduled(jobIdentifier.getBuildId());
} catch (Exception e) {
throw wrappedException(e);
}
}
private RemoteAccessException wrappedException(Exception e) {
return new RemoteAccessException(e.getMessage(), e);
}
public String getCookie(AgentIdentifier identifier, String location) {
try {
String cookie = agentService.assignCookie(identifier);
LOGGER.info(format("[Agent Cookie] Agent [%s] at location [%s] asked for a new cookie, assigned [%s]", identifier, location, cookie));
return cookie;
} catch (Exception e) {
LOGGER.error(String.format("[Agent Cookie] Agent [%s] at location [%s] could not get a cookie.", identifier, location), e);
throw wrappedException(e);
}
}
private interface ReportingAction {
void call() throws Exception;
}
}