/
Chebarik
/
PackageManagement
Обзор
Документация
Войти
/
Chebarik
/
PackageManagement
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/main/java/com/packagemanagement/application/service/PackageApplicationService.java
265 строк
10 KB
Николай Мехоношин
Implemented non functional requirements
14 апр 2026, 18:37
14 апр 2026, 18:37
2e86838
Код
Авторство
О чём код?
package com.packagemanagement.application.service; import com.packagemanagement.application.dto.PackageDto; import com.packagemanagement.application.dto.PackageMapper; import com.packagemanagement.application.dto.VersionDto; import com.packagemanagement.application.port.AuditService; import com.packagemanagement.application.port.CacheService; import com.packagemanagement.application.port.StorageService; import com.packagemanagement.domain.exception.InvalidPackageFormatException; import com.packagemanagement.domain.exception.PackageAlreadyExistsException; import com.packagemanagement.domain.exception.PackageNotFoundException; import com.packagemanagement.domain.exception.VersionNotFoundException; import com.packagemanagement.domain.model.Package; import com.packagemanagement.domain.model.PackageFormat; import com.packagemanagement.domain.model.PackageId; import com.packagemanagement.domain.model.PackageVersion; import com.packagemanagement.domain.repository.PackageRepository; import com.packagemanagement.domain.service.PackageDomainService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.util.List; import java.util.stream.Collectors; @Service @Transactional public class PackageApplicationService { private static final Logger log = LoggerFactory.getLogger(PackageApplicationService.class); private static final String CACHE_PREFIX = "package:"; private static final Duration CACHE_TTL = Duration.ofMinutes(30); private final PackageRepository packageRepository; private final PackageDomainService packageDomainService; private final CacheService cacheService; private final StorageService storageService; private final AuditService auditService; private final PackageMapper packageMapper; public PackageApplicationService( PackageRepository packageRepository, PackageDomainService packageDomainService, CacheService cacheService, StorageService storageService, AuditService auditService, PackageMapper packageMapper ) { this.packageRepository = packageRepository; this.packageDomainService = packageDomainService; this.cacheService = cacheService; this.storageService = storageService; this.auditService = auditService; this.packageMapper = packageMapper; } public PackageDto createPackage(String name, String description, PackageFormat format) { log.info("Creating package: {} with format: {}", name, format); if (packageRepository.existsByName(name)) { throw new PackageAlreadyExistsException(name); } Package pkg = Package.create(name, description, format); Package savedPackage = packageRepository.save(pkg); auditService.logPackageCreated(savedPackage.getId().getValue(), name, getCurrentUserId()); PackageDto dto = packageMapper.toDto(savedPackage); cacheService.put(CACHE_PREFIX + savedPackage.getId().getValue(), dto, CACHE_TTL); log.info("Package created successfully: {}", savedPackage.getId()); return dto; } public VersionDto uploadVersion(String packageId, String versionNumber, byte[] content, String filename) { log.info("Uploading version {} for package {} (file: {})", versionNumber, packageId, filename); if (!packageDomainService.isValidVersionNumber(versionNumber)) { throw new IllegalArgumentException("Invalid version number format: " + versionNumber); } Package pkg = packageRepository.findById(PackageId.of(packageId)) .orElseThrow(() -> new PackageNotFoundException(packageId)); validateFileExtension(filename, pkg.getFormat()); if (!packageDomainService.validateFormat(content, pkg.getFormat())) { throw new InvalidPackageFormatException(pkg.getFormat(), "Uploaded file content does not match the expected package format. " + "Expected " + pkg.getFormat() + " format (NuGet packages must contain .nuspec file, " + "Maven packages must contain META-INF/ directory)"); } if (packageDomainService.checkVersionConflict(pkg, versionNumber)) { throw new IllegalArgumentException("Version " + versionNumber + " already exists"); } String hash = packageDomainService.calculateHash(content); storageService.store(packageId, versionNumber, content); PackageVersion version = PackageVersion.create(versionNumber, content.length, hash); version.publish(); pkg.addVersion(version); packageRepository.save(pkg); auditService.logVersionUploaded(packageId, versionNumber, getCurrentUserId()); cacheService.evict(CACHE_PREFIX + packageId); log.info("Version {} uploaded successfully for package {}", versionNumber, packageId); return packageMapper.toDto(version); } private void validateFileExtension(String filename, PackageFormat expectedFormat) { if (filename == null || filename.isEmpty()) { throw new InvalidPackageFormatException(expectedFormat, "Filename is required"); } String extension = ""; int lastDot = filename.lastIndexOf('.'); if (lastDot > 0) { extension = filename.substring(lastDot + 1).toLowerCase(); } String[] validExtensions = getValidExtensions(expectedFormat); boolean isValid = false; for (String validExt : validExtensions) { if (validExt.equalsIgnoreCase(extension)) { isValid = true; break; } } if (!isValid) { throw new InvalidPackageFormatException(expectedFormat, "Invalid file extension '." + extension + "'. Expected: " + String.join(", ", validExtensions) + " for " + expectedFormat + " format"); } } private String[] getValidExtensions(PackageFormat format) { return switch (format) { case NUGET -> new String[]{"nupkg"}; case MAVEN -> new String[]{"jar", "war", "aar"}; }; } public void deletePackage(String packageId) { log.info("Deleting package: {}", packageId); Package pkg = packageRepository.findById(PackageId.of(packageId)) .orElseThrow(() -> new PackageNotFoundException(packageId)); String packageName = pkg.getName(); storageService.deleteAll(packageId); packageRepository.delete(PackageId.of(packageId)); auditService.logPackageDeleted(packageId, packageName, getCurrentUserId()); cacheService.evict(CACHE_PREFIX + packageId); cacheService.evictByPattern(CACHE_PREFIX + "list:*"); log.info("Package {} deleted successfully", packageId); } public void deleteVersion(String packageId, String versionNumber) { log.info("Deleting version {} from package {}", versionNumber, packageId); Package pkg = packageRepository.findById(PackageId.of(packageId)) .orElseThrow(() -> new PackageNotFoundException(packageId)); pkg.removeVersion(versionNumber); storageService.delete(packageId, versionNumber); packageRepository.save(pkg); auditService.logVersionDeleted(packageId, versionNumber, getCurrentUserId()); cacheService.evict(CACHE_PREFIX + packageId); log.info("Version {} deleted successfully from package {}", versionNumber, packageId); } @Transactional(readOnly = true) public PackageDto getPackage(String packageId) { String cacheKey = CACHE_PREFIX + packageId; return cacheService.get(cacheKey, PackageDto.class) .orElseGet(() -> { Package pkg = packageRepository.findById(PackageId.of(packageId)) .orElseThrow(() -> new PackageNotFoundException(packageId)); PackageDto dto = packageMapper.toDto(pkg); cacheService.put(cacheKey, dto, CACHE_TTL); return dto; }); } @Transactional(readOnly = true) public List<PackageDto> getAllPackages() { return packageRepository.findAll().stream() .map(packageMapper::toDto) .collect(Collectors.toList()); } @Transactional(readOnly = true) public List<PackageDto> getAllPackages(int page, int size) { return packageRepository.findAll(page, size).stream() .map(packageMapper::toDto) .collect(Collectors.toList()); } @Transactional(readOnly = true) public List<PackageDto> searchPackages(String query) { return packageRepository.searchByName(query).stream() .map(packageMapper::toDto) .collect(Collectors.toList()); } @Transactional(readOnly = true) public byte[] downloadVersion(String packageId, String versionNumber) { log.info("Downloading version {} of package {}", versionNumber, packageId); Package pkg = packageRepository.findById(PackageId.of(packageId)) .orElseThrow(() -> new PackageNotFoundException(packageId)); PackageVersion version = pkg.findVersion(versionNumber) .orElseThrow(() -> new VersionNotFoundException(packageId, versionNumber)); if (!version.getStatus().isDownloadable()) { throw new IllegalStateException("Version " + versionNumber + " is not available for download"); } byte[] content = storageService.retrieve(packageId, versionNumber); auditService.logVersionDownloaded(packageId, versionNumber, getCurrentUserId()); return content; } @Transactional(readOnly = true) public long getPackageCount() { return packageRepository.count(); } private String getCurrentUserId() { try { var authentication = org.springframework.security.core.context.SecurityContextHolder .getContext().getAuthentication(); if (authentication != null && authentication.isAuthenticated()) { return authentication.getName(); } } catch (Exception e) { log.debug("Could not resolve current user from SecurityContext: {}", e.getMessage()); } return "system"; } }