class CorrespondenceGenerator {

    public EcmFile generateCorrespondence(Authentication user, String parentObjectType, Long parentObjectId, String targetFolderCmisId,
            CorrespondenceTemplate template, Object[] queryArguments, OutputStream correspondenceOutputStream,
            InputStream correspondenceInputStream)
            throws IOException, AcmCreateObjectFailedException, AcmUserActionFailedException, CorrespondenceMergeFieldVersionException
    {
        Map<String, Object> queryResult = query(template, queryArguments);

        if (queryResult == null || queryResult.isEmpty())
        {
            throw new IllegalStateException("Database query returned no results");
        }

        Map<String, String> substitutions = prepareSubstitutionMap(template, queryResult);

        Resource templateFile = new FileSystemResource(getCorrespondenceFolderName() + File.separator + template.getTemplateFilename());

        log.debug("Generating correspondence from template '{}'", templateFile.getFile().getAbsolutePath());

        getWordGenerator().generate(templateFile, correspondenceOutputStream, substitutions);

        EcmFile retval = null;

        // Check for existing correspondence template in same folder. If so, update the ecm file (new version) instead
        // of creating new ecm file.
        EcmFile existing = ecmFileDao.findSingleFileByParentObjectAndFolderCmisIdAndFileType(parentObjectType, parentObjectId,
                targetFolderCmisId,
                template.getDocumentType());

        if (existing == null)
        {
            String fileName = generateUniqueFilename(template);
            retval = ecmFileService.upload(template.getDocumentType() + ".docx", template.getDocumentType(),
                    CORRESPONDENCE_CATEGORY,
                    correspondenceInputStream, WORD_MIME_TYPE, fileName, user, targetFolderCmisId, parentObjectType, parentObjectId);
        }
        else
        {
            retval = ecmFileService.update(existing, correspondenceInputStream, SecurityContextHolder.getContext().getAuthentication());
        }

        return retval;
    }

}