1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.kuali.coeus.s2sgen.impl.generate;
20
21
22 import gov.grants.apply.system.attachmentsV10.AttachedFileDataType;
23 import gov.grants.apply.system.attachmentsV10.AttachedFileDataType.FileLocation;
24 import gov.grants.apply.system.globalV10.HashValueDocument.HashValue;
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.xmlbeans.impl.util.Base64;
27 import org.kuali.coeus.common.questionnaire.api.answer.AnswerContract;
28 import org.kuali.coeus.common.questionnaire.api.answer.AnswerHeaderContract;
29 import org.kuali.coeus.common.questionnaire.api.core.QuestionAnswerService;
30 import org.kuali.coeus.propdev.api.core.DevelopmentProposalContract;
31 import org.kuali.coeus.propdev.api.person.ProposalPersonContract;
32 import org.kuali.coeus.propdev.api.questionnaire.PropDevQuestionAnswerService;
33 import org.kuali.coeus.propdev.api.person.attachment.ProposalPersonBiographyContract;
34 import org.kuali.coeus.propdev.api.core.ProposalDevelopmentDocumentContract;
35 import org.kuali.coeus.common.api.sponsor.hierarchy.SponsorHierarchyService;
36 import org.kuali.coeus.propdev.api.attachment.NarrativeContract;
37 import org.kuali.coeus.propdev.api.attachment.NarrativeService;
38 import org.kuali.coeus.s2sgen.api.core.InfastructureConstants;
39 import org.kuali.coeus.s2sgen.api.generate.AttachmentData;
40 import org.kuali.coeus.s2sgen.api.generate.FormMappingInfo;
41 import org.kuali.coeus.s2sgen.api.generate.FormMappingService;
42 import org.kuali.coeus.s2sgen.impl.generate.support.GlobalLibraryV1_0Generator;
43 import org.kuali.coeus.s2sgen.impl.generate.support.GlobalLibraryV2_0Generator;
44 import org.kuali.coeus.s2sgen.api.core.AuditError;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.factory.BeanNameAware;
48 import org.springframework.beans.factory.InitializingBean;
49 import org.springframework.beans.factory.annotation.Autowired;
50 import org.springframework.beans.factory.annotation.Qualifier;
51 import org.springframework.core.io.Resource;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.NodeList;
54
55 import javax.xml.parsers.DocumentBuilder;
56 import javax.xml.parsers.DocumentBuilderFactory;
57 import java.io.ByteArrayInputStream;
58 import java.security.MessageDigest;
59 import java.security.NoSuchAlgorithmException;
60 import java.util.ArrayList;
61 import java.util.List;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
64
65
66
67
68
69
70
71 public abstract class S2SBaseFormGenerator implements S2SFormGenerator, InitializingBean, BeanNameAware {
72
73 private static final Logger LOG = LoggerFactory.getLogger(S2SBaseFormGenerator.class);
74
75 protected static final String NOT_ANSWERED = "No";
76 protected static final String KEY_VALUE_SEPARATOR = "-";
77 protected static final String AREAS_AFFECTED_ABSTRACT_TYPE_CODE="16";
78 protected static final int ORGANIZATON_NAME_MAX_LENGTH = 60;
79 protected static final int DUNS_NUMBER_MAX_LENGTH = 13;
80 protected static final int PRIMARY_TITLE_MAX_LENGTH = 45;
81 protected static final int CONGRESSIONAL_DISTRICT_MAX_LENGTH = 6;
82 private static final String NARRATIVE_ATTACHMENT_FILE_LOCATION = "att:FileLocation";
83 protected static final String DEFAULT_SORT_INDEX = "1000";
84 private static final String REPLACEMENT_CHARACTER = "_";
85 private static final String REGEX_TITLE_FILENAME_PATTERN = "([^0-9a-zA-Z\\.\\-_])";
86
87 protected ProposalDevelopmentDocumentContract pdDoc = null;
88 private List<AuditError> auditErrors = new ArrayList<>();
89 private List<AttachmentData> attachments = new ArrayList<>();
90
91 private String beanName;
92
93 @Autowired
94 @Qualifier("narrativeService")
95 private NarrativeService narrativeService;
96
97 @Autowired
98 @Qualifier("propDevQuestionAnswerService")
99 private PropDevQuestionAnswerService propDevQuestionAnswerService;
100
101 @Autowired
102 @Qualifier("questionAnswerService")
103 private QuestionAnswerService questionAnswerService;
104
105 @Autowired
106 @Qualifier("sponsorHierarchyService")
107 private SponsorHierarchyService sponsorHierarchyService;
108
109 @Autowired
110 @Qualifier("formMappingService")
111 private FormMappingService formMappingService;
112
113
114
115
116
117 @Autowired
118 @Qualifier("GlobalLibraryV1_0Generator")
119 protected GlobalLibraryV1_0Generator globLibV10Generator;
120
121 @Autowired
122 @Qualifier("GlobalLibraryV2_0Generator")
123 protected GlobalLibraryV2_0Generator globLibV20Generator;
124
125
126
127
128
129
130
131
132
133 public List<AttachmentData> getAttachments() {
134 return attachments;
135 }
136
137
138
139
140
141
142
143 protected void addAttachment(AttachmentData attachment) {
144 attachments.add(attachment);
145 }
146
147
148
149
150
151
152
153
154
155 protected HashValue getHashValue(byte[] fileData) {
156 return createHashValue(computeAttachmentHash(fileData));
157 }
158
159
160
161
162 public String createContentId(NarrativeContract narrative) {
163 String retVal = "N-" + narrative.getModuleNumber();
164 if(narrative.getNarrativeType()!=null){
165 if (narrative.getNarrativeType().isAllowMultiple() &&
166 StringUtils.isNotBlank(narrative.getModuleTitle())) {
167 retVal += "_" + narrative.getModuleTitle().trim();
168 }else{
169 retVal += "_" + narrative.getNarrativeType().getDescription().trim();
170 }
171 }
172 int index = getIndexOfAttachmentAlreadyAdded(retVal);
173 if(index > 0){
174 retVal+=("-"+index);
175 }
176 return retVal;
177 }
178
179 private int getIndexOfAttachmentAlreadyAdded(String contentId) {
180 int index = 0;
181 List<AttachmentData> attachments = getAttachments();
182 for (AttachmentData attachmentData : attachments) {
183 String attContentId = attachmentData.getContentId();
184 int lastIndex = attContentId.indexOf('-',6);
185 if(lastIndex!=-1){
186 attContentId = attContentId.substring(0, attContentId.lastIndexOf('-'));
187 }
188 if(attContentId.equals(contentId)){
189 index++;
190 }
191 }
192 return index;
193 }
194
195 public String createContentId(ProposalPersonBiographyContract biography) {
196 String retVal = "B-" + biography.getProposalPersonNumber() + "_" + biography.getBiographyNumber();
197 if(biography.getPropPerDocType() != null)
198 retVal += "_" + biography.getPropPerDocType().getDescription().trim();
199 if (StringUtils.isNotBlank(biography.getDescription())) {
200 retVal += "_" + biography.getDescription().trim();
201 }
202 int index = getIndexOfAttachmentAlreadyAdded(retVal);
203 if(index > 0){
204 retVal+=index;
205 }
206 return retVal;
207 }
208
209
210
211
212
213
214
215
216
217
218
219 private synchronized static HashValue createHashValue(byte[] hashValueStr) {
220 HashValue hashValue = null;
221 hashValue = HashValue.Factory.newInstance();
222 hashValue.setHashAlgorithm(InfastructureConstants.HASH_ALGORITHM);
223 hashValue.setByteArrayValue(Base64.decode(hashValueStr));
224 return hashValue;
225 }
226
227
228
229
230
231
232
233
234 protected final static byte[] computeAttachmentHash(byte[] attachment) {
235 MessageDigest messageDigester;
236 try {
237 messageDigester = MessageDigest.getInstance(InfastructureConstants.HASH_ALGORITHM);
238 byte[] rawDigest = messageDigester.digest(attachment);
239 return Base64.encode(rawDigest);
240 }
241 catch (NoSuchAlgorithmException e) {
242 throw new RuntimeException(e);
243 }
244 }
245
246 protected AttachedFileDataType getAttachedFileType(NarrativeContract narrative) {
247 AttachedFileDataType attachedFileDataType = null;
248 byte[] attachementContent = null;
249 if(narrative.getNarrativeAttachment()!= null){
250 attachementContent = narrative.getNarrativeAttachment().getData();
251 }
252 if(attachementContent != null && attachementContent.length > 0 ){
253
254 FileLocation fileLocation = FileLocation.Factory.newInstance();
255 String contentId = createContentId(narrative);
256 fileLocation.setHref(contentId);
257
258 attachedFileDataType = AttachedFileDataType.Factory.newInstance();
259 attachedFileDataType.setFileLocation(fileLocation);
260 attachedFileDataType.setFileName(getS2sNarrativeFileName(narrative));
261 attachedFileDataType.setMimeType(InfastructureConstants.CONTENT_TYPE_OCTET_STREAM);
262 attachedFileDataType.setHashValue(getHashValue(attachementContent));
263 AttachmentData attachmentData = new AttachmentData();
264 attachmentData.setContent(attachementContent);
265 attachmentData.setContentId(contentId);
266 attachmentData.setContentType(InfastructureConstants.CONTENT_TYPE_OCTET_STREAM);
267 attachmentData.setFileName(getS2sNarrativeFileName(narrative));
268 addAttachment(attachmentData);
269 }
270 return attachedFileDataType;
271 }
272
273
274
275
276
277
278 protected AttachedFileDataType[] getAttachedFileDataTypes(String narrativeTypeCode) {
279
280 int size = 0;
281 for (NarrativeContract narrative : pdDoc.getDevelopmentProposal().getNarratives()) {
282 if (narrative.getNarrativeType() != null
283 && narrative.getNarrativeType().getCode().equals(narrativeTypeCode)) {
284 size++;
285 }
286 }
287 AttachedFileDataType[] attachedFileDataTypes = new AttachedFileDataType[size];
288 int attachments = 0;
289 for (NarrativeContract narrative : pdDoc.getDevelopmentProposal().getNarratives()) {
290 if (narrative.getNarrativeType() != null
291 && narrative.getNarrativeType().getCode().equals(narrativeTypeCode)) {
292 attachedFileDataTypes[attachments] = getAttachedFileType(narrative);
293 attachments++;
294 }
295 }
296 return attachedFileDataTypes;
297 }
298
299
300
301
302
303
304 protected AttachedFileDataType getAttachedFileDataType(String narrativeTypeCode) {
305
306 for (NarrativeContract narrative : pdDoc.getDevelopmentProposal().getNarratives()) {
307 if (narrative.getNarrativeType() != null
308 && narrative.getNarrativeType().getCode().equals(narrativeTypeCode)) {
309 return getAttachedFileType(narrative);
310 }
311 }
312 return null;
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326 protected AttachedFileDataType getPernonnelAttachments(ProposalDevelopmentDocumentContract pdDoc, String personId, Integer rolodexId,
327 String documentType) {
328 boolean personBiographyFound = false;
329 for (ProposalPersonBiographyContract proposalPersonBiography : pdDoc.getDevelopmentProposal().getPropPersonBios()) {
330 if (personId != null && proposalPersonBiography.getPersonId() != null
331 && proposalPersonBiography.getPersonId().equals(personId)
332 && documentType.equals(proposalPersonBiography.getPropPerDocType().getCode())) {
333 personBiographyFound = true;
334 }
335 else if (rolodexId != null && proposalPersonBiography.getRolodexId() != null
336 && proposalPersonBiography.getRolodexId().toString().equals(rolodexId.toString())
337 && proposalPersonBiography.getPropPerDocType() != null
338 && documentType.equals(proposalPersonBiography.getPropPerDocType().getCode())) {
339 personBiographyFound = true;
340 }
341 byte[] attachmentContent = null;
342 if(proposalPersonBiography.getPersonnelAttachment() != null){
343 attachmentContent = proposalPersonBiography.getPersonnelAttachment().getData();
344 }
345
346 if (personBiographyFound && attachmentContent != null && attachmentContent.length > 0) {
347 FileLocation fileLocation = FileLocation.Factory.newInstance();
348 String contentId = createContentId(proposalPersonBiography);
349 fileLocation.setHref(contentId);
350 AttachedFileDataType attachedFileDataType = AttachedFileDataType.Factory.newInstance();
351 attachedFileDataType.setFileLocation(fileLocation);
352 attachedFileDataType.setFileName(getS2sPersonnelAttachmentFileName(pdDoc.getDevelopmentProposal(),proposalPersonBiography));
353 attachedFileDataType.setMimeType(InfastructureConstants.CONTENT_TYPE_OCTET_STREAM);
354 attachedFileDataType.setHashValue(getHashValue(proposalPersonBiography.getPersonnelAttachment()
355 .getData()));
356 AttachmentData attachmentData = new AttachmentData();
357 attachmentData.setContent(proposalPersonBiography.getPersonnelAttachment().getData());
358 attachmentData.setContentId(contentId);
359 attachmentData.setContentType(InfastructureConstants.CONTENT_TYPE_OCTET_STREAM);
360 attachmentData.setFileName(getS2sPersonnelAttachmentFileName(pdDoc.getDevelopmentProposal(),proposalPersonBiography));
361 addAttachment(attachmentData);
362 return attachedFileDataType;
363 }
364 }
365 return null;
366 }
367
368 protected String getS2sNarrativeFileName(NarrativeContract narrative){
369 String fileName = null;
370 if (narrative.getNarrativeType().isAllowMultiple()) {
371 fileName = narrative.getModuleTitle();
372 } else {
373 fileName = narrative.getNarrativeType().getDescription();
374 }
375 String extension = StringUtils.substringAfter(narrative.getNarrativeAttachment().getName(),".");
376 return cleanFileName(fileName) + "." + extension;
377 }
378
379 protected String getS2sPersonnelAttachmentFileName(DevelopmentProposalContract developmentProposal, ProposalPersonBiographyContract biography) {
380
381 String extension = StringUtils.substringAfter(biography.getName(),".");
382 String fullName = getPerson(developmentProposal,biography.getProposalPersonNumber()).getFullName();
383 String docType = biography.getPropPerDocType().getDescription();
384 String fileName = fullName + "_" + docType;
385
386 return cleanFileName(fileName) + "." + extension;
387
388 }
389
390 protected String cleanFileName(String fileName) {
391 Pattern pattern = Pattern.compile(REGEX_TITLE_FILENAME_PATTERN);
392 Matcher matcher = pattern.matcher(fileName);
393 return matcher.replaceAll(REPLACEMENT_CHARACTER);
394 }
395
396 protected ProposalPersonContract getPerson(DevelopmentProposalContract developmentProposal, Integer proposalPersonNumber) {
397 for (ProposalPersonContract person : developmentProposal.getProposalPersons()) {
398 if (proposalPersonNumber.equals(person.getProposalPersonNumber())) {
399 return person;
400 }
401 }
402 return null;
403 }
404
405
406
407
408
409 public List<AuditError> getAuditErrors() {
410 return auditErrors;
411 }
412
413
414
415
416
417 public void setAuditErrors(List<AuditError> auditErrors) {
418 this.auditErrors = auditErrors;
419 }
420
421 protected boolean isSponsorNIH(ProposalDevelopmentDocumentContract document) {
422 return sponsorHierarchyService.isSponsorNihMultiplePi(document.getDevelopmentProposal().getSponsor().getSponsorCode());
423 }
424
425 protected NarrativeContract saveNarrative(byte[] attachment, String narrativeTypeCode,String fileName,String comment) {
426 return narrativeService.createSystemGeneratedNarrative(pdDoc.getDevelopmentProposal().getProposalNumber(), narrativeTypeCode, attachment, fileName, comment);
427 }
428
429
430
431
432
433 public void setAttachments(List<AttachmentData> attachments) {
434 this.attachments = attachments;
435 }
436
437
438
439
440
441 public void sortAttachments(ByteArrayInputStream byteArrayInputStream) {
442 List<String> attachmentNameList = new ArrayList<String> ();
443 List<AttachmentData> attacmentList = getAttachments();
444 List<AttachmentData> tempAttacmentList = new ArrayList<AttachmentData>();
445
446 try{
447 DocumentBuilderFactory domParserFactory = DocumentBuilderFactory.newInstance();
448 DocumentBuilder domParser = domParserFactory.newDocumentBuilder();
449 Document document = domParser.parse(byteArrayInputStream);
450 byteArrayInputStream.close();
451 NodeList fileLocationList = document.getElementsByTagName(NARRATIVE_ATTACHMENT_FILE_LOCATION);
452
453 for(int itemLocation=0;itemLocation<fileLocationList.getLength();itemLocation++){
454 String attachmentName =fileLocationList.item(itemLocation).getAttributes().item(0).getNodeValue();
455 String[] name = attachmentName.split(KEY_VALUE_SEPARATOR);
456 String fileName =name[name.length-1];
457 attachmentNameList.add(fileName);
458 }
459 }catch (Exception e) {
460 LOG.error(e.getMessage(), e);
461 }
462
463 for(String attachmentName :attachmentNameList){
464 for(AttachmentData attachment : attacmentList){
465 String[] names = attachment.getContentId().split(KEY_VALUE_SEPARATOR);
466 String fileName =names[names.length-1];
467 if(fileName.equalsIgnoreCase(attachmentName)){
468 tempAttacmentList.add(attachment);
469 }
470 }
471 }
472 if(tempAttacmentList.size() > 0){
473 attachments.clear();
474 for(AttachmentData tempAttachment :tempAttacmentList){
475 attachments.add(tempAttachment);
476 }
477 }
478 }
479
480
481
482
483
484
485
486
487
488
489
490 protected String getAnswer(Integer questionSeqId, List<? extends AnswerHeaderContract> answerHeaders) {
491 for(AnswerHeaderContract answerHeader:answerHeaders){
492 if(answerHeader!=null){
493 List<? extends AnswerContract> answerDetails = answerHeader.getAnswers();
494 for(AnswerContract answers:answerDetails){
495 if(questionSeqId.equals(getQuestionAnswerService().findQuestionById(answers.getQuestionId()).getQuestionSeqId())){
496 return answers.getAnswer();
497 }
498 }
499 }
500 }
501
502 return null;
503 }
504
505
506
507
508
509
510
511
512
513
514
515 protected Long getAnswerId(Integer questionSeqId, List<? extends AnswerHeaderContract> answerHeaders) {
516 if (answerHeaders != null && !answerHeaders.isEmpty()) {
517 for (AnswerHeaderContract answerHeader : answerHeaders) {
518 List<? extends AnswerContract> answerDetails = answerHeader.getAnswers();
519 for (AnswerContract answers : answerDetails) {
520 if (answers.getAnswer() != null && questionSeqId.equals(getQuestionAnswerService().findQuestionById(answers.getQuestionId()).getQuestionSeqId())) {
521 return answers.getId();
522 }
523 }
524 }
525 }
526 return null;
527 }
528
529
530
531
532
533
534
535
536
537
538
539 protected String getChildQuestionAnswer(Integer parentQuestionSeqId,Integer questionSeqId, List<? extends AnswerHeaderContract> answerHeaders) {
540 for(AnswerHeaderContract answerHeader:answerHeaders){
541 if(answerHeader!=null){
542 List<? extends AnswerContract> answerDetails = answerHeader.getAnswers();
543 for(AnswerContract answers:answerDetails){
544 if(answers.getParentAnswers()!= null){
545 AnswerContract parentAnswer = answers.getParentAnswers().get(0);
546 if(questionSeqId.equals(getQuestionAnswerService().findQuestionById(answers.getQuestionId()).getQuestionSeqId()) &&
547 parentQuestionSeqId.equals(getQuestionAnswerService().findQuestionById(parentAnswer.getQuestionId()).getQuestionSeqId()) ){
548 return answers.getAnswer();
549 }
550 }
551 }
552 }
553 }
554
555 return null;
556
557 }
558
559
560
561
562 protected String getAnswers(Integer questionSeqId, List<? extends AnswerHeaderContract> answerHeaders) {
563
564 String answer = null;
565 String childAnswer = null;
566 StringBuilder stringBuilder = new StringBuilder();
567 if (answerHeaders != null && !answerHeaders.isEmpty()) {
568 for (AnswerHeaderContract answerHeader : answerHeaders) {
569 List<? extends AnswerContract> answerDetails = answerHeader.getAnswers();
570 for (AnswerContract answers : answerDetails) {
571 if (questionSeqId.equals(getQuestionAnswerService().findQuestionById(answers.getQuestionId()).getQuestionSeqId())) {
572 answer = answers.getAnswer();
573 if (answer != null) {
574 if (!answer.equals(NOT_ANSWERED)) {
575 stringBuilder.append(answer);
576 stringBuilder.append(",");
577 }
578 }
579 childAnswer = stringBuilder.toString();
580 }
581 }
582 }
583 }
584 return childAnswer;
585 }
586
587 @Override
588 public void setBeanName(String beanName) {
589 this.beanName = beanName;
590 }
591
592 public abstract String getNamespace();
593
594 public String getGeneratorName() {
595 return beanName;
596 }
597
598 public abstract String getFormName();
599
600 public abstract Resource getStylesheet();
601
602 public abstract String getPackageName();
603
604 public abstract int getSortIndex();
605
606 public NarrativeService getNarrativeService() {
607 return narrativeService;
608 }
609
610 public PropDevQuestionAnswerService getPropDevQuestionAnswerService() {
611 return propDevQuestionAnswerService;
612 }
613
614 public QuestionAnswerService getQuestionAnswerService() {
615 return questionAnswerService;
616 }
617
618 public void setNarrativeService(NarrativeService narrativeService) {
619 this.narrativeService = narrativeService;
620 }
621
622 public void setPropDevQuestionAnswerService(PropDevQuestionAnswerService propDevQuestionAnswerService) {
623 this.propDevQuestionAnswerService = propDevQuestionAnswerService;
624 }
625
626 public void setQuestionAnswerService(QuestionAnswerService questionAnswerService) {
627 this.questionAnswerService = questionAnswerService;
628 }
629
630 public SponsorHierarchyService getSponsorHierarchyService() {
631 return sponsorHierarchyService;
632 }
633
634 public void setSponsorHierarchyService(SponsorHierarchyService sponsorHierarchyService) {
635 this.sponsorHierarchyService = sponsorHierarchyService;
636 }
637
638 public FormMappingService getFormMappingService() {
639 return formMappingService;
640 }
641
642 public void setFormMappingService(FormMappingService formMappingService) {
643 this.formMappingService = formMappingService;
644 }
645
646 public GlobalLibraryV1_0Generator getGlobLibV10Generator() {
647 return globLibV10Generator;
648 }
649
650 public void setGlobLibV10Generator(GlobalLibraryV1_0Generator globLibV10Generator) {
651 this.globLibV10Generator = globLibV10Generator;
652 }
653
654 public GlobalLibraryV2_0Generator getGlobLibV20Generator() {
655 return globLibV20Generator;
656 }
657
658 public void setGlobLibV20Generator(GlobalLibraryV2_0Generator globLibV20Generator) {
659 this.globLibV20Generator = globLibV20Generator;
660 }
661
662 @Override
663 public void afterPropertiesSet() throws Exception {
664 formMappingService.registerForm(new FormMappingInfo(getNamespace(), getGeneratorName(), getFormName(), getStylesheet().getURL().toString(), getSortIndex(), false));
665 }
666 }