Java tutorial
/* The MIT License (MIT) Copyright (c) 2015 QAXML Pty Ltd Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.qatickets.service; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.inject.Inject; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.qatickets.dao.TicketBodyDao; import com.qatickets.dao.TicketComponentDao; import com.qatickets.dao.TicketDao; import com.qatickets.dao.TicketWatcherDao; import com.qatickets.domain.Comment; import com.qatickets.domain.Component; import com.qatickets.domain.Link; import com.qatickets.domain.Project; import com.qatickets.domain.Ticket; import com.qatickets.domain.TicketBody; import com.qatickets.domain.TicketComponent; import com.qatickets.domain.TicketFileAttachment; import com.qatickets.domain.TicketWatcher; import com.qatickets.domain.UserProfile; import com.qatickets.domain.Version; import com.qatickets.search.SearchService; import com.qatickets.search.model.SearchIndexableEntity; @Service public class TicketService { private static final Log log = LogFactory.getLog(TicketService.class); @Inject private TicketDao dao; @Inject private LinkService linkService; @Inject private TicketBodyDao bodyDao; @Inject private ProjectService projectService; @Inject private VersionService versionService; @Inject private UserService userService; @Inject private ComponentService componentService; @Inject private SpamService spamService; @Inject private SearchService searchService; @Inject private TicketActivityEventService eventService; @Inject private TicketWatcherDao watcherDao; @Inject private TicketFileAttachmentService attachmentService; @Inject private TicketComponentDao ticketComponentDao; @Transactional(readOnly = true) public List<Ticket> findByProject(Project project, Pageable pageable) { log.debug("Get bugs for: " + project); List<Ticket> list = dao.findByProject(project, pageable); log.debug("Found bugs: " + list.size()); return list; } @Transactional(readOnly = false) public void save(Ticket t) { log.debug("Save Ticket: " + t); this.dao.save(t); } @Transactional(readOnly = true) public Ticket findById(int id) { return dao.findOne(id); } @Transactional(readOnly = true) public List<Comment> findCommentsByTicketId(int ticketId) { List<Comment> comments = null; Ticket ticket = this.findById(ticketId); if (ticket != null) { comments = new ArrayList<Comment>(ticket.getComments()); Collections.sort(comments, new Comparator<Comment>() { @Override public int compare(Comment c1, Comment c2) { return c1.getDate().compareTo(c2.getDate()); } }); } return comments; } @Transactional(readOnly = false) public void resetAssignee(int userId) { dao.resetAssignee(userId); } @Transactional(readOnly = false) public void resetReporter(int userId) { dao.resetReporter(userId); } @Transactional(readOnly = false) public void removeFixVersion(int versionId) { dao.removeFixVersion(versionId); } @Transactional(readOnly = false) public void removeFoundVersion(int versionId) { dao.removeFoundVersion(versionId); } @Transactional(readOnly = false) public Ticket saveNew(UserProfile user, int projectId, String summary, int type, int status, int businessImpact, int foundInVersion, int fixInVersion, int assigneeId, int reporterId, String description, String environment, String components, Integer parent) { log.debug("Save new ticket to " + projectId); // get num Project project = projectService.findById(projectId); // check if project belongs to and user is a project user if (project == null) { return null; } // clean summary summary = spamService.clean(summary, 256); // clean description description = spamService.clean(description, 40000); // clean environment environment = spamService.clean(environment, 128); // validate input values if (false == Ticket.isValidTypeValue(type)) { return null; } if (false == Ticket.isValidBusinessImpactValue(businessImpact)) { return null; } if (false == Ticket.isValidStatusValue(status)) { return null; } // get ticket number int num = project.getLastNum(); project.setLastNum(num + 1); this.projectService.save(project); // create new ticket Ticket ticket = new Ticket(); // parent if (parent != null && parent > 0) { Ticket parentTicket = this.dao.findOne(parent); ticket.setParent(parentTicket); } // load assignee and reporter UserProfile assignee = this.userService.findById(assigneeId); UserProfile reporter = this.userService.findById(reporterId); // load versions Version fixScheduledVersion = versionService.findByProjectAndId(project, fixInVersion); Version foundVersion = versionService.findByProjectAndId(project, foundInVersion); ticket.setNum(project.getIdentifier() + "-" + num); ticket.setAssignee(assignee); ticket.setBusinessImpact(businessImpact); ticket.setCreateDate(new Date()); ticket.setFixScheduledVersion(fixScheduledVersion); ticket.setFoundVersion(foundVersion); ticket.setProject(project); ticket.setReporter(reporter); ticket.setStatus(status); ticket.setSummary(summary); if (reporter != null && assignee != null && false == reporter.equals(assignee)) { ticket.addWatcher(new TicketWatcher(ticket, reporter)); ticket.addWatcher(new TicketWatcher(ticket, assignee)); } else { ticket.addWatcher(new TicketWatcher(ticket, assignee == null ? reporter : assignee)); } TicketBody body = new TicketBody(); body.setTicket(ticket); body.setDescription(description); body.setEnvironment(environment); // components if (StringUtils.isNotBlank(components)) { String[] split = components.split(","); if (split != null && split.length > 0) { for (String id : split) { id = id.trim(); if (NumberUtils.isDigits(id)) { int componentId = Integer.parseInt(id); Component component = this.componentService.findByProjectAndId(project, componentId); if (component != null) { ticket.addComponent(new TicketComponent(ticket, component)); } } } } } bodyDao.save(body); ticket.setTicketBody(body); ticket.setType(type); ticket.setUpdateDate(new Date()); ticket.setUser(user); this.save(ticket); log.debug("Ticket saved: " + ticket); body.setTicket(ticket); bodyDao.save(body); // save to SOLR SearchIndexableEntity entity = new SearchIndexableEntity(); entity.setProject(project.getId()); entity.setPk(ticket.getId()); entity.setText(ticket.getSearchableText()); entity.setDate(ticket.getCreateDate()); entity.setType(SearchService.Type.TICKET.name()); searchService.save(entity); // create ticket activity event eventService.saveNewTicket(ticket); return ticket; } @Transactional(readOnly = false) public void updateSummary(UserProfile user, int pk, String summary) { log.debug("Update summary to '" + summary + "' for PK: " + pk); final Ticket ticket = this.dao.findOne(pk); String oldSummary = StringUtils.EMPTY; if (ticket != null) { oldSummary = ticket.getSummary(); summary = spamService.clean(summary, 256); ticket.setSummary(summary); this.save(ticket); // event if (false == StringUtils.equals(summary, oldSummary)) { eventService.updateTicketSummary(user, ticket, oldSummary); } } } @Transactional(readOnly = false) public Ticket updateStatus(UserProfile user, int id, int value) { log.debug("Update status to '" + value + "' for PK: " + id); final Ticket ticket = this.dao.findOne(id); if (ticket != null) { if (Ticket.isValidStatusValue(value)) { int oldStatus = ticket.getStatus(); ticket.setStatus(value); this.save(ticket); // event if (oldStatus != ticket.getStatus()) { eventService.updateTicketStatus(user, ticket, oldStatus); } } } return ticket; } @Transactional(readOnly = true) public List<Ticket> findByProjectOrderByCreateDateDesc(Integer projectId, PageRequest pageable) { final Project project = this.projectService.findById(projectId); return dao.findByProjectOrderByCreateDateDesc(project, pageable); } @Transactional(readOnly = true) public List<Ticket> findByProjectAndAssigneeOrderByCreateDateDesc(Integer project, UserProfile user, PageRequest pageable) { return dao.findByProjectAndAssigneeOrderByCreateDateDesc(project, user, pageable); } @Transactional(readOnly = true) public List<Ticket> findByProjectAndStatusIn(Project project, List<Integer> statuses) { return dao.findByProjectAndStatusIn(project, statuses); } @Transactional(readOnly = true) public int countOpenedByProjectAndAssignee(Project project, UserProfile user) { return dao.countByProjectAndAssigneeAndStatusIn(project, user, Ticket.OPENED_STATUSES); } @Transactional(readOnly = true) public int countOpenedByProjectAndReporter(Project project, UserProfile user) { return dao.countByProjectAndReporterAndStatusIn(project, user, Ticket.OPENED_STATUSES); } @Transactional(readOnly = true) public int countOpenedByAssignee(UserProfile user) { return dao.countByAssigneeAndStatusIn(user, Ticket.OPENED_STATUSES); } @Transactional(readOnly = true) public int countOpenedByReporter(UserProfile user) { return dao.countByReporterAndStatusIn(user, Ticket.OPENED_STATUSES); } @Transactional(readOnly = true) public int countByProjectAndStatus(Project project, int status) { return dao.countByProjectAndStatus(project, status); } @Transactional(readOnly = true) public int countByProject(Project project) { return dao.countByProject(project); } @Transactional(readOnly = false) public Ticket updateType(UserProfile user, int id, int value) { log.debug("Update type to '" + value + "' for PK: " + id); final Ticket ticket = this.dao.findOne(id); if (ticket != null) { if (Ticket.isValidTypeValue(value)) { int oldType = ticket.getType(); ticket.setType(value); this.save(ticket); // event if (oldType != ticket.getType()) { eventService.updateTicketType(user, ticket, oldType); } } } return ticket; } @Transactional(readOnly = false) public Ticket updateBusinessImpact(UserProfile user, int id, int value) { log.debug("Update business impact to '" + value + "' for PK: " + id); final Ticket ticket = this.dao.findOne(id); if (ticket != null) { if (Ticket.isValidBusinessImpactValue(value)) { final int oldImpact = ticket.getBusinessImpact(); ticket.setBusinessImpact(value); this.save(ticket); // event if (oldImpact != ticket.getBusinessImpact()) { eventService.updateTicketBusinessImpact(user, ticket, oldImpact); } } } return ticket; } @Transactional(readOnly = true) public List<TicketFileAttachment> findAttachmentsByTicketId(int ticketId) { List<TicketFileAttachment> list = null; Ticket ticket = this.findById(ticketId); if (ticket != null) { list = new ArrayList<TicketFileAttachment>(ticket.getFileAttachments()); Collections.sort(list, new Comparator<TicketFileAttachment>() { @Override public int compare(TicketFileAttachment c1, TicketFileAttachment c2) { return c1.getDate().compareTo(c2.getDate()); } }); } return list; } @Transactional(readOnly = true) public List<Ticket> findAllByNumLike(String query, Integer page) { query = query.toUpperCase(); Pageable pageable = new PageRequest(0, page); // return dao.findByNumContaining(query, pageable); return null; } @Transactional(readOnly = true) public List<Ticket> findAllByIds(List<Integer> ids) { return dao.findAll(ids); } @Transactional(readOnly = true) public List<Ticket> findByParent(Ticket parent) { if (parent == null) { return Collections.<Ticket>emptyList(); } return dao.findByParent(parent); } @Transactional(readOnly = false) public void updateReporter(UserProfile user, int ticketId, int reporterId) { log.debug("Update ticket '" + ticketId + "' to reporter: " + reporterId); final Ticket ticket = this.findById(ticketId); if (ticket != null) { UserProfile oldReporter = ticket.getReporter(); UserProfile newReporter = this.userService.findById(reporterId); ticket.setReporter(newReporter); this.save(ticket); // event eventService.updateReporter(user, ticket, oldReporter, newReporter); } } @Transactional(readOnly = false) public void updateAssignee(UserProfile user, int ticketId, int assigneeId) { log.debug("Update ticket '" + ticketId + "' to assignee: " + assigneeId); final Ticket ticket = this.findById(ticketId); if (ticket != null) { UserProfile oldAssignee = ticket.getAssignee(); UserProfile newAssignee = this.userService.findById(assigneeId); ticket.setAssignee(newAssignee); this.save(ticket); // event eventService.updateAssignee(user, ticket, oldAssignee, newAssignee); } } @Transactional(readOnly = false) public void updateVersionFound(UserProfile user, int ticketId, int versionId) { log.debug("Update ticket '" + ticketId + "' to version found: " + versionId); final Ticket ticket = this.findById(ticketId); if (ticket != null) { Version oldVersion = ticket.getFoundVersion(); Version newVersion = this.versionService.findByProjectAndId(ticket.getProject(), versionId); ticket.setFoundVersion(newVersion); this.save(ticket); // event eventService.updateFoundVersion(user, ticket, oldVersion, newVersion); } } @Transactional(readOnly = false) public void updateVersionFix(UserProfile user, int ticketId, int versionId) { log.debug("Update ticket '" + ticketId + "' to version fix: " + versionId); final Ticket ticket = this.findById(ticketId); if (ticket != null) { Version oldVersion = ticket.getFixScheduledVersion(); Version newVersion = this.versionService.findByProjectAndId(ticket.getProject(), versionId); ticket.setFixScheduledVersion(newVersion); this.save(ticket); // event eventService.updateFixVersion(user, ticket, oldVersion, newVersion); } } @Transactional(readOnly = false) public void removeSubTicket(UserProfile user, int ticketId, int subTicketId) { log.debug("Remove subticket from " + ticketId + "' by PK: " + subTicketId); final Ticket ticket = this.findById(ticketId); final Ticket subticket = this.findById(subTicketId); if (ticket != null && subticket != null) { subticket.setParent(null); this.save(subticket); // event eventService.removedSubTicket(user, ticket, subticket); } } @Transactional(readOnly = false) public void addSubTicket(UserProfile user, int ticketId, int subTicketId) { log.debug("Add subticket to " + ticketId + "' by PK: " + subTicketId); final Ticket ticket = this.findById(ticketId); final Ticket subticket = this.findById(subTicketId); if (ticket != null && subticket != null) { subticket.setParent(ticket); this.save(subticket); // event eventService.addedSubTicket(user, ticket, subticket); } } @Transactional(readOnly = false) public void removeParent(UserProfile user, int ticketId) { log.debug("Remove parent from " + ticketId); final Ticket ticket = this.findById(ticketId); final Ticket parent = ticket.getParent(); if (ticket != null && parent != null) { ticket.setParent(null); this.save(ticket); // event eventService.removedSubTicket(user, parent, ticket); } } @Transactional(readOnly = false) public void updateDescription(UserProfile user, int ticketId, String description) { log.debug("updateDescription " + ticketId); final Ticket ticket = this.findById(ticketId); if (ticket != null) { String oldDesc = ticket.getTicketBody().getDescription(); description = spamService.clean(description, 40000); ticket.getTicketBody().setDescription(description); this.bodyDao.save(ticket.getTicketBody()); // event eventService.updatedDesc(user, ticket, oldDesc, description); } } @Transactional(readOnly = true) public List<TicketWatcher> findWatchersByTicket(Ticket t) { return this.watcherDao.findByTicket(t); } @Transactional(readOnly = false) public void stopWatching(UserProfile user, Ticket t) { TicketWatcher w = this.watcherDao.findByTicketAndUser(t, user); if (w != null) { this.watcherDao.delete(w); } } @Transactional(readOnly = false) public void startWatching(UserProfile user, Ticket t) { TicketWatcher w = this.watcherDao.findByTicketAndUser(t, user); if (w == null) { w = new TicketWatcher(t, user); this.watcherDao.save(w); } } @Transactional(readOnly = false) public void updateProgress(UserProfile user, int ticketId, int progress) { Ticket ticket = this.findById(ticketId); if (ticket != null) { if (progress < 0) { progress = 0; } if (progress > 100) { progress = 100; } int oldProgress = ticket.getProgress(); ticket.setProgress(progress); this.save(ticket); // event this.eventService.updateProgress(user, ticket, oldProgress, progress); } } @Transactional(readOnly = false) public void addLink(UserProfile user, String linkTicketId, int ticketId) { Ticket ticket = this.findById(ticketId); Ticket link = this.findById(ticketId); if (ticket != null && link != null && ticket.equals(link) == false) { Link l = new Link(); l.setDate(new Date()); l.setSource(ticket); l.setDestination(link); l.setType(Link.LinkType.REL); l.setUser(user); this.linkService.save(l); // event // this.eventService.addedLink(user, ticket, oldProgress, progress); } } @Transactional(readOnly = false) public void updateComponents(UserProfile user, int projectId, int ticketId, Integer[] components) { log.debug("Update components for ticket: " + ticketId + " to '" + components + "'"); final Ticket ticket = this.findById(ticketId); final Project project = this.projectService.findById(projectId); if (ticket == null || project == null) { return; } // delete existing ticket components ticketComponentDao.deleteByTicket(ticket); final Set<TicketComponent> list = new HashSet<TicketComponent>(); ticket.setComponents(list); if (!ArrayUtils.isEmpty(components)) { for (Integer componentId : components) { final Component component = this.componentService.findByProjectAndId(project, componentId); if (component != null) { log.debug("Add component: " + component.getName() + " to ticket: " + ticket.getNum()); ticket.addComponent(new TicketComponent(ticket, component)); } } } this.save(ticket); } @Transactional(readOnly = false) public void deleteComponent(UserProfile user, int ticketId, int componentId) { log.debug("Delete component from ticket: " + ticketId + " '" + componentId + "'"); final Ticket ticket = this.findById(ticketId); if (ticket == null) { return; } ticketComponentDao.deleteComponentFromTicket(ticket, componentId); } @Transactional(readOnly = false) public void deleteTicket(int id) { // delete from search engine this.searchService.deleteByTicket(id); // delete links this.linkService.deleteByTicket(id); // delete attachments // this.attachmentService.deleteByTicket(id); this.dao.delete(id); } @Transactional(readOnly = true) public List<Integer> findIdsByProjectId(int id) { return dao.findIdsByProjectId(id); } }