command.line/java/com/jetbrains/teamcity/Server.java (192 lines of code) (raw):
package com.jetbrains.teamcity;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import jetbrains.buildServer.*;
import jetbrains.buildServer.core.runtime.IProgressMonitor;
import jetbrains.buildServer.core.runtime.IProgressStatus;
import jetbrains.buildServer.core.runtime.ProgressStatus;
import jetbrains.buildServer.serverProxy.RemoteServerFacade;
import jetbrains.buildServer.serverProxy.RemoteServerFacadeImpl;
import jetbrains.buildServer.serverProxy.SessionXmlRpcTarget;
import jetbrains.buildServer.serverProxy.impl.SessionXmlRpcTargetImpl;
import jetbrains.buildServer.serverSide.TriggeredByBuilder;
import jetbrains.buildServer.serverSide.auth.AuthenticationFailedException;
import jetbrains.buildServer.serverSide.userChanges.PreTestedCommitType;
import jetbrains.buildServer.util.ExceptionUtil;
import jetbrains.buildServer.version.ServerVersionHolder;
import jetbrains.buildServer.xmlrpc.RemoteCallException;
import jetbrains.buildServer.xmlrpc.XmlRpcTarget.Cancelable;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.jetbrains.annotations.NotNull;
public class Server {
public static final String UPLOAD_URL = "uploadChanges.html";
private final URL myUrl;
private SessionXmlRpcTarget mySession;
private RemoteServerFacade myServerFacade;
private List<ProjectData> myProjects;
public Server(final URL url) {
myUrl = url;
}
public void connect() throws ECommunicationException {
try {
final int timeout = getTimeout();
mySession = new SessionXmlRpcTargetImpl(myUrl.toExternalForm(), getUserAgent(), timeout);
Debug.getInstance().debug(Server.class, String.format("XmlRpc session %s created. Timeout set to %s", mySession.describeMe(), timeout));
} catch (Throwable e) {
throw new ECommunicationException(String.format("Could not connect to server %s", myUrl), Util.getRootCause(e));
}
}
@NotNull
private static String getUserAgent() {
final String version = ServerVersionHolder.getVersion().getDisplayVersion();
return "Command Line Tool/" + version;
}
private int getTimeout() {
final String timeoutStr = System.getProperty(Constants.XMLRPC_TIMEOUT_SYSTEM_PROPERTY);
if (timeoutStr != null) {
try {
final int timeout = new Integer(timeoutStr.trim());
if (timeout > 0) {
return timeout;
}
} catch (Throwable t) {
Debug.getInstance().error(Server.class, "Could not parse timeout", t);
}
}
return Constants.DEFAULT_XMLRPC_TIMEOUT;
}
public void logon(final String username, final String password) throws ECommunicationException, EAuthorizationException {
mySession.setCredentials(username, password);
try {
mySession.authenticate(new Cancelable() {
public long sleepingPeriod() {
return 0;
}
public boolean isCanceled() {
return false;
}
});
} catch (AuthenticationFailedException e) {
throw new EAuthorizationException(Util.getRootCause(e));
} catch (RemoteCallException e) {
throw new ECommunicationException(Util.getRootCause(e));
}
}
private RemoteServerFacade getServerFacade() {
if (myServerFacade == null) {
myServerFacade = new RemoteServerFacadeImpl(mySession);
}
return myServerFacade;
}
public int getCurrentUser() {
final Integer userId = mySession.getUserId();
return userId != null ? userId : -1;
}
@SuppressWarnings("rawtypes")
public synchronized Collection<ProjectData> getProjects() throws ECommunicationException {
if (myProjects == null) {
myProjects = getServerFacade().getRegisteredProjects();
}
return myProjects;
}
public synchronized Collection<BuildTypeData> getConfigurations() throws ECommunicationException {
final Collection<ProjectData> allProjects = getProjects();
final ArrayList<BuildTypeData> configurations = new ArrayList<BuildTypeData>(allProjects.size() * 5);
for (ProjectData project : allProjects) {
configurations.addAll(project.getBuildTypes());
}
return configurations;
}
public TeamServerSummaryData getSummary() throws ECommunicationException {
return getServerFacade().getSummaryData(String.valueOf(getCurrentUser()));
}
public String getURL() {
return mySession.getServerURL();
}
@NotNull
public AddToQueueResult addRemoteRunToQueue(@NotNull List<AddToQueueRequest> batch) throws ECommunicationException {
final TriggeredByBuilder builder = new TriggeredByBuilder();
builder.addParameter(TriggeredByBuilder.USER_PARAM_NAME, String.valueOf(getCurrentUser()));
builder.addParameter(TriggeredByBuilder.IDE_PLUGIN_PARAM_NAME, "Command line remote run");
builder.addParameter(TriggeredByBuilder.TYPE_PARAM_NAME, "commandLineRemoteRun");
return getServerFacade().addToQueue(batch, builder.toString());
}
public Collection<String> getApplicableConfigurations(final Collection<String> urls) throws ECommunicationException {
return getServerFacade().getSuitableConfigurations(urls);
}
public long createChangeList(@NotNull final File patchFile, @NotNull final String comment, @NotNull final IProgressMonitor monitor) throws ECommunicationException {
HttpConnection connection = null;
try {
monitor.beginTask("Sending patch to TeamCity Server");
connection = getHttpConnection();
final PostMethod postMethod = new PostMethod(createUploadPatchUrl());
final BufferedInputStream content = new BufferedInputStream(new FileInputStream(patchFile));
try {
addAuthorizationHeader(postMethod);
postMethod.setRequestHeader("Connection", "close");
postMethod.setRequestHeader("Accept", "text/plain");
postMethod.addRequestHeader("User-Agent", mySession.getUserAgent());
postMethod.setRequestEntity(new InputStreamRequestEntity(content, patchFile.length()));
postMethod.setQueryString(new NameValuePair[] { new NameValuePair("userId", String.valueOf(getCurrentUser())),
new NameValuePair("description", comment),
new NameValuePair("date", String.valueOf(System.currentTimeMillis())),
new NameValuePair("commitType", String.valueOf(PreTestedCommitType.NONE.getId())), });
postMethod.execute(new HttpState(), connection);
} finally {
content.close();
}
if (postMethod.getStatusCode() >= 400) {
throw new ECommunicationException("Error creating change list on server with /" + UPLOAD_URL + ": " + postMethod.getResponseBodyAsString() +
"; take a look at TeamCity/logs/teamcity-server.log file for details. HTTP Status code: " + postMethod.getStatusCode());
}
// post requests to queue
final String response = postMethod.getResponseBodyAsString();
monitor.status(new ProgressStatus(IProgressStatus.INFO, String.format("sent %d bytes", patchFile.length())));
monitor.done();
return Long.parseLong(response);
} catch (IOException e) {
throw new ECommunicationException(e);
} finally {
if (connection != null) {
connection.close();
}
}
}
@NotNull
private String createUploadPatchUrl() {
String result = getURL();
if (!result.endsWith("/")) {
result += "/";
}
result += UPLOAD_URL;
return result;
}
@NotNull
private HttpConnection getHttpConnection() throws IOException {
final SimpleHttpConnectionManager manager = new SimpleHttpConnectionManager(true);
HostConfiguration hostConfiguration = new HostConfiguration();
hostConfiguration.setHost(new URI(getURL(), false));
HttpConnection connection = manager.getConnection(hostConfiguration);
if (!connection.isOpen()) {
connection.open();
}
return connection;
}
private void addAuthorizationHeader(@NotNull PostMethod method) {
final String crePair = mySession.getUsername() + ":" + mySession.getPassword();
try {
String encoded = Base64.getEncoder().encodeToString(crePair.getBytes("US-ASCII")); // we expect ASCII login name and password here
method.addRequestHeader("Authorization", "Basic " + encoded);
} catch (UnsupportedEncodingException e) {
ExceptionUtil.rethrowAsRuntimeException(e);
}
}
public void dispose() {
mySession.dispose();
}
}