Плагин будет представлять собой вкладку в административной части проекта, через которую и будем осуществлять работу с базой данных.
Плагин буду делать для джира 4.4.4. Для начала создадим пустой проект. Проект можно создать с помощью Atlassian SDK, а затем открыть в любимой IDE. В данном случае я буду работать с Netbeans. Файловая структура проекта будет выглядеть следующим образом:
Создадим страничку, на которой будет находиться наш функционал. В джире есть несколько механизмов для создания страниц – report, webwork actions, servlet, для решения этой задачи выберем webwork actions. В момент знакомства с JIRA в этом механизме все было предельно просто, понятно и знакомо (по сути это тот же Apache Struts). Создадим новый класс MyAction.java, унаследованный от класса JiraWebActionSupport. И создадим velocity шаблон succeess.vm такого содержания:
MyAction template
Теперь осталось добавить следующий элемент в atlassian-plugin.xml для создания новой страницы:
<webwork1 key="actions" name="MyActions"> <actions> <action name="com.edsd.jira.plugins.simpleplugin.action.MyAction" alias="action" roles-required="admin"> <view name="success">/myaction/success.vm</view> </action> </actions> </webwork1>
И при переходе по ссылке http://myserver/secure/action.jspa мы увидим созданную нами страницу:
Теперь сделаем так, чтоб эта страничка стала такой же, как вкладка в админской части проекта.
Для начала сделаем саму ссылку:
Чтоб ссылка выглядела отдельной группой, добавим в atlassian-plugin.xml новую секцию (web-section). Затем в эту секцию уже добавим саму ссылку (web-item):
<web-section key="my_section" name="MySection" location="atl.jira.proj.config" weight="50"/> <web-item key="my_item_link" name="MyTab" section="atl.jira.proj.config/my_section" weight="10"> <label key="MyLink" /> <link linkId="my_item_link">/secure/action.jspa</link> </web-item>
Но при клике по ссылке мы все равно будем получать страницу без оформления, чтобы это исправить внесем изменения в MyAction.java. На самом деле при переходе по ссылке http://myserver/secure/action.jspa вызывается метод execute() и возвращаемое им значение –это success поэтому-то мы именно так описали наш action в atlassian-plugin.xml. Так мы будем явно передавать, какой проект сейчас активен, и добавлять «шапку» проекта к вкладке.
public class MyAction extends JiraWebActionSupport { private Project project; @Override public String execute() throws Exception { project = getSelectedProjectObject(); //добавление шапки проекта к вкладке request.setAttribute("com.atlassian.jira.projectconfig.util.ServletRequestProjectConfigRequestCache:project", project); return super.execute(); } }
Но так передается только html код без css. Чтоб добавить css к странице допишем в atlassian-plugin.xml
<web-resource key="my-resources"> <dependency>com.atlassian.jira.jira-project-config-plugin:project-config-global</dependency> <context>my-resources</context> </web-resource>
Здесь мы добавили зависимость dependency для самих ресурсов и объявили через context то, как мы можем получить доступ к этим ресурсам через менеджера.
Тогда velocity шаблон приведем к такому виду:
<!DOCTYPE HTML> <html> <head> <title>MyTestPage</title> <meta name="decorator" content="atl.admin"/> <meta name="projectKey" content="$project.getKey()"/> <meta name="projectId" content="$project.getId()"/> <meta name="admin.active.tab" content="my_item_link"/> <meta name="admin.active.section" content="atl.jira.proj.config"/> $webResourceManager.requireResourcesForContext("my-resources") </head> <body> MyAction template </body> </html>
В результате получим страницу:
Добавим функционал работы с базой данных. Пользоваться будем Active Objects (дальше AO). Для начала создадим пакет logic. В нем опишем объект, с которым будем работать, пусть это будет элементарный Student:
public interface Student { public void setName(String name); public String getName(); }
В пакете entity опишем наш интерфейс-сущность, который будем хранить в БД. Пусть для примера в базе еще будем хранить время создания этой записи:
import java.util.Date; import net.java.ao.Entity; public interface StudentEntity extends Entity, Student { public Date getCreated(); public void setCreated(Date created); }
Добавим теперь наш AO в atlassian-plugin.xml:
<component-import key="ao" name="Active Objects service" interface="com.atlassian.activeobjects.external.ActiveObjects"> <description>Component to access Active Objects functionality from the plugin</description> </component-import> <ao key="ao-module"> <entity>com.edsd.jira.plugins.simpleplugin.entity.StudentEntity</entity> </ao>
Подробнее про подключение AO к плагину можно почитать тут.
Теперь разберемся с взаимодействием нашего приложения с базой данных. Определим интерфейс StudentDAO из пакета DAO, содержащий набор необходимых методов:
public interface StudentDAO { public StudentEntity addStudent(Student student) throws Exception; public StudentEntity[] getStudents() throws Exception; } Реализацию интерфейса сделаем в пакете DAO.Impl в классе StudentDAOImpl. public class StudentDAOImpl implements StudentDAO { private final ActiveObjects ao; public StudentDAOImpl(ActiveObjects ao) { this.ao = ao; } @Override public StudentEntity addStudent(final Student student) throws Exception { return ao.executeInTransaction(new TransactionCallback<StudentEntity>() { @Override public StudentEntity doInTransaction() { StudentEntity entity = ao.create(StudentEntity.class); entity.setName(student.getName()); entity.setCreated(new Date(System.currentTimeMillis())); entity.save(); return entity; } }); } @Override public StudentEntity[] getStudents() throws Exception { return ao.executeInTransaction(new TransactionCallback<StudentEntity[]>() { @Override public StudentEntity[] doInTransaction() { return ao.find(StudentEntity.class); } }); } }
Теперь создадим класс DAOFactory в пакете DAO, к которому будем обращаться за нашими реализациями DAO, от которых и будем вызывать необходимые нам методы:
public class DAOFactory { private static StudentDAO studentDAO = null; private static DAOFactory instance = null; private static ActiveObjects ao; public DAOFactory(ActiveObjects ao) { DAOFactory.ao = ao; } public static synchronized DAOFactory getInstance() { if (instance == null) { instance = new DAOFactory(ao); } return instance; } public StudentDAO getStudentDAO() { if (studentDAO == null) { studentDAO = new StudentDAOImpl(ao); } return studentDAO; } }
Добавим в atlassian-plugin.xml нашу DAOFactory. Это необходимо чтобы избежать проблем с обращением к AO. Кому интересно: рассуждение на тему Active Objects injection.
<component key="dao-factory" class="com.edsd.jira.plugins.simpleplugin.DAO.DAOFactory"> </component>
Собственно, все необходимое для работы с базой данных мы описали и реализовали, осталось теперь добавить функционал в MyAction:
public class MyAction extends JiraWebActionSupport { private Project project; private StudentEntity[] students; @Override public String execute() throws Exception { project = getSelectedProjectObject(); request.setAttribute("com.atlassian.jira.projectconfig.util.ServletRequestProjectConfigRequestCache:project", project); students = DAOFactory.getInstance().getStudentDAO().getStudents(); return super.execute(); } public String doAdd() throws Exception { String name = request.getParameterValues("name")[0]; Student student = new StudentImpl(name); DAOFactory.getInstance().getStudentDAO().addStudent(student); ServletActionContext.getResponse().sendRedirect("/secure/action.jspa"); return NONE; } }
И в шаблоне velocity привести тег body к такому виду:
<body> <form action="/secure/action!add.jspa"> <input type="text" name="name"/> <input type="submit" value="OK"/> </form> <table> <thead> <th>id</th> <th>name</th> <th>created</th> </thead> <tbody> #foreach($student in $students) <tr> <td>$student.getID()</td> <td>$student.getName()</td> <td>$student.getCreated()</td> </tr> #end </tbody> </table> </body>
В общем, запускаем, тестируем, получаем:
На этом на первый раз все, в следующей статье расскажу:
- как создать таблицы, аналогичные таблицам во вкладках Компоненты и Версии,
- как создать выпадающий список, с таким же оформлением как стандартный в JIRA,
- что такое JIRA.Restfultable
- и как пользоваться JIRA REST API.
Весь код плагина на GitHub
ссылка на оригинал статьи http://habrahabr.ru/post/256789/
Добавить комментарий