Java tutorial
/* * Copyright 2013 the original author or authors. * * 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 org.brekka.pegasus.core.services.impl; import java.util.Date; import java.util.List; import java.util.UUID; import org.brekka.commons.persistence.model.ListingCriteria; import org.brekka.commons.persistence.support.EntityUtils; import org.brekka.paveway.core.model.CryptedFile; import org.brekka.pegasus.core.dao.AllocationDAO; import org.brekka.pegasus.core.dao.AllocationFileDAO; import org.brekka.pegasus.core.event.AllocationFileDeleteEvent; import org.brekka.pegasus.core.model.AccessorContext; import org.brekka.pegasus.core.model.Allocation; import org.brekka.pegasus.core.model.AllocationFile; import org.brekka.pegasus.core.model.Dispatch; import org.brekka.pegasus.core.model.FileDownloadEvent; import org.brekka.pegasus.core.model.KeySafeAware; import org.brekka.pegasus.core.model.XmlEntity; import org.brekka.pegasus.core.services.AllocationService; import org.brekka.xml.pegasus.v2.model.AllocationDocument; import org.brekka.xml.pegasus.v2.model.BundleType; import org.brekka.xml.pegasus.v2.model.FileType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * Providing operations for the base {@link Allocation} type. * * @author Andrew Taylor (andrew@brekka.org) */ @Service @Transactional public class AllocationServiceImpl extends AllocationServiceSupport implements AllocationService { @Autowired private AllocationFileDAO allocationFileDAO; @Autowired private AllocationDAO allocationDAO; @Autowired private ApplicationEventPublisher applicationEventPublisher; @Override @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ) public void incrementDownloadCounter(final AllocationFile allocationFile) { FileType xml = allocationFile.getXml(); int maxDownloads = Integer.MAX_VALUE; if (xml.isSetMaxDownloads()) { maxDownloads = xml.getMaxDownloads(); } AllocationFile managed = this.allocationFileDAO.retrieveById(allocationFile.getId()); int downloadCount = managed.getDownloadCount(); // Increment the downloads downloadCount++; managed.setDownloadCount(downloadCount); if (downloadCount == maxDownloads) { // Mark this file for deletion managed.setExpires(new Date()); } this.allocationFileDAO.update(managed); } @Override @Transactional(readOnly = true) public AllocationFile retrieveFile(final UUID allocationFileId) { AccessorContext currentContext = AccessorContextImpl.getCurrent(); AllocationFile unlockedAllocationFile = currentContext.retrieve(allocationFileId, AllocationFile.class); if (unlockedAllocationFile != null) { this.allocationFileDAO.refresh(unlockedAllocationFile); return unlockedAllocationFile; } AllocationFile allocationFile = this.allocationFileDAO.retrieveById(allocationFileId); if (allocationFile == null) { return null; } Allocation allocation = allocationFile.getAllocation(); Allocation unlockedAllocation = currentContext.retrieve(allocation.getId(), Allocation.class); if (unlockedAllocation == null) { // Allocation has not yet been unlocked decryptDocument(allocation); currentContext.retain(allocation.getId(), allocation); unlockedAllocation = allocation; } allocationFile.setAllocation(unlockedAllocation); if (unlockedAllocation.getXml() != null) { BundleType bundle = unlockedAllocation.getXml().getBean().getAllocation().getBundle(); List<FileType> fileList = bundle.getFileList(); for (FileType fileType : fileList) { if (allocationFile.getCryptedFile().getId().toString().equals(fileType.getUUID())) { allocationFile.setXml(fileType); break; } } } currentContext.retain(allocationFile.getId(), allocationFile); return allocationFile; } @Override @Transactional(isolation = Isolation.SERIALIZABLE) public void clearAllocation(final Allocation allocation) { List<AllocationFile> fileList = this.allocationFileDAO.retrieveByAllocation(allocation); for (AllocationFile file : fileList) { clearAllocationFile(file, false); } XmlEntity<AllocationDocument> xml = allocation.getXml(); allocation.setDeleted(new Date()); allocation.setXml(null); this.allocationDAO.update(allocation); this.xmlEntityService.delete(xml.getId()); } @Override @Transactional(readOnly = true) public <T extends Allocation & KeySafeAware> void releaseDetails(final List<T> allocationList) { for (T allocation : allocationList) { if (allocation == null) { continue; } decryptDocument(allocation); } } @Override @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ) public void forceExpireAllocation(final Allocation allocation) { Date expiryDate = new Date(); // Update the incoming reference with the date allocation.setExpires(expiryDate); Allocation managed = this.allocationDAO.retrieveById(allocation.getId()); managed.setExpires(expiryDate); this.allocationDAO.update(managed); } @Override @Transactional(isolation = Isolation.REPEATABLE_READ) public void clearAllocationFile(final AllocationFile file) { clearAllocationFile(file, true); } @Override @Transactional(isolation = Isolation.SERIALIZABLE) public void updateDetails(final Allocation allocation) { XmlEntity<AllocationDocument> updatedXml = allocation.getXml(); Allocation latest = this.allocationDAO.retrieveById(allocation.getId()); XmlEntity<AllocationDocument> updatedEntity = this.xmlEntityService.updateEntity(updatedXml, latest.getXml(), AllocationDocument.class); latest.setXml(updatedEntity); this.allocationDAO.update(latest); } @Override @Transactional(readOnly = true) public List<Allocation> retrieveDerivedFromListing(final Dispatch derivedFrom, final ListingCriteria listingCriteria) { List<Allocation> listing = this.allocationDAO.retrieveDerivedFromListing(derivedFrom, listingCriteria); return listing; } @Override @Transactional(readOnly = true) public int retrieveDerivedFromListingRowCount(final Dispatch derivedFrom) { return retrieveDerivedFromListingRowCount(derivedFrom); } @Override @Transactional(readOnly = true) public List<FileDownloadEvent> retrievePopulatedDownloadEvents(final Allocation allocation) { Allocation managed = this.allocationDAO.retrieveById(allocation.getId()); Dispatch derivedFrom = managed.getDerivedFrom(); decryptDocument(derivedFrom); List<FileDownloadEvent> downloads = this.eventService.retrieveFileDownloads(managed); List<AllocationFile> files = derivedFrom.getFiles(); for (FileDownloadEvent fileDownloadEvent : downloads) { AllocationFile eventTransferFile = fileDownloadEvent.getTransferFile(); for (AllocationFile dispatchTransferFile : files) { if (EntityUtils.identityEquals(dispatchTransferFile, eventTransferFile.getDerivedFrom())) { // Copy XML to event transfer - just to provide the name. The UUID will be incorrect. eventTransferFile.setXml(dispatchTransferFile.getXml()); break; } } } return downloads; } protected void clearAllocationFile(final AllocationFile file, final boolean deleteAllocationIfPossible) { AllocationFile allocationFile = this.allocationFileDAO.retrieveById(file.getId()); this.applicationEventPublisher.publishEvent(new AllocationFileDeleteEvent(allocationFile)); if (allocationFile.getDeleted() != null) { // Already deleted return; } CryptedFile cryptedFile = allocationFile.getCryptedFile(); List<AllocationFile> active = this.allocationFileDAO.retrieveActiveForCryptedFile(cryptedFile); boolean canDeleteCryptedFile = active.size() == 1; // Check whether we can delete the rest of the allocation also if (deleteAllocationIfPossible) { Allocation allocation = allocationFile.getAllocation(); active = this.allocationFileDAO.retrieveActiveForAllocation(allocation); if (active.size() == 1) { // Make the allocation as expired. The reaper will pick it up soon allocation.setExpires(new Date()); this.allocationDAO.update(allocation); } } allocationFile.setDeleted(new Date()); allocationFile.setCryptedFile(null); this.allocationFileDAO.update(allocationFile); if (canDeleteCryptedFile) { // This is the only file. Safe to obliterate the crypted file this.pavewayService.removeFile(cryptedFile); } } }