Newer
Older
pmd-jenkins-library / src / uk / org / floop / jenkins_pmd / Drafter.groovy
package uk.org.floop.jenkins_pmd

import groovy.json.JsonSlurper
import hudson.FilePath
import org.apache.http.HttpHost
import org.apache.http.HttpResponse
import org.apache.http.client.fluent.Executor
import org.apache.http.client.fluent.Request
import org.apache.http.entity.ContentType
import org.apache.http.util.EntityUtils

class Drafter implements Serializable {
    private PMD pmd
    private URI apiBase
    private HttpHost host, cacheHost
    private String user, pass, cacheUser, cachePass

    enum Include {
        ALL("all"), OWNED("owned"), CLAIMABLE("claimable")
        public final String value
        Include(String v) {
            this.value = v
        }
    }

    Drafter(PMD pmd, String user, String pass, String cacheUser, String cachePass) {
        this.pmd = pmd
        this.apiBase = new URI(pmd.config.pmd_api)
        this.host = new HttpHost(apiBase.getHost(), apiBase.getPort(), apiBase.getScheme())
        this.user = user
        this.pass = pass
        if (pmd.config.empty_cache) {
            URI cacheBase = new URI(pmd.config.empty_cache)
            this.cacheHost = new HttpHost(cacheBase.getHost(), cacheBase.getPort(), cacheBase.getScheme())
            this.cacheUser = cacheUser
            this.cachePass = cachePass
        }
    }

    private Executor getExec() {
        Executor exec = Executor.newInstance()
                .auth(this.host, this.user, this.pass)
                .authPreemptive(this.host)
        if (pmd.config.cache_credentials) {
            return exec
                    .auth(this.cacheHost, this.cacheUser, this.cachePass)
                    .authPreemptive(this.cacheHost)
        } else {
            return exec
        }
    }

    def listDraftsets(Include include=Include.ALL) {
        def js = new JsonSlurper()
        String path = (include == Include.ALL) ? "/v1/draftsets" : "/v1/draftsets?include=" + include.value
        def response = js.parse(
                getExec().execute(
                        Request.Get(apiBase.resolve(path))
                                .addHeader("Accept", "application/json")
                                .userAgent(PMDConfig.UA)
                ).returnContent().asStream()
        )
        response
    }

    private static String errorMsg(HttpResponse response) {
        EntityUtils.consume(response.getEntity())
        "${response.getStatusLine()} : ${EntityUtils.toString(response.getEntity())}"
    }

    def createDraftset(String label) {
        String displayName = URLEncoder.encode(label, "UTF-8")
        String path = "/v1/draftsets?display-name=${displayName}"
        HttpResponse response = getExec().execute(
                        Request.Post(apiBase.resolve(path))
                                .addHeader("Accept", "application/json")
                                .userAgent(PMDConfig.UA)
                ).returnResponse()
        if (response.getStatusLine().statusCode == 200) {
            return new JsonSlurper().parse(EntityUtils.toByteArray(response.getEntity()))
        } else {
            throw new DrafterException("Problem creating draftset ${errorMsg(response)}")
        }
    }

    def deleteGraph(String draftsetId, String graph) {
        String encGraph = URLEncoder.encode(graph, "UTF-8")
        String path = "/v1/draftset/${draftsetId}/graph?graph=${encGraph}&silent=true"
        HttpResponse response = getExec().execute(
                Request.Delete(apiBase.resolve(path))
                        .addHeader("Accept", "application/json")
                        .userAgent(PMDConfig.UA)
        ).returnResponse()
        if (response.getStatusLine().statusCode == 200) {
            return new JsonSlurper().parse(EntityUtils.toByteArray(response.getEntity()))
        } else {
            throw new DrafterException("Problem deleting graph ${errorMsg(response)}")
        }
    }

    def deleteDraftset(String draftsetId) {
        String path = "/v1/draftset/${draftsetId}"
        HttpResponse response = getExec().execute(
                        Request.Delete(apiBase.resolve(path))
                                .addHeader("Accept", "application/json")
                                .userAgent(PMDConfig.UA)
        ).returnResponse()
        if (response.getStatusLine().statusCode == 202) {
            def jobObj = new JsonSlurper().parse(EntityUtils.toByteArray(response.getEntity()))
            waitForJob(apiBase.resolve(jobObj['finished-job'] as String), jobObj['restart-id'] as String)
        } else {
            throw new DrafterException("Problem deleting draftset ${errorMsg(response)}")
        }
    }

    def waitForJob(URI finishedJob, String restartId) {
        Executor exec = getExec()
        while (true) {
            HttpResponse jobResponse = exec.execute(
                    Request.Get(finishedJob)
                            .setHeader("Accept", "application/json")
                            .userAgent(PMDConfig.UA)
            ).returnResponse()
            int status = jobResponse.getStatusLine().statusCode
            def jobObj
            try {
                jobObj = new JsonSlurper().parse(EntityUtils.toByteArray(jobResponse.getEntity()))
            } catch(e) {
                throw new DrafterException("Failed waiting for job ${errorMsg(jobResponse)}.\n${e}")
            }
            if (status == 404) {
                if (jobObj['restart-id'] != restartId) {
                    throw new DrafterException("Failed waiting for job to finish, no/different restart-id ${errorMsg(jobResponse)}")
                } else {
                    sleep(10000)
                }
            } else if (status == 200) {
                if (jobObj['restart-id'] != restartId) {
                    throw new DrafterException("Failed waiting for job to finish, restart-id is different.")
                } else if (jobObj['type'] != 'ok') {
                    throw new DrafterException("Pipeline error in ${jobObj.details?.pipeline?.name}. ${jobObj.message}")
                } else {
                    break
                }
            } else {
                throw new DrafterException("Unexpected response waiting for job to complete: ${errorMsg(jobResponse)}")
            }
        }
    }

    def addData(String draftId, String fileName, String mimeType, String encoding, String graph=null) {
        String path = "/v1/draftset/${draftId}/data"
        if (graph) {
            String encGraph = URLEncoder.encode(graph, "UTF-8")
            path = path + "?graph=${encGraph}"
        }
        HttpResponse response = getExec().execute(
                Request.Put(apiBase.resolve(path))
                        .addHeader("Accept", "application/json")
                        .userAgent(PMDConfig.UA)
                        .bodyStream(new FilePath(new File(fileName)).read(), ContentType.create(mimeType, encoding))
        ).returnResponse()
        if (response.getStatusLine().statusCode == 202) {
            def jobObj = new JsonSlurper().parse(EntityUtils.toByteArray(response.getEntity()))
            waitForJob(apiBase.resolve(jobObj['finished-job'] as String), jobObj['restart-id'] as String)
        } else {
            throw new DrafterException("Problem adding data ${errorMsg(response)}")
        }
    }

    def findDraftset(String displayName) {
        def drafts = listDraftsets(Include.OWNED)
        def draftset = drafts.find  { it['display-name'] == displayName }
        if (draftset) {
            draftset
        } else {
            throw new DrafterException("Can't find draftset with the display-name '${displayName}'")
        }

    }

    def publishDraftset(String id) {
        String path = "/v1/draftset/${id}/publish"
        Executor exec = getExec()
        HttpResponse response = exec.execute(
                Request.Post(apiBase.resolve(path))
                        .addHeader("Accept", "application/json")
                        .userAgent(PMDConfig.UA)
        ).returnResponse()
        if (response.getStatusLine().statusCode == 202) {
            def jobObj = new JsonSlurper().parse(EntityUtils.toByteArray(response.getEntity()))
            waitForJob(apiBase.resolve(jobObj['finished-job'] as String), jobObj['restart-id'] as String)
            if (pmd.config.empty_cache) {
                exec.execute(
                        Request.Put(pmd.config.empty_cache)
                                .addHeader("Accept", "application/json")
                                .userAgent(PMDConfig.UA))
            }
            if (pmd.config.sync_search) {
                exec.execute(
                        Request.Put(pmd.config.sync_search)
                                .addHeader("Accept", "application/json")
                                .userAgent(PMDConfig.UA))
            }

        } else {
            throw new DrafterException("Problem publishing draftset ${errorMsg(response)}")
        }


    }

}

class DrafterException extends Throwable {
    String message

    DrafterException(String message) {
        this.message = message
    }

}