Created
September 21, 2015 16:47
-
-
Save khaosans/7a42f1a4c1b5c274ccc1 to your computer and use it in GitHub Desktop.
documentService impl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2005-2006 Jama Software, Inc. 600 NW 14th Avenue, Portland, Oregon 97209 U.S.A. All rights reserved. | |
* | |
* This software is the confidential and proprietary information of Jama Software, Inc. ("Confidential Information"). | |
* You shall not disclose such Confidential Information and shall use it only in accordance with the terms of the | |
* license agreement you entered into with Jama Software. | |
*/ | |
package com.jamasoftware.contour.service.impl; | |
import com.jamasoftware.contour.api.domain.ContourItem; | |
import com.jamasoftware.contour.api.domain.Document; | |
import com.jamasoftware.contour.api.domain.DocumentField; | |
import com.jamasoftware.contour.api.domain.DocumentGroup; | |
import com.jamasoftware.contour.api.domain.DocumentNode; | |
import com.jamasoftware.contour.api.domain.DocumentTypeCategory; | |
import com.jamasoftware.contour.api.domain.Document_Document; | |
import com.jamasoftware.contour.api.domain.Lookup; | |
import com.jamasoftware.contour.api.domain.PropertyEntry; | |
import com.jamasoftware.contour.api.domain.User; | |
import com.jamasoftware.contour.api.domain.Version; | |
import com.jamasoftware.contour.api.exception.DocumentNullOrInactiveException; | |
import com.jamasoftware.contour.api.exception.ValidationException; | |
import com.google.common.collect.Sets; | |
import com.jamasoftware.contour.api.domain.*; | |
import com.jamasoftware.contour.api.exception.*; | |
import com.jamasoftware.contour.api.qa.domain.TestCaseStep; | |
import com.jamasoftware.contour.api.qa.dto.TestCaseStepDTO; | |
import com.jamasoftware.contour.api.reuse.domain.ReusedItemSummary; | |
import com.jamasoftware.contour.api.service.ClientServiceSupport; | |
import com.jamasoftware.contour.api.service.CurrentUserFinder; | |
import com.jamasoftware.contour.api.service.dto.ContourItemDTO; | |
import com.jamasoftware.contour.api.service.dto.DistributionUsersAndGroupsDTO; | |
import com.jamasoftware.contour.api.service.dto.DocumentDTO; | |
import com.jamasoftware.contour.api.service.dto.property.DocumentPropertyDTO; | |
import com.jamasoftware.contour.api.service.dto.visitor.contourItemDTO.SaveContourItemDTOOptions; | |
import com.jamasoftware.contour.api.service.property.ProjectProperty; | |
import com.jamasoftware.contour.api.service.property.PropertyType; | |
import com.jamasoftware.contour.api.service.search.PageInfo; | |
import com.jamasoftware.contour.api.service.search.SearchResults; | |
import com.jamasoftware.contour.api.service.search.SorterList; | |
import com.jamasoftware.contour.api.util.DocumentFieldNames; | |
import com.jamasoftware.contour.api.util.ScopeRefWrap; | |
import com.jamasoftware.contour.dao.DocumentDao; | |
import com.jamasoftware.contour.dao.DocumentGroupDao; | |
import com.jamasoftware.contour.dao.DocumentNodeDao; | |
import com.jamasoftware.contour.dao.VersionDao; | |
import com.jamasoftware.contour.data.HibernateUtil; | |
import com.jamasoftware.contour.data.dao.GenericDao; | |
import com.jamasoftware.contour.data.util.search.indexer.Indexer; | |
import com.jamasoftware.contour.document.move.ItemMover; | |
import com.jamasoftware.contour.documentKey.SetKeyChanger; | |
import com.jamasoftware.contour.domain.EventEntryImpl; | |
import com.jamasoftware.contour.domain.EventTypeImpl; | |
import com.jamasoftware.contour.domain.ObjectTypeImpl; | |
import com.jamasoftware.contour.domain.visitor.contourItem.*; | |
import com.jamasoftware.contour.exception.HierarchyViolationException; | |
import com.jamasoftware.contour.qa.service.assembler.TestCaseStepAssembler; | |
import com.jamasoftware.contour.reuse.copier.ItemReuser; | |
import com.jamasoftware.contour.search.service.FilterService; | |
import com.jamasoftware.contour.service.ContourItemService; | |
import com.jamasoftware.contour.service.DocumentService; | |
import com.jamasoftware.contour.service.PropertyService; | |
import com.jamasoftware.contour.service.RelationshipService; | |
import com.jamasoftware.contour.service.assembler.DocumentDndHelper; | |
import com.jamasoftware.contour.service.assembler.DocumentTreeHelper; | |
import com.jamasoftware.contour.service.documentNode.DocumentNodeManager; | |
import com.jamasoftware.contour.service.documentNode.TreeChangeCommand; | |
import com.jamasoftware.contour.service.documentNode.TreeChangeResult; | |
import com.jamasoftware.contour.service.documentNode.TreeNodeChangeInfo; | |
import com.jamasoftware.contour.service.documentNode.cache.CachedDocumentNode; | |
import com.jamasoftware.contour.service.dto.ExtDocumentTreeNode; | |
import com.jamasoftware.contour.service.dto.FilterOrSmartFilterDTOHolder; | |
import com.jamasoftware.contour.service.dto.TreeOptions; | |
import com.jamasoftware.contour.service.event.system.BatchSystemEvent; | |
import com.jamasoftware.contour.service.event.system.SystemEvent; | |
import com.jamasoftware.contour.service.helper.ContourItemHelper; | |
import com.jamasoftware.contour.service.impl.helper.ItemReuseContext; | |
import com.jamasoftware.contour.service.impl.helper.PaginationHelper; | |
import com.jamasoftware.contour.service.impl.helper.validation.ContourItemValidationHelper; | |
import com.jamasoftware.contour.service.property.OrgProperties; | |
import com.jamasoftware.contour.util.*; | |
import com.jamasoftware.contour.util.hierarchy.HierarchyUtil; | |
import com.jamasoftware.contour.work.ThreadWorkProgress; | |
import com.jamasoftware.contour.work.WorkProgressTracker; | |
import org.apache.commons.collections.CollectionUtils; | |
import org.apache.log4j.Level; | |
import org.apache.log4j.Logger; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.context.ApplicationContext; | |
import org.springframework.context.ApplicationContextAware; | |
import org.springframework.transaction.annotation.Transactional; | |
import javax.validation.ConstraintViolation; | |
import java.util.*; | |
import static java.util.Collections.EMPTY_LIST; | |
/** | |
* Default implementation of {@link DocumentService}. | |
*/ | |
@Transactional | |
public class DocumentServiceImpl implements DocumentService, ApplicationContextAware { | |
private final Logger logger = Logger.getLogger(DocumentServiceImpl.class); | |
private static final List<String> GLOBAL_ID_OVERRIDE_LIST = Arrays.asList(DocumentFieldNames.FIELD_GLOBAL_ID); | |
private DocumentDao documentDao; | |
private RelationshipService relationshipService; | |
private DocumentGroupDao documentGroupDao; | |
private CurrentUserFinder currentUserFinder; | |
private VersionDao versionDao; | |
private DocumentDndHelper documentDndHelper; | |
private DocumentTreeHelper documentTreeHelper; | |
private PropertyService propertyService; | |
private ApplicationContext applicationContext; | |
private DocumentNodeDao documentNodeDao; | |
private DocumentNodeManager documentNodeManager; | |
private GenericDao genericDao; | |
private ContourItemHelper contourItemHelper; | |
private ContourItemService contourItemService; | |
private TestCaseStepAssembler testCaseStepAssembler; | |
private SetKeyChanger setKeyChanger; | |
private HierarchyUtil hierarchyUtil; | |
private ItemReuser itemReuser; | |
private FilterService filterService; | |
private ContourItemValidationHelper contourItemValidationHelper; | |
private ItemMover itemMover; | |
@Autowired private Indexer indexer; | |
@Autowired | |
private ClientServiceSupport clientServiceSupport; | |
@Override | |
public DocumentDTO getDocumentDto(Integer id) { | |
if (logger.isDebugEnabled()) { | |
logger.debug("getting document by id: " + id); | |
} | |
Document doc = documentDao.getDocument(id); | |
DocumentDTO dto = (DocumentDTO) doc.accept(ToDTOContourItemVisitor.INSTANCE, ToDTOContourItemOptions.create(true, null, true)); | |
if (logger.isDebugEnabled()) { | |
logger.debug("found document: " + dto); | |
} | |
return dto; | |
} | |
@Override | |
public DocumentPropertyDTO getDocumentPropertyDTO(Integer id) { | |
Document doc = documentDao.getDocument(id); | |
String fullPath = documentNodeManager.getFullPath(doc); | |
return new DocumentPropertyDTO(doc, fullPath); | |
} | |
@Override | |
public Document getDocument(Integer id) { | |
return id == null ? null : documentDao.getDocument(id); | |
} | |
@Override | |
public List<Document> getDocumentByIds(List<Integer> docIds) { | |
return documentDao.getDocumentByIds(docIds); | |
} | |
@Override | |
public ReusedItemSummary copyDocuments(List<Integer> docIds, Map<String, String> params, Map<Integer, ScopeRefWrap> itemTypeToLocationMap, List<Integer> sourceIdsWithMissingTargets) { | |
String message = String.format("Copying doc %s", docIds.get(0)); | |
if (docIds.size() > 1) { | |
message += " and " + (docIds.size() - 1) + " other documents"; | |
} | |
int sessionId = JamaTimer.begin(message, Level.INFO); | |
ReusedItemSummary summary = itemReuser.copyDocuments(docIds, params, itemTypeToLocationMap, sourceIdsWithMissingTargets); | |
JamaTimer.end(sessionId, message, Level.INFO); | |
return summary; | |
} | |
@Override | |
public ReusedItemSummary syncDocuments(List<Integer> docIds, Map<String, String> params, List<Integer> sourceItemsWithMissingTargets, Map<Integer, ScopeRefWrap> itemTypeToLocationMap) { | |
String message = String.format("Syncing doc %s", docIds.get(0)); | |
if (docIds.size() > 1) { | |
message += " and " + (docIds.size() - 1) + " other documents"; | |
} | |
int sessionId = JamaTimer.begin(message); | |
ReusedItemSummary summary = itemReuser.syncDocuments(docIds, params, sourceItemsWithMissingTargets, itemTypeToLocationMap); | |
JamaTimer.end(sessionId, message); | |
return summary; | |
} | |
@Override | |
public ReusedItemSummary syncToBatchDocuments(List<Integer> sourceDocIds, List<Integer> copyToDocsIds, Map<String, String> params) { | |
WorkProgressTracker work = ThreadWorkProgress.get(); | |
work.pushStep("Synchronizing to items", copyToDocsIds.size()); | |
for (Integer docId : copyToDocsIds) { | |
work.addProgress(); | |
params.put(ItemReuseContext.COPY_TARGET_ID, docId.toString()); | |
params.put(ItemReuseContext.COPY_LOCATION_PARAM, "a-" + docId.toString()); | |
copyDocuments(sourceDocIds, params, null, new ArrayList<Integer>(0)); | |
} | |
work.popStep(); | |
return null; | |
} | |
@Override | |
public ReusedItemSummary syncToBatchProjects(Integer sourceProjectId, List<Integer> copyToProjectIds, Map<String, String> params) { | |
WorkProgressTracker work = ThreadWorkProgress.get(); | |
work.pushStep("Synchronizing to projects", copyToProjectIds.size()); | |
List<Integer> docIdsToCopy = getTopLevelDocumentIdsForProject(sourceProjectId); | |
for (Integer projectId : copyToProjectIds) { | |
work.addProgress(); | |
params.put(ItemReuseContext.COPY_LOCATION_PARAM, "p-" + projectId); | |
copyDocuments(docIdsToCopy, params, null, new ArrayList<Integer>(0)); | |
} | |
work.popStep(); | |
return null; | |
} | |
@Override | |
public List<Integer> getTopLevelDocumentIdsForProject(int projectId) { | |
CachedDocumentNode projectNode = DocumentNodeManager.getInstance().getCachedDocumentNode(Scope.PROJECT, projectId, true); | |
List<Integer> docIds = new ArrayList<Integer>(); | |
if (projectNode != null) { | |
for (CachedDocumentNode child : projectNode.getChildren()) { | |
if (Scope.DOCUMENT.equals(child.getScopeId())) { | |
docIds.add(child.getRefId()); | |
} | |
} | |
} | |
return docIds; | |
} | |
@Override | |
public ReusedItemSummary getReuseSummary(List<Integer> docIds, Map<String, String> params, Map<Integer, ScopeRefWrap> itemTypeToLocationMap) { | |
return itemReuser.previewCopyDocuments(docIds, params, itemTypeToLocationMap); | |
} | |
@Override | |
public Integer getReuseCount(List<Integer> docIds, Map<String, String> params, Map<Integer, ScopeRefWrap> itemTypeToLocationMap) { | |
return itemReuser.getReuseCount(docIds, params, itemTypeToLocationMap); | |
} | |
/** | |
* Deactivates (set active=false) a document or folder. | |
* | |
* @param documentId the document to delete | |
* @return list of errors such as relationships existing. | |
*/ | |
@Override | |
public List<TreeNodeChangeInfo> deactivateDocument(Integer documentId) { | |
ContourItem item = contourItemService.getContourItem(documentId); | |
if (item == null) { | |
return new ArrayList<TreeNodeChangeInfo>(0); | |
} | |
logger.info("Deactivate doc " + documentId + ' ' + item.getName()); | |
return item.accept(DeactivateContourItemVisitor.INSTANCE, DeactivateContourItemOptions.create(currentUserFinder.getCurrentUser())); | |
} | |
@Override | |
public List<TreeNodeChangeInfo> deactivateDocument(Document doc, User checkLockedByUser, Set<Integer> skipDocIds, Boolean indexNow) { | |
String flushMode = genericDao.doNotFlushTemporarily(); | |
try { | |
if (skipDocIds == null) { | |
skipDocIds = new HashSet<Integer>(0); | |
} | |
User user = currentUserFinder.getCurrentUser(); | |
List<SystemEvent> events = new ArrayList<SystemEvent>(); | |
List<TreeNodeChangeInfo> numChanges = deactivateDocument(doc, true, checkLockedByUser, skipDocIds, indexNow); | |
List<ContourItem> deletedDocs = new ArrayList<ContourItem>(); | |
for (TreeNodeChangeInfo changes : numChanges) { | |
if (changes.getDeleted() && Scope.DOCUMENT.equals(changes.getScopeId())) { | |
Document subDoc = documentDao.getDocument(changes.getRefId()); | |
deletedDocs.add(subDoc); | |
events.add(new SystemEvent(this, ObjectTypeImpl.Document, changes.getRefId(), subDoc, user, EventEntryImpl.DOCUMENT_DELETE, doc.getProject(), EventTypeImpl.BATCH_DELETE, null, null)); | |
} | |
} | |
int numDocsDeleted = deletedDocs.size(); | |
if (numDocsDeleted == 0 && !DocumentTypeCategory.isCategory(doc.getDocumentType(), DocumentTypeCategory.ATTACHMENT)) { | |
return numChanges; | |
} | |
String comments = EventUtil.getMultiItemActivityComment("deleted", deletedDocs); | |
String details = ""; | |
String action; | |
Integer type; | |
Integer objType; | |
if (numDocsDeleted > 1) { | |
action = EventEntryImpl.MULTIPLE_ITEMS_DELETED; | |
type = EventTypeImpl.BATCH_SUMMARY; | |
objType = ObjectTypeImpl.Anonymous; | |
details = EventUtil.getMultiItemEventDetails(deletedDocs); | |
} | |
else { | |
action = EventEntryImpl.DOCUMENT_DELETE; | |
type = EventTypeImpl.DELETE; | |
objType = ObjectTypeImpl.Document; | |
} | |
ContourItem deletedDoc = doc.getActive() ? deletedDocs.get(0) : doc; | |
SystemEvent se = new SystemEvent(this, objType, deletedDoc.getId(), deletedDoc, user, action, deletedDoc.getProject(), type, comments, details); | |
applicationContext.publishEvent(numDocsDeleted > 1 ? new BatchSystemEvent(se, events) : se); | |
return numChanges; | |
} | |
finally { | |
genericDao.resumeNormalFlushOperation(flushMode); | |
} | |
} | |
private List<TreeNodeChangeInfo> deactivateDocument(Document doc, boolean removeNode, User checkLockedByUser, Set<Integer> skipDocIds, Boolean indexNow) { | |
if (skipDocIds.contains(doc.getId())) { | |
return Collections.emptyList(); | |
} | |
if (checkLockedByUser != null && !ItemLockUtil.canUserHaveLock(checkLockedByUser.getId(), doc)) { | |
return Collections.singletonList(TreeNodeChangeInfo.couldNotDelete(doc, doc.getDocumentKey() + " " + doc.getName() + " is locked")); | |
} | |
List<TreeNodeChangeInfo> allChanges = new ArrayList<TreeNodeChangeInfo>(); | |
List<Document> childDocs = documentNodeManager.getChildDocumentList(doc.getId()); | |
for (Document d : childDocs) { | |
allChanges.addAll(deactivateDocument(d, false, checkLockedByUser, skipDocIds, indexNow)); | |
} | |
boolean hasChildLocked = false; | |
List<Integer> lockedChildren = new ArrayList<Integer>(); | |
for (TreeNodeChangeInfo changeInfo : allChanges) { | |
if (Scope.DOCUMENT.equals(changeInfo.getScopeId()) && !changeInfo.getDeleted() && changeInfo.getTriedToDelete()) { | |
hasChildLocked = true; | |
lockedChildren.add(changeInfo.getRefId()); | |
} | |
} | |
if (hasChildLocked) { | |
//remove nodes that can be deleted | |
for (Document child : childDocs) { | |
if (!lockedChildren.contains(child.getId())) { | |
allChanges.addAll(removeDocumentNode(child.getId(), indexNow)); | |
} | |
} | |
allChanges.add(0, TreeNodeChangeInfo.couldNotDelete(doc, doc.getDocumentKey() + " " + doc.getName() + " has a locked child")); | |
} | |
else { | |
createDocumentVersion(doc, "Deleted item", false); | |
contourItemService.deactivateContourItem(doc); | |
if (removeNode) { | |
allChanges.addAll(removeDocumentNode(doc.getId(), indexNow)); | |
} | |
} | |
return allChanges; | |
} | |
private List<TreeNodeChangeInfo> removeDocumentNode(Integer docId, Boolean indexNow) { | |
DocumentNode node = documentNodeDao.getDocumentNode(Scope.DOCUMENT, docId); | |
TreeChangeResult result = documentNodeManager.removeSubtree(node, indexNow); | |
return result.createChangeInfoList(); | |
} | |
/** | |
* Called from front end to save or update a document. | |
* | |
* @param dto the dto with all possible values. | |
* @return the DocumentDTO for front end to use. | |
*/ | |
@Override | |
public DocumentDTO saveDocumentDto(DocumentDTO dto, SaveContourItemDTOOptions options) { | |
boolean newDoc = isDTOForNewDocument(dto); | |
if (newDoc && dto.getAttachment() == null) { | |
hierarchyUtil.assertValidHierarchyForDocumentDTO(dto); | |
} | |
if (CollectionUtils.isNotEmpty(dto.getTestCaseSteps())) { | |
for (TestCaseStepDTO tcsdto : dto.getTestCaseSteps()) { | |
if (newDoc || !dto.getId().equals(tcsdto.getTestCaseId())) { | |
tcsdto.setId(null); | |
} | |
tcsdto.setTestCaseId(dto.getId()); | |
} | |
} | |
DocumentDTO docDto = contourItemService.saveContourItemDto(dto, options); | |
if (newDoc) { | |
Document document = (Document) contourItemService.getContourItem(docDto.getId()); | |
if (CollectionUtils.isNotEmpty(dto.getTestCaseSteps())) { | |
List<TestCaseStep> steps = testCaseStepAssembler.toDomainList(dto.getTestCaseSteps()); | |
document.getTestCaseSteps().clear(); | |
for (TestCaseStep step : steps) { | |
step.setTestCase(document); | |
document.getTestCaseSteps().add(step); | |
} | |
contourItemService.saveContourItem(document); | |
docDto.setTestCaseSteps(testCaseStepAssembler.toDTOList(document.getTestCaseSteps())); | |
} | |
documentNodeManager.createDocumentNodeForDocument(document, dto.getParentId(), dto.getPlaceAfterId(), null); | |
} | |
return docDto; | |
} | |
@Override | |
public DocumentDTO verifyAndSaveDocumentDTO(DocumentDTO dto, SaveContourItemDTOOptions options) { | |
contourItemValidationHelper.setMissingValuesAndValidateDTO(dto, options.allowGlobalIdChange() ? GLOBAL_ID_OVERRIDE_LIST : EMPTY_LIST); | |
moveDocumentIfParentHasChanged(dto); | |
return saveDocumentDto(dto, options); | |
} | |
@Override | |
public String moveDocumentToProjectAsynchronously(Integer itemId, Integer newParentId, Integer newProjectId) { | |
ContourItem originalDoc = contourItemService.getContourItem(itemId); | |
Integer oldDocProjectId = originalDoc.getProject().getId(); | |
if (newProjectId != null && !oldDocProjectId.equals(newProjectId)) { | |
assertNewParentIdForProjectMove(newParentId); | |
moveToNewProjectValidation(itemId,newProjectId); | |
return itemMover.moveItem(itemId, newProjectId); | |
} | |
throw new ValidationException("move within same project not supported"); | |
} | |
private void assertNewParentIdForProjectMove(Integer newParentId) { | |
if(newParentId != null) { | |
throw new ValidationException("new parent item not supported when moving to another project"); | |
} | |
} | |
private void moveDocumentIfParentHasChanged(DocumentDTO dto) { | |
if (!isDTOForNewDocument(dto)) { | |
DocumentNode docNode = documentNodeDao.getDocumentNode(Scope.DOCUMENT, dto.getId()); | |
Integer oldParentId = docNode.getParentNode().getRefId(); | |
Integer parentId = dto.getParentId(); | |
if (!oldParentId.equals(parentId)) { | |
ContourItem originalDoc = contourItemService.getContourItem(dto.getId()); | |
moveDocument(originalDoc, docNode, parentId); | |
} | |
} | |
} | |
private void moveToNewProjectValidation(Integer itemToMove, Integer projectToMoveTo) { | |
List<ValidationFailure> listOfValidationFailures = new LinkedList<>(); | |
List<Integer> itemsUnableToWrite; | |
List<Integer> itemsLocked; | |
List<Integer> itemsWithDuplicateGlobalIds; | |
List<Integer> listOfParentAndChildrenItems = documentNodeManager.getFullChildDocumentIdList(itemToMove); | |
listOfParentAndChildrenItems.add(itemToMove); | |
assertRootItemIsComponentOrSetAndIsActive(itemToMove); | |
clientServiceSupport.assertUserCanWriteProject(projectToMoveTo); | |
itemsUnableToWrite = checkUserCanWriteItems(listOfParentAndChildrenItems); | |
itemsLocked = checkItemsNotLocked(listOfParentAndChildrenItems); | |
itemsWithDuplicateGlobalIds = checkDuplicateGlobalIds(listOfParentAndChildrenItems,projectToMoveTo); | |
if(!itemsLocked.isEmpty() ) { | |
ItemsLockedValidationFailure itemsLockedValidationFailure = new ItemsLockedValidationFailure("Items are locked",itemsLocked); | |
listOfValidationFailures.add(itemsLockedValidationFailure); | |
} | |
if(!itemsUnableToWrite.isEmpty()) { | |
ItemsPermissionsNotAuthorized itemsPermissionsNotAuthorized = new ItemsPermissionsNotAuthorized("Items don't have write permissions", itemsUnableToWrite); | |
listOfValidationFailures.add(itemsPermissionsNotAuthorized); | |
} | |
if(!itemsWithDuplicateGlobalIds.isEmpty()){ | |
ItemsDuplicateGlobalIdException itemsDuplicateGlobalIdException = new ItemsDuplicateGlobalIdException("Items are duplicate global Ids", itemsWithDuplicateGlobalIds); | |
listOfValidationFailures.add(itemsDuplicateGlobalIdException); | |
} | |
if(!listOfValidationFailures.isEmpty()) { | |
throw new ValidationException("Cannot move Items", listOfValidationFailures); | |
} | |
} | |
private List<Integer> checkDuplicateGlobalIds(List<Integer> listToCheck, Integer projectIdToMoveTo){ | |
PropertyEntry propertyEntry = propertyService.getOrganizationProperty(OrgProperties.ORGANIZATION_ALLOW_NONUNIQUE_GLOBALID_IN_PROJECTS, getOrganizationId()); | |
Boolean isGlobalAllowedInProject = PropertyType.BOOLEAN.convertPropertyEntryValue(propertyEntry); | |
if(!isGlobalAllowedInProject){ | |
return documentDao.getItemsWithSameGlobalIdWithInProject(listToCheck, projectIdToMoveTo); | |
}else { | |
return Collections.emptyList(); | |
} | |
} | |
private void assertRootItemIsComponentOrSetAndIsActive(Integer itemToMove){ | |
Document document = documentDao.getDocument(itemToMove); | |
if(!document.getActive()){ | |
throw new ValidationException("Selected item to move is not active"); | |
} | |
if(document.getDocumentType().getCategory() == null){ | |
throw new ValidationException("The item you are trying to move is not a set or component"); | |
} | |
if(!document.getDocumentType().getCategory().getDbId().equals(DocumentTypeCategory.COMPONENT.getDbId()) | |
&& !document.getDocumentType().getCategory().getDbId().equals(DocumentTypeCategory.SET.getDbId()) ){ | |
throw new ValidationException("The item you are trying to move is not a set or component"); | |
} | |
} | |
private List<Integer> checkItemsNotLocked(List<Integer> listOfItems){ | |
return documentDao.getLockedItems(listOfItems); | |
} | |
private List<Integer> checkUserCanWriteItems(List<Integer> listOfItems){ | |
List<Integer> listOfNonWritableItems = new LinkedList<>(); | |
List<Integer> listOfDocumentKeys = new LinkedList<>(); | |
List<Document> listOfDocuments; | |
List<Integer> activeListOfDocuments = documentDao.getActiveDocumentsFromList(listOfItems); | |
for(Integer item: activeListOfDocuments){ | |
try { | |
clientServiceSupport.assertUserCanWriteContourItem(item); | |
}catch (org.springframework.security.access.AccessDeniedException permissionException){ | |
listOfNonWritableItems.add(item); | |
} | |
} | |
if(listOfNonWritableItems.size()>0){ | |
listOfDocuments = documentDao.getDocumentByIds(listOfItems); | |
for(Document document: listOfDocuments){ | |
listOfDocumentKeys.add(document.getId()); | |
} | |
return listOfDocumentKeys; | |
} else { | |
return Collections.emptyList(); | |
} | |
} | |
private void moveDocument(ContourItem originalDoc, DocumentNode docNode, Integer parentId) { | |
ContourItem parentDoc = parentId == null ? null : contourItemService.getContourItem(parentId); | |
if (!HierarchyUtil.isValidDocumentChild(parentDoc, originalDoc.getDocumentType(), null)) { | |
throw new HierarchyViolationException("The item with ID " + parentId + " is an invalid location"); | |
} | |
Integer scopeId = parentDoc == null ? Scope.PROJECT : Scope.DOCUMENT; | |
Integer refId = parentDoc == null ? originalDoc.getProject().getId() : parentId; | |
DocumentNode newParentNode = documentNodeDao.getDocumentNode(scopeId, refId); | |
documentNodeManager.moveNodes(Collections.singletonList(docNode), newParentNode, null, TreeChangeCommand.getAllCommand()); | |
} | |
/** | |
* | |
* @param dto the dto with all possible values. | |
* @return the DocumentDTO for front end to use. | |
* @throws Exception | |
*/ | |
@Override | |
public DocumentDTO saveIncrementDocumentDto(DocumentDTO dto, SaveContourItemDTOOptions options) throws Exception { | |
if (dto.getTestCaseSteps() != null) { | |
for (TestCaseStepDTO tcsdto : dto.getTestCaseSteps()) { | |
tcsdto.setTestCaseId(dto.getId()); | |
} | |
} | |
return contourItemService.saveIncrementContourItemDto(dto, options); | |
} | |
private boolean isDTOForNewDocument(DocumentDTO dto) { | |
return (dto.getId() == null || dto.getId() == 0); | |
} | |
/** | |
* Creates an activity entry for a document. This is used after | |
* a user does one or more incremental saves and then cancels | |
* out of the window. | |
* | |
* @param docId id of the document to create the event for | |
*/ | |
@Override | |
public void publishDocEventAfterCancel(Integer docId) { | |
Version version = versionDao.getVersionByDocumentId(docId); | |
if (version != null && version.getOriginDocument().getId().equals(docId)) { | |
User user = currentUserFinder.getCurrentUser(); | |
SystemEvent se = new SystemEvent(this, ObjectTypeImpl.Document, docId, version.getDocument(), user, EventEntryImpl.MODIFIED, version.getDocument().getProject(), EventTypeImpl.UPDATE, version.getComments(), ""); | |
applicationContext.publishEvent(se); | |
} | |
} | |
@Override | |
public DocumentDTO saveDocumentDtoKeepVersion(DocumentDTO dto) throws Exception { | |
Document doc = documentDao.getDocument(dto.getId()); | |
if (doc == null) { | |
return null; | |
} | |
doc.accept(MergeDtoIntoContourItemVisitor.INSTANCE, dto); | |
documentDao.saveDocument(doc); | |
return (DocumentDTO) doc.accept(ToDTOContourItemVisitor.INSTANCE, null); | |
} | |
@Override | |
public void saveDocumentWithComment(Document doc, String versionComment, Boolean shouldVersion) { | |
documentDao.saveDocument(doc); | |
if (Boolean.TRUE.equals(shouldVersion)) { | |
createDocumentVersion(doc, versionComment, true); | |
} | |
} | |
@Override | |
public ContourItemDTO updateDocumentFromItemWrapper(ItemWrapper itemWrapper, DistributionUsersAndGroupsDTO distributionList, String userComment, SaveContourItemDTOOptions options) { | |
return contourItemService.updateContourItemFromItemWrapper(itemWrapper, distributionList, userComment, options); | |
} | |
@Override | |
public ContourItem updateDocumentFromItemWrapper(ItemWrapper itemWrapper, DistributionUsersAndGroupsDTO distributionList, String userComment, SaveContourItemDTOOptions options, boolean updateSyncRelationships) { | |
return contourItemService.updateContourItemFromItemWrapper(itemWrapper, distributionList, userComment, options, updateSyncRelationships); | |
} | |
@Override | |
public Version createDocumentVersion(ContourItem document, String versionComments, boolean newDoc) { | |
return createDocumentVersion(document, versionComments, null, newDoc); | |
} | |
@Override | |
public Version createDocumentVersion(ContourItem document, String versionComments, String userComment, boolean newDoc) { | |
return createDocumentVersion(document, versionComments, userComment, newDoc, currentUserFinder.getCurrentUser()); | |
} | |
@Override | |
public Version createDocumentVersion(ContourItem document, String versionComments, String userComment, boolean newDoc, User user) { | |
return contourItemHelper.createContourItemVersion(document, versionComments, userComment, newDoc, user); | |
} | |
@Override | |
public Version createVersionForDocumentWithout(ContourItem doc) { | |
return createDocumentVersion(doc, "Auto-created version", true); | |
} | |
private Boolean getShowIdInTree(Integer projectId) { | |
Boolean showIdInTree = Boolean.FALSE; | |
PropertyEntry config = propertyService.getProjectProperty(projectId, ProjectProperty.PROJECT_SHOW_ID_IN_TREE.getName()); | |
if (config != null) { | |
showIdInTree = PropertyType.BOOLEAN.convertPropertyEntryValue(config, false); | |
} | |
return showIdInTree; | |
} | |
private static final Integer MAX_NODES = 250; | |
private Integer getMaxTreeNodes(Integer projectId) { | |
Integer maxNodes = MAX_NODES; | |
if (projectId != null) { | |
PropertyEntry config = propertyService.getProjectProperty(projectId, ProjectProperty.PROJECT_MAX_TREE_NODES.getName()); | |
maxNodes = PropertyType.INTEGER.convertPropertyEntryValue(config, maxNodes); | |
} | |
return maxNodes; | |
} | |
@Override | |
public ExtDocumentTreeNode getExtTreeNodeForDocument(Integer docId, TreeOptions options) { | |
Document doc = documentDao.getDocument(docId); | |
if (options == null) { | |
options = new TreeOptions(); | |
} | |
return documentTreeHelper.documentToNode(doc, options, null, true, null, false); | |
} | |
/** | |
* called by explorer and enhanced release trees on initial and subsequent node ticks | |
*/ | |
@Override | |
public List<ExtDocumentTreeNode> getExtTreeNodes(ExtDocumentTreeNode node, TreeOptions options) throws Exception { | |
Integer projectId = options.getProjectId(); | |
if (options.getMaxNodes() == null || options.getMaxNodes() <= 0) { | |
options.setMaxNodes(getMaxTreeNodes(projectId)); | |
} | |
if (options.getShowKey() == null) { | |
boolean showId = (projectId == null) ? false : getShowIdInTree(projectId); | |
options.setShowKey(showId); | |
} | |
return documentTreeHelper.getExtTreeNodes(node, options); | |
} | |
@Override | |
public List<ExtDocumentTreeNode> getOutOfSyncTree(ExtDocumentTreeNode node, TreeOptions options) throws Exception { | |
String previousFlushMode = genericDao.doNotFlushTemporarily(); | |
Integer projectId = options.getProjectId(); | |
if (options.getMaxNodes() == null || options.getMaxNodes() <= 0) { | |
Integer maxNodes = (projectId == null) ? MAX_NODES : getMaxTreeNodes(projectId); | |
options.setMaxNodes(maxNodes); | |
} | |
if (options.getShowKey() == null) { | |
boolean showId = (projectId == null) ? false : getShowIdInTree(projectId); | |
options.setShowKey(showId); | |
} | |
List<ExtDocumentTreeNode> list = documentTreeHelper.getExtTreeNodes(node, options); | |
genericDao.flush(); | |
genericDao.resumeNormalFlushOperation(previousFlushMode); | |
return list; | |
} | |
@Override | |
public String getPath(Integer documentId) { | |
CachedDocumentNode node = documentNodeManager.getCachedDocumentNode(Scope.DOCUMENT, documentId, true); | |
if (node == null) { | |
throw new RuntimeException("Item not found in tree!"); | |
} | |
return node.getExtTreePath(); | |
} | |
@Override | |
public void sortDocumentHeadingsByProject(Integer projectId) { | |
DocumentNodeManager.getInstance().regenerateStateAndFlushToDatabase(projectId, true); | |
} | |
@Override | |
public void moveItems(List<String> nodeList, String newParentId, String siblingId) { | |
String flushMode = genericDao.doNotFlushTemporarily(); | |
try { | |
documentDndHelper.moveItems(nodeList, newParentId, siblingId, this); | |
} | |
finally { | |
genericDao.resumeNormalFlushOperation(flushMode); | |
} | |
} | |
@Override | |
public void moveItemsInFilter(FilterOrSmartFilterDTOHolder filter, String newParentId, String siblingId) { | |
List<Integer> ids = filterService.getItemIdsFromFilter(filter); | |
List<String> nodeList = new ArrayList<>(ids.size()); | |
for(Integer id : ids) { | |
nodeList.add(ExtDocumentTreeNode.buildTreeNodeId(ExtDocumentTreeNode.TreeNodeKey.DOCUMENT, id)); | |
} | |
moveItems(nodeList, newParentId, siblingId); | |
} | |
@Override | |
public boolean hasPendingChanges(DocumentDTO updContourDocDTO) { | |
return contourItemService.hasPendingChanges(updContourDocDTO); | |
} | |
/** | |
* Given a document and group, fetch the downstream related documents | |
*/ | |
@Override | |
public List<DocumentDTO> getDownStreamRelatedDocuments(Integer documentId, Integer groupId) { | |
if (logger.isDebugEnabled()) { | |
logger.debug("getting downstream related documents for document: " + documentId + " and group" + groupId); | |
} | |
List<DocumentDTO> documents = new ArrayList<DocumentDTO>(); | |
DocumentGroup group = documentGroupDao.getDocumentGroup(groupId); | |
if (group != null) { | |
boolean isForward = true; | |
List<Document_Document> relatedDocuments = relationshipService.getRelationshipsForDocument(documentId, isForward); | |
for (Document_Document dd : relatedDocuments) { | |
if (dd.getToDocument().getDocumentType().equals(group.getDocumentType())) { | |
ContourItem d = dd.getToDocument(); | |
d = HibernateUtil.deproxy(d, ContourItem.class); | |
//TODO: When we allow relationships to other ContourItems, we should move this | |
// method of DocumentService and not perform this type checking | |
if (d instanceof Document) { | |
DocumentDTO ddto = (DocumentDTO) d.accept(ToDTOContourItemVisitor.INSTANCE, null); | |
documents.add(ddto); | |
if (logger.isDebugEnabled()) { | |
logger.debug(" - related document: " + d); | |
logger.debug(" - related document dto: " + ddto); | |
} | |
} | |
} | |
} | |
} | |
return documents; | |
} | |
/** | |
* given a parent release document and a group, fetch the paged downstream relationship documents for that group | |
*/ | |
@Override | |
public SearchResults<DocumentDTO> getPagedDownStreamDocuments(int documentId, int groupId, int start, int count, String orderBy) { | |
if (logger.isDebugEnabled()) { | |
logger.debug("getting paged downstream documents for document: " + documentId + " and group: " + groupId); | |
} | |
SorterList sorter = HibernateUtil.createSorterList(orderBy); | |
PageInfo pageInfo = HibernateUtil.createPageInfo(start, count); | |
List<DocumentDTO> relatedDocuments = this.getDownStreamRelatedDocuments(documentId, groupId); | |
return PaginationHelper.createSearchResults(new ArrayList<DocumentDTO>(relatedDocuments), sorter, pageInfo, DocumentDTO.class); | |
} | |
@Override | |
public void ensureDocumentsHaveVersion() { | |
List<Document> docsWithoutVersions = versionDao.getDocumentsWithoutVersion(); | |
List<Document> createdVersionDocs = new ArrayList<Document>(docsWithoutVersions.size()); | |
for (Document docWithoutVersion : docsWithoutVersions) { | |
createVersionForDocumentWithout(docWithoutVersion); | |
createdVersionDocs.add(docWithoutVersion); | |
} | |
genericDao.flush(); | |
for (Document doc : createdVersionDocs) { | |
genericDao.detatchObject(doc.getDocumentType()); | |
genericDao.detatchObject(doc.getCurrentVersion()); | |
genericDao.detatchObject(doc); | |
} | |
} | |
@Override | |
public void changeSetKey(Integer setId, String newSetKey, Boolean updateChildItems) { | |
setKeyChanger.changeSetKey(setId, newSetKey, updateChildItems); | |
} | |
@Override | |
public int getTotalProjectItems(int projectId) { | |
return documentDao.getTotalProjectItems(projectId); | |
} | |
@Override | |
public void replaceLookupById(Integer originalLookupId, Lookup newLookup) { | |
Integer orgId = newLookup.getOrganizationId(); | |
List<DocumentField> docLookupFields = documentDao.getDocumentLookupFields(orgId); | |
for (DocumentField dField : docLookupFields) { | |
if (Boolean.TRUE.equals(dField.getCustom())) { | |
documentDao.replaceCustomLookupById(originalLookupId, newLookup, dField); | |
} | |
else { | |
documentDao.replacePredefinedLookupById(originalLookupId, newLookup, dField); | |
} | |
} | |
} | |
@Override | |
public void setApplicationContext(ApplicationContext applicationContext) { | |
this.applicationContext = applicationContext; | |
} | |
private Integer getOrganizationId() { | |
return currentUserFinder.getCurrentUser() != null ? currentUserFinder.getCurrentUser().getOrganizationId() : null; | |
} | |
public void setVersionDao(VersionDao versionDao) { | |
this.versionDao = versionDao; | |
} | |
public void setCurrentUserFinder(CurrentUserFinder currentUserFinder) { | |
this.currentUserFinder = currentUserFinder; | |
} | |
public void setDocumentDao(DocumentDao documentDao) { | |
this.documentDao = documentDao; | |
} | |
public void setDocumentGroupDao(DocumentGroupDao documentGroupDao) { | |
this.documentGroupDao = documentGroupDao; | |
} | |
public void setPropertyService(PropertyService propertyService) { | |
this.propertyService = propertyService; | |
} | |
public void setDocumentDndHelper(DocumentDndHelper documentDndHelper) { | |
this.documentDndHelper = documentDndHelper; | |
} | |
public void setDocumentTreeHelper(DocumentTreeHelper documentTreeHelper) { | |
this.documentTreeHelper = documentTreeHelper; | |
} | |
public void setRelationshipService(RelationshipService relationshipService) { | |
this.relationshipService = relationshipService; | |
} | |
public void setDocumentNodeDao(DocumentNodeDao documentNodeDao) { | |
this.documentNodeDao = documentNodeDao; | |
} | |
public void setDocumentNodeManager(DocumentNodeManager documentNodeManager) { | |
this.documentNodeManager = documentNodeManager; | |
} | |
public void setGenericDao(GenericDao genericDao) { | |
this.genericDao = genericDao; | |
} | |
public void setContourItemHelper(ContourItemHelper contourItemHelper) { | |
this.contourItemHelper = contourItemHelper; | |
} | |
public void setContourItemService(ContourItemService contourItemService) { | |
this.contourItemService = contourItemService; | |
} | |
public void setSetKeyChanger(SetKeyChanger setKeyChanger) { | |
this.setKeyChanger = setKeyChanger; | |
} | |
public void setTestCaseStepAssembler(TestCaseStepAssembler testCaseStepAssembler) { | |
this.testCaseStepAssembler = testCaseStepAssembler; | |
} | |
public void setHierarchyUtil(HierarchyUtil hierarchyUtil) { | |
this.hierarchyUtil = hierarchyUtil; | |
} | |
public void setItemReuser(ItemReuser itemReuser) { | |
this.itemReuser = itemReuser; | |
} | |
public void setFilterService(FilterService filterService) { | |
this.filterService = filterService; | |
} | |
public void setContourItemValidationHelper(ContourItemValidationHelper contourItemValidationHelper) { | |
this.contourItemValidationHelper = contourItemValidationHelper; | |
} | |
public void setItemMover(ItemMover itemMover) { | |
this.itemMover = itemMover; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment