Java tutorial
/* * Code contributed to the Learning Layers project * http://www.learning-layers.eu * Development is partly funded by the FP7 Programme of the European * Commission under Grant Agreement FP7-ICT-318209. * Copyright (c) 2015, Karlsruhe University of Applied Sciences. * For a list of contributors see the AUTHORS file at the top-level directory * of this distribution. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.hska.ld.content.service.impl; import de.hska.ld.content.dto.BreadcrumbDto; import de.hska.ld.content.dto.DiscussionSectionDto; import de.hska.ld.content.persistence.domain.*; import de.hska.ld.content.persistence.repository.DocumentRepository; import de.hska.ld.content.service.*; import de.hska.ld.core.exception.NotFoundException; import de.hska.ld.core.exception.UserNotAuthorizedException; import de.hska.ld.core.exception.ValidationException; import de.hska.ld.core.persistence.domain.User; import de.hska.ld.core.service.UserService; import de.hska.ld.core.service.annotation.Logging; import de.hska.ld.core.util.Core; import org.hibernate.LobHelper; import org.hibernate.Session; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.persistence.EntityManager; import java.io.IOException; import java.io.InputStream; import java.sql.Blob; import java.util.*; @Service public class DocumentServiceImpl extends AbstractContentService<Document> implements DocumentService { @Autowired private DocumentRepository repository; @Autowired private AttachmentService attachmentService; @Autowired private TagService tagService; @Autowired private SubscriptionService subscriptionService; @Autowired private UserService userService; @Autowired private CommentService commentService; @Autowired private EntityManager em; private Comparator<Content> byDateTime = (c1, c2) -> { if (c1.getCreatedAt() == null) { return -1; } else if (c2.getCreatedAt() == null) { return 1; } else { int compareVal = c2.getCreatedAt().compareTo(c1.getCreatedAt()); return compareVal; } }; @Override public Page<Document> getDocumentsPage(Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty) { return getDocumentsPage(pageNumber, pageSize, sortDirection, sortProperty, null); } @Override public Page<Document> getDocumentsPage(Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty, String searchTerm) { Sort.Direction direction; if (Sort.Direction.ASC.toString().equals(sortDirection)) { direction = Sort.Direction.ASC; } else { direction = Sort.Direction.DESC; } Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty); User user = Core.currentUser(); if (searchTerm == null || searchTerm.isEmpty()) { return repository.findAll(user, pageable); } else { return repository.searchDocumentByTitleOrDescription(searchTerm, pageable); } } @Override @Logging("Save document auditing example") @Transactional public Document save(Document document) { if (document.getTitle() == null) { throw new ValidationException("title"); } Document dbDocument = findById(document.getId()); if (dbDocument == null) { // TODO more dynamic solution document.setAccessList(null); document.setAttachmentList(null); document.setCommentList(null); document.setSubscriptionList(null); document.setTagList(null); Attachment attachment = new Attachment(); attachment.setName("maincontent.html"); attachment.setMimeType("text/html"); attachment.setSource("".getBytes()); document.getAttachmentList().add(0, attachment); document.setCreator(Core.currentUser()); } else { checkPermission(dbDocument, Access.Permission.WRITE); dbDocument.setModifiedAt(new Date()); dbDocument.setTitle(document.getTitle()); dbDocument.setDescription(document.getDescription()); if (document.isAccessAll()) { dbDocument.setAccessAll(true); } document = dbDocument; } createNotifications(document, Subscription.Type.MAIN_CONTENT); return super.save(document); } @Override @Transactional public Comment addComment(Long id, Comment comment) { Document document = findById(id); checkPermission(document, Access.Permission.COMMENT_DOCUMENT, Access.Permission.WRITE, Access.Permission.ATTACH_FILES); document.getCommentList().add(comment); comment.setParent(document); comment.setCreator(Core.currentUser()); document = super.save(document); createNotifications(document, Subscription.Type.COMMENT); // retrieves the latest comment Optional<Comment> optional = document.getCommentList().stream().sorted(byDateTime).findFirst(); commentService.sendMentionNotifications(comment); return optional.get(); } @Override @Transactional public Document removeComment(Long id, Comment comment) { Document document = findById(id); document.getCommentList().remove(comment); return super.save(document); } @Override @Transactional(readOnly = false) public Document addTag(Long id, Long tagId) { Document document = findById(id); Tag tag = tagService.findById(tagId); tag.setCreator(Core.currentUser()); checkPermission(document, Access.Permission.WRITE, Access.Permission.ATTACH_FILES, Access.Permission.READ, Access.Permission.COMMENT_DOCUMENT); if (!document.getTagList().contains(tag)) { document.getTagList().add(tag); } return super.save(document); } @Override @Transactional public Document removeTag(Long id, Long tagId) { Document document = findById(id); Tag tag = tagService.findById(tagId); document.getTagList().remove(tag); return super.save(document); } @Override @Transactional(readOnly = false) public Document addDiscussionToDocument(Long id, Document discussion) { Document document = findById(id); discussion.setParent(document); discussion.setAccessList(null); discussion.setAttachmentList(null); discussion.setCommentList(null); discussion.setSubscriptionList(null); discussion.setTagList(null); Attachment attachment = new Attachment(); attachment.setName("maincontent.html"); attachment.setMimeType("text/html"); attachment.setSource("".getBytes()); discussion.getAttachmentList().add(0, attachment); discussion.setCreator(Core.currentUser()); discussion = super.save(discussion); document.getDiscussionList().add(discussion); // TODO missing permission check document = super.save(document); document.getDiscussionList().size(); createNotifications(document, Subscription.Type.DISCUSSION); return document; } @Override public Long addAttachment(Long documentId, MultipartFile file, String fileName) { try { return addAttachment(documentId, file.getInputStream(), fileName, file.getSize()); } catch (IOException e) { throw new ValidationException("file"); } } @Override @Transactional public Long addAttachment(Long documentId, InputStream is, String fileName, long fileSize) { Document document = findById(documentId); if (document == null) { throw new ValidationException("id"); } checkPermission(document, Access.Permission.WRITE); Attachment attachment = new Attachment(fileName); Session session = (Session) em.getDelegate(); LobHelper lobHelper = session.getLobHelper(); Blob dataBlob = lobHelper.createBlob(is, fileSize); FileBlobBean fileBlobBean = new FileBlobBean(); fileBlobBean.setSourceBlob(dataBlob); attachment.setFileBlobBean(fileBlobBean); attachment.setCreator(Core.currentUser()); document.getAttachmentList().add(attachment); document = super.save(document); createNotifications(document, Subscription.Type.ATTACHMENT); return document.getAttachmentList().get(document.getAttachmentList().size() - 1).getId(); } @Override public Attachment getAttachment(Long documentId, int position) { Document document = findById(documentId); checkPermission(document, Access.Permission.READ); if (position < 0 || position >= document.getAttachmentList().size()) { throw new ValidationException("position"); } Attachment attachment = document.getAttachmentList().get(position); return attachment; /*byte[] source = attachment.getSource(); return new ByteArrayInputStream(source);*/ } @Override public Page<Tag> getDocumentTagsPage(Long documentId, Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty) { Sort.Direction direction; if (Sort.Direction.ASC.toString().equals(sortDirection)) { direction = Sort.Direction.ASC; } else { direction = Sort.Direction.DESC; } Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty); return repository.findAllTagsForDocument(documentId, pageable); } @Override public Long updateAttachment(Long documentId, Long attachmentId, MultipartFile file, String fileName) { try { return updateAttachment(documentId, attachmentId, file.getInputStream(), fileName); } catch (IOException e) { throw new ValidationException("file"); } } @Override @Transactional public Attachment updateAttachment(Long documentId, Long attachmentId, Attachment attachment) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } document.getAttachmentList().size(); boolean found = false; for (Attachment attachmentItem : document.getAttachmentList()) { if (attachmentItem.getId().equals(attachmentId)) { found = true; } } if (!found) { throw new NotFoundException("attachmentId"); } Attachment dbAttachment = attachmentService.findById(attachmentId); dbAttachment.setName(attachment.getName()); return attachmentService.save(dbAttachment); } @Override public List<Tag> getDocumentTagsList(Long documentId) { Document document = findById(documentId); return document.getTagList(); } @Override @Transactional public Document addSubscription(Long id, Subscription.Type... types) { User user = Core.currentUser(); Document document = findById(id); if (document == null) { throw new NotFoundException("id"); } checkPermission(document, Access.Permission.READ); Subscription subscription = null; if (document.getSubscriptionList().size() != 0) { // retrieve subscription if already present for the current user subscription = document.getSubscriptionList().stream().filter(s -> s.getUser().equals(user)).findFirst() .get(); } if (subscription != null) { // if the subscription was already present on the document List<Subscription.Type> typeList = Arrays.asList(types); // remove all the types that shall be added (to prevent duplicates) subscription.getTypeList().removeAll(typeList); // add all types subscription.getTypeList().addAll(typeList); } else { // add a new subscription subscription = new Subscription(user, types); document.getSubscriptionList().add(subscription); } return super.save(document); } @Override @Transactional public Document removeSubscription(Long id, Subscription.Type... types) { User user = Core.currentUser(); Document document = findById(id); if (document == null) { throw new NotFoundException("id"); } Subscription subscription = document.getSubscriptionList().stream().filter(s -> s.getUser().equals(user)) .findFirst().get(); List<Subscription.Type> stl = subscription.getTypeList(); for (Subscription.Type st : types) { if (stl.contains(st)) { stl.remove(st); } } if (stl.size() == 0) { document.getSubscriptionList().remove(subscription); } return save(document); } @Override public Page<Document> getDiscussionDocumentsPage(Long documentId, Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty) { Sort.Direction direction; if (Sort.Direction.ASC.toString().equals(sortDirection)) { direction = Sort.Direction.ASC; } else { direction = Sort.Direction.DESC; } Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty); User user = Core.currentUser(); return repository.findDiscussionsAll(documentId, user, pageable); } @Override public List<BreadcrumbDto> getBreadcrumbs(Long documentId) { Document document = findById(documentId); List<BreadcrumbDto> breadcrumbList = new ArrayList<>(); if (document != null) { // add the document itself to the breadcrumbs BreadcrumbDto breadcrumbDto = new BreadcrumbDto(); breadcrumbDto.setCurrent(true); breadcrumbDto.setDocumentId(document.getId()); breadcrumbDto.setDocumentTitle(document.getTitle()); breadcrumbList.add(breadcrumbDto); // retrieve parent document information Document currentParent = document.getParent(); while (currentParent != null) { BreadcrumbDto parentBreadcrumbDto = new BreadcrumbDto(); parentBreadcrumbDto.setCurrent(false); parentBreadcrumbDto.setDocumentId(currentParent.getId()); parentBreadcrumbDto.setDocumentTitle(currentParent.getTitle()); breadcrumbList.add(parentBreadcrumbDto); currentParent = currentParent.getParent(); } } return breadcrumbList; } @Override public Page<Attachment> getDocumentAttachmentPage(Long documentId, String attachmentType, String excludedAttachmentTypes, Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty) { Sort.Direction direction; if (Sort.Direction.ASC.toString().equals(sortDirection)) { direction = Sort.Direction.ASC; } else { direction = Sort.Direction.DESC; } Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty); List<String> attachmentTypes = Arrays.asList(attachmentType.split(";")); if (attachmentTypes.size() == 0) { attachmentTypes.add("NoValue"); } List<String> excludedAttachmentTypesList; if (!"".equals(excludedAttachmentTypes)) { excludedAttachmentTypesList = Arrays.asList(excludedAttachmentTypes.split(";")); } else { excludedAttachmentTypesList = new ArrayList<>(); excludedAttachmentTypesList.add("NoValue"); } if ("all".equals(attachmentType)) { return repository.findAttachmentsWithTypeExclusionForDocument(documentId, excludedAttachmentTypesList, pageable); } else { return repository.findAttachmentsByTypeWithExclusionForDocument(documentId, attachmentTypes, excludedAttachmentTypesList, pageable); } } @Override @Transactional public Attachment getAttachmentByAttachmentId(Long documentId, Long attachmentId) { Document document = findById(documentId); checkPermission(document, Access.Permission.READ); Attachment attachment = attachmentService.findById(attachmentId); if (attachment != null && !document.getAttachmentList().contains(attachment)) { throw new UserNotAuthorizedException(); } return attachment; } @Override @Transactional public Hyperlink addHyperlink(Long documentId, Hyperlink hyperlink) { Document document = findById(documentId); checkPermission(document, Access.Permission.WRITE); document.getHyperlinkList().add(hyperlink); hyperlink.setCreator(Core.currentUser()); document = super.save(document); int index = document.getHyperlinkList().indexOf(hyperlink); return document.getHyperlinkList().get(index); } @Override @Transactional public List<Attachment> getDocumentAttachmentList(Long documentId) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } this.loadContentCollection(document, Attachment.class); return document.getAttachmentList(); } @Override @Transactional public void removeAttachment(Long documentId, Long attachmentId) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } Attachment attachment = attachmentService.findById(attachmentId); if (attachment == null) { throw new NotFoundException("attachmentId"); } if (!document.getAttachmentList().contains(attachment)) { throw new UserNotAuthorizedException(); } attachment.setDeleted(true); attachmentService.save(attachment); } @Override public Document saveContainsList(Document d) { return super.save(d); } @Override @Transactional public Document addAccess(Long documentId, String combinedUserIdString, String combinedPermissionString) { return addAccessWithoutTransactional(documentId, combinedUserIdString, combinedPermissionString); } @Override @Transactional public Document addAccessWithoutTransactional(Long documentId, String combinedUserIdString, String combinedPermissionString) { Document document = findById(documentId); List<User> userList; try { String[] userIdStringArray = combinedUserIdString.split(";"); userList = new ArrayList<>(); for (String userIdString : userIdStringArray) { Long userId = Long.valueOf(userIdString); User user = userService.findById(userId); userList.add(user); } } catch (Exception e) { throw new ValidationException("userIdString"); } List<Access.Permission> permissionList; try { String[] permissionStringArray = combinedPermissionString.split(";"); permissionList = new ArrayList<>(); for (String permissionString : permissionStringArray) { Access.Permission permission = Access.Permission.valueOf(permissionString); permissionList.add(permission); } } catch (Exception e) { throw new ValidationException("permissionString"); } addAccess(documentId, userList, permissionList); return document; } @Override public List<Access> getUsersByPermissions(Long documentId, String combinedPermissionString) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } if ("all".equals(combinedPermissionString)) { combinedPermissionString = "WRITE;READ"; } List<Access.Permission> permissionList; try { String[] permissionStringArray = combinedPermissionString.split(";"); permissionList = new ArrayList<>(); for (String permissionString : permissionStringArray) { Access.Permission permission = Access.Permission.valueOf(permissionString); permissionList.add(permission); } } catch (Exception e) { throw new ValidationException("permissionString"); } List<Access> resultUsers = createUserAccessDtoList(document, permissionList); return resultUsers; } private List<Access> createUserAccessDtoList(Document document, List<Access.Permission> permissionList) { List<Access> resultAccess = new ArrayList<>(); for (Access access : document.getAccessList()) { for (Access.Permission permission : permissionList) { if (access.getPermissionList().contains(permission) && !resultAccess.contains(access)) { resultAccess.add(access); } } } return resultAccess; } @Override public Document loadCurrentUserPermissions(Document document) { List<Access> access = repository.getCurrentUserPermissionsForDocument(document.getId(), Core.currentUser().getId()); document.setAccessList(access); return document; } @Override @Transactional(readOnly = true) public Access getCurrentUserPermissions(Long documentId, String permissions) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } if (document.getCreator().equals(Core.currentUser())) { return null; } List<Access> accessList = getUsersByPermissions(documentId, permissions); Access tempAccess = new Access(); tempAccess.setUser(Core.currentUser()); int idx = accessList.indexOf(tempAccess); if (idx != -1) { return accessList.get(idx); } else { return null; } } @Override @Transactional public Document addExpert(Long documentId, String username) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } User expert = userService.findByUsername(username); if (expert == null) { throw new NotFoundException("username"); } document.getExpertList().add(expert); return save(document); } @Override @Transactional public Document setAccessAll(Long documentId, boolean accessAll) { Document document = findById(documentId); checkPermission(document, Access.Permission.WRITE); document.setAccessAll(accessAll); return save(document); } @Override @Transactional(readOnly = false) public Document addDiscussionToDocument(Long documentId, DiscussionSectionDto discussionSectionDto) { Document document = addDiscussionToDocument(documentId, discussionSectionDto.getDocument()); Document discussion = createDiscussionContent(discussionSectionDto, document); return discussion; } @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false) private Document createDiscussionContent(DiscussionSectionDto discussionSectionDto, Document document) { Document discussion = document.getDiscussionList().get(document.getDiscussionList().size() - 1); discussion.setCreator(Core.currentUser()); if (discussionSectionDto.getSectionText() != null) { List<Attachment> attachmentList = discussion.getAttachmentList(); Attachment mainAttachment = attachmentList.get(0); mainAttachment.setCreator(Core.currentUser()); mainAttachment.setSource(discussionSectionDto.getSectionText().getBytes()); } discussion = super.save(discussion); return discussion; } @Override @Transactional(readOnly = true) public Page<Access> getUsersByDocumentPermission(Long documentId, String combinedPermissionString, Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty) { Document document = findById(documentId); if (document == null) { throw new NotFoundException("documentId"); } if ("all".equals(combinedPermissionString)) { combinedPermissionString = "WRITE;READ"; } List<Access.Permission> permissionList; try { String[] permissionStringArray = combinedPermissionString.split(";"); permissionList = new ArrayList<>(); for (String permissionString : permissionStringArray) { Access.Permission permission = Access.Permission.valueOf(permissionString); permissionList.add(permission); } } catch (Exception e) { throw new ValidationException("permissionString"); } Sort.Direction direction; if (Sort.Direction.ASC.toString().equals(sortDirection)) { direction = Sort.Direction.ASC; } else { direction = Sort.Direction.DESC; } Pageable pageable; if ("createdAt".equals(sortProperty)) { String newSortProperty = "acc.createdAt"; pageable = new PageRequest(pageNumber, pageSize, direction, newSortProperty); } else { pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty); } Page<Access> usersByDocumentPermission = repository.getUsersByDocumentPermission(documentId, permissionList, pageable); for (Access access : usersByDocumentPermission) { access.getPermissionList().size(); } return usersByDocumentPermission; } @Override @Transactional public void removeAccess(Long documentId, Long userId) { Document document = findById(documentId); User user = userService.findById(userId); Access userAccess = new Access(); userAccess.setUser(user); document.getAccessList().remove(userAccess); save(document); } @Override public void updatedByUser(User user, Document document) { document.setModifiedAt(new Date()); document = findById(document.getId()); document.getAttachmentList().size(); Attachment mainContent = document.getAttachmentList().get(0); mainContent.setModifiedAt(new Date()); attachmentService.save(mainContent); } @Override public void fillAttachedEntitiesCounters(Document document) { String[] imageMimeType = { "image/cis-cod", "image/cmu-raster", "image/fif", "image/gif", "image/ief", "image/jpeg", "image/png", "image/tiff", "image/vasa", "image/vnd.wap.wbmp", "image/x-freehand", "image/x-icon", "image/x-portable-anymap", "image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap", "image/x-rgb", "image/x-windowdump", "image/x-xbitmap", "image/x-xpixmap" }; String concatImageMimeType = String.join(";", imageMimeType); long fileAttachmentCount = getAttachmentCount(document, "all", concatImageMimeType); // exclude image types document.setFileAttachmentCount((int) fileAttachmentCount); long mediaAttachmentCount = getAttachmentCount(document, concatImageMimeType, ""); // include image types document.setMediaAttachmentCount((int) mediaAttachmentCount); } private long getAttachmentCount(Document document, String attachmentType, String excludedAttachmentTypes) { List<String> attachmentTypes = Arrays.asList(attachmentType.split(";")); if (attachmentTypes.size() == 0) { attachmentTypes.add("NoValue"); } List<String> excludedAttachmentTypesList; if (!"".equals(excludedAttachmentTypes)) { excludedAttachmentTypesList = Arrays.asList(excludedAttachmentTypes.split(";")); } else { excludedAttachmentTypesList = new ArrayList<>(); excludedAttachmentTypesList.add("NoValue"); } if ("all".equals(attachmentType)) { return repository.countAttachmentsWithTypeExclusionForDocument(document.getId(), excludedAttachmentTypesList); } else { return repository.countAttachmentsByTypeWithExclusionForDocument(document.getId(), attachmentTypes, excludedAttachmentTypesList); } } public void addAccess(Long documentId, List<User> userList, List<Access.Permission> permissionList) { Document document = findById(documentId); for (User user : userList) { Access.Permission[] permissionArray = permissionList .toArray(new Access.Permission[permissionList.size()]); addAccess(document.getId(), user, permissionArray); } } @Transactional private Long updateAttachment(Long documentId, Long attachmentId, InputStream is, String fileName) { Document document = findById(documentId); if (document == null) { throw new ValidationException("id"); } checkPermission(document, Access.Permission.WRITE); Attachment attachment = attachmentService.findById(attachmentId); // check if attachment belongs to the document if (!document.getAttachmentList().contains(attachment)) { throw new UserNotAuthorizedException(); } // update attachment attachment.setNewValues(is, fileName); attachment = attachmentService.save(attachment); createNotifications(document, Subscription.Type.ATTACHMENT); return attachment.getId(); } private void createNotifications(Document document, Subscription.Type type) { User editor = Core.currentUser(); Long documentId = document.getId(); List<Subscription> subscriptionList = document.getSubscriptionList(); subscriptionList.stream().forEach(s -> { if (s.getTypeList().contains(type)) { if (!s.getUser().getId().equals(editor.getId())) { subscriptionService.saveNotification(documentId, s.getUser().getId(), editor.getId(), type); } } }); } @Override @Transactional(readOnly = true) public Document loadContentCollection(Document document, Class... clazzArray) { document = super.loadContentCollection(document, clazzArray); if (document != null) { for (Class clazz : clazzArray) { if (Attachment.class.equals(clazz)) { document.setAttachmentList( filterDeletedListItems(document.getAttachmentList(), Attachment.class)); } if (User.class.equals(clazz)) { document.getExpertList().size(); } } } return document; } @Override public DocumentRepository getRepository() { return repository; } }