package com.jspxcms.core.service.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; 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 org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import com.jspxcms.core.domain.Node; import com.jspxcms.core.domain.NodeBuffer; import com.jspxcms.core.domain.NodeDetail; import com.jspxcms.core.listener.ModelDeleteListener; import com.jspxcms.core.listener.NodeDeleteListener; import com.jspxcms.core.listener.NodeListener; import com.jspxcms.core.listener.SiteDeleteListener; import com.jspxcms.core.listener.UserDeleteListener; import com.jspxcms.core.listener.WorkflowDeleteListener; import com.jspxcms.core.repository.NodeDao; import com.jspxcms.core.service.InfoNodeService; import com.jspxcms.core.service.ModelService; import com.jspxcms.core.service.NodeBufferService; import com.jspxcms.core.service.NodeDetailService; import com.jspxcms.core.service.NodeService; import com.jspxcms.core.service.SiteService; import com.jspxcms.core.service.UserService; import com.jspxcms.core.service.WorkflowService; import com.jspxcms.core.support.DeleteException; /** * NodeServiceImpl * * @author liufang * */ @Service @Transactional public class NodeServiceImpl implements NodeService, SiteDeleteListener, UserDeleteListener, WorkflowDeleteListener, ModelDeleteListener { public Node save(Node bean, NodeDetail detail, Map<String, String> customs, Map<String, String> clobs, Integer parentId, Integer nodeModelId, Integer infoModelId, Integer workflowId, Integer creatorId, Integer siteId) { Node parent = null; if (parentId != null) { parent = dao.findOne(parentId); bean.setParent(parent); } if (nodeModelId != null) { bean.setNodeModel(modelService.get(nodeModelId)); } if (infoModelId != null) { bean.setInfoModel(modelService.get(infoModelId)); bean.setRealNode(true); } else { // 首页必须为真实节点 bean.setRealNode(bean.getParent() == null); } if (workflowId != null) { bean.setWorkflow(workflowService.get(workflowId)); } bean.setCreator(userService.get(creatorId)); bean.setSite(siteService.get(siteId)); bean.setCustoms(customs); bean.setClobs(clobs); bean.applyDefaultValue(); treeSave(bean, parent); bean = dao.save(bean); nodeDetailService.save(detail, bean); nodeBufferService.save(new NodeBuffer(), bean); firePostSave(new Node[] { bean }); return bean; } private void treeSave(Node bean, Node parent) { bean.setTreeMax(Node.long2hex(0)); if (parent == null) { bean.setTreeLevel(0); bean.setTreeNumber(Node.long2hex(0)); bean.setTreeMax(Node.long2hex(0)); } else { bean.setTreeLevel(parent.getTreeLevel() + 1); String max = parent.getTreeMax(); bean.setTreeNumber(parent.getTreeNumber() + "-" + max); long big = parent.getTreeMaxLong() + 1; parent.setTreeMax(Node.long2hex(big)); dao.save(parent); } } public Node update(Node bean, NodeDetail detail, Map<String, String> customs, Map<String, String> clobs, Integer nodeModelId, Integer infoModelId, Integer workflowId) { if (nodeModelId != null) { bean.setNodeModel(modelService.get(nodeModelId)); } if (infoModelId != null) { bean.setInfoModel(modelService.get(infoModelId)); bean.setRealNode(true); } else { bean.setInfoModel(null); // 首页必须为真实节点 bean.setRealNode(bean.getParent() == null); } if (workflowId != null) { bean.setWorkflow(workflowService.get(workflowId)); } else { bean.setWorkflow(null); } bean.getCustoms().clear(); if (!CollectionUtils.isEmpty(customs)) { bean.getCustoms().putAll(customs); } bean.getClobs().clear(); if (!CollectionUtils.isEmpty(clobs)) { bean.getClobs().putAll(clobs); } nodeDetailService.update(detail, bean); bean.applyDefaultValue(); bean = dao.save(bean); firePostUpdate(new Node[] { bean }); return bean; } public Node[] batchUpdate(Integer[] id, String[] name, String[] number, Integer[] views, Boolean[] hidden, Integer siteId, boolean isUpdateTree) { Map<Integer, List<Integer>> listMap = new HashMap<Integer, List<Integer>>(); Node[] beans = new Node[id.length]; for (int i = 0, len = id.length; i < len; i++) { beans[i] = dao.findOne(id[i]); beans[i].setName(name[i]); beans[i].setNumber(number[i]); beans[i].setViews(views[i]); beans[i].setHidden(hidden[i]); dao.save(beans[i]); if (isUpdateTree) { Node parent = beans[i].getParent(); Integer parentId; if (parent != null) { parentId = parent.getId(); } else { parentId = -1; } List<Integer> list = listMap.get(parentId); if (list != null) { list.add(id[i]); } else { list = new ArrayList<Integer>(); list.add(id[i]); listMap.put(parentId, list); } } } String parentTreeNumber, origTreeNumber, treeNumber; for (Entry<Integer, List<Integer>> entry : listMap.entrySet()) { Integer parentId = entry.getKey(); List<Integer> ids = entry.getValue(); if (parentId == -1) { continue; } int len = ids.size(); if (dao.countByParentId(parentId) != len) { continue; } parentTreeNumber = dao.findTreeNumber(parentId); dao.appendModifiedFlag(parentTreeNumber + "-%", siteId); for (int i = 0; i < len; i++) { origTreeNumber = dao.findTreeNumber(ids.get(i)); treeNumber = parentTreeNumber + "-" + Node.long2hex(i); dao.updateTreeNumber(origTreeNumber + "%", treeNumber, treeNumber.length() + 2, siteId); } // 修改父节点的treeMax dao.updateTreeMax(parentId, Node.long2hex(len)); } return beans; } public int move(Integer[] ids, Integer id, Integer siteId) { Node parent = dao.findOne(id); String parentTreeNumber = parent.getTreeNumber(); long treeMax = parent.getTreeMaxLong(); String modifiedTreeNumber, treeNumber; int count = 0; for (int i = 0, len = ids.length; i < len; i++) { dao.updateTreeMax(id, Node.long2hex(treeMax + 1)); treeNumber = dao.findTreeNumber(ids[i]); modifiedTreeNumber = parentTreeNumber + "-" + Node.long2hex(treeMax++); count += dao.updateTreeNumber(treeNumber + "%", modifiedTreeNumber, treeNumber.length() + 1, siteId); dao.updateParentId(ids[i], id); } return count; } // 获取节点及其子节点ID private Set<Integer> getChildrenIds(Node bean, Set<Integer> ids) { if (bean != null) { Collection<Node> children = bean.getChildren(); if (!CollectionUtils.isEmpty(children)) { for (Node n : children) { getChildrenIds(n, ids); } } ids.add(bean.getId()); } return ids; } private Set<Node> doDelete(Node bean, Set<Node> deleted) { if (bean != null) { Collection<Node> children = bean.getChildren(); if (!CollectionUtils.isEmpty(children)) { for (Node n : children) { doDelete(n, deleted); } } infoNodeService.deleteByNodeId(bean.getId()); dao.delete(bean); deleted.add(bean); } return deleted; } public Node delete(Integer id) { Node bean = dao.findOne(id); if (bean == null) { return null; } Set<Integer> toDeleteIdSet = new HashSet<Integer>(); getChildrenIds(bean, toDeleteIdSet); firePreDelete(toDeleteIdSet.toArray(new Integer[toDeleteIdSet.size()])); Set<Node> deleted = new HashSet<Node>(); firePreDelete(new Integer[] { id }); doDelete(bean, deleted); firePostDelete(deleted.toArray(new Node[deleted.size()])); return bean; } public Node[] delete(Integer[] ids) { Set<Integer> toDeleteIdSet = new HashSet<Integer>(); for (Integer id : ids) { getChildrenIds(dao.findOne(id), toDeleteIdSet); } firePreDelete(toDeleteIdSet.toArray(new Integer[toDeleteIdSet.size()])); Set<Node> deleted = new HashSet<Node>(); Node bean; for (int i = 0; i < ids.length; i++) { bean = dao.findOne(ids[i]); doDelete(bean, deleted); } Node[] beans = deleted.toArray(new Node[deleted.size()]); firePostDelete(beans); return beans; } /** * @see NodeService#refer(Integer) */ public Node refer(Integer nodeId) { Node node = dao.findOne(nodeId); node.setRefers(node.getRefers() + 1); return node; } public List<Node> refer(Integer[] nodeIds) { if (ArrayUtils.isEmpty(nodeIds)) { return Collections.emptyList(); } Set<Integer> nodeIdSet = new HashSet<Integer>(); List<Node> nodes = new ArrayList<Node>(nodeIds.length); for (Integer nodeId : nodeIds) { if (!nodeIdSet.contains(nodeId)) { nodes.add(refer(nodeId)); nodeIdSet.add(nodeId); } } return nodes; } public void derefer(Node node) { node.setRefers(node.getRefers() - 1); } public void derefer(Collection<Node> nodes) { for (Node node : nodes) { derefer(node); } } public void preSiteDelete(Integer[] ids) { if (ArrayUtils.isNotEmpty(ids)) { if (dao.countBySiteId(Arrays.asList(ids)) > 0) { throw new DeleteException("node.management"); } } } public void preModelDelete(Integer[] ids) { if (ArrayUtils.isNotEmpty(ids)) { if (dao.countByNodeModelId(Arrays.asList(ids)) > 0 || dao.countByInfoModelId(Arrays.asList(ids)) > 0) { throw new DeleteException("node.management"); } } } public void preUserDelete(Integer[] ids) { if (ArrayUtils.isNotEmpty(ids)) { if (dao.countByCreatorId(Arrays.asList(ids)) > 0) { throw new DeleteException("node.management"); } } } public void preWorkflowDelete(Integer[] ids) { if (ArrayUtils.isNotEmpty(ids)) { if (dao.countByWorkflowId(Arrays.asList(ids)) > 0) { throw new DeleteException("node.management"); } } } private void firePostSave(Node[] bean) { if (!CollectionUtils.isEmpty(listeners)) { for (NodeListener listener : listeners) { listener.postNodeSave(bean); } } } private void firePostUpdate(Node[] bean) { if (!CollectionUtils.isEmpty(listeners)) { for (NodeListener listener : listeners) { listener.postNodeUpdate(bean); } } } private void firePreDelete(Integer[] ids) { if (!CollectionUtils.isEmpty(deleteListeners)) { for (NodeDeleteListener listener : deleteListeners) { listener.preNodeDelete(ids); } } } private void firePostDelete(Node[] bean) { if (!CollectionUtils.isEmpty(listeners)) { for (NodeListener listener : listeners) { listener.postNodeDelete(bean); } } } private List<NodeListener> listeners; private List<NodeDeleteListener> deleteListeners; @Autowired(required = false) public void setDeleteListeners(List<NodeDeleteListener> deleteListeners) { this.deleteListeners = deleteListeners; } @Autowired(required = false) public void setListeners(List<NodeListener> listeners) { this.listeners = listeners; } private WorkflowService workflowService; private ModelService modelService; private InfoNodeService infoNodeService; private NodeDetailService nodeDetailService; private NodeBufferService nodeBufferService; private UserService userService; private SiteService siteService; @Autowired public void setWorkflowService(WorkflowService workflowService) { this.workflowService = workflowService; } @Autowired public void setModelService(ModelService modelService) { this.modelService = modelService; } @Autowired public void setInfoNodeService(InfoNodeService infoNodeService) { this.infoNodeService = infoNodeService; } @Autowired public void setNodeDetailService(NodeDetailService nodeDetailService) { this.nodeDetailService = nodeDetailService; } @Autowired public void setNodeBufferService(NodeBufferService nodeBufferService) { this.nodeBufferService = nodeBufferService; } @Autowired public void setUserService(UserService userService) { this.userService = userService; } @Autowired public void setSiteService(SiteService siteService) { this.siteService = siteService; } private NodeDao dao; @Autowired public void setDao(NodeDao dao) { this.dao = dao; } }