Java tutorial
/** * GRAVITY WORKFLOW AUTOMATION * (C) Copyright 2015 Orcon Limited * (C) Copyright 2016 Peter Harrison * * This file is part of Gravity Workflow Automation. * * Gravity Workflow Automation is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * Gravity Workflow Automation is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Gravity Workflow Automation. * If not, see <http://www.gnu.org/licenses/>. */ package nz.net.orcon.kanban.controllers; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import javax.annotation.Resource; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.version.VersionException; import nz.net.orcon.kanban.automation.AutomationEngine; import nz.net.orcon.kanban.automation.CardListener; import nz.net.orcon.kanban.automation.ClusterManager; import nz.net.orcon.kanban.model.Board; import nz.net.orcon.kanban.model.Card; import nz.net.orcon.kanban.model.CardEvent; import nz.net.orcon.kanban.model.CardHolder; import nz.net.orcon.kanban.model.CardNotification; import nz.net.orcon.kanban.model.CardTask; import nz.net.orcon.kanban.model.Rule; import nz.net.orcon.kanban.tools.CardTools; import nz.net.orcon.kanban.tools.ListTools; import nz.net.orcon.kanban.tools.OcmMapperFactory; import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.ocm.manager.ObjectContentManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; /** * */ @Controller @RequestMapping("/board/{boardId}/phases/{phaseId}/cards") public class CardController { private static final Logger logger = LoggerFactory.getLogger(CardController.class); @Resource(name = "ocmFactory") OcmMapperFactory ocmFactory; @Autowired TemplateCache templateCache; @Autowired BoardsCache boardCache; @Autowired RuleCache ruleCache; @Autowired CardTools cardTools; @Autowired ListTools listTools; @Autowired CardLockInterface cardsLockCache; @Autowired CardListener cardListener; //@Autowired //AutomationEngine automationEngine; @Autowired private NotificationController notificationController; @Autowired ClusterManager clusterManager; @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}", method = RequestMethod.GET) public @ResponseBody Card getCard(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @RequestParam(required = false) String view) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Card card = null; try { card = cardTools.getCard(boardId, phaseId, cardId, ocm); if (card == null) { throw new ResourceNotFoundException(); } if (StringUtils.equals(view, "full")) { card.setFields(this.cardTools.getFieldsForCard(card, ocm)); } else { card.setFields(this.cardTools.getFieldsForCard(card, view, ocm)); } templateCache.applyTemplate(card); cardsLockCache.applyLockState(card); } finally { ocm.logout(); } return card; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/examine", method = RequestMethod.GET) public @ResponseBody Boolean examineCard(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { logger.info("Automation to Examine Card: " + boardId + "/" + phaseId + "/" + cardId); CardHolder cardHolder = new CardHolder(); cardHolder.setBoardId(boardId); cardHolder.setCardId(cardId); cardListener.addCardHolder(cardHolder); return true; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/explain", method = RequestMethod.GET) public @ResponseBody Map<String, Map<String, Boolean>> explainCard(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { logger.info("Explain Card: " + boardId + "/" + phaseId + "/" + cardId); CardHolder cardHolder = new CardHolder(); cardHolder.setBoardId(boardId); cardHolder.setCardId(cardId); //Map<String, Map<String,Boolean>> explain = automationEngine.explain(cardHolder); //return explain; return null; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/view/{viewId}", method = RequestMethod.GET) public @ResponseBody Card getCardByView(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String viewId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Card card; try { card = cardTools.getCard(boardId, phaseId, cardId, ocm); if (card == null) { throw new ResourceNotFoundException(); } card.setFields(this.cardTools.getFieldsForCard(card, viewId, ocm)); templateCache.applyTemplate(card); cardsLockCache.applyLockState(card); } finally { ocm.logout(); } return card; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/move/{newPhaseId}", method = RequestMethod.GET) public @ResponseBody Card moveCard(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String newPhaseId) throws Exception { logger.info("Moving Card - card:" + boardId + "/" + phaseId + "/" + cardId + " -> " + newPhaseId); ObjectContentManager ocm = ocmFactory.getOcm(); Card card; try { Session session = ocm.getSession(); listTools.ensurePresence(String.format(URI.PHASES_URI, boardId, newPhaseId), "cards", session); String source = String.format(URI.CARDS_URI, boardId, phaseId, cardId); String destination = String.format(URI.CARDS_URI, boardId, newPhaseId, cardId); session.move(source, destination); storeCardEvent(URI.HISTORY_URI, "Moving card from " + phaseId + " to " + newPhaseId, boardId, newPhaseId, cardId, "info", "move-" + newPhaseId, ocm); ocm.save(); card = (Card) ocm.getObject(Card.class, destination); cardsLockCache.applyLockState(card); boardCache.incrementCardCount(boardId, phaseId, -1); boardCache.incrementCardCount(boardId, newPhaseId, 1); } finally { ocm.logout(); } return card; } @RequestMapping(value = "", method = RequestMethod.POST) public @ResponseBody Card createCard(@PathVariable String boardId, @PathVariable String phaseId, @RequestBody Card card) throws Exception { templateCache.correctCardFieldTypes(boardId, card); ObjectContentManager ocm = ocmFactory.getOcm(); try { if (card.getPath() == null) { listTools.ensurePresence(String.format(URI.PHASES_URI, boardId, phaseId), "cards", ocm.getSession()); Long newId = this.clusterManager.getId(String.format(URI.BOARD_URI, boardId), "cardno"); card.setPath(String.format(URI.CARDS_URI, boardId, phaseId, newId.toString())); card.setId(newId); card.setCreated(new Date()); card.setCreator(listTools.getCurrentUser()); ocm.insert(card); ocm.save(); ensureCardNodes(boardId, phaseId, newId.toString(), ocm); Node node = ocm.getSession() .getNode(String.format(URI.FIELDS_URI, boardId, phaseId, card.getId().toString())); // Add Fields for (Entry<String, Object> entry : card.getFields().entrySet()) { Object correctedValue = templateCache.correctFieldType(entry.getKey(), entry.getValue(), card.getBoard(), card.getTemplate()); updateValue(node, entry.getKey(), correctedValue, null); } storeCardEvent(URI.HISTORY_URI, "Creating Card", boardId, phaseId, card.getId().toString(), "info", "create", ocm); ocm.save(); logger.info("New Card - board:" + card.getBoard() + " ID: " + card.getId()); boardCache.incrementCardCount(boardId, phaseId, 1); } else { logger.warn("Attempt to update card using POST"); throw new Exception("Attempt to Update Card using POST. Use PUT instead"); } } finally { ocm.logout(); } return card; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "", method = RequestMethod.GET) public @ResponseBody Map<String, String> getCardList(@PathVariable String boardId, @PathVariable String phaseId, @RequestParam(required = false) String filter) throws Exception { if (phaseId.startsWith("archive")) { return new HashMap<String, String>(); } ObjectContentManager ocm = ocmFactory.getOcm(); Map<String, String> result; try { if (StringUtils.isNotBlank(filter)) { result = listTools.basicQuery(boardId, phaseId, filter, "id", ocm); } else { result = listTools.list(String.format(URI.CARDS_URI, boardId, phaseId, ""), "id", ocm.getSession()); } } catch (PathNotFoundException e) { result = new HashMap<String, String>(); } finally { ocm.logout(); } return result; } // TODO remove this method once not used. @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/basicsummary/{junk}", method = RequestMethod.GET) public @ResponseBody Map<String, String> getBasicCardList(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String junk) throws Exception { return getCardList(boardId, phaseId, null); } // TODO Remove this method once calling methods use a request parameter for filter. @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/filter/{filterId}/basicsummary", method = RequestMethod.GET) public @ResponseBody Map<String, String> getFilteredCardList(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String filterId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { return listTools.basicQuery(boardId, phaseId, filterId, "id", ocm); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'ADMIN')") @RequestMapping(value = "/{cardId}", method = RequestMethod.DELETE) public @ResponseBody void deleteCard(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { Node node = ocm.getSession().getNode(String.format(URI.CARDS_URI, boardId, phaseId, cardId)); if (node == null) { ocm.logout(); throw new ResourceNotFoundException(); } node.remove(); ocm.save(); boardCache.incrementCardCount(boardId, phaseId, -1); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/fields/{field}", method = RequestMethod.POST) public @ResponseBody void updateField(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String field, @RequestBody Map<String, Object> body) throws Exception { if (!cardsLockCache.lock(boardId, cardId)) { logger.info("Card is Locked : " + boardId + "/" + cardId); throw new Exception("Card is Locked"); } String value = getField("value", body); updateValue(boardId, phaseId, cardId, field, value); } public void updateValue(String boardId, String phaseId, String cardId, String field, Object value) throws Exception { logger.info("Setting " + field + " = " + value); ObjectContentManager ocm = ocmFactory.getOcm(); try { Card card = cardTools.getCard(boardId, phaseId, cardId, ocm); Node node = ocm.getSession() .getNode(String.format(URI.FIELDS_URI, card.getBoard(), card.getPhase(), card.getId())); Object correctedValue = templateCache.correctFieldType(field, value, card.getBoard(), card.getTemplate()); Object currentValue = null; try { Property property = node.getProperty(field); currentValue = this.cardTools.getRealValue(property); } catch (PathNotFoundException e) { // Situation Normal } boolean corrected = updateValue(node, field, correctedValue, currentValue); if (corrected) { storeCardEvent(URI.HISTORY_URI, "Changing field " + field + " from " + currentValue + " to " + value, boardId, phaseId, cardId, "info", "update-" + field, ocm); } ocm.save(); } finally { ocm.logout(); } } private boolean updateValue(Node node, String field, Object value, Object currentValue) throws RepositoryException, VersionException, LockException, ConstraintViolationException { if (value instanceof Boolean) { Boolean booleanValue = (Boolean) value; if (!value.equals(currentValue)) { node.setProperty(field, booleanValue); return true; } } else if (value instanceof Integer) { Integer integerValue = (Integer) value; if (!value.equals(currentValue)) { node.setProperty(field, integerValue); return true; } } else if (value instanceof Long) { Long longValue = (Long) value; if (!value.equals(currentValue)) { node.setProperty(field, longValue); return true; } } else if (value instanceof String) { String stringValue = (String) value; if (!value.equals(currentValue)) { node.setProperty(field, stringValue); return true; } } else if (value instanceof Date) { Calendar dateValue = new GregorianCalendar(); dateValue.setTime((Date) value); if (!value.equals(currentValue)) { node.setProperty(field, dateValue); return true; } } else if (value != null) { if (!value.equals(currentValue)) { node.setProperty(field, value.toString()); return true; } } return false; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/history", method = RequestMethod.GET) public @ResponseBody Collection<CardEvent> getHistoryList(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { return ocm.getChildObjects(CardEvent.class, String.format(URI.HISTORY_URI, boardId, phaseId, cardId, "")); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/history/{historyId}", method = RequestMethod.GET) public @ResponseBody CardEvent getHistory(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String historyId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { return (CardEvent) ocm.getObject(CardEvent.class, String.format(URI.HISTORY_URI, boardId, phaseId, cardId, historyId)); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/history", method = RequestMethod.POST) public @ResponseBody CardEvent saveHistory(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @RequestBody Map<String, Object> body) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardEvent event; try { String value = getField("value", body); event = storeCardEvent(URI.HISTORY_URI, value, boardId, phaseId, cardId, "info", "", ocm); ocm.save(); } finally { ocm.logout(); } return event; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/comments", method = RequestMethod.GET) public @ResponseBody Collection<CardEvent> getComments(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Collection<CardEvent> cardEvents; try { cardEvents = ocm.getChildObjects(CardEvent.class, String.format(URI.COMMENTS_URI, boardId, phaseId, cardId, "")); } finally { ocm.logout(); } return cardEvents; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/comments", method = RequestMethod.POST) public @ResponseBody CardEvent saveComment(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @RequestBody Map<String, Object> body) throws Exception { String value = getField("value", body); String user = getField("user", body); String time = getField("time", body); ObjectContentManager ocm = ocmFactory.getOcm(); CardEvent event; try { if ((user != null) || (time != null)) { event = storeCardEvent(URI.COMMENTS_URI, value, boardId, phaseId, cardId, "info", "", user, templateCache.stringToDate(time), ocm); } else { event = storeCardEvent(URI.COMMENTS_URI, value, boardId, phaseId, cardId, "info", "comment", ocm); } ocm.save(); } finally { ocm.logout(); } return event; } public CardEvent saveComment(String boardId, String phaseId, String cardId, String comment) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardEvent event; try { event = storeCardEvent(URI.COMMENTS_URI, comment, boardId, phaseId, cardId, "info", "comment", ocm); ocm.save(); } finally { ocm.logout(); } return event; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/alerts", method = RequestMethod.POST) public @ResponseBody CardEvent saveAlert(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @RequestBody Map<String, Object> body) throws Exception { String value = getField("value", body); String user = getField("user", body); String time = getField("time", body); String level = getField("level", body); ObjectContentManager ocm = ocmFactory.getOcm(); CardEvent event = null; try { if ((user != null) || (time != null)) { event = storeCardEvent(URI.ALERTS_URI, value, boardId, phaseId, cardId, level, "alert", user, templateCache.stringToDate(time), ocm); } else { event = storeCardEvent(URI.ALERTS_URI, value, boardId, phaseId, cardId, level, "alert", ocm); } ocm.save(); } finally { ocm.logout(); } return event; } public CardEvent saveAlert(String boardId, String phaseId, String cardId, String message, String level) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardEvent event; try { event = storeCardEvent(URI.ALERTS_URI, message, boardId, phaseId, cardId, level, "alert", ocm); ocm.save(); } finally { ocm.logout(); } return event; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/alerts", method = RequestMethod.GET) public @ResponseBody Collection<CardEvent> getAlerts(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Collection<CardEvent> cardEvents; try { cardEvents = ocm.getChildObjects(CardEvent.class, String.format(URI.ALERTS_URI, boardId, phaseId, cardId, "")); } finally { ocm.logout(); } return cardEvents; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/alerts/{alertId}", method = RequestMethod.GET) public @ResponseBody CardEvent getAlert(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String alertId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Object cardEvent; try { cardEvent = ocm.getObject(CardEvent.class, String.format(URI.ALERTS_URI, boardId, phaseId, cardId, alertId)); } finally { ocm.logout(); } return (CardEvent) cardEvent; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/alerts/{alertId}/dismiss", method = RequestMethod.GET) public @ResponseBody void dismisAlert(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String alertId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { Session session = ocm.getSession(); listTools.ensurePresence(String.format(URI.ALERTS_URI, boardId, phaseId, cardId, alertId), "alerts", session); String source = String.format(URI.ALERTS_URI, boardId, phaseId, cardId, alertId); String destination = String.format(URI.HISTORY_URI, boardId, phaseId, cardId, alertId); session.move(source, destination); storeCardEvent(URI.HISTORY_URI, "Moving Alert " + alertId + " to " + "History " + alertId, boardId, phaseId, cardId, "info", "dismiss-alert", ocm); ocm.save(); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks", method = RequestMethod.GET) public @ResponseBody Collection<CardTask> getTasks(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Collection<CardTask> cardTasks; try { cardTasks = ocm.getChildObjects(CardTask.class, String.format(URI.TASKS_URI, boardId, phaseId, cardId, "")); Map<Integer, CardTask> cardTaskMap = new TreeMap<Integer, CardTask>(); if (cardTasks != null) { for (CardTask cardTask : cardTasks) { Rule rule = ruleCache.getItem(boardId, cardTask.getTaskid()); if (rule != null) { cardTaskMap.put(rule.getIndex(), cardTask); } } } cardTasks = cardTaskMap.values(); } finally { ocm.logout(); } return cardTasks; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/fixtasks", method = RequestMethod.GET) public @ResponseBody Set<String> fixTasks(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { Collection<CardTask> tasks = getTasks(boardId, phaseId, cardId); Set<String> tasksToCleanUp = new HashSet<String>(); for (CardTask task : tasks) { if (task.getId().contains("[")) { tasksToCleanUp.add(task.getTaskid()); } } for (String taskId : tasksToCleanUp) { logger.info("Duplicate Task Found - Cleaning Up: " + taskId + " on card " + cardId); try { int count = 2; while (true) { logger.info("Cleaning Up Task : " + taskId + "[" + count + "] on card " + cardId); deleteTask(boardId, phaseId, cardId, taskId + "[2]"); count++; } } catch (ResourceNotFoundException e) { logger.info("(Resource Not found) Cleaning Up Complete for : " + taskId + " on card " + cardId); } catch (PathNotFoundException e) { logger.info("(Path Not found) Cleaning Up Complete for : " + taskId + " on card " + cardId); } } return tasksToCleanUp; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks", method = RequestMethod.POST) public @ResponseBody void saveTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @RequestBody CardTask task) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { ensureCardNodes(boardId, phaseId, cardId, ocm); saveTask(boardId, phaseId, cardId, task, ocm); ocm.save(); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasksummary", method = RequestMethod.GET) public @ResponseBody Map<String, Integer> getTaskSummary(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); Map<String, Integer> result; try { Node node = ocm.getSession().getNode(String.format(URI.TASKS_URI, boardId, phaseId, cardId, "")); int complete = 0; int incomplete = 0; int all = 0; NodeIterator nodes = node.getNodes(); while (nodes.hasNext()) { Node nextNode = nodes.nextNode(); Property property = nextNode.getProperty("complete"); if (property != null) { all++; if (property.getBoolean()) { complete++; } else { incomplete++; } } } result = new HashMap<String, Integer>(); result.put("complete", complete); result.put("incomplete", incomplete); result.put("all", all); } finally { ocm.logout(); } return result; } public void saveTask(String boardId, String phaseId, String cardId, CardTask task, ObjectContentManager ocm) throws Exception { task.setPath(String.format(URI.TASKS_URI, boardId, phaseId, cardId, task.getTaskid())); ocm.insert(task); } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks/{taskId}", method = RequestMethod.GET) public @ResponseBody CardTask getTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String taskId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardTask cardTask; try { cardTask = cardTools.getCardTask(boardId, phaseId, cardId, taskId, ocm); } finally { ocm.logout(); } return cardTask; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks/{taskId}/complete", method = RequestMethod.GET) public @ResponseBody CardTask completeTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String taskId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardTask cardTask; try { cardTask = cardTools.getCardTask(boardId, phaseId, cardId, taskId, ocm); if (cardTask == null) { cardTask = createTask(boardId, phaseId, cardId, taskId, true, ocm); return cardTask; } if (cardTask.getComplete()) { return cardTask; } cardTask.setComplete(true); cardTask.setOccuredTime(new Date()); cardTask.setUser(listTools.getCurrentUser()); ocm.update(cardTask); Card card = new Card(); card.setPath(cardTask.getPath()); storeCardEvent(URI.HISTORY_URI, "Completing Task " + cardTask.getDetail() + " by " + cardTask.getUser(), card.getBoard(), card.getPhase(), cardId, "info", "complete-" + cardTask.getTaskid(), ocm); ocm.save(); } finally { ocm.logout(); } return cardTask; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks/{taskId}/take", method = RequestMethod.GET) public @ResponseBody CardTask takeTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String taskId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardTask cardTask; try { cardTask = cardTools.getCardTask(boardId, phaseId, cardId, taskId, ocm); if (cardTask == null) { cardTask = createTask(boardId, phaseId, cardId, taskId, true, ocm); return cardTask; } if (cardTask.getComplete() || !StringUtils.isEmpty(cardTask.getUser())) { return cardTask; } cardTask.setUser(listTools.getCurrentUser()); ocm.update(cardTask); Card card = new Card(); card.setPath(cardTask.getPath()); storeCardEvent(URI.HISTORY_URI, "Assigning Task " + cardTask.getDetail() + " to " + cardTask.getUser(), card.getBoard(), card.getPhase(), cardId, "info", "assign-" + cardTask.getTaskid(), ocm); ocm.save(); } finally { ocm.logout(); } return cardTask; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks/{taskId}/revert", method = RequestMethod.GET) public @ResponseBody CardTask revertTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String taskId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); CardTask cardTask; try { cardTask = cardTools.getCardTask(boardId, phaseId, cardId, taskId, ocm); if (cardTask == null) { throw new ResourceNotFoundException(); } cardTask.setComplete(false); cardTask.setOccuredTime(null); cardTask.setUser(null); ocm.update(cardTask); Card card = new Card(); card.setPath(cardTask.getPath()); storeCardEvent(URI.HISTORY_URI, "Reverting Task " + cardTask.getDetail(), card.getBoard(), card.getPhase(), cardId, "info", "revert-" + cardTask.getTaskid(), ocm); ocm.save(); } finally { ocm.logout(); } return cardTask; } private CardTask createTask(String boardId, String phaseId, String cardId, String taskId, boolean complete, ObjectContentManager ocm) throws Exception { Card card = this.cardTools.getCard(boardId, phaseId, cardId, ocm); if (card == null) { return null; } Rule rule = ruleCache.getItem(boardId, taskId); CardTask cardTask = new CardTask(); cardTask.setTaskid(rule.getId()); cardTask.setDetail(rule.getName()); cardTask.setComplete(complete); cardTask.setOccuredTime(new Date()); cardTask.setUser(listTools.getCurrentUser()); saveTask(card.getBoard(), card.getPhase(), cardId, cardTask, ocm); if (complete) { storeCardEvent(URI.HISTORY_URI, "Completing Task " + cardTask.getDetail() + " by " + cardTask.getUser(), card.getBoard(), card.getPhase(), cardId, "info", "complete-" + cardTask.getTaskid(), ocm); } return cardTask; } private CardEvent storeCardEvent(String uri, String detail, String boardId, String phaseId, String cardId, String level, String category, ObjectContentManager ocm) throws Exception { return storeCardEvent(uri, detail, boardId, phaseId, cardId, level, category, listTools.getCurrentUser(), new Date(), ocm); } private CardEvent storeCardEvent(String uri, String detail, String boardId, String phaseId, String cardId, String level, String category, String user, Date time, ObjectContentManager ocm) throws Exception { Card card = cardTools.getCard(boardId, phaseId, cardId, ocm); if (card == null) { logger.warn("Card Not Found when Storing Card Event: " + boardId + "/" + phaseId + "/" + cardId); return null; } ensureCardNodes(card.getBoard(), card.getPhase(), cardId, ocm); Long newId = clusterManager.getId(String.format(URI.BOARD_URI, boardId), "historyno"); CardEvent event = new CardEvent(); event.setPath(String.format(uri, card.getBoard(), card.getPhase(), cardId, newId.toString())); event.setUser(user); event.setOccuredTime(time); event.setDetail(detail); event.setLevel(level); event.setCategory(category); ocm.insert(event); return event; } private void ensureCardNodes(String boardId, String phaseId, String cardId, ObjectContentManager ocm) throws RepositoryException { listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "history", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "attachments", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "comments", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "tasks", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "alerts", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "fields", ocm.getSession()); listTools.ensurePresence(String.format(URI.CARDS_URI, boardId, phaseId, cardId), "notifications", ocm.getSession()); } private String getField(String name, Map<String, Object> list) { Object ob = list.get(name); if (ob != null) { return ob.toString(); } return null; } @SuppressWarnings("unchecked") private List<CardNotification> retrieveNotifications(ObjectContentManager ocm, String cardNotificationUrl, String startDate, String endDate) throws ParseException { final List<CardNotification> cardNotifications = new ArrayList<CardNotification>(); for (CardNotification cardNotification : (Collection<CardNotification>) ocm .getChildObjects(CardNotification.class, cardNotificationUrl)) { final Date notificationTime = cardNotification.getOccuredTime(); if (notificationTime.after(listTools.decodeShortDate(startDate))) { if (notificationTime.before(listTools.decodeShortDate(endDate))) { cardNotifications.add(cardNotification); } } } return cardNotifications; } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/tasks/{taskId}", method = RequestMethod.DELETE) public void deleteTask(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String taskId) throws Exception { ObjectContentManager ocm = ocmFactory.getOcm(); try { Node node = ocm.getSession().getNode(String.format(URI.TASKS_URI, boardId, phaseId, cardId, taskId)); if (node == null) { throw new ResourceNotFoundException(); } node.remove(); ocm.save(); } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/notifications/{type}/reprocess", method = RequestMethod.GET, params = { "startDate", "endDate" }) public @ResponseBody void reprocessNotifications(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String type, @RequestParam String startDate, @RequestParam String endDate) throws Exception { logger.debug("Attempting to move Notification for reprocessing notifications between startDate:'" + startDate + "' endDate:'" + endDate + "' with type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); ObjectContentManager ocm = ocmFactory.getOcm(); try { final String cardNotificationUrl = String.format(URI.CARD_NOTIFICATIONS_URI, boardId, phaseId, cardId, type); Collection<CardNotification> cardNotifications = retrieveNotifications(ocm, cardNotificationUrl, startDate, endDate); for (CardNotification cardNotification : cardNotifications) { notificationController.reprocessNotification(cardNotification, type); } logger.info("Successfully moved '" + cardNotifications.size() + "' Notifications for reprocessing notifications between startDate:'" + startDate + "' endDate:'" + endDate + "' with type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); } catch (Exception e) { logger.error("Failed to move Notification for reprocessing notifications between startDate:'" + startDate + "' endDate:'" + endDate + "' with type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); throw e; } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/notifications/{type}/reprocess/{notificationId}", method = RequestMethod.GET) public @ResponseBody void reprocessNotification(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String type, @PathVariable String notificationId) throws Exception { logger.debug( "Attempting to move Notification for reprocessing notificationId:'" + notificationId + "' type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); ObjectContentManager ocm = ocmFactory.getOcm(); try { final String cardNotificationUrl = String.format(URI.CARD_NOTIFICATIONS_BY_ID_URI, boardId, phaseId, cardId, type, notificationId); CardNotification cardNotification = (CardNotification) ocm.getObject(CardNotification.class, cardNotificationUrl); notificationController.reprocessNotification(cardNotification, type); logger.info("Successfully moved Notification for reprocessing notificationId:'" + notificationId + "' type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); } catch (Exception e) { logger.error("Failed to move Notification for reprocessing notificationId:'" + notificationId + "' type:'" + type + "' on board:'" + boardId + "' phase:'" + phaseId + "' card:'" + cardId + "' ."); throw e; } finally { ocm.logout(); } } @PreAuthorize("hasPermission(#boardId, 'BOARD', 'READ,WRITE,ADMIN')") @RequestMapping(value = "/{cardId}/notifications/{type}", method = RequestMethod.GET, params = { "startDate", "endDate" }) public @ResponseBody Collection<CardNotification> getNotifications(@PathVariable String boardId, @PathVariable String phaseId, @PathVariable String cardId, @PathVariable String type, @RequestParam String startDate, @RequestParam String endDate) throws Exception { logger.debug("Attempting to retrieve all unprocessed Notifications of type:'" + type + "' from startDate:'" + startDate + "' to endDate:'" + startDate + " for card:'" + cardId + " in phase:'" + phaseId + " on board:'" + boardId + "''."); final List<CardNotification> notifications = new ArrayList<CardNotification>(); if (StringUtils.isAlphanumeric(type)) { ObjectContentManager ocm = ocmFactory.getOcm(); try { notifications.addAll(retrieveNotifications(ocm, String.format(URI.CARD_NOTIFICATIONS_URI, boardId, phaseId, cardId, type), startDate, endDate)); logger.info("Successfully retrieved '" + notifications.size() + "' Notifications of type:'" + type + "'."); } catch (Exception e) { logger.error("Failed to retrieve '" + notifications.size() + "' Notifications of type:'" + type + "' from startDate:'" + startDate + "' to endDate:'" + startDate + " for card:'" + cardId + " in phase:'" + phaseId + " on board:'" + boardId + "''."); throw e; } finally { ocm.logout(); } } return notifications; } }