Пишем Jenkins Plugin: Web Methods

Первое знакомство с Web Methods

Если вы уже использовали методы объекта, начинающиеся с do в дескрипторе (обычно doFill[Field], doCheck[Field]), то значит, вы уже работали с Web Methods. Если посмотреть в консоль браузера, по каждому полю с таким связанным методом уходят ajax-запросы на валидацию или получение списка с вариантами.

Что это?

Веб-методы, это просто способ перехватить и обработать HTTP-запрос к одному из ресурсов, обслуживащих один из путей. Если кто сталкивался с Jersey, то класс, в котором определен метод подобен ресурсу, а сам метод - это путь, лежащий внутри ресурса. Jenkins - это веб-приложение, в котором всей кухней низкоуровнего взаимодействия по HTTP занимается Stapler. Именно он вводит это понятие.

Как происходит адресация?

Название метода, начинающееся с do позволяет через reflection-api достать конкретный эндпоинт, на котором и обслуживать запросы. Например метод doStart() будет слушать запросы по пути /.../start, где /.../ - это путь с которым связан родительский объект, будь то дескриптор, экшен или что-то иное. При этом на корень можно повесить метод, который будет называться doIndex.

Алиасы

Каждый метод может обладать несколькими алиасами, которые будут лежать по другому пути, но ссылаться на тот же метод. Для этого существует аннотация @WebMethod:

@WebMethod(name = {"run","go.xml"})
public HttpResponse doStart() {
  ...
}

При добавлении такой аннотации метод будет так же отзываться и на /run и на /go.xml. Это бывает полезно, если конечный урл должен содержать символ, запрещенный к употреблению в Java идентификаторах.

Параметры метода

В метод могут инжектиться следующие параметры:

  • StaplerRequest/HttpServletRequest - все что изначально содержалось в запросе.
  • StaplerResponse/HttpServletResponse - при помощи этого объекта можно повлиять на конечный ответ.
  • Параметры с аннотациями. Например @Header или @QueryParameter. В этом случае важно имя параметра, именно по нему определяется, какой конкретно заголовок или параметр достать из запроса. Тип объекта может быть впринципе любым, для конвертации используется библиотека Apache Commons Beanutils.

Аннотации, аналогичные @Header или @QueryParameter возможно создать и самому, при помощи @InjectedParameter. Как это сделать - будет рассказано чуть позже.

Дополнительная логика обработки запроса

Стоит упомянуть о возможностях дополнительной пред-обработки (или пост-обработки)при помощи таких аннотаций как

  • @RequirePOST - в случае если запрос не POST, возвращает код ответа 405. Это полезно, чтобы защитить методы, делающие изменения при помощи csrf токена (о проблемах которые это может вызвать я писал ранее
  • @RespondSuccess - автоматически добавляется если метод void. Если все прошло успешно - возвращаем ok.

О том как сделать свою аннотацию с какой то логикой при помощи @InterceptorAnnotation, мы обязательно поговорим отдельно.

Возвращаемое значение

Метод может быть void, тогда при его успешности автоматом вернется 200 OK. Помимо уже известных ранее возвращаемых значений с набором элементов, можно вернуть вообще любой ответ. Много полезных методов-фабрик содержится в классе HttpResponses