From be8d7b3ed4a22debd8604aa0c0d45519b582453d Mon Sep 17 00:00:00 2001 From: mogoodrich Date: Tue, 7 Jan 2025 18:58:58 -0500 Subject: [PATCH] remove OpenMRS Formatter and re-format --- OpenMRSFormatter.xml | 278 ------------------ .../attachments/AttachmentsActivator.java | 47 +-- .../attachments/AttachmentsConstants.java | 122 ++++---- .../attachments/AttachmentsContext.java | 171 +++++------ .../attachments/AttachmentsService.java | 71 +++-- .../attachments/AttachmentsServiceImpl.java | 49 ++- .../module/attachments/ComplexObsSaver.java | 48 +-- .../attachments/VisitCompatibility.java | 4 +- .../attachments/VisitCompatibilityImpl.java | 4 +- .../obs/AbstractAttachmentHandler.java | 111 +++---- .../module/attachments/obs/Attachment.java | 74 ++--- .../obs/AttachmentComplexData.java | 19 +- .../obs/AttachmentComplexDataImpl.java | 27 +- .../attachments/obs/BaseComplexData.java | 31 +- .../attachments/obs/ComplexDataHelper.java | 8 +- .../obs/ComplexDataHelperImpl.java | 15 +- .../attachments/obs/ComplexViewHelper.java | 29 +- .../obs/ComplexViewHelperImpl.java | 4 +- .../obs/DefaultAttachmentHandler.java | 26 +- .../obs/ImageAttachmentHandler.java | 54 ++-- .../module/attachments/obs/ValueComplex.java | 50 ++-- .../attachments/AttachmentsContextTest.java | 26 +- .../obs/ImageAttachmentHandlerTest.java | 108 +++---- .../module/attachments/obs/TestHelper.java | 183 ++++++------ .../attachments/obs/ValueComplexTest.java | 27 +- .../rest/AttachmentBytesResource.java | 40 +-- .../attachments/rest/AttachmentResource.java | 228 +++++++------- .../rest/ObsByConceptListSearchHandler.java | 84 +++--- .../AttachmentResourceIntegrationTest.java | 16 +- .../rest/AttachmentResourceTest.java | 40 +-- .../rest/AttachmentRestControllerTest.java | 198 ++++++------- .../ObsByConceptListSearchHandlerTest.java | 78 ++--- 32 files changed, 1025 insertions(+), 1245 deletions(-) delete mode 100644 OpenMRSFormatter.xml diff --git a/OpenMRSFormatter.xml b/OpenMRSFormatter.xml deleted file mode 100644 index 6881eea3..00000000 --- a/OpenMRSFormatter.xml +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/src/main/java/org/openmrs/module/attachments/AttachmentsActivator.java b/api/src/main/java/org/openmrs/module/attachments/AttachmentsActivator.java index 9f296780..c7225ade 100644 --- a/api/src/main/java/org/openmrs/module/attachments/AttachmentsActivator.java +++ b/api/src/main/java/org/openmrs/module/attachments/AttachmentsActivator.java @@ -27,49 +27,50 @@ import org.springframework.stereotype.Component; /** - * This class contains the logic that is run every time this module is either started or stopped. + * This class contains the logic that is run every time this module is either + * started or stopped. */ @Component(AttachmentsConstants.COMPONENT_ATT_ACTIVATOR) public class AttachmentsActivator extends BaseModuleActivator { - + protected Log log = LogFactory.getLog(getClass()); - + /** * @see ModuleActivator${symbol_pound}willRefreshContext() */ public void willRefreshContext() { log.info("Refreshing " + AttachmentsConstants.MODULE_NAME + " Module"); } - + /** * @see ModuleActivator${symbol_pound}contextRefreshed() */ public void contextRefreshed() { log.info(AttachmentsConstants.MODULE_NAME + " Module refreshed"); } - + /** * @see ModuleActivator${symbol_pound}willStart() */ public void willStart() { log.info("Starting " + AttachmentsConstants.MODULE_NAME + " Module"); } - + /** * @see ModuleActivator${symbol_pound}started() */ public void started() { - + // Concepts Complex { final String name = AttachmentsConstants.MODULE_SHORT_ID + " DEFAULT ATTACHMENT"; final String desc = "Concept complex for 'default attachment' complex obs."; final String uuid = AttachmentsConstants.CONCEPT_DEFAULT_UUID; - + ConceptService conceptService = Context.getConceptService(); - + if (null == conceptService.getConceptByUuid(uuid)) { - + ConceptComplex conceptComplex = new ConceptComplex(); conceptComplex.setUuid(uuid); conceptComplex.setHandler(DefaultAttachmentHandler.class.getSimpleName()); @@ -79,7 +80,7 @@ public void started() { conceptComplex.setConceptClass(conceptService.getConceptClassByName("Question")); conceptComplex.setDatatype(conceptService.getConceptDatatypeByUuid(ConceptDatatype.COMPLEX_UUID)); conceptComplex.addDescription(new ConceptDescription(desc, Locale.ENGLISH)); - + conceptService.saveConcept(conceptComplex); } } @@ -87,11 +88,11 @@ public void started() { final String name = AttachmentsConstants.MODULE_SHORT_ID + " IMAGE ATTACHMENT"; final String desc = "Concept complex for 'image attachments with thumbnails' complex obs."; final String uuid = AttachmentsConstants.CONCEPT_IMAGE_UUID; - + ConceptService conceptService = Context.getConceptService(); - + if (null == conceptService.getConceptByUuid(uuid)) { - + ConceptComplex conceptComplex = new ConceptComplex(); conceptComplex.setUuid(uuid); conceptComplex.setHandler(ImageAttachmentHandler.class.getSimpleName()); @@ -101,43 +102,43 @@ public void started() { conceptComplex.setConceptClass(conceptService.getConceptClassByName("Question")); conceptComplex.setDatatype(conceptService.getConceptDatatypeByUuid(ConceptDatatype.COMPLEX_UUID)); conceptComplex.addDescription(new ConceptDescription(desc, Locale.ENGLISH)); - + conceptService.saveConcept(conceptComplex); } } - + // Encounter Type { final String name = "Attachment Upload"; final String desc = "Encounters used to record uploads of attachments."; final String uuid = AttachmentsConstants.ENCOUNTER_TYPE_UUID; // this is also the default GP value set in - // config.xml - + // config.xml + EncounterService es = Context.getEncounterService(); EncounterType encounterType = es.getEncounterTypeByUuid(uuid); - + if (encounterType == null) { encounterType = new EncounterType(name, desc); encounterType.setUuid(uuid); es.saveEncounterType(encounterType); } } - + log.info(AttachmentsConstants.MODULE_NAME + " Module started"); } - + /** * @see ModuleActivator${symbol_pound}willStop() */ public void willStop() { log.info("Stopping " + AttachmentsConstants.MODULE_NAME + " Module"); } - + /** * @see ModuleActivator${symbol_pound}stopped() */ public void stopped() { log.info(AttachmentsConstants.MODULE_NAME + " Module stopped"); } - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/AttachmentsConstants.java b/api/src/main/java/org/openmrs/module/attachments/AttachmentsConstants.java index 50449b8e..207232f1 100644 --- a/api/src/main/java/org/openmrs/module/attachments/AttachmentsConstants.java +++ b/api/src/main/java/org/openmrs/module/attachments/AttachmentsConstants.java @@ -10,135 +10,133 @@ package org.openmrs.module.attachments; public class AttachmentsConstants { - + public static enum ContentFamily { - IMAGE, - PDF, - OTHER + IMAGE, PDF, OTHER } - + /* * Module ids */ public static final String MODULE_NAME = "Attachments"; - + public static final String MODULE_ARTIFACT_ID = "attachments"; - + public static final String MODULE_SHORT_ID = "ATT"; - + public static final String MODULE_BASE_URL = "/" + MODULE_ARTIFACT_ID; - + public static final String ATTACHMENT_URI = "attachment"; - + public static final String UPLOAD_ATTACHMENT_URL = "/rest/v1/" + ATTACHMENT_URI; - + public static final String LEGACY_UPLOAD_ATTACHMENT_URL = MODULE_BASE_URL + "/upload"; - + public static final String DOWNLOAD_ATTACHMENT_URL = MODULE_BASE_URL + "/download"; - + public static final String ATTACHMENT_BYTES_URI = "/{uuid}/bytes"; - + /* * Spring components qualifiers */ public static final String COMPONENT_ATT_CONTEXT = MODULE_ARTIFACT_ID + ".AttachmentsContext"; - + public static final String COMPONENT_ATT_ACTIVATOR = MODULE_ARTIFACT_ID + ".AttachmentsActivator"; - + public static final String COMPONENT_COMPLEXDATA_HELPER = MODULE_ARTIFACT_ID + ".ComplexDataHelper"; - + public static final String COMPONENT_VISIT_COMPATIBILITY = MODULE_ARTIFACT_ID + ".VisitCompatibility"; - + public static final String COMPONENT_COMPLEXOBS_SAVER = MODULE_ARTIFACT_ID + ".ComplexObsSaver"; - + public static final String COMPONENT_COMPLEXVIEW_HELPER = MODULE_ARTIFACT_ID + ".ComplexViewHelper"; - + /* * Concepts (also used in global prop. in config.xml) */ public static final String CONCEPT_DEFAULT_UUID = "42ed45fd-f3f6-44b6-bfc2-8bde1bb41e00"; - + public static final String CONCEPT_IMAGE_UUID = "7cac8397-53cd-4f00-a6fe-028e8d743f8e"; - + public static final String ENCOUNTER_TYPE_UUID = "5021b1a1-e7f6-44b4-ba02-da2f2bcf8718"; - + /* * Docs config */ public static final String INSTRUCTIONS_PREFIX = "instructions"; - + public static final String UNKNOWN_MIME_TYPE = "application/octet-stream"; - + public static final String ATT_VIEW_ORIGINAL = "complexdata.view.original"; - + public static final String ATT_VIEW_THUMBNAIL = "complexdata.view.thumbnail"; - + public static final String ATT_VIEW_CRUD = ATT_VIEW_ORIGINAL; // Use this view for CRUD operations where a view must - // be provided. - + // be provided. + public static final String ATT_VIEW_RANDOM = "complexdata.view.random:m3k0m"; - + public static final String IMAGE_HANDLER_VIEW = "RAW_VIEW"; // Default/unique view handled by Core's ImageHandler - + public static final String BINARYDATA_HANDLER_VIEW = "RAW_VIEW"; // Default/unique view handled by Core's - // BinaryDataHandler - + // BinaryDataHandler + /* * Global properties */ public static final String GP_DEFAULT_CONCEPT_COMPLEX_UUID = MODULE_ARTIFACT_ID + ".defaultConceptComplexUuid"; - + public static final String GP_CONCEPT_COMPLEX_UUID_MAP = MODULE_ARTIFACT_ID + ".conceptComplexUuidMap"; // Map - // between - // content - // families - // and - // concept - // complex - // UUIDs - + // between + // content + // families + // and + // concept + // complex + // UUIDs + public static final String GP_CONCEPT_COMPLEX_UUID_LIST = MODULE_ARTIFACT_ID + ".conceptComplexUuidList"; // List of - // concepts - // complex - // UUIDs - // for - // listing/viewing. - + // concepts + // complex + // UUIDs + // for + // listing/viewing. + public static final String GP_ENCOUNTER_TYPE_UUID = MODULE_ARTIFACT_ID + ".encounterTypeUuid"; - + public static final String GP_ASSOCIATE_WITH_VISIT = MODULE_ARTIFACT_ID + ".associateWithVisit"; - + public static final String GP_MAX_UPLOAD_FILE_SIZE = MODULE_ARTIFACT_ID + ".maxUploadFileSize"; - + public static final String GP_MAX_STORAGE_FILE_SIZE = MODULE_ARTIFACT_ID + ".maxStorageFileSize"; - + public static final String GP_ALLOWED_FILE_EXTENSIONS = MODULE_ARTIFACT_ID + ".allowedFileExtensions"; - + public static final String GP_DENIED_FILE_NAMES = MODULE_ARTIFACT_ID + ".deniedFileNames"; - + public static final String GP_WEBCAM_ALLOWED = MODULE_ARTIFACT_ID + ".allowWebcam"; - + public static final String GP_ENCOUNTER_SAVING_FLOW = MODULE_ARTIFACT_ID + ".encounterSavingFlow"; - + public static final String GP_ALLOW_NO_CAPTION = MODULE_ARTIFACT_ID + ".allowNoCaption"; - + public static final String GP_DASHBOARD_THUMBNAIL_COUNT = MODULE_ARTIFACT_ID + ".dashboardThumbnailCount"; - + // Should always be the same as // RestConstants.MAX_RESULTS_DEFAULT_GLOBAL_PROPERTY_NAME public static final String GP_RESTWS_MAX_RESULTS_DEFAULT_GLOBAL_PROPERTY_NAME = "webservices.rest.maxResultsDefault"; - + /* * REST */ public static final String REPRESENTATION_OBS = "(uuid:ref,comment:ref,obsDatetime:ref)"; - + public static final String REPRESENTATION_VISIT = "(uuid:ref,stopDatetime:ref)"; - + /** * PRIVILEGES */ public static final String CREATE_ATTACHMENTS = "Create Attachments"; - + public static final String VIEW_ATTACHMENTS = "View Attachments"; } diff --git a/api/src/main/java/org/openmrs/module/attachments/AttachmentsContext.java b/api/src/main/java/org/openmrs/module/attachments/AttachmentsContext.java index 8b74628c..10e50dab 100644 --- a/api/src/main/java/org/openmrs/module/attachments/AttachmentsContext.java +++ b/api/src/main/java/org/openmrs/module/attachments/AttachmentsContext.java @@ -54,117 +54,117 @@ */ @Component(AttachmentsConstants.COMPONENT_ATT_CONTEXT) public class AttachmentsContext { - + protected final Log log = LogFactory.getLog(getClass()); - + @Autowired @Qualifier("obsService") protected ObsService obsService; - + @Autowired @Qualifier("locationService") protected LocationService locationService; - + @Autowired @Qualifier("conceptService") protected ConceptService conceptService; - + @Autowired @Qualifier("encounterService") protected EncounterService encounterService; - + @Autowired @Qualifier("visitService") protected VisitService visitService; - + @Autowired @Qualifier("patientService") protected PatientService patientService; - + @Autowired @Qualifier("providerService") protected ProviderService providerService; - + @Autowired @Qualifier("adminService") protected AdministrationService administrationService; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXDATA_HELPER) protected ComplexDataHelper complexDataHelper; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXVIEW_HELPER) protected ComplexViewHelper complexViewHelper; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_VISIT_COMPATIBILITY) protected VisitCompatibility visitCompatibility; - + /* * Exposing all needed services through OUR context */ - + public ConceptService getConceptService() { return conceptService; } - + public ObsService getObsService() { return obsService; } - + public VisitService getVisitService() { return visitService; } - + public ProviderService getProviderService() { return providerService; } - + public PatientService getPatientService() { return patientService; } - + public EncounterService getEncounterService() { return encounterService; } - + public LocationService getLocationService() { return locationService; } - + public ComplexDataHelper getComplexDataHelper() { return complexDataHelper; } - + public ComplexViewHelper getComplexViewHelper() { return complexViewHelper; } - + public AdministrationService getAdministrationService() { return administrationService; } - + public AttachmentsService getAttachmentsService() { return Context.getService(AttachmentsService.class); } - + public boolean doAllowEmptyCaption() { return this.getBooleanByGlobalProperty(AttachmentsConstants.GP_ALLOW_NO_CAPTION); } - + public boolean isOneEncounterPerVisit() { String flowStr = getAdministrationService().getGlobalProperty(AttachmentsConstants.GP_ENCOUNTER_SAVING_FLOW); return StringUtils.equalsIgnoreCase(flowStr, "unique"); } - + public Encounter getAttachmentEncounter(Patient patient, Visit visit, Provider provider) { Encounter encounter = new Encounter(); encounter.setVisit(visit); encounter.setEncounterType(getEncounterType()); encounter.setPatient(patient); encounter.setLocation(visit != null ? visit.getLocation() : null); - + boolean saveEncounter = true; if (visit != null && isOneEncounterPerVisit()) { List encounters = visitCompatibility.getNonVoidedEncounters(visit); @@ -189,7 +189,7 @@ public Encounter getAttachmentEncounter(Patient patient, Visit visit, Provider p } return encounter; } - + /* * @return An array of comma-separated values for the named global property */ @@ -197,7 +197,7 @@ protected String[] getCommaSeparatedGlobalPropertyValues(String globalPropertyNa String globalProperty = administrationService.getGlobalProperty(globalPropertyName); return StringUtils.isEmpty(globalProperty) ? new String[0] : globalProperty.split(","); } - + /* * See super#getIntegerByGlobalProperty(String globalPropertyName) */ @@ -205,13 +205,12 @@ protected Double getDoubleByGlobalProperty(String globalPropertyName) { String globalProperty = administrationService.getGlobalProperty(globalPropertyName); try { return Double.valueOf(globalProperty); - } - catch (Exception e) { + } catch (Exception e) { throw new APIException("Global property " + globalPropertyName + " with value " + globalProperty - + " is not parsable as a Double", e); + + " is not parsable as a Double", e); } } - + /* * See super#getIntegerByGlobalProperty(String globalPropertyName) */ @@ -219,7 +218,7 @@ protected Boolean getBooleanByGlobalProperty(String globalPropertyName) { String globalProperty = administrationService.getGlobalProperty(globalPropertyName); return BooleanUtils.toBoolean(globalProperty); } - + protected Concept getConceptByGlobalProperty(String globalPropertyName) { String globalProperty = administrationService.getGlobalProperty(globalPropertyName); Concept concept = conceptService.getConceptByUuid(globalProperty); @@ -228,7 +227,7 @@ protected Concept getConceptByGlobalProperty(String globalPropertyName) { } return concept; } - + protected EncounterType getEncounterTypeByGlobalProperty(String globalPropertyName, boolean required) { String globalProperty = administrationService.getGlobalProperty(globalPropertyName); EncounterType encounterType = encounterService.getEncounterTypeByUuid(globalProperty); @@ -237,18 +236,17 @@ protected EncounterType getEncounterTypeByGlobalProperty(String globalPropertyNa } return encounterType; } - + protected int getIntegerByGlobalProperty(String globalPropertyName) { String globalProperty = getGlobalProperty(globalPropertyName, true); try { return Integer.parseInt(globalProperty); - } - catch (Exception e) { + } catch (Exception e) { throw new APIException("Global property " + globalPropertyName + " with value " + globalProperty - + " is not parsable as an Integer", e); + + " is not parsable as an Integer", e); } } - + protected String getGlobalProperty(String globalPropertyName, boolean required) { String globalProperty = administrationService.getGlobalProperty(globalPropertyName); if (required && StringUtils.isEmpty(globalProperty)) { @@ -256,7 +254,7 @@ protected String getGlobalProperty(String globalPropertyName, boolean required) } return globalProperty; } - + /** * @return The default concept complex used to save uploaded documents. */ @@ -269,30 +267,32 @@ public ConceptComplex getDefaultConceptComplex() { } return conceptComplex; } - + /** - * Returns a simple String-String map from its JSON representation saved as a global property. + * Returns a simple String-String map from its JSON representation saved as a + * global property. */ protected Map getMapByGlobalProperty(String globalPropertyName) { - Map map = Collections. emptyMap(); + Map map = Collections.emptyMap(); String globalProperty = administrationService.getGlobalProperty(globalPropertyName); - + ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - TypeReference> typeRef = new TypeReference>() {}; + TypeReference> typeRef = new TypeReference>() { + }; try { map = mapper.readValue(globalProperty, typeRef); - } - catch (Exception e) { + } catch (Exception e) { log.error("Could not parse global property '" + globalPropertyName + "' into a Map.", e); } return map; } - + /** - * @param contentFamily The content family ('IMAGE', 'PDF', 'OTHER', ... etc). - * @return The concept complex configured to save files belonging to the content family, and if none - * is found the default concept complex is returned. + * @param contentFamily + * The content family ('IMAGE', 'PDF', 'OTHER', ... etc). + * @return The concept complex configured to save files belonging to the content + * family, and if none is found the default concept complex is returned. */ public ConceptComplex getConceptComplex(ContentFamily contentFamily) { Map map = getMapByGlobalProperty(AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_MAP); @@ -302,68 +302,70 @@ public ConceptComplex getConceptComplex(ContentFamily contentFamily) { } return getDefaultConceptComplex(); } - + public List getConceptComplexList() { - List list = Collections. emptyList(); + List list = Collections.emptyList(); final String globalPropertyName = AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_LIST; String globalProperty = administrationService.getGlobalProperty(globalPropertyName); - + ObjectMapper mapper = new ObjectMapper(); - TypeReference> typeRef = new TypeReference>() {}; + TypeReference> typeRef = new TypeReference>() { + }; try { list = mapper.readValue(StringEscapeUtils.unescapeHtml(globalProperty), typeRef); - } - catch (Exception e) { + } catch (Exception e) { log.error("Could not parse global property '" + globalPropertyName + "' into a List.", e); } return list; } - + /** * @return The encounter type for encounters recording the upload of an image. */ public EncounterType getEncounterType() { - EncounterType encounterType = getEncounterTypeByGlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, false); + EncounterType encounterType = getEncounterTypeByGlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, + false); return encounterType; } - + public Boolean associateWithVisit() { - String associateWithVisitGP = administrationService.getGlobalProperty(AttachmentsConstants.GP_ASSOCIATE_WITH_VISIT); + String associateWithVisitGP = administrationService + .getGlobalProperty(AttachmentsConstants.GP_ASSOCIATE_WITH_VISIT); return associateWithVisitGP != null ? Boolean.valueOf(associateWithVisitGP) : true; } - + /** * @return The max file size allowed to be uploaded (in Megabytes). */ public Double getMaxUploadFileSize() { return getDoubleByGlobalProperty(AttachmentsConstants.GP_MAX_UPLOAD_FILE_SIZE); } - + /** * @return The allowed file extensions. */ public String[] getAllowedFileExtensions() { return getCommaSeparatedGlobalPropertyValues(AttachmentsConstants.GP_ALLOWED_FILE_EXTENSIONS); } - + /** * @return The denied file names. */ public String[] getDeniedFileNames() { return getCommaSeparatedGlobalPropertyValues(AttachmentsConstants.GP_DENIED_FILE_NAMES); } - + /** * @return The max file size allowed to be stored (in Megabytes). */ public Double getMaxStorageFileSize() { return getDoubleByGlobalProperty(AttachmentsConstants.GP_MAX_STORAGE_FILE_SIZE); } - + public boolean isWebcamAllowed() { return getBooleanByGlobalProperty(AttachmentsConstants.GP_WEBCAM_ALLOWED); } - + public double getMaxCompressionRatio() { double maxStorageSize = getMaxStorageFileSize(); double maxUploadSize = getMaxUploadFileSize(); @@ -372,25 +374,26 @@ public double getMaxCompressionRatio() { else return 1; } - + public Integer getDashboardThumbnailCount() { return getIntegerByGlobalProperty(AttachmentsConstants.GP_DASHBOARD_THUMBNAIL_COUNT); } - + public Integer getMaxRestResultsCount() { return getIntegerByGlobalProperty(AttachmentsConstants.GP_RESTWS_MAX_RESULTS_DEFAULT_GLOBAL_PROPERTY_NAME); } - + // TODO: Figure out if this is good enough public EncounterRole getEncounterRole() { - EncounterRole unknownRole = getEncounterService().getEncounterRoleByUuid(EncounterRole.UNKNOWN_ENCOUNTER_ROLE_UUID); + EncounterRole unknownRole = getEncounterService() + .getEncounterRoleByUuid(EncounterRole.UNKNOWN_ENCOUNTER_ROLE_UUID); if (unknownRole == null) { throw new APIException( - "No 'Unknown' encounter role with uuid " + EncounterRole.UNKNOWN_ENCOUNTER_ROLE_UUID + "."); + "No 'Unknown' encounter role with uuid " + EncounterRole.UNKNOWN_ENCOUNTER_ROLE_UUID + "."); } return unknownRole; } - + public static String getExtension(String mimeType) { String ext = "bin"; if (mimeTypes.containsKey(mimeType)) { @@ -398,14 +401,15 @@ public static String getExtension(String mimeType) { } return ext; } - + /** - * @return The 'view' that should be affected when performing CRUD operation on complex obs. + * @return The 'view' that should be affected when performing CRUD operation on + * complex obs. */ public String getCRUDDocumentView() { return AttachmentsConstants.ATT_VIEW_ORIGINAL; } - + public static double getCompressionRatio(double fileByteSize, double maxByteSize) { double compressionRatio = 1; if (fileByteSize > 0) { @@ -413,9 +417,10 @@ public static double getCompressionRatio(double fileByteSize, double maxByteSize } return compressionRatio; } - + /** - * @param mimeType The MIME type of the uploaded content. + * @param mimeType + * The MIME type of the uploaded content. * @return The type/family of uploaded content based on the MIME type. */ public static ContentFamily getContentFamily(String mimeType) { @@ -428,7 +433,7 @@ public static ContentFamily getContentFamily(String mimeType) { } return contentFamily; } - + public static Map getContentFamilyMap() { Map map = new HashMap(); for (String mimeType : mimeTypes.keySet()) { @@ -436,11 +441,11 @@ public static Map getContentFamilyMap() { } return map; } - + public static boolean isMimeTypeHandled(String mimeType) { return mimeTypes.containsKey(mimeType); } - + private static final Map mimeTypes; static { mimeTypes = new HashMap(); diff --git a/api/src/main/java/org/openmrs/module/attachments/AttachmentsService.java b/api/src/main/java/org/openmrs/module/attachments/AttachmentsService.java index 76ea7551..35190d31 100644 --- a/api/src/main/java/org/openmrs/module/attachments/AttachmentsService.java +++ b/api/src/main/java/org/openmrs/module/attachments/AttachmentsService.java @@ -11,62 +11,77 @@ import org.openmrs.module.attachments.AttachmentsConstants; public interface AttachmentsService { - + /** - * Get a patient's attachments including attachments that are not associated with any visits or - * encounters. + * Get a patient's attachments including attachments that are not associated + * with any visits or encounters. * - * @param includeVoided Specifies whether the underlying complex obs that are fetched should include - * voided ones or not. - * @throws APIException if non-complex obs are mistakenly returned + * @param includeVoided + * Specifies whether the underlying complex obs that are fetched + * should include voided ones or not. + * @throws APIException + * if non-complex obs are mistakenly returned */ @Authorized(AttachmentsConstants.VIEW_ATTACHMENTS) List getAttachments(Patient patient, boolean includeVoided); - + /** * Get a patient's attachments. * - * @param includeVoided Specifies whether the underlying complex obs that are fetched should include - * voided ones or not. - * @param includeEncounterless Specifies whether the underlying attachments that are fetched should - * include attachments that are not associated with any visits or encounters. - * @throws APIException if non-complex obs are mistakenly returned + * @param includeVoided + * Specifies whether the underlying complex obs that are fetched + * should include voided ones or not. + * @param includeEncounterless + * Specifies whether the underlying attachments that are fetched + * should include attachments that are not associated with any visits + * or encounters. + * @throws APIException + * if non-complex obs are mistakenly returned */ @Authorized(AttachmentsConstants.VIEW_ATTACHMENTS) List getAttachments(Patient patient, boolean includeEncounterless, boolean includeVoided); - + /** - * Get a patient's attachments that are not associated with any visits or encounters. + * Get a patient's attachments that are not associated with any visits or + * encounters. * - * @param includeVoided Specifies whether the underlying complex obs that are fetched should include - * voided ones or not. - * @throws APIException if non-complex obs are mistakenly returned + * @param includeVoided + * Specifies whether the underlying complex obs that are fetched + * should include voided ones or not. + * @throws APIException + * if non-complex obs are mistakenly returned */ @Authorized(AttachmentsConstants.VIEW_ATTACHMENTS) List getEncounterlessAttachments(Patient patient, boolean includeVoided); - + /** * Get a patient's attachments that are associated with a specified encounter. * - * @param encounter the encounter which attachment to get - * @param includeVoided Specifies whether the underlying complex obs that are fetched should include - * voided ones or not. - * @throws APIException if non-complex obs are mistakenly returned + * @param encounter + * the encounter which attachment to get + * @param includeVoided + * Specifies whether the underlying complex obs that are fetched + * should include voided ones or not. + * @throws APIException + * if non-complex obs are mistakenly returned */ @Authorized(AttachmentsConstants.VIEW_ATTACHMENTS) List getAttachments(Patient patient, Encounter encounter, boolean includeVoided); - + /** * Get a patient's attachments that are associated with a specified visit. * - * @param visit the visit which attachments to get - * @param includeVoided Specifies whether the underlying complex obs that are fetched should include - * voided ones or not. - * @throws APIException if non-complex obs are mistakenly returned + * @param visit + * the visit which attachments to get + * @param includeVoided + * Specifies whether the underlying complex obs that are fetched + * should include voided ones or not. + * @throws APIException + * if non-complex obs are mistakenly returned */ @Authorized(AttachmentsConstants.VIEW_ATTACHMENTS) List getAttachments(Patient patient, Visit visit, boolean includeVoided); - + @Authorized(AttachmentsConstants.CREATE_ATTACHMENTS) Attachment save(Attachment attachment, String reason); } diff --git a/api/src/main/java/org/openmrs/module/attachments/AttachmentsServiceImpl.java b/api/src/main/java/org/openmrs/module/attachments/AttachmentsServiceImpl.java index fda1f989..5040e9be 100644 --- a/api/src/main/java/org/openmrs/module/attachments/AttachmentsServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/attachments/AttachmentsServiceImpl.java @@ -21,24 +21,24 @@ @Transactional(readOnly = true) public class AttachmentsServiceImpl implements AttachmentsService { - + private final Log log = LogFactory.getLog(getClass()); - + protected final static String NON_COMPLEX_OBS_ERR = "A non-complex obs was returned while fetching attachments, are the concepts complex configured properly?"; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_ATT_CONTEXT) private AttachmentsContext ctx; - + @Override public List getAttachments(Patient patient, boolean includeEncounterless, boolean includeVoided) { List persons = new ArrayList<>(); List questionConcepts = getAttachmentConcepts(); persons.add(patient); - + List obsList = ctx.getObsService().getObservations(persons, null, questionConcepts, null, null, null, null, - null, null, null, null, includeVoided); - + null, null, null, null, includeVoided); + List attachments = new ArrayList<>(); for (Obs obs : obsList) { if (!obs.isComplex()) { @@ -52,21 +52,21 @@ public List getAttachments(Patient patient, boolean includeEncounter } return attachments; } - + @Override public List getAttachments(Patient patient, boolean includeVoided) { return getAttachments(patient, true, includeVoided); } - + @Override public List getEncounterlessAttachments(Patient patient, boolean includeVoided) { List persons = new ArrayList<>(); List questionConcepts = getAttachmentConcepts(); persons.add(patient); - + List obsList = ctx.getObsService().getObservations(persons, null, questionConcepts, null, null, null, null, - null, null, null, null, includeVoided); - + null, null, null, null, includeVoided); + List attachments = new ArrayList<>(); for (Obs obs : obsList) { if (!obs.isComplex()) { @@ -79,7 +79,7 @@ public List getEncounterlessAttachments(Patient patient, boolean inc } return attachments; } - + @Override public List getAttachments(Patient patient, Encounter encounter, boolean includeVoided) { List persons = new ArrayList<>(); @@ -87,10 +87,10 @@ public List getAttachments(Patient patient, Encounter encounter, boo List questionConcepts = getAttachmentConcepts(); persons.add(patient); encounters.add(encounter); - + List obsList = ctx.getObsService().getObservations(persons, encounters, questionConcepts, null, null, null, - null, null, null, null, null, includeVoided); - + null, null, null, null, null, includeVoided); + List attachments = new ArrayList<>(); for (Obs obs : obsList) { if (!obs.isComplex()) { @@ -101,21 +101,21 @@ public List getAttachments(Patient patient, Encounter encounter, boo } return attachments; } - + @Override public List getAttachments(Patient patient, final Visit visit, boolean includeVoided) { List visits = new ArrayList<>(); visits.add(visit); - List encounters = ctx.getEncounterService().getEncounters(patient, null, null, null, null, null, null, - null, visits, includeVoided); - + List encounters = ctx.getEncounterService().getEncounters(patient, null, null, null, null, null, + null, null, visits, includeVoided); + List attachments = new ArrayList<>(); for (Encounter encounter : encounters) { attachments.addAll(getAttachments(patient, encounter, includeVoided)); } return attachments; } - + // Get list of attachment complex concepts protected List getAttachmentConcepts() { List conceptsComplex = ctx.getConceptComplexList(); @@ -133,7 +133,7 @@ protected List getAttachmentConcepts() { } return questionConcepts; } - + @Transactional @Override public Attachment save(Attachment delegate, String reason) { @@ -142,13 +142,12 @@ public Attachment save(Attachment delegate, String reason) { try { obs = Context.getObsService().saveObs(delegate.getObs(), reason); attachment = new Attachment(obs); - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException("Failed to save the complex obs: " + obs, e); } return attachment; } - + private Obs getComplexObs(Obs obs) { if (obs.getComplexData() != null) { return obs; diff --git a/api/src/main/java/org/openmrs/module/attachments/ComplexObsSaver.java b/api/src/main/java/org/openmrs/module/attachments/ComplexObsSaver.java index a7c11de4..d7f966b2 100644 --- a/api/src/main/java/org/openmrs/module/attachments/ComplexObsSaver.java +++ b/api/src/main/java/org/openmrs/module/attachments/ComplexObsSaver.java @@ -33,62 +33,64 @@ @Component(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER) public class ComplexObsSaver { - + protected final Log log = LogFactory.getLog(getClass()); - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_ATT_CONTEXT) protected AttachmentsContext context; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXDATA_HELPER) protected ComplexDataHelper complexDataHelper; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_VISIT_COMPATIBILITY) protected VisitCompatibility visitCompatibility; - + protected Obs obs = new Obs(); - + protected ConceptComplex conceptComplex; - + public Obs getObs() { return obs; } - + protected void prepareComplexObs(Visit visit, Person person, Encounter encounter, String fileCaption) { obs = new Obs(person, conceptComplex, - visit == null || visit.getStopDatetime() == null ? new Date() : visit.getStopDatetime(), - encounter != null ? encounter.getLocation() : null); + visit == null || visit.getStopDatetime() == null ? new Date() : visit.getStopDatetime(), + encounter != null ? encounter.getLocation() : null); obs.setEncounter(encounter); // may be null obs.setComment(fileCaption); } - + public Obs saveImageAttachment(Visit visit, Person person, Encounter encounter, String fileCaption, - MultipartFile multipartFile, String instructions) throws IOException { - + MultipartFile multipartFile, String instructions) throws IOException { + conceptComplex = context.getConceptComplex(ContentFamily.IMAGE); prepareComplexObs(visit, person, encounter, fileCaption); - + Object image = multipartFile.getInputStream(); - double compressionRatio = getCompressionRatio(multipartFile.getSize(), 1000000 * context.getMaxStorageFileSize()); + double compressionRatio = getCompressionRatio(multipartFile.getSize(), + 1000000 * context.getMaxStorageFileSize()); if (compressionRatio < 1) { - image = Thumbnails.of(ImageIO.read(multipartFile.getInputStream())).scale(compressionRatio).asBufferedImage(); + image = Thumbnails.of(ImageIO.read(multipartFile.getInputStream())).scale(compressionRatio) + .asBufferedImage(); } - obs.setComplexData( - complexDataHelper.build(instructions, multipartFile.getOriginalFilename(), image, multipartFile.getContentType()) - .asComplexData()); + obs.setComplexData(complexDataHelper + .build(instructions, multipartFile.getOriginalFilename(), image, multipartFile.getContentType()) + .asComplexData()); obs = context.getObsService().saveObs(obs, getClass().toString()); return obs; } - + public Obs saveOtherAttachment(Visit visit, Person person, Encounter encounter, String fileCaption, - MultipartFile multipartFile, String instructions) throws IOException { + MultipartFile multipartFile, String instructions) throws IOException { conceptComplex = context.getConceptComplex(ContentFamily.OTHER); prepareComplexObs(visit, person, encounter, fileCaption); - + obs.setComplexData(complexDataHelper.build(instructions, multipartFile.getOriginalFilename(), - multipartFile.getBytes(), multipartFile.getContentType()).asComplexData()); + multipartFile.getBytes(), multipartFile.getContentType()).asComplexData()); obs = context.getObsService().saveObs(obs, getClass().toString()); return obs; } diff --git a/api/src/main/java/org/openmrs/module/attachments/VisitCompatibility.java b/api/src/main/java/org/openmrs/module/attachments/VisitCompatibility.java index 406c2186..5b5ddd6e 100644 --- a/api/src/main/java/org/openmrs/module/attachments/VisitCompatibility.java +++ b/api/src/main/java/org/openmrs/module/attachments/VisitCompatibility.java @@ -6,7 +6,7 @@ import org.openmrs.Visit; public interface VisitCompatibility { - + public List getNonVoidedEncounters(Visit visit); - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/VisitCompatibilityImpl.java b/api/src/main/java/org/openmrs/module/attachments/VisitCompatibilityImpl.java index 192aa515..8a8bd6bd 100644 --- a/api/src/main/java/org/openmrs/module/attachments/VisitCompatibilityImpl.java +++ b/api/src/main/java/org/openmrs/module/attachments/VisitCompatibilityImpl.java @@ -12,7 +12,7 @@ @Component(AttachmentsConstants.COMPONENT_VISIT_COMPATIBILITY) @OpenmrsProfile(openmrsPlatformVersion = "2.2.* - 9.*") public class VisitCompatibilityImpl implements VisitCompatibility { - + @Override public List getNonVoidedEncounters(Visit visit) { List nonVoidedEncounters = new ArrayList(); @@ -26,5 +26,5 @@ public List getNonVoidedEncounters(Visit visit) { } return nonVoidedEncounters; } - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/AbstractAttachmentHandler.java b/api/src/main/java/org/openmrs/module/attachments/obs/AbstractAttachmentHandler.java index c5c4b9b7..fed77d4e 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/AbstractAttachmentHandler.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/AbstractAttachmentHandler.java @@ -24,82 +24,82 @@ import net.coobird.thumbnailator.Thumbnails; /** - * Double inheritance class. The actual implementation parent must be set through - * {@link #setParentComplexObsHandler()}. + * Double inheritance class. The actual implementation parent must be set + * through {@link #setParentComplexObsHandler()}. */ public abstract class AbstractAttachmentHandler implements ComplexObsHandler { - - private static final String[] supportedViews = { ATT_VIEW_ORIGINAL, ATT_VIEW_THUMBNAIL }; - + + private static final String[] supportedViews = {ATT_VIEW_ORIGINAL, ATT_VIEW_THUMBNAIL}; + public final static String NO_THUMBNAIL_SUFFIX = "___nothumb__"; - + public final static String THUMBNAIL_SUFFIX = "_thumb"; - + protected final Log log = LogFactory.getLog(getClass()); - + private ComplexObsHandler parent; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXDATA_HELPER) private ComplexDataHelper complexDataHelper; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXVIEW_HELPER) private ComplexViewHelper complexViewHelper; - + public void setComplexViewHelper(ComplexViewHelper complexViewHelper) { this.complexViewHelper = complexViewHelper; } - + public AbstractAttachmentHandler() { super(); setParentComplexObsHandler(); } - + protected ComplexDataHelper getComplexDataHelper() { return complexDataHelper; } - + /* * To set the "real" implementation parent. */ abstract protected void setParentComplexObsHandler(); - + /* * Complex data CRUD - Read */ abstract protected ComplexData readComplexData(Obs obs, ValueComplex valueComplex, String view); - + /* * Complex data CRUD - Delete */ abstract protected boolean deleteComplexData(Obs obs, AttachmentComplexData complexData); - + /* * Complex data CRUD - Save (Update) */ abstract protected ValueComplex saveComplexData(Obs obs, AttachmentComplexData complexData); - + public String[] getSupportedViews() { return supportedViews; } - + public boolean supportsView(String view) { return Arrays.asList(getSupportedViews()).contains(view); } - + protected void setParent(ComplexObsHandler complexObsHandler) { this.parent = complexObsHandler; } - + final protected ComplexObsHandler getParent() { return parent; } - + public static boolean isThumbnail(String fileName) { return StringUtils.endsWith(FilenameUtils.removeExtension(fileName), NO_THUMBNAIL_SUFFIX); } - + /* * Appends NO_THUMBNAIL_SUFFIX the file */ @@ -108,34 +108,38 @@ protected static String buildNoThumbnailFileFileName(String fileName) { return fileName; } else { return FilenameUtils.removeExtension(fileName) + NO_THUMBNAIL_SUFFIX + "." - + FilenameUtils.getExtension(fileName); + + FilenameUtils.getExtension(fileName); } } - + /* * Appends THUMBNAIL_SUFFIX the file */ public static String buildThumbnailFileName(String fileName) { return FilenameUtils.removeExtension(fileName) + "_thumb" + "." + FilenameUtils.getExtension(fileName); } - + /** *

- * The saveThumbnailOrRename method checks image dimension to see if the image is small enough to be - * its own thumbnail. If so, it will rename the image file by appending the - * NO_THUMBNAIL_SUFFIX to the file. Otherwise, it will create a small thumbnail file - * alongside the original file to be used as thumbnail image. + * The saveThumbnailOrRename method checks image dimension to see if the image + * is small enough to be its own thumbnail. If so, it will rename the image file + * by appending the NO_THUMBNAIL_SUFFIX to the file. Otherwise, it will + * create a small thumbnail file alongside the original file to be used as + * thumbnail image. *

* - * @param savedFile original file pointer - * @param imageHight image height - * @param imageWidth image width + * @param savedFile + * original file pointer + * @param imageHight + * image height + * @param imageWidth + * image width * @return savedFileName new renamed file name or original file name */ public static String saveThumbnailOrRename(File savedFile, int imageHeight, int imageWidth) { - + String savedFileName = savedFile.getName(); - + if ((imageHeight <= THUMBNAIL_MAX_HEIGHT) && (imageWidth <= THUMBNAIL_MAX_WIDTH)) { String newSavedFileName = buildNoThumbnailFileFileName(savedFile.getAbsolutePath()); File newSavedFile = new File(newSavedFileName); @@ -146,62 +150,61 @@ public static String saveThumbnailOrRename(File savedFile, int imageHeight, int String thumbnailFileName = buildThumbnailFileName(savedFileName); try { Thumbnails.of(savedFile.getAbsolutePath()).size(THUMBNAIL_MAX_HEIGHT, THUMBNAIL_MAX_WIDTH) - .toFile(new File(dir, thumbnailFileName)); - } - catch (IOException e) { + .toFile(new File(dir, thumbnailFileName)); + } catch (IOException e) { throw new APIException("A thumbnail file could not be saved for obs with", e); } } - + return savedFileName; } - + public AttachmentComplexData getAttachmentComplexData(ComplexData complexData) { - + if (!(complexData instanceof AttachmentComplexData)) { - return complexDataHelper.build(ValueComplex.INSTRUCTIONS_DEFAULT, complexData.getTitle(), complexData.getData(), - complexDataHelper.getContentType(complexData)); + return complexDataHelper.build(ValueComplex.INSTRUCTIONS_DEFAULT, complexData.getTitle(), + complexData.getData(), complexDataHelper.getContentType(complexData)); } - + return (AttachmentComplexData) complexData; } - + /* * Drifts to our own CRUD overloadable routine when it is our implementation. */ @Override final public Obs getObs(Obs obs, String view) { - + ValueComplex valueComplex = new ValueComplex(obs.getValueComplex()); - + if (StringUtils.isEmpty(view)) { view = AttachmentsConstants.ATT_VIEW_ORIGINAL; } - + ComplexData attData = readComplexData(obs, valueComplex, view); obs.setComplexData(attData); return obs; } - + /* * Drifts to our own CRUD overloadable routine when it is our implementation. */ @Override final public boolean purgeComplexData(Obs obs) { - + AttachmentComplexData complexData = getAttachmentComplexData(obs.getComplexData()); - + return deleteComplexData(obs, complexData); } - + /* * Drifts to our own CRUD overloadable routine when it is our implementation. */ @Override final public Obs saveObs(Obs obs) { - + AttachmentComplexData complexData = getAttachmentComplexData(obs.getComplexData()); - + ValueComplex valueComplex = saveComplexData(obs, complexData); obs.setValueComplex(valueComplex.getValueComplex()); return obs; diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/Attachment.java b/api/src/main/java/org/openmrs/module/attachments/obs/Attachment.java index 29213c74..8a03de37 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/Attachment.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/Attachment.java @@ -10,37 +10,39 @@ import org.openmrs.obs.ComplexData; /** - * Attachment represents all the parts of a complex obs that make an "attachment". + * Attachment represents all the parts of a complex obs that make an + * "attachment". * * @author Mekom Solutions */ public class Attachment extends BaseOpenmrsData implements java.io.Serializable { - + private static final long serialVersionUID = -3552798988737497690L; - + protected Integer id = null; - + protected Date dateTime = null; - + protected String comment = ""; - + protected String filename = ""; - + protected String bytesMimeType = null; - + protected ContentFamily bytesContentFamily = null; - + protected ComplexData complexData = null; - + public Attachment() { } - + /** - * @param obs A complex obs + * @param obs + * A complex obs */ public Attachment(Obs obs) { super(); - + setUuid(obs.getUuid()); setId(obs.getId()); setCreator(obs.getCreator()); @@ -50,10 +52,10 @@ public Attachment(Obs obs) { setVoided(obs.getVoided()); setVoidedBy(obs.getVoidedBy()); setVoidReason(obs.getVoidReason()); - + setDateTime(obs.getObsDatetime()); setComment(obs.getComment()); - + // Chomp the UUID off the end of the obs if any String filename = new ValueComplex(obs.getValueComplex()).getFileName(); if (filename != null) { @@ -67,21 +69,23 @@ public Attachment(Obs obs) { filename = filename.substring(0, uuidIdx) + extension; } } - + setFilename(filename); setComplexData(obs.getComplexData()); } - + /** - * @param obs A complex obs + * @param obs + * A complex obs */ public Attachment(Obs obs, ComplexDataHelper complexDataHelper) { this(obs); - + setBytesMimeType(complexDataHelper.getContentType(obs.getComplexData())); - setBytesContentFamily(AttachmentsContext.getContentFamily(complexDataHelper.getContentType(obs.getComplexData()))); + setBytesContentFamily( + AttachmentsContext.getContentFamily(complexDataHelper.getContentType(obs.getComplexData()))); } - + public Obs getObs() { Obs obs = Context.getObsService().getObsByUuid(getUuid()); if (obs == null) { @@ -101,61 +105,61 @@ public Obs getObs() { obs.setComplexData(getComplexData()); return obs; } - + @Override public Integer getId() { return id; } - + @Override public void setId(Integer id) { this.id = id; } - + public Date getDateTime() { return dateTime; } - + public void setDateTime(Date dateTime) { this.dateTime = dateTime; } - + public String getComment() { return comment; } - + public void setComment(String comment) { this.comment = comment; } - + public String getFilename() { return filename; } - + public void setFilename(String filename) { this.filename = filename; } - + public ComplexData getComplexData() { return complexData; } - + public void setComplexData(ComplexData complexData) { this.complexData = complexData; } - + public void setBytesMimeType(String bytesMimeType) { this.bytesMimeType = bytesMimeType; } - + public String getBytesMimeType() { return bytesMimeType; } - + public ContentFamily getBytesContentFamily() { return bytesContentFamily; } - + public void setBytesContentFamily(ContentFamily bytesContentFamily) { this.bytesContentFamily = bytesContentFamily; } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexData.java b/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexData.java index fa01db88..be721158 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexData.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexData.java @@ -3,23 +3,24 @@ import org.openmrs.obs.ComplexData; /** - * Our implementation of {@link ComplexData}. This will either wrap of inherit ComplexData - * and expose the methods that are needed in the context of our module. + * Our implementation of {@link ComplexData}. This will either wrap of + * inherit ComplexData and expose the methods that are needed in the context of + * our module. * * @author Mekom Solutions */ public interface AttachmentComplexData { - + public ComplexData asComplexData(); - + public byte[] asByteArray(); - + public String getTitle(); - + public Object getData(); - + public String getMimeType(); - + public String getInstructions(); - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexDataImpl.java b/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexDataImpl.java index 9200d58f..884cdcb9 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexDataImpl.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/AttachmentComplexDataImpl.java @@ -5,17 +5,20 @@ import org.openmrs.obs.ComplexData; public class AttachmentComplexDataImpl extends BaseComplexData implements AttachmentComplexData { - + private static final long serialVersionUID = 1L; - + private String instructions = ValueComplex.INSTRUCTIONS_NONE; - + private String mimeType = AttachmentsConstants.UNKNOWN_MIME_TYPE; - + /** - * @param instructions Custom instructions to be processed by {@link DefaultAttachmentHandler} - * @param mimeType Same as HTTP content type, @see - * + * @param instructions + * Custom instructions to be processed by + * {@link DefaultAttachmentHandler} + * @param mimeType + * Same as HTTP content type, @see */ public AttachmentComplexDataImpl(String instructions, String title, Object data, String mimeType) { super(title, data); @@ -27,26 +30,26 @@ public AttachmentComplexDataImpl(String instructions, String title, Object data, if (!StringUtils.isEmpty(instructions)) this.instructions = instructions; } - + public AttachmentComplexDataImpl(String title, Object data) { this("", title, data, ""); } - + @Override public String getInstructions() { return instructions; } - + @Override public ComplexData asComplexData() { return this; } - + @Override public void setMimeType(String mimeType) { this.mimeType = mimeType; } - + @Override public String getMimeType() { return this.mimeType; diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/BaseComplexData.java b/api/src/main/java/org/openmrs/module/attachments/obs/BaseComplexData.java index 43078cbe..4953070d 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/BaseComplexData.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/BaseComplexData.java @@ -13,30 +13,31 @@ import org.openmrs.obs.ComplexData; /** - * Extends {@link ComplexData} so that it provides a method to extract the underlying byte array. - * Whenever we need to extend {@link ComplexData} we should actually extend this class. + * Extends {@link ComplexData} so that it provides a method to extract the + * underlying byte array. Whenever we need to extend {@link ComplexData} we + * should actually extend this class. * * @author Mekom Solutions */ public class BaseComplexData extends ComplexData { - + private static final long serialVersionUID = 1L; - + public BaseComplexData(String title, Object data) { super(title, data); } - + /** - * This returns the byte array out of a complex data's inner data. This is borrowed from - * {@link ComplexObsServlet}. + * This returns the byte array out of a complex data's inner data. This is + * borrowed from {@link ComplexObsServlet}. * * @return The byte array, or an empty array if an error occurred. */ public static byte[] getByteArray(ComplexData complexData) { final byte[] emptyContent = new byte[0]; - + Object data = (complexData != null) ? complexData.getData() : emptyContent; - + if (data == null) { return emptyContent; } @@ -46,18 +47,17 @@ public static byte[] getByteArray(ComplexData complexData) { return ((String) data).getBytes(); } else if (RenderedImage.class.isAssignableFrom(data.getClass())) { RenderedImage image = (RenderedImage) data; - + ByteArrayOutputStream bytesOutStream = new ByteArrayOutputStream(); try { ImageOutputStream imgOutStream = ImageIO.createImageOutputStream(bytesOutStream); String extension = FilenameUtils.getExtension(complexData.getTitle()); ImageIO.write(image, extension, imgOutStream); imgOutStream.close(); - } - catch (IOException e) { + } catch (IOException e) { return emptyContent; } - + return bytesOutStream.toByteArray(); } else if (InputStream.class.isAssignableFrom(data.getClass())) { try { @@ -67,15 +67,14 @@ public static byte[] getByteArray(ComplexData complexData) { is.reset(); } return bytes; - } - catch (IOException e) { + } catch (IOException e) { return emptyContent; } } else { return emptyContent; } } - + public byte[] asByteArray() { return getByteArray(this); } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelper.java b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelper.java index b03fe151..acc8df77 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelper.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelper.java @@ -8,11 +8,11 @@ * @author Mekom Solutions */ public interface ComplexDataHelper { - + public AttachmentComplexData build(String instructions, String title, Object data, String mimeType); - + public AttachmentComplexData build(String instructions, ComplexData complexData); - + public String getContentType(ComplexData complexData); - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelperImpl.java b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelperImpl.java index 1639c893..4d9faa7c 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelperImpl.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexDataHelperImpl.java @@ -17,39 +17,38 @@ @Component(AttachmentsConstants.COMPONENT_COMPLEXDATA_HELPER) @OpenmrsProfile(openmrsPlatformVersion = "2.2.* - 9.*") public class ComplexDataHelperImpl implements ComplexDataHelper { - + @Override public AttachmentComplexData build(String instructions, String title, Object data, String mimeType) { return new AttachmentComplexDataImpl(instructions, title, data, mimeType); } - + @Override public AttachmentComplexData build(String instructions, ComplexData complexData) { return build(instructions, complexData.getTitle(), complexData.getData(), getContentType(complexData)); } - + @Override public String getContentType(ComplexData complexData) { - + if (complexData instanceof AttachmentComplexData) { // In case it's our module's implementation AttachmentComplexData attComplexData = (AttachmentComplexData) complexData; if (isMimeTypeHandled(attComplexData.getMimeType())) { // Perhaps too restrictive return attComplexData.getMimeType(); } } - + byte[] bytes = BaseComplexData.getByteArray(complexData); if (ArrayUtils.isEmpty(bytes)) { return AttachmentsConstants.UNKNOWN_MIME_TYPE; } - + // guessing the content type InputStream stream = new BufferedInputStream(new ByteArrayInputStream(bytes)); try { String mimeType = URLConnection.guessContentTypeFromStream(stream); return mimeType == null ? AttachmentsConstants.UNKNOWN_MIME_TYPE : mimeType; - } - catch (IOException e) { + } catch (IOException e) { return AttachmentsConstants.UNKNOWN_MIME_TYPE; } } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelper.java b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelper.java index 2467e125..1a297f9e 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelper.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelper.java @@ -3,25 +3,28 @@ import org.openmrs.Obs; /** - * The contents of this file are subject to the OpenMRS Public License Version 1.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://license.openmrs.org Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the - * specific language governing rights and limitations under the License. Copyright (C) OpenMRS, LLC. - * All Rights Reserved. + * The contents of this file are subject to the OpenMRS Public License Version + * 1.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://license.openmrs.org + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ public interface ComplexViewHelper { - + /** - * This method handles providing a usable/correct view argument to both OpenMRS 1.10+ and 2.0+ given - * an OpenMRS 1.10+ view string + * This method handles providing a usable/correct view argument to both OpenMRS + * 1.10+ and 2.0+ given an OpenMRS 1.10+ view string * - * @param obs This will help the 2.x implementation support fetching the supported views for that - * obs,using for example: + * @param obs + * This will help the 2.x implementation support fetching the + * supported views for that obs,using for example: * https://github.com/openmrs/openmrs-core/blob/7da5be1bc34fc4928779f303cd48d42b8a3cae0a/api/src/main/java/org/openmrs/api/ObsService.java#L417-L428 - * @param view the ATT or OpenMRS 1.10+ view string + * @param view + * the ATT or OpenMRS 1.10+ view string * @return a corresponding 1.10+ or 2.0+ view string */ public String getView(Obs obs, String view); - + } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelperImpl.java b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelperImpl.java index 23ab67e1..4785ad8b 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelperImpl.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ComplexViewHelperImpl.java @@ -8,9 +8,9 @@ @Component(AttachmentsConstants.COMPONENT_COMPLEXVIEW_HELPER) @OpenmrsProfile(openmrsPlatformVersion = "2.2.* - 9.*") public class ComplexViewHelperImpl implements ComplexViewHelper { - + public String getView(Obs obs, String view) { - + return view; } } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/DefaultAttachmentHandler.java b/api/src/main/java/org/openmrs/module/attachments/obs/DefaultAttachmentHandler.java index 038635ae..aeacd7c9 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/DefaultAttachmentHandler.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/DefaultAttachmentHandler.java @@ -9,50 +9,50 @@ import org.openmrs.obs.handler.BinaryDataHandler; public class DefaultAttachmentHandler extends AbstractAttachmentHandler { - + public DefaultAttachmentHandler() { super(); } - + protected void setParentComplexObsHandler() { setParent(new BinaryDataHandler()); } - + protected ComplexData readComplexData(Obs obs, ValueComplex valueComplex, String view) { // We invoke the parent to inherit from the file reading routines. Obs tmpObs = new Obs(); tmpObs.setValueComplex(valueComplex.getFileName()); // Temp obs used as a safety - + ComplexData complexData; if (view.equals(AttachmentsConstants.ATT_VIEW_THUMBNAIL)) { // This handler doesn't have data for thumbnails, we return a null content complexData = new ComplexData(valueComplex.getFileName(), null); } else { tmpObs = getParent().getObs(tmpObs, AttachmentsConstants.BINARYDATA_HANDLER_VIEW); // BinaryDataHandler - // doesn't handle - // several views + // doesn't handle + // several views complexData = tmpObs.getComplexData(); } - + // Then we build our own custom complex data - return getComplexDataHelper().build(valueComplex.getInstructions(), complexData.getTitle(), complexData.getData(), - valueComplex.getMimeType()).asComplexData(); + return getComplexDataHelper().build(valueComplex.getInstructions(), complexData.getTitle(), + complexData.getData(), valueComplex.getMimeType()).asComplexData(); } - + protected boolean deleteComplexData(Obs obs, AttachmentComplexData complexData) { // We use a temp obs whose value complex points to the file name Obs tmpObs = new Obs(); tmpObs.setValueComplex(complexData.asComplexData().getTitle()); // Temp obs used as a safety return getParent().purgeComplexData(tmpObs); } - + protected ValueComplex saveComplexData(Obs obs, AttachmentComplexData complexData) { // We invoke the parent to inherit from the file saving routines. obs = getParent().saveObs(obs); - + File savedFile = AbstractHandler.getComplexDataFile(obs); String savedFileName = savedFile.getName(); - + return new ValueComplex(complexData.getInstructions(), complexData.getMimeType(), savedFileName); } } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ImageAttachmentHandler.java b/api/src/main/java/org/openmrs/module/attachments/obs/ImageAttachmentHandler.java index a18cc4fa..a7744534 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ImageAttachmentHandler.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ImageAttachmentHandler.java @@ -14,91 +14,89 @@ import org.openmrs.obs.handler.ImageHandler; public class ImageAttachmentHandler extends AbstractAttachmentHandler { - + public final static int THUMBNAIL_MAX_HEIGHT = 200; - + public final static int THUMBNAIL_MAX_WIDTH = THUMBNAIL_MAX_HEIGHT; - + public ImageAttachmentHandler() { super(); } - + @Override protected void setParentComplexObsHandler() { setParent(new ImageHandler()); } - + @Override protected ComplexData readComplexData(Obs obs, ValueComplex valueComplex, String view) { - + String fileName = valueComplex.getFileName(); if (view.equals(AttachmentsConstants.ATT_VIEW_THUMBNAIL) && !isThumbnail(fileName)) { fileName = buildThumbnailFileName(fileName); } - + // We invoke the parent to inherit from the file reading routines. Obs tmpObs = new Obs(); tmpObs.setValueComplex(fileName); // Temp obs used as a safety tmpObs = getParent().getObs(tmpObs, AttachmentsConstants.IMAGE_HANDLER_VIEW); // ImageHandler doesn't handle // several views ComplexData complexData = tmpObs.getComplexData(); - + // Then we build our own custom complex data - return getComplexDataHelper().build(valueComplex.getInstructions(), complexData.getTitle(), complexData.getData(), - valueComplex.getMimeType()).asComplexData(); + return getComplexDataHelper().build(valueComplex.getInstructions(), complexData.getTitle(), + complexData.getData(), valueComplex.getMimeType()).asComplexData(); } - + @Override protected boolean deleteComplexData(Obs obs, AttachmentComplexData complexData) { - + // We use a temp obs whose complex data points to the file names String fileName = complexData.getTitle(); boolean isThumbNailPurged = true; Obs tmpObs = new Obs(); - + if (!isThumbnail(fileName)) { String thumbnailFileName = buildThumbnailFileName(fileName); tmpObs.setValueComplex(thumbnailFileName); isThumbNailPurged = getParent().purgeComplexData(tmpObs); } - + tmpObs.setValueComplex(fileName); boolean isImagePurged = getParent().purgeComplexData(tmpObs); - + return isThumbNailPurged && isImagePurged; } - + @Override protected ValueComplex saveComplexData(Obs obs, AttachmentComplexData complexData) { int imageHeight = Integer.MAX_VALUE; int imageWidth = Integer.MAX_VALUE; - + // We invoke the parent to inherit from the file saving routines. obs = getParent().saveObs(obs); - + File savedFile = AbstractHandler.getComplexDataFile(obs); String savedFileName = savedFile.getName(); - + // Get image dimensions try { BufferedImage image = ImageIO.read(savedFile); imageHeight = image.getHeight(); imageWidth = image.getWidth(); - } - catch (IOException e) { + } catch (IOException e) { log.warn("The dimensions of image file '" + savedFileName - + "' could not be determined, continuing with generating its thumbnail anyway."); + + "' could not be determined, continuing with generating its thumbnail anyway."); } - + try { savedFileName = saveThumbnailOrRename(savedFile, imageHeight, imageWidth); - } - catch (APIException e) { + } catch (APIException e) { getParent().purgeComplexData(obs); - throw new APIException("A thumbnail file could not be saved for obs with" + "OBS_ID='" + obs.getObsId() + "', " - + "FILE='" + complexData.getTitle() + "'.", e); + throw new APIException("A thumbnail file could not be saved for obs with" + "OBS_ID='" + obs.getObsId() + + "', " + "FILE='" + complexData.getTitle() + "'.", e); } - + return new ValueComplex(complexData.getInstructions(), complexData.getMimeType(), savedFileName); } } diff --git a/api/src/main/java/org/openmrs/module/attachments/obs/ValueComplex.java b/api/src/main/java/org/openmrs/module/attachments/obs/ValueComplex.java index a5c505e2..0c466435 100644 --- a/api/src/main/java/org/openmrs/module/attachments/obs/ValueComplex.java +++ b/api/src/main/java/org/openmrs/module/attachments/obs/ValueComplex.java @@ -11,36 +11,36 @@ import org.openmrs.module.attachments.AttachmentsContext; public class ValueComplex { - + public static final String INSTRUCTIONS_NONE = AttachmentsConstants.INSTRUCTIONS_PREFIX + ".none"; - + public static final String INSTRUCTIONS_DEFAULT = AttachmentsConstants.INSTRUCTIONS_PREFIX + ".default"; - + protected static final String FILENAME_DEFAULT = AttachmentsConstants.MODULE_SHORT_ID.toLowerCase() + "_file"; - + protected String instructions = INSTRUCTIONS_NONE; - + protected String mimeType = AttachmentsConstants.UNKNOWN_MIME_TYPE; - + protected String fileName = AttachmentsConstants.MODULE_SHORT_ID.toLowerCase() + "_file.dat"; - + protected final static String UNIQUE_PREFIX = "m3ks"; // This is used to identify our implementation from saved - // valueComplex. - + // valueComplex. + protected final static String SEP = " | "; - + protected final static int METADATA_PARTS_COUNT = StringUtils.countMatches(buildValueComplex("", "", ""), SEP); - + public ValueComplex(String valueComplex) { - + if (!StringUtils.substringBefore(valueComplex, SEP).equals(UNIQUE_PREFIX)) { this.instructions = INSTRUCTIONS_NONE; return; } - + String metaData = StringUtils.substringAfter(valueComplex, SEP); String[] metaParts = metaData.split(Pattern.quote(SEP)); - + if (metaParts.length > 0) { instructions = metaParts[0]; if (!isValidInstructions(instructions)) { @@ -63,49 +63,49 @@ public ValueComplex(String valueComplex) { pos += SEP.length(); fileName = StringUtils.substring(valueComplex, pos); } else { // That'd be a case where the file name is not even part of the valueComplex - // String, anything else looking valid. + // String, anything else looking valid. fileName = FilenameUtils.removeExtension(fileName) + "." + AttachmentsContext.getExtension(mimeType); } } } - + public ValueComplex(String instructions, String mimeType, String fileName) { this(buildValueComplex(instructions, mimeType, fileName)); } - + @Override public String toString() { return buildValueComplex(instructions, mimeType, fileName); } - + public boolean isOwnImplementation() { return instructions != INSTRUCTIONS_NONE; } - + public String getInstructions() { return instructions; } - + public String getFileName() { return fileName; } - + public String getMimeType() { return mimeType; } - + public String getValueComplex() { return buildValueComplex(instructions, mimeType, fileName); } - + public static String buildValueComplex(String instructions, String mimeType, String savedFileName) { return UNIQUE_PREFIX + SEP + instructions + SEP + mimeType + SEP + savedFileName; } - + protected static boolean isValidInstructions(String str) { return StringUtils.startsWith(str, AttachmentsConstants.INSTRUCTIONS_PREFIX + "."); } - + protected static boolean isValidMimeType(String str) { return isMimeTypeHandled(str); } diff --git a/api/src/test/java/org/openmrs/module/attachments/AttachmentsContextTest.java b/api/src/test/java/org/openmrs/module/attachments/AttachmentsContextTest.java index 9fdc0185..3d3f5856 100644 --- a/api/src/test/java/org/openmrs/module/attachments/AttachmentsContextTest.java +++ b/api/src/test/java/org/openmrs/module/attachments/AttachmentsContextTest.java @@ -17,54 +17,54 @@ import org.openmrs.test.Verifies; public class AttachmentsContextTest { - + private AttachmentsContext context = new AttachmentsContext(); - + private AdministrationService adminService = mock(AdministrationService.class); - + @Before public void setup() { context.administrationService = adminService; } - + @Test @Verifies(value = "A simple JSON saved as a global property should be parse into a Map.", method = "getMapByGlobalProperty(globalPropertyName)") public void context_shouldReturnSimpleMap() { - + // Setup final String IMAGE_STR = ContentFamily.IMAGE.toString(); final String IMAGE_UUID = "7cac8397-53cd-4f00-a6fe-028e8d743f8e"; final String OTHER_STR = ContentFamily.OTHER.toString(); final String OTHER_UUID = "42ed45fd-f3f6-44b6-bfc2-8bde1bb41e00"; - + String jsonMap = "{\"" + IMAGE_STR + "\":\"" + IMAGE_UUID + "\",\"" + OTHER_STR + "\":\"" + OTHER_UUID + "\"}"; String gpName = AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_MAP; when(adminService.getGlobalProperty(eq(gpName))).thenReturn(jsonMap); - + // Replay Map map = context.getMapByGlobalProperty(gpName); - + // Verif assertEquals(2, map.size()); assertEquals(IMAGE_UUID, map.get(IMAGE_STR)); assertEquals(OTHER_UUID, map.get(OTHER_STR)); } - + @Test @Verifies(value = "A JSON saved as a global property should be parse into a List.", method = "getMapByGlobalProperty(globalPropertyName)") public void context_shouldReturnList() { - + // Setup final String IMAGE_UUID = "7cac8397-53cd-4f00-a6fe-028e8d743f8e"; final String OTHER_UUID = "42ed45fd-f3f6-44b6-bfc2-8bde1bb41e00"; - + String jsonList = "[\"" + IMAGE_UUID + "\",\"" + OTHER_UUID + "\"]"; String gpName = AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_LIST; when(adminService.getGlobalProperty(eq(gpName))).thenReturn(jsonList); - + // Replay List list = context.getConceptComplexList(); - + // Verif assertEquals(2, list.size()); assertEquals(IMAGE_UUID, list.get(0)); diff --git a/api/src/test/java/org/openmrs/module/attachments/obs/ImageAttachmentHandlerTest.java b/api/src/test/java/org/openmrs/module/attachments/obs/ImageAttachmentHandlerTest.java index 86f99fc7..1e47fb03 100644 --- a/api/src/test/java/org/openmrs/module/attachments/obs/ImageAttachmentHandlerTest.java +++ b/api/src/test/java/org/openmrs/module/attachments/obs/ImageAttachmentHandlerTest.java @@ -21,121 +21,124 @@ import org.springframework.mock.web.MockMultipartFile; public class ImageAttachmentHandlerTest extends BaseModuleContextSensitiveTest { - + @Autowired protected TestHelper testHelper; - + @Before public void setup() throws IOException { testHelper.init(); } - + @After public void tearDown() throws IOException { testHelper.tearDown(); } - + @Test public void saveComplexData_shouldSaveThumbnailToDisk() throws IOException { - + // Replay Obs obs = testHelper.saveNormalSizeImageAttachment(); - + // Verif MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); File file = new File( - testHelper.getComplexObsDir() + "/" + FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" - + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename())); + testHelper.getComplexObsDir() + "/" + FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" + + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename())); Assert.assertTrue(file.exists()); File thumbnail = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) - + "_" + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); + + ImageAttachmentHandler + .buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" + + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); Assert.assertTrue(thumbnail.exists()); - + Assert.assertThat(thumbnail.length(), lessThan(file.length())); BufferedImage img = ImageIO.read(thumbnail); Assert.assertEquals(ImageAttachmentHandler.THUMBNAIL_MAX_HEIGHT, Math.max(img.getHeight(), img.getWidth())); - + File noThumbnailFile = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler - .buildNoThumbnailFileFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" - + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); + + ImageAttachmentHandler + .buildNoThumbnailFileFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" + + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); Assert.assertFalse(noThumbnailFile.exists()); } - + @Test public void deleteComplexData_shouldDeleteThumbnailFromDisk() throws IOException { - + // Setup Obs obs = testHelper.saveNormalSizeImageAttachment(); MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); - + // Replay obs = Context.getObsService().getComplexObs(obs.getId(), AttachmentsConstants.ATT_VIEW_CRUD); Context.getObsService().purgeObs(obs); - + // Verif File file = new File(testHelper.getComplexObsDir() + "/" + mpFile.getOriginalFilename()); Assert.assertFalse(file.exists()); File thumbnail = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) - + "_" + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); + + ImageAttachmentHandler + .buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" + + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); Assert.assertFalse(thumbnail.exists()); } - + @Test public void readComplexData_shouldFetchThumbnail() throws IOException { - + // Setup Obs obs = testHelper.saveNormalSizeImageAttachment(); MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); File thumbnail = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) - + "_" + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); + + ImageAttachmentHandler + .buildThumbnailFileName(FilenameUtils.removeExtension(mpFile.getOriginalFilename()) + "_" + + obs.getUuid() + "." + FilenameUtils.getExtension(mpFile.getOriginalFilename()))); Assert.assertTrue(thumbnail.exists()); byte[] expectedBytes = new BaseComplexData(thumbnail.getName(), ImageIO.read(thumbnail)).asByteArray(); - + // Replay obs = Context.getObsService().getComplexObs(obs.getId(), AttachmentsConstants.ATT_VIEW_THUMBNAIL); - + // Verif Assert.assertArrayEquals(expectedBytes, BaseComplexData.getByteArray(obs.getComplexData())); } - + @Test public void saveComplexData_shouldNotSaveThumbnailWhenSmallImage() throws IOException { - + // Setup Obs obs = testHelper.saveSmallSizeImageAttachment(); MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); String originalFileName = mpFile.getOriginalFilename(); - + // Verif the buildNotThumbnailFileFileName() File noThumbnailFile = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildNoThumbnailFileFileName(FilenameUtils.removeExtension(originalFileName) + "_" - + obs.getUuid() + "." + FilenameUtils.getExtension(originalFileName))); + + ImageAttachmentHandler.buildNoThumbnailFileFileName(FilenameUtils.removeExtension(originalFileName) + + "_" + obs.getUuid() + "." + FilenameUtils.getExtension(originalFileName))); Assert.assertTrue(noThumbnailFile.exists()); // Not create new file name since it contained NO_THUMBNAIL_SUFFIX noThumbnailFile = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildNoThumbnailFileFileName(noThumbnailFile.getName())); + + ImageAttachmentHandler.buildNoThumbnailFileFileName(noThumbnailFile.getName())); Assert.assertTrue(noThumbnailFile.exists()); - + // Verif the thumbnail file was NOT created File thumbnail = new File( - testHelper.getComplexObsDir() + "/" + ImageAttachmentHandler.buildThumbnailFileName(originalFileName)); + testHelper.getComplexObsDir() + "/" + ImageAttachmentHandler.buildThumbnailFileName(originalFileName)); Assert.assertFalse(thumbnail.exists()); - + // Assert.assertThat(thumbnail.length(), lessThan(file.length())); BufferedImage img = ImageIO.read(noThumbnailFile); Assert.assertTrue(ImageAttachmentHandler.THUMBNAIL_MAX_HEIGHT >= Math.max(img.getHeight(), img.getWidth())); - + // Check that the file name contains the no thumbnail suffix Assert.assertTrue(ImageAttachmentHandler.isThumbnail(FilenameUtils.removeExtension(noThumbnailFile.getName()))); } - + @Test public void deleteComplexData_shouldDeleteNoThumbnailFromDisk() throws IOException { - + // Setup Obs obs = testHelper.saveSmallSizeImageAttachment(); MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); @@ -143,30 +146,33 @@ public void deleteComplexData_shouldDeleteNoThumbnailFromDisk() throws IOExcepti // Replay obs = Context.getObsService().getComplexObs(obs.getId(), AttachmentsConstants.ATT_VIEW_CRUD); Context.getObsService().purgeObs(obs); - + // Verif - File noThumbnailFile = new File( - testHelper.getComplexObsDir() + "/" + ImageAttachmentHandler.buildNoThumbnailFileFileName(originalFileName)); + File noThumbnailFile = new File(testHelper.getComplexObsDir() + "/" + + ImageAttachmentHandler.buildNoThumbnailFileFileName(originalFileName)); Assert.assertFalse(noThumbnailFile.exists()); } - + @Test public void readComplexData_shouldAlwaysFetchOriginalImageWhenSmallImage() throws IOException { - + // Setup Obs obs = testHelper.saveSmallSizeImageAttachment(); MockMultipartFile mpFile = testHelper.getLastSavedTestImageFile(); String originalFileName = mpFile.getOriginalFilename(); File noThumbnailFile = new File(testHelper.getComplexObsDir() + "/" - + ImageAttachmentHandler.buildNoThumbnailFileFileName(FilenameUtils.removeExtension(originalFileName) + "_" - + obs.getUuid() + "." + FilenameUtils.getExtension(originalFileName))); + + ImageAttachmentHandler.buildNoThumbnailFileFileName(FilenameUtils.removeExtension(originalFileName) + + "_" + obs.getUuid() + "." + FilenameUtils.getExtension(originalFileName))); Assert.assertTrue(noThumbnailFile.exists()); - byte[] expectedBytes = new BaseComplexData(noThumbnailFile.getName(), ImageIO.read(noThumbnailFile)).asByteArray(); - + byte[] expectedBytes = new BaseComplexData(noThumbnailFile.getName(), ImageIO.read(noThumbnailFile)) + .asByteArray(); + // Replay - Obs obsThumbnailView = Context.getObsService().getComplexObs(obs.getId(), AttachmentsConstants.ATT_VIEW_THUMBNAIL); - Obs obsOriginalView = Context.getObsService().getComplexObs(obs.getId(), AttachmentsConstants.ATT_VIEW_ORIGINAL); - + Obs obsThumbnailView = Context.getObsService().getComplexObs(obs.getId(), + AttachmentsConstants.ATT_VIEW_THUMBNAIL); + Obs obsOriginalView = Context.getObsService().getComplexObs(obs.getId(), + AttachmentsConstants.ATT_VIEW_ORIGINAL); + // Verif Assert.assertArrayEquals(expectedBytes, BaseComplexData.getByteArray(obsThumbnailView.getComplexData())); Assert.assertArrayEquals(expectedBytes, BaseComplexData.getByteArray(obsOriginalView.getComplexData())); diff --git a/api/src/test/java/org/openmrs/module/attachments/obs/TestHelper.java b/api/src/test/java/org/openmrs/module/attachments/obs/TestHelper.java index 09f37b9a..a17b4447 100644 --- a/api/src/test/java/org/openmrs/module/attachments/obs/TestHelper.java +++ b/api/src/test/java/org/openmrs/module/attachments/obs/TestHelper.java @@ -39,93 +39,94 @@ @Component public class TestHelper { - + public static final String ATTACHMENTS_FOLDER = "attachments"; - + @Autowired protected AttachmentsActivator activator; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_ATT_CONTEXT) protected AttachmentsContext context; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXDATA_HELPER) protected ComplexDataHelper complexDataHelper; - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER) protected ComplexObsSaver obsSaver; - + protected File complexObsDir; - + protected String fileName = "mock_file_name"; - + protected String fileExt = "ext"; - + protected MockMultipartFile multipartDefaultFile = new MockMultipartFile(fileName, fileName + "." + fileExt, - "application/octet-stream", "mock_content".getBytes()); - + "application/octet-stream", "mock_content".getBytes()); + protected MockMultipartFile lastSavedMultipartImageFile; - + protected final static String OTHER_CONCEPT_COMPLEX_NAME = "OutOfAttachmentsTestComplex"; - + protected Concept otherConceptComplex; - + /** * @return The last saved test image file, null if none was ever saved. */ public MockMultipartFile getLastSavedTestImageFile() { return lastSavedMultipartImageFile; } - + public MockMultipartFile getTestDefaultFile() { return multipartDefaultFile; } - + public String getTestFileName() { return fileName; } - + public String getTestFileNameWithExt() { return getTestFileName() + "." + fileExt; } - + /** - * This initialization routine configure a lot of boilerplate settings to mimic the actual - * environment. This method should be invoked when setting up unit tests. + * This initialization routine configure a lot of boilerplate settings to mimic + * the actual environment. This method should be invoked when setting up unit + * tests. * * @throws IOException */ public void init() throws IOException { activator.started(); // so our concepts complex are created - + String conceptComplexUuidMap = "{\"IMAGE\":\"" + AttachmentsConstants.CONCEPT_IMAGE_UUID + "\",\"OTHER\":\"" - + AttachmentsConstants.CONCEPT_DEFAULT_UUID + "\"}"; + + AttachmentsConstants.CONCEPT_DEFAULT_UUID + "\"}"; context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_MAP, conceptComplexUuidMap)); - + new GlobalProperty(AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_MAP, conceptComplexUuidMap)); + complexObsDir = OpenmrsUtil.getDirectoryInApplicationDataDirectory("complex_obs"); context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_COMPLEX_OBS_DIR, getComplexObsDir())); - + new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_COMPLEX_OBS_DIR, getComplexObsDir())); + context.getAdministrationService() - .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_LIST, - "[\"7cac8397-53cd-4f00-a6fe-028e8d743f8e\",\"42ed45fd-f3f6-44b6-bfc2-8bde1bb41e00\"]")); + .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_CONCEPT_COMPLEX_UUID_LIST, + "[\"7cac8397-53cd-4f00-a6fe-028e8d743f8e\",\"42ed45fd-f3f6-44b6-bfc2-8bde1bb41e00\"]")); context.getAdministrationService() - .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_MAX_STORAGE_FILE_SIZE, "1.2")); + .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_MAX_STORAGE_FILE_SIZE, "1.2")); context.getAdministrationService() - .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_MAX_UPLOAD_FILE_SIZE, "5.0")); + .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_MAX_UPLOAD_FILE_SIZE, "5.0")); context.getAdministrationService() - .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_ALLOW_NO_CAPTION, "false")); + .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_ALLOW_NO_CAPTION, "false")); context.getAdministrationService() - .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_WEBCAM_ALLOWED, "true")); - context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_RESTWS_MAX_RESULTS_DEFAULT_GLOBAL_PROPERTY_NAME, "50")); - + .saveGlobalProperty(new GlobalProperty(AttachmentsConstants.GP_WEBCAM_ALLOWED, "true")); context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, AttachmentsConstants.ENCOUNTER_TYPE_UUID)); - + new GlobalProperty(AttachmentsConstants.GP_RESTWS_MAX_RESULTS_DEFAULT_GLOBAL_PROPERTY_NAME, "50")); + + context.getAdministrationService().saveGlobalProperty(new GlobalProperty( + AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, AttachmentsConstants.ENCOUNTER_TYPE_UUID)); + // Create a concept complex that is not managed by Attachments if (context.getConceptService().getConceptByName(OTHER_CONCEPT_COMPLEX_NAME) == null) { ConceptComplex conceptComplex = new ConceptComplex(); @@ -134,21 +135,24 @@ public void init() throws IOException { conceptComplex.setFullySpecifiedName(conceptName); conceptComplex.setPreferredName(conceptName); conceptComplex.setConceptClass(context.getConceptService().getConceptClassByName("Question")); - conceptComplex.setDatatype(context.getConceptService().getConceptDatatypeByUuid(ConceptDatatype.COMPLEX_UUID)); - conceptComplex.addDescription(new ConceptDescription("Out-of-Attachments test concept complex", Locale.ENGLISH)); + conceptComplex + .setDatatype(context.getConceptService().getConceptDatatypeByUuid(ConceptDatatype.COMPLEX_UUID)); + conceptComplex + .addDescription(new ConceptDescription("Out-of-Attachments test concept complex", Locale.ENGLISH)); context.getConceptService().saveConcept(conceptComplex); otherConceptComplex = conceptComplex; } } - + /** * This method should be invoked when tearing down unit tests. */ public void tearDown() throws IOException { - context.getConceptService().purgeConcept(context.getConceptService().getConceptByName(OTHER_CONCEPT_COMPLEX_NAME)); + context.getConceptService() + .purgeConcept(context.getConceptService().getConceptByName(OTHER_CONCEPT_COMPLEX_NAME)); OpenmrsUtil.deleteDirectory(complexObsDir); } - + /** * Boilerplate method to get an test encounter * @@ -160,33 +164,34 @@ public Encounter getTestEncounter() throws IOException { EncounterService encounterService = Context.getEncounterService(); EncounterType encounterType = encounterService.getEncounterType(1); Provider provider = Context.getProviderService().getProvider(1); - + context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); + new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); Encounter encounter = context.getAttachmentEncounter(patient, visit, provider); return encounter; } - + public Obs getTestComplexObs() throws IOException { Patient patient = Context.getPatientService().getPatient(2); Visit visit = Context.getVisitService().getVisit(1); EncounterService encounterService = Context.getEncounterService(); EncounterType encounterType = encounterService.getEncounterType(1); Provider provider = Context.getProviderService().getProvider(1); - + context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); + new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); Encounter encounter = context.getAttachmentEncounter(patient, visit, provider); - + String fileCaption = RandomStringUtils.randomAlphabetic(12); return obsSaver.saveOtherAttachment(visit, patient, encounter, fileCaption, getTestDefaultFile(), - ValueComplex.INSTRUCTIONS_DEFAULT); + ValueComplex.INSTRUCTIONS_DEFAULT); } - + /** * Boilerplate method to save an image attachment. * - * @param imagePath The path of the image resource. + * @param imagePath + * The path of the image resource. */ public Obs saveImageAttachment(String imagePath, String mimeType) throws IOException { Patient patient = Context.getPatientService().getPatient(2); @@ -194,63 +199,69 @@ public Obs saveImageAttachment(String imagePath, String mimeType) throws IOExcep EncounterService encounterService = Context.getEncounterService(); EncounterType encounterType = encounterService.getEncounterType(1); Provider provider = Context.getProviderService().getProvider(1); - + context.getAdministrationService().saveGlobalProperty( - new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); + new GlobalProperty(AttachmentsConstants.GP_ENCOUNTER_TYPE_UUID, encounterType.getUuid())); Encounter encounter = context.getAttachmentEncounter(patient, visit, provider); - + String imageFileName = FilenameUtils.getName(imagePath); lastSavedMultipartImageFile = new MockMultipartFile(FilenameUtils.getBaseName(imageFileName), imageFileName, - mimeType, IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream(imagePath))); - + mimeType, IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream(imagePath))); + String fileCaption = RandomStringUtils.randomAlphabetic(12); return obsSaver.saveImageAttachment(visit, patient, encounter, fileCaption, lastSavedMultipartImageFile, - ValueComplex.INSTRUCTIONS_DEFAULT); + ValueComplex.INSTRUCTIONS_DEFAULT); } - + /** - * Boilerplate method to save an 'normal sized' image attachment. This method doesn't ensure that - * the size is normal, the method just uses an image file that is assumed to fit. + * Boilerplate method to save an 'normal sized' image attachment. This method + * doesn't ensure that the size is normal, the method just uses an image file + * that is assumed to fit. */ public Obs saveNormalSizeImageAttachment() throws IOException { return saveImageAttachment(ATTACHMENTS_FOLDER + "/" + "OpenMRS_banner.jpg", "image/jpeg"); } - + /** - * Boilerplate method to save an 'small sized' image attachment. Small sized mean already small - * enough to be its own thumbnail. This method doesn't ensure that the size is small, the method - * just uses an image file that is assumed to fit. + * Boilerplate method to save an 'small sized' image attachment. Small sized + * mean already small enough to be its own thumbnail. This method doesn't ensure + * that the size is small, the method just uses an image file that is assumed to + * fit. */ public Obs saveSmallSizeImageAttachment() throws IOException { return saveImageAttachment(ATTACHMENTS_FOLDER + "/" + "OpenMRS_icon_100x100.png", "image/png"); } - + public Obs getTestComplexObsWithoutAssociatedEncounterOrVisit() throws Exception { Patient patient = Context.getPatientService().getPatient(2); - + String fileCaption = RandomStringUtils.randomAlphabetic(12); return obsSaver.saveOtherAttachment(null, patient, null, fileCaption, getTestDefaultFile(), - ValueComplex.INSTRUCTIONS_DEFAULT); + ValueComplex.INSTRUCTIONS_DEFAULT); } - + public String getComplexObsDir() { return complexObsDir.getAbsolutePath(); } - + /** * @return The file path of the file 'behind' the complex obs. */ public String getTestComplexObsFilePath() { return getComplexObsDir() + "/" + getTestFileNameWithExt(); } - + /** - * Boilerplate method to save a collection of complex obs based on the encounter. + * Boilerplate method to save a collection of complex obs based on the + * encounter. * - * @param encounter target encounter for save the complex obs. Leave null to save encounter-less - * complex obs. - * @param count The number of the attachments/complex obs to be saved. - * @param otherCount The number of other complex obs to be saved. + * @param encounter + * target encounter for save the complex obs. Leave null to save + * encounter-less complex obs. + * @param count + * The number of the attachments/complex obs to be saved. + * @param otherCount + * The number of other complex obs to be saved. * @return List of saved attachments/complex obs. */ public List saveComplexObs(Encounter encounter, int count, int otherCount) throws IOException { @@ -258,19 +269,19 @@ public List saveComplexObs(Encounter encounter, int count, int otherCount) byte[] randomData = new byte[20]; Patient patient = (encounter == null) ? context.getPatientService().getPatient(2) : encounter.getPatient(); Visit visit = (encounter == null) ? null : encounter.getVisit(); - + // Saves a complex obs as if they had been saved relevant to the attachment. for (int i = 0; i < count; i++) { String fileCaption = RandomStringUtils.randomAlphabetic(12); new Random().nextBytes(randomData); - + String filename = RandomStringUtils.randomAlphabetic(7) + ".ext"; MockMultipartFile multipartRandomFile = new MockMultipartFile(FilenameUtils.getBaseName(filename), filename, - "application/octet-stream", randomData); + "application/octet-stream", randomData); obsList.add(obsSaver.saveOtherAttachment(visit, patient, encounter, fileCaption, multipartRandomFile, - ValueComplex.INSTRUCTIONS_DEFAULT)); + ValueComplex.INSTRUCTIONS_DEFAULT)); } - + // Saves a complex obs as if they had been saved outside of Attachments for (int i = 0; i < otherCount; i++) { Obs obs = new Obs(); @@ -278,16 +289,18 @@ public List saveComplexObs(Encounter encounter, int count, int otherCount) obs.setObsDatetime(new Date()); obs.setPerson(patient); obs.setEncounter(encounter); - + new Random().nextBytes(randomData); String filename = RandomStringUtils.randomAlphabetic(7) + ".ext"; MockMultipartFile multipartRandomFile = new MockMultipartFile(FilenameUtils.getBaseName(filename), filename, - "application/octet-stream", randomData); + "application/octet-stream", randomData); obs.setComplexData( - complexDataHelper.build(ValueComplex.INSTRUCTIONS_DEFAULT, multipartRandomFile.getOriginalFilename(), - multipartRandomFile.getBytes(), multipartRandomFile.getContentType()).asComplexData()); + complexDataHelper + .build(ValueComplex.INSTRUCTIONS_DEFAULT, multipartRandomFile.getOriginalFilename(), + multipartRandomFile.getBytes(), multipartRandomFile.getContentType()) + .asComplexData()); obs = context.getObsService().saveObs(obs, null); - + } return obsList; } diff --git a/api/src/test/java/org/openmrs/module/attachments/obs/ValueComplexTest.java b/api/src/test/java/org/openmrs/module/attachments/obs/ValueComplexTest.java index fb1e68ca..0e8fb4ac 100644 --- a/api/src/test/java/org/openmrs/module/attachments/obs/ValueComplexTest.java +++ b/api/src/test/java/org/openmrs/module/attachments/obs/ValueComplexTest.java @@ -10,58 +10,59 @@ import org.openmrs.test.Verifies; public class ValueComplexTest { - + @Test @Verifies(value = "ValueComplex should handle file names even when containing the reserved separator.", method = "ValueComplex(String, String, String)") public void valueComplex_shouldHandleFileNamesWithSeparator() { - + // Setup String instr = ValueComplex.INSTRUCTIONS_DEFAULT; String mimeType = AttachmentsConstants.UNKNOWN_MIME_TYPE; String fileName; ValueComplex valueComplex; - + // Replay fileName = "my file name .ext"; valueComplex = new ValueComplex(instr, mimeType, fileName); - + // Verification assertEquals(instr, valueComplex.getInstructions()); assertEquals(mimeType, valueComplex.getMimeType()); assertEquals(fileName, valueComplex.getFileName()); - + // Replay fileName = "my file" + ValueComplex.SEP + "name .ext"; valueComplex = new ValueComplex(instr, mimeType, fileName); - + // Verification assertEquals(instr, valueComplex.getInstructions()); assertEquals(mimeType, valueComplex.getMimeType()); assertEquals(fileName, valueComplex.getFileName()); - + // Replay - fileName = ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + ".ext"; + fileName = ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + ValueComplex.SEP + + ".ext"; valueComplex = new ValueComplex(instr, mimeType, fileName); - + // Verification assertEquals(instr, valueComplex.getInstructions()); assertEquals(mimeType, valueComplex.getMimeType()); assertEquals(fileName, valueComplex.getFileName()); - + // Replay fileName = ValueComplex.SEP; valueComplex = new ValueComplex(instr, mimeType, fileName); - + // Verification assertEquals(instr, valueComplex.getInstructions()); assertEquals(mimeType, valueComplex.getMimeType()); assertEquals(fileName, valueComplex.getFileName()); - + // Replay String sepNoBlanks = StringUtils.remove(ValueComplex.SEP, " "); fileName = ValueComplex.SEP + sepNoBlanks + ValueComplex.SEP + sepNoBlanks; valueComplex = new ValueComplex(instr, mimeType, fileName); - + // Verification assertEquals(instr, valueComplex.getInstructions()); assertEquals(mimeType, valueComplex.getMimeType()); diff --git a/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentBytesResource.java b/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentBytesResource.java index 82631e3b..a3c0ad56 100644 --- a/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentBytesResource.java +++ b/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentBytesResource.java @@ -35,41 +35,42 @@ @OpenmrsProfile(openmrsPlatformVersion = "2.2.* - 9.*") @RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/" + AttachmentsConstants.ATTACHMENT_URI) public class AttachmentBytesResource extends BaseRestController { - + protected final Log log = LogFactory.getLog(getClass()); - + @RequestMapping(value = AttachmentsConstants.ATTACHMENT_BYTES_URI, method = RequestMethod.GET) public void getFile(@PathVariable("uuid") String uuid, @RequestParam(required = false, value = "view") String view, - HttpServletResponse response) throws ResponseException { + HttpServletResponse response) throws ResponseException { AttachmentsContext context = Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, - AttachmentsContext.class); - + AttachmentsContext.class); + // Getting the Core/Platform complex data object Obs obs = context.getObsService().getObsByUuid(uuid); - + if (!obs.isComplex()) { - throw new IllegalRequestException("The following obs is not a complex obs, no complex data can be retrieved. " - + "Obs UUID: " + obs.getUuid()); + throw new IllegalRequestException( + "The following obs is not a complex obs, no complex data can be retrieved. " + "Obs UUID: " + + obs.getUuid()); } - + ComplexViewHelper viewHelper = context.getComplexViewHelper(); - + Obs complexObs = Context.getObsService().getComplexObs(obs.getObsId(), viewHelper.getView(obs, view)); ComplexData complexData = complexObs.getComplexData(); - + // Switching to our complex data object ValueComplex valueComplex = new ValueComplex(obs.getValueComplex()); AttachmentComplexData attComplexData = context.getComplexDataHelper().build(valueComplex.getInstructions(), - complexData); - + complexData); + String mimeType = attComplexData.getMimeType(); - + // The attachment metadata is sent as HTTP headers. response.setContentType(mimeType); response.addHeader("Content-Family", getContentFamily(mimeType).name()); response.addHeader("File-Name", attComplexData.getTitle()); response.addHeader("File-Ext", getExtension(attComplexData.getTitle(), mimeType)); - + try { byte[] bytes = attComplexData.asByteArray(); if (mimeType != null && mimeType.startsWith("text/html")) { @@ -77,15 +78,14 @@ public void getFile(@PathVariable("uuid") String uuid, @RequestParam(required = bytes = byteString.getBytes(StandardCharsets.UTF_8); } response.getOutputStream().write(bytes); - } - catch (IOException ex) { + } catch (IOException ex) { response.setStatus(500); throw new GenericRestException("There was an error when downloading the attachment's bytes content." - + " Perhaps the file content is corrupted.", ex); + + " Perhaps the file content is corrupted.", ex); } - + } - + public static String getExtension(String fileName, String mimeType) { String ext = FilenameUtils.getExtension(fileName); String extFromMimeType = AttachmentsContext.getExtension(mimeType); diff --git a/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentResource.java b/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentResource.java index 988e6a5e..b501bd03 100644 --- a/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentResource.java +++ b/omod/src/main/java/org/openmrs/module/attachments/rest/AttachmentResource.java @@ -60,25 +60,25 @@ import org.springframework.web.multipart.MultipartFile; @Resource(name = RestConstants.VERSION_1 + "/" - + AttachmentsConstants.ATTACHMENT_URI, supportedClass = Attachment.class, supportedOpenmrsVersions = { - "2.2.* - 9.*" }) + + AttachmentsConstants.ATTACHMENT_URI, supportedClass = Attachment.class, supportedOpenmrsVersions = { + "2.2.* - 9.*"}) public class AttachmentResource extends DataDelegatingCrudResource implements Uploadable { - + protected static final String REASON = "REST web service"; - + @Override public Attachment newDelegate() { return new Attachment(); } - + @Override public Attachment save(Attachment delegate) { Obs obs = Context.getObsService().saveObs(delegate.getObs(), REASON); return new Attachment(obs, - Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) - .getComplexDataHelper()); + Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) + .getComplexDataHelper()); } - + @Override public Attachment getByUniqueId(String uniqueId) { Obs obs = Context.getObsService().getObsByUuid(uniqueId); @@ -86,25 +86,29 @@ public Attachment getByUniqueId(String uniqueId) { throw new GenericRestException(uniqueId + " does not identify a complex obs.", null); else { return new Attachment(obs, - Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) - .getComplexDataHelper()); + Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) + .getComplexDataHelper()); } } - + @Override protected void delete(Attachment delegate, String reason, RequestContext context) throws ResponseException { - String encounterUuid = delegate.getObs().getEncounter() != null ? delegate.getObs().getEncounter().getUuid() : null; + String encounterUuid = delegate.getObs().getEncounter() != null + ? delegate.getObs().getEncounter().getUuid() + : null; Context.getObsService().voidObs(delegate.getObs(), REASON); voidEncounterIfEmpty(Context.getEncounterService(), encounterUuid); } - + @Override public void purge(Attachment delegate, RequestContext context) throws ResponseException { - String encounterUuid = delegate.getObs().getEncounter() != null ? delegate.getObs().getEncounter().getUuid() : null; + String encounterUuid = delegate.getObs().getEncounter() != null + ? delegate.getObs().getEncounter().getUuid() + : null; Context.getObsService().purgeObs(delegate.getObs()); voidEncounterIfEmpty(Context.getEncounterService(), encounterUuid); } - + @Override public Object upload(MultipartFile file, RequestContext context) throws ResponseException, IOException { // Prepare Parameters @@ -115,10 +119,10 @@ public Object upload(MultipartFile file, RequestContext context) throws Response String fileCaption = context.getParameter("fileCaption"); String instructions = context.getParameter("instructions"); String base64Content = context.getParameter("base64Content"); - + AttachmentsContext ctx = Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, - AttachmentsContext.class); - + AttachmentsContext.class); + if (base64Content != null) { file = new Base64MultipartFile(base64Content, file.getName(), file.getOriginalFilename()); } @@ -126,60 +130,59 @@ public Object upload(MultipartFile file, RequestContext context) throws Response if (ctx.getMaxUploadFileSize() * 1024 * 1024 < (double) file.getSize()) { throw new IllegalRequestException("The file exceeds the maximum size"); } - + // Verify file extension String fileName = file.getOriginalFilename(); int idx = fileName.lastIndexOf("."); String fileExtension = idx > 0 && idx < fileName.length() - 1 ? fileName.substring(idx + 1) : ""; - + String[] allowedExtensions = ctx.getAllowedFileExtensions(); if (allowedExtensions != null && allowedExtensions.length > 0 && Arrays.stream(allowedExtensions) - .filter(s -> s != null && !s.isEmpty()).noneMatch(fileExtension::equalsIgnoreCase)) { + .filter(s -> s != null && !s.isEmpty()).noneMatch(fileExtension::equalsIgnoreCase)) { throw new IllegalRequestException("The extension " + fileExtension + " is not valid"); } - + // Verify file name String[] deniedFileNames = ctx.getDeniedFileNames(); if (deniedFileNames != null && deniedFileNames.length > 0 && Arrays.stream(deniedFileNames) - .filter(s -> s != null && !s.isEmpty()).anyMatch(fileName::equalsIgnoreCase)) { + .filter(s -> s != null && !s.isEmpty()).anyMatch(fileName::equalsIgnoreCase)) { throw new IllegalRequestException("The file name is not valid"); } - + // Verify Parameters if (patient == null) { throw new IllegalRequestException("A patient parameter must be provided when uploading an attachment."); } - + if (StringUtils.isEmpty(instructions)) instructions = ValueComplex.INSTRUCTIONS_DEFAULT; - + // Verify Parameters if (encounter != null && visit != null) { if (encounter.getVisit() != visit) { throw new IllegalRequestException( - "The specified encounter does not belong to the provided visit, upload aborted."); + "The specified encounter does not belong to the provided visit, upload aborted."); } } - + // Verify Content Type if (allowedExtensions != null && allowedExtensions.length > 0) { Tika tika = new Tika(); String fileType = tika.detect(file.getInputStream()); try { MimeType mimeType = MimeTypes.getDefaultMimeTypes().forName(fileType); - + List mimeTypeExtensions = mimeType.getExtensions().stream() - .map(extension -> extension.replace(".", "")).collect(Collectors.toList()); - + .map(extension -> extension.replace(".", "")).collect(Collectors.toList()); + if (!CollectionUtils.containsAny(mimeTypeExtensions, Arrays.asList(allowedExtensions))) { throw new IllegalRequestException("The file content type " + fileType + " is not allowed"); } - } - catch (MimeTypeException ex) { + } catch (MimeTypeException ex) { throw new APIException("Failed to detect the file content type", ex); } } - + // Verify the file contents // Just in case the magic bytes are manipulated, we are using the submitted file // extension to get the mime type @@ -187,54 +190,54 @@ public Object upload(MultipartFile file, RequestContext context) throws Response if (mimeType.startsWith("image/") && !isValidImage(file.getInputStream())) { throw new IllegalRequestException("The file has invalid content"); } - + if (visit != null && encounter == null) { encounter = ctx.getAttachmentEncounter(patient, visit, provider); } - + if (encounter != null && visit == null) { visit = encounter.getVisit(); } - + // Save Obs Obs obs; switch (getContentFamily(file.getContentType())) { - case IMAGE: - obs = Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER, ComplexObsSaver.class) - .saveImageAttachment(visit, patient, encounter, fileCaption, file, instructions); + case IMAGE : + obs = Context + .getRegisteredComponent(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER, ComplexObsSaver.class) + .saveImageAttachment(visit, patient, encounter, fileCaption, file, instructions); break; - - case OTHER: - default: - obs = Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER, ComplexObsSaver.class) - .saveOtherAttachment(visit, patient, encounter, fileCaption, file, instructions); + + case OTHER : + default : + obs = Context + .getRegisteredComponent(AttachmentsConstants.COMPONENT_COMPLEXOBS_SAVER, ComplexObsSaver.class) + .saveOtherAttachment(visit, patient, encounter, fileCaption, file, instructions); break; } - + return ConversionUtil.convertToRepresentation(obs, - new CustomRepresentation(AttachmentsConstants.REPRESENTATION_OBS)); + new CustomRepresentation(AttachmentsConstants.REPRESENTATION_OBS)); } - + private boolean isValidImage(InputStream fileStream) { try { BufferedImage image = ImageIO.read(fileStream); image.getHeight(); image.getWidth(); return true; - } - catch (IOException e) { + } catch (IOException e) { return false; - } - finally { + } finally { if (fileStream.markSupported()) { try { fileStream.reset(); + } catch (IOException e) { } - catch (IOException e) {} } } } - + @Override public DelegatingResourceDescription getCreatableProperties() { DelegatingResourceDescription description = new DelegatingResourceDescription(); @@ -246,21 +249,21 @@ public DelegatingResourceDescription getCreatableProperties() { description.addProperty("complexData"); return description; } - + @Override public Model getCREATEModel(Representation rep) { return new ModelImpl().property("comment", new StringProperty()).property("dateTime", new DateProperty()) - .property("filename", new StringProperty()).property("bytesMimeType", new StringProperty()) - - .property("bytesContentFamily", new EnumProperty(AttachmentsConstants.ContentFamily.class)) - .property("complexData", new StringProperty(StringProperty.Format.URI)); + .property("filename", new StringProperty()).property("bytesMimeType", new StringProperty()) + + .property("bytesContentFamily", new EnumProperty(AttachmentsConstants.ContentFamily.class)) + .property("complexData", new StringProperty(StringProperty.Format.URI)); } - + @Override public Model getUPDATEModel(Representation rep) { return getCREATEModel(rep); } - + @Override public DelegatingResourceDescription getRepresentationDescription(Representation rep) { DelegatingResourceDescription description = new DelegatingResourceDescription(); @@ -273,16 +276,16 @@ public DelegatingResourceDescription getRepresentationDescription(Representation description.addSelfLink(); return description; } - + @Override public Model getGETModel(Representation rep) { ModelImpl model = (ModelImpl) super.getGETModel(rep); return model.property("uuid", new StringProperty()).property("dateTime", new DateProperty()) - .property("filename", new StringProperty()).property("comment", new StringProperty()) - .property("bytesMimeType", new StringProperty()) - .property("bytesContentFamily", new EnumProperty(AttachmentsConstants.ContentFamily.class)); + .property("filename", new StringProperty()).property("comment", new StringProperty()) + .property("bytesMimeType", new StringProperty()) + .property("bytesContentFamily", new EnumProperty(AttachmentsConstants.ContentFamily.class)); } - + /** * Voids the encounter if it contains no non-voided obs. * @@ -295,11 +298,12 @@ public static void voidEncounterIfEmpty(EncounterService encounterService, Strin encounterService.voidEncounter(encounter, "foo"); } } - + /** * Get the Attachments using AttachmentService. * - * @param as specifies the AttachmentService instance. + * @param as + * specifies the AttachmentService instance. * @param patient * @param visit * @param encounter @@ -307,16 +311,17 @@ public static void voidEncounterIfEmpty(EncounterService encounterService, Strin * @param includeVoided */ public List search(AttachmentsService as, Patient patient, Visit visit, Encounter encounter, - String includeEncounterless, boolean includeVoided) { - + String includeEncounterless, boolean includeVoided) { + List attachmentList = new ArrayList<>(); - + if (includeEncounterless != null) { if (includeEncounterless.equals("only")) { attachmentList = as.getEncounterlessAttachments(patient, includeVoided); - + } else { - attachmentList = as.getAttachments(patient, BooleanUtils.toBoolean(includeEncounterless), includeVoided); + attachmentList = as.getAttachments(patient, BooleanUtils.toBoolean(includeEncounterless), + includeVoided); } } else { if (encounter != null && visit == null) { @@ -328,16 +333,16 @@ public List search(AttachmentsService as, Patient patient, Visit vis if (encounter == null && visit == null) { attachmentList = as.getAttachments(patient, includeVoided); } - + } return attachmentList; } - + /** - * Get Attachments by given parameters (paged according to context if necessary) only if a patient - * parameter exists in the request set on the {@link RequestContext}, optional encounter, visit , - * includeEncounterless , includeVoided request parameters can be specified to filter the - * attachments. + * Get Attachments by given parameters (paged according to context if necessary) + * only if a patient parameter exists in the request set on the + * {@link RequestContext}, optional encounter, visit , includeEncounterless , + * includeVoided request parameters can be specified to filter the attachments. * * @param context * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#doSearch(org.openmrs.module.webservices.rest.web.RequestContext) @@ -345,61 +350,62 @@ public List search(AttachmentsService as, Patient patient, Visit vis */ @Override protected PageableResult doSearch(RequestContext context) { - + // Prepare Parameters Patient patient = Context.getPatientService().getPatientByUuid(context.getParameter("patient")); Visit visit = Context.getVisitService().getVisitByUuid(context.getParameter("visit")); Encounter encounter = Context.getEncounterService().getEncounterByUuid(context.getParameter("encounter")); String includeEncounterless = context.getParameter("includeEncounterless"); boolean includeVoided = BooleanUtils.toBoolean(context.getParameter("includeVoided")); - + // Verify Parameters if (patient == null) { throw new IllegalRequestException("A patient parameter must be provided when searching the attachments."); } - + // Search Attachments List attachmentList = search( - Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) - .getAttachmentsService(), - patient, visit, encounter, includeEncounterless, includeVoided); - + Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class) + .getAttachmentsService(), + patient, visit, encounter, includeEncounterless, includeVoided); + if (attachmentList != null) { return new NeedsPaging<>(attachmentList, context); } return new EmptySearchResult(); } - + /** * Wrapper class to be passed to ComplexObsSaver#saveImageAttachment - * ComplexObsSaver#saveImageAttachment needs a MultipartFile but the image could either be a - * MultipartFile or a base64 encoded image. This class will only implement the methods used by - * ComplexObsSaver#saveImageAttachment. This way we won't have to make any changes to the - * implementation of ComplexObsSaver#saveImageAttachment and will also make very little change to - * the AttachmentResource1_10#upload implementation. This is also helps us avoid adding an extra - * dependency to MockMultipartFile for converting the base64 encoded String to a MultipartFile - * object. + * ComplexObsSaver#saveImageAttachment needs a MultipartFile but the image could + * either be a MultipartFile or a base64 encoded image. This class will only + * implement the methods used by ComplexObsSaver#saveImageAttachment. This way + * we won't have to make any changes to the implementation of + * ComplexObsSaver#saveImageAttachment and will also make very little change to + * the AttachmentResource1_10#upload implementation. This is also helps us avoid + * adding an extra dependency to MockMultipartFile for converting the base64 + * encoded String to a MultipartFile object. */ static final class Base64MultipartFile implements MultipartFile { - + private final String fileName; - + private final String originalFileName; - + private final String contentType; - + private final long size; - + private final InputStream in; - + private final byte[] bytes; - + public Base64MultipartFile(String base64Image, String fileName, String originalFileName) throws IOException { String[] parts = base64Image.split(",", 2); String contentType = parts[0].split(":")[1].split(";")[0].trim(); String contents = parts[1].trim(); byte[] decodedImage = Base64.decodeBase64(contents.getBytes()); - + this.fileName = fileName; this.originalFileName = originalFileName; this.in = new ByteArrayInputStream(decodedImage); @@ -407,46 +413,46 @@ public Base64MultipartFile(String base64Image, String fileName, String originalF this.bytes = decodedImage; this.size = decodedImage.length; } - + @Override public String getName() { return this.fileName; } - + @Override public String getOriginalFilename() { return this.originalFileName; } - + @Override public String getContentType() { return this.contentType; } - + @Override public boolean isEmpty() { return false; } - + @Override public long getSize() { return this.size; } - + @Override public byte[] getBytes() { return this.bytes; } - + @Override public InputStream getInputStream() { return this.in; } - + @Override public void transferTo(File dest) throws IllegalStateException { throw new APIException("Operation transferTo is not supported for Base64MultipartFile"); } } - + } diff --git a/omod/src/main/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandler.java b/omod/src/main/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandler.java index dee6bc89..9f03ddba 100644 --- a/omod/src/main/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandler.java +++ b/omod/src/main/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandler.java @@ -29,100 +29,102 @@ import org.springframework.stereotype.Component; /** - * The contents of this file are subject to the OpenMRS Public License Version 1.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://license.openmrs.org Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the - * specific language governing rights and limitations under the License. Copyright (C) OpenMRS, LLC. - * All Rights Reserved. + * The contents of this file are subject to the OpenMRS Public License Version + * 1.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://license.openmrs.org + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ @Component public class ObsByConceptListSearchHandler implements SearchHandler { - + protected final Log log = LogFactory.getLog(getClass()); - + @Autowired @Qualifier(AttachmentsConstants.COMPONENT_ATT_CONTEXT) protected AttachmentsContext context; - + private final SearchConfig searchConfig = new SearchConfig("obsByConceptList", RestConstants.VERSION_1 + "/obs", - Arrays.asList("2.2.*", "2.3.*", "2.4.*", "2.5.*", "2.6.*"), - Arrays.asList( - new SearchQuery.Builder("Allows you to retrieve Observations for a patient and a for list of concepts") - .withRequiredParameters("patient", "conceptList").build())); - + Arrays.asList("2.2.*", "2.3.*", "2.4.*", "2.5.*", "2.6.*"), + Arrays.asList(new SearchQuery.Builder( + "Allows you to retrieve Observations for a patient and a for list of concepts") + .withRequiredParameters("patient", "conceptList").build())); + @Override public SearchConfig getSearchConfig() { return this.searchConfig; } - + @Override public PageableResult search(RequestContext requestContext) throws ResponseException { - + String patientUuid = requestContext.getRequest().getParameter("patient"); - + String conceptListStr = requestContext.getRequest().getParameter("conceptList"); - + List conceptList = parseConceptList(conceptListStr, context.getConceptService()); - + if (patientUuid != null) { - + Patient patient = context.getPatientService().getPatientByUuid(patientUuid); - + if (patient == null) { log.warn("Patient \"" + patientUuid + "\" was not found. Returning empty set."); return new EmptySearchResult(); } - + List obsList = new ArrayList<>(); - + if (patient != null & conceptList.size() != 0) { - + ObsService obsService = context.getObsService(); - + for (Concept concept : conceptList) { obsList.addAll(obsService.getObservationsByPersonAndConcept(patient, concept)); } } - + if (obsList.size() != 0) { // Sorting obs by descending obsDatetime Collections.sort(obsList, new Comparator() { - + public int compare(Obs obs1, Obs obs2) { return obs2.getObsDatetime().compareTo(obs1.getObsDatetime()); } }); - + return new NeedsPaging(obsList, requestContext); } } - + return new EmptySearchResult(); } - + /** - * Returns a {@link List} of {@link Concept} from a provided {@link String} of comma separated - * concepts. Each concept of the list can be provided either as UUID or as Concept Mapping + * Returns a {@link List} of {@link Concept} from a provided {@link String} of + * comma separated concepts. Each concept of the list can be provided either as + * UUID or as Concept Mapping * * @param conceptListStr * @param conceptService * @return a list of concepts */ protected List parseConceptList(String conceptListStr, ConceptService conceptService) { - + List conceptUuidsList = Arrays.asList(conceptListStr.split("\\s*,\\s*")); - + List conceptList = new ArrayList<>(); - + if (conceptUuidsList != null) { for (String conceptStr : conceptUuidsList) { - + Concept concept = new Concept(); - + // See if the concept is a mapping or a uuid List conceptMapping = Arrays.asList(conceptStr.split(":")); - + if (conceptMapping.size() > 1) { // it is a mapping concept = conceptService.getConceptByMapping(conceptMapping.get(1), conceptMapping.get(0)); @@ -130,7 +132,7 @@ protected List parseConceptList(String conceptListStr, ConceptService c // it is a uuid concept = conceptService.getConceptByUuid(conceptStr); } - + if (concept == null) { log.warn("Concept \"" + conceptStr + "\" was not found. Ignoring it."); } else { @@ -138,8 +140,8 @@ protected List parseConceptList(String conceptListStr, ConceptService c } } } - + return conceptList; - + } } diff --git a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceIntegrationTest.java b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceIntegrationTest.java index ba773a35..5409bde1 100644 --- a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceIntegrationTest.java +++ b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceIntegrationTest.java @@ -12,38 +12,38 @@ import org.springframework.beans.factory.annotation.Autowired; public class AttachmentResourceIntegrationTest extends BaseDelegatingResourceTest { - + @Autowired protected TestHelper testHelper; - + private Obs obs; - + @Before public void before() throws Exception { testHelper.init(); obs = testHelper.saveNormalSizeImageAttachment(); } - + @After public void tearDown() throws IOException { testHelper.tearDown(); } - + @Override public Attachment newObject() { return new Attachment(obs); } - + @Override public String getDisplayProperty() { return null; } - + @Override public String getUuidProperty() { return obs.getUuid(); } - + @Override public void validateDefaultRepresentation() throws Exception { super.validateDefaultRepresentation(); diff --git a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceTest.java b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceTest.java index 8c83727f..c0042c98 100644 --- a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceTest.java +++ b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentResourceTest.java @@ -36,7 +36,7 @@ @PrepareForTest(Context.class) @PowerMockIgnore("javax.management.*") public class AttachmentResourceTest { - + @Before public void setup() { initMocks(this); @@ -44,9 +44,9 @@ public void setup() { AttachmentsContext ctx = mock(AttachmentsContext.class); when(ctx.getComplexDataHelper()).thenReturn(new ComplexDataHelperImpl()); when(Context.getRegisteredComponent(AttachmentsConstants.COMPONENT_ATT_CONTEXT, AttachmentsContext.class)) - .thenReturn(ctx); + .thenReturn(ctx); } - + @Test public void get_shouldReturnFilenameProperty() { // Arrange @@ -64,14 +64,14 @@ public void get_shouldReturnFilenameProperty() { attachmentObs.setValueComplex("m3ks | instructions.default | text/plain | filename.png"); when(service.getObsByUuid("1234")).thenReturn(attachmentObs); when(service.getComplexObs(1, AttachmentsConstants.ATT_VIEW_CRUD)).thenReturn(attachmentObs); - + // Act Attachment attachment = res.getByUniqueId("1234"); - + // Assert assertThat(attachment.getFilename(), equalTo("filename.png")); } - + @Test public void search_shouldInvokeApiForEncounterAttachments() { // Setup @@ -79,15 +79,15 @@ public void search_shouldInvokeApiForEncounterAttachments() { AttachmentsService attachmentsService = mock(AttachmentsService.class); Patient patient = new Patient(); Encounter encounter = new Encounter(); - + // Replay res.search(attachmentsService, patient, null, encounter, null, true); - + // Verify verify(attachmentsService, times(1)).getAttachments(patient, encounter, true); verifyNoMoreInteractions(attachmentsService); } - + @Test public void search_shouldInvokeApiForVisitAttachments() { // Setup @@ -95,55 +95,55 @@ public void search_shouldInvokeApiForVisitAttachments() { AttachmentsService attachmentsService = mock(AttachmentsService.class); Patient patient = new Patient(); Visit visit = new Visit(); - + // Replay res.search(attachmentsService, patient, visit, null, null, true); - + // Verify verify(attachmentsService, times(1)).getAttachments(patient, visit, true); verifyNoMoreInteractions(attachmentsService); } - + @Test public void search_shouldInvokeApiForAllAttachments() { // Setup AttachmentResource res = new AttachmentResource(); AttachmentsService attachmentsService = mock(AttachmentsService.class); Patient patient = new Patient(); - + // Replay res.search(attachmentsService, patient, null, null, null, true); - + // Verify verify(attachmentsService, times(1)).getAttachments(patient, true); verifyNoMoreInteractions(attachmentsService); } - + @Test public void search_shouldInvokeApiForEncounterlessAttachments() { // Setup AttachmentResource res = new AttachmentResource(); AttachmentsService attachmentsService = mock(AttachmentsService.class); Patient patient = new Patient(); - + // Replay res.search(attachmentsService, patient, null, null, "only", true); - + // Verify verify(attachmentsService, times(1)).getEncounterlessAttachments(patient, true); verifyNoMoreInteractions(attachmentsService); } - + @Test public void search_shouldInvokeApiForAllAttachmentsButEncounterless() { // Setup AttachmentResource res = new AttachmentResource(); AttachmentsService attachmentsService = mock(AttachmentsService.class); Patient patient = new Patient(); - + // Replay res.search(attachmentsService, patient, null, null, "false", true); - + // Verify verify(attachmentsService, times(1)).getAttachments(patient, false, true); verifyNoMoreInteractions(attachmentsService); diff --git a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentRestControllerTest.java b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentRestControllerTest.java index 136fc7b2..b78b79bc 100644 --- a/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentRestControllerTest.java +++ b/omod/src/test/java/org/openmrs/module/attachments/rest/AttachmentRestControllerTest.java @@ -47,195 +47,195 @@ import org.springframework.web.bind.annotation.RequestMethod; public class AttachmentRestControllerTest extends MainResourceControllerTest { - + @Autowired protected ObsService obsService; - + @Autowired protected TestHelper testHelper; - + @Autowired private AttachmentsContext ctx; - + private byte[] randomData = new byte[20]; - + private Obs obs; - + @Before public void setup() throws IOException { testHelper.init(); obs = testHelper.getTestComplexObs(); new Random().nextBytes(randomData); } - + @After public void tearDown() throws IOException { testHelper.tearDown(); } - + @Override public String getURI() { return AttachmentsConstants.ATTACHMENT_URI; } - + @Override public String getUuid() { return obs.getUuid(); } - + @Override public long getAllCount() { return 0; } - + @Override @Test public void shouldGetAll() { } - + @Override @Test public void shouldGetDefaultByUuid() { } - + @Override @Test public void shouldGetRefByUuid() { } - + @Override @Test public void shouldGetFullByUuid() { } - + @Test public void getAttachment_shouldGetAttachment() throws Exception { // Setup MockHttpServletRequest req = request(RequestMethod.GET, getURI() + "/" + getUuid()); - + // Replay SimpleObject result = deserialize(handle(req)); - + // Verify Assert.assertEquals(getUuid(), PropertyUtils.getProperty(result, "uuid")); Assert.assertNotNull(PropertyUtils.getProperty(result, "comment")); Assert.assertNotNull(PropertyUtils.getProperty(result, "bytesMimeType")); Assert.assertNotNull(PropertyUtils.getProperty(result, "bytesContentFamily")); } - + @Test public void getBytesMimeType_shouldGetBytesMimeTypeOfAttachment() throws Exception { // Setup MockHttpServletRequest req = request(RequestMethod.GET, getURI() + "/" + getUuid()); - + // Replay SimpleObject result = deserialize(handle(req)); - + ComplexData complexData = obs.getComplexData(); - + // Verify assertEquals(result.get("bytesMimeType"), ctx.getComplexDataHelper().getContentType(complexData)); assertEquals(result.get("bytesMimeType"), "application/octet-stream"); } - + @Test public void getBytesContentFamily_getshouldGetBytesContentFamilyOfAttachment() throws Exception { // Setup MockHttpServletRequest req = request(RequestMethod.GET, getURI() + "/" + getUuid()); - + // Replay SimpleObject result = deserialize(handle(req)); - + ComplexData complexData = obs.getComplexData(); ContentFamily contentFamily = AttachmentsContext - .getContentFamily(ctx.getComplexDataHelper().getContentType(complexData)); - + .getContentFamily(ctx.getComplexDataHelper().getContentType(complexData)); + // Verify assertEquals(result.get("bytesContentFamily"), contentFamily.toString()); assertEquals(result.get("bytesContentFamily"), "OTHER"); } - + @Test public void deleteAttachment_shouldVoidObs() throws Exception { - + // Setup File file = new File(testHelper.getTestComplexObsFilePath()); - + // Replay handle(newDeleteRequest(getURI() + "/" + getUuid())); - + // Verify assertTrue(obsService.getObsByUuid(getUuid()).isVoided()); } - + @Test public void deleteAttachmentWithMissingFile_shouldVoidObs() throws Exception { // Setup File file = new File(testHelper.getTestComplexObsFilePath()); file.delete(); assertFalse(file.exists()); - + // Replay handle(newDeleteRequest(getURI() + "/" + getUuid())); - + // Verify assertTrue(obsService.getObsByUuid(getUuid()).isVoided()); } - + @Test public void purgeAttachment_shouldPurgeObsAndRemoveFile() throws Exception { // Setup String testComplexObsFilePath = FilenameUtils.removeExtension(testHelper.getTestComplexObsFilePath()) + "_" - + obs.getUuid() + "." + FilenameUtils.getExtension(testHelper.getTestComplexObsFilePath()); + + obs.getUuid() + "." + FilenameUtils.getExtension(testHelper.getTestComplexObsFilePath()); File file = new File(testComplexObsFilePath); assertTrue(file.exists()); - + // Replay handle(newDeleteRequest(getURI() + "/" + getUuid(), new Parameter("purge", "true"))); - + // Verify assertNull(obsService.getObsByUuid(getUuid())); assertFalse(file.exists()); } - + @Test public void purgeAttachmentWithMissingFile_shouldPurgeObs() throws Exception { // Setup File file = new File(testHelper.getTestComplexObsFilePath()); file.delete(); assertFalse(file.exists()); - + // Replay handle(newDeleteRequest(getURI() + "/" + getUuid(), new Parameter("purge", "true"))); - + // Verify assertNull(obsService.getObsByUuid(getUuid())); } - + @Test public void deleteAttachment_shouldVoidObsWithoutAssociatedEncounter() throws Exception { // Setup Obs obs = testHelper.getTestComplexObsWithoutAssociatedEncounterOrVisit(); - + // Replay handle(newDeleteRequest(getURI() + "/" + obs.getUuid())); - + // Verify assertTrue(obsService.getObsByUuid(obs.getUuid()).isVoided()); } - + @Test public void purgeAttachment_shouldPurgeObsWithoutAssociatedEncounter() throws Exception { // Setup Obs obs = testHelper.getTestComplexObsWithoutAssociatedEncounterOrVisit(); - + // Replay handle(newDeleteRequest(getURI() + "/" + obs.getUuid(), new Parameter("purge", "true"))); - + // Verify assertNull(obsService.getObsByUuid(obs.getUuid())); } - + @Test public void postAttachment_shouldUploadFileToVisit() throws Exception { String fileCaption = "Test file caption"; @@ -244,21 +244,21 @@ public void postAttachment_shouldUploadFileToVisit() throws Exception { String fileName = "testFile1.dat"; Patient patient = Context.getPatientService().getPatient(2); Visit visit = Context.getVisitService().getVisit(1); - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", randomData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("visit", visit.getUuid()); request.addParameter("fileCaption", fileCaption); - + // Replay SimpleObject response = deserialize(handle(request)); fileName = "testFile1_" + (String) response.get("uuid") + ".dat"; Obs obs = Context.getObsService().getObsByUuid((String) response.get("uuid")); ComplexData complexData = obs.getComplexData(); - + // Verify Assert.assertEquals(obs.getComment(), fileCaption); Assert.assertEquals(complexData.getTitle(), fileName); @@ -267,37 +267,37 @@ public void postAttachment_shouldUploadFileToVisit() throws Exception { Assert.assertEquals(obs.getEncounter().getEncounterType(), ctx.getEncounterType()); } } - + @Test public void postAttachment_shouldUploadFileAsEncounterless() throws Exception { String fileCaption = "Test file caption"; - + // Setup String fileName = "testFile2.dat"; Patient patient = Context.getPatientService().getPatient(2); - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", randomData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("fileCaption", fileCaption); - + // Replay SimpleObject response = deserialize(handle(request)); - + Obs obs = Context.getObsService().getObsByUuid(response.get("uuid")); fileName = "testFile2_" + response.get("uuid") + ".dat"; ComplexData complexData = obs.getComplexData(); - + // Verify Assert.assertEquals(obs.getComment(), fileCaption); Assert.assertEquals(complexData.getTitle(), fileName); Assert.assertArrayEquals(randomData, (byte[]) complexData.getData()); Assert.assertNull(obs.getEncounter()); - + } - + @Test public void postAttachment_shouldUploadFileToEncounter() throws Exception { String fileCaption = "Test file caption"; @@ -305,28 +305,28 @@ public void postAttachment_shouldUploadFileToEncounter() throws Exception { String fileName = "testFile3.dat"; Patient patient = Context.getPatientService().getPatient(2); Encounter encounter = testHelper.getTestEncounter(); - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", randomData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("encounter", encounter.getUuid()); request.addParameter("fileCaption", fileCaption); - + // Replay SimpleObject response = deserialize(handle(request)); fileName = "testFile3_" + (String) response.get("uuid") + ".dat"; Obs obs = Context.getObsService().getObsByUuid((String) response.get("uuid")); ComplexData complexData = obs.getComplexData(); - + // Verify Assert.assertEquals(obs.getComment(), fileCaption); Assert.assertEquals(complexData.getTitle(), fileName); Assert.assertArrayEquals(randomData, (byte[]) complexData.getData()); Assert.assertEquals(obs.getEncounter().getUuid(), encounter.getUuid()); } - + @Test public void postAttachment_shouldAcceptBase64Content() throws Exception { // Read file OpenMRS_logo.png and copy bytes to baos @@ -335,39 +335,39 @@ public void postAttachment_shouldAcceptBase64Content() throws Exception { Objects.requireNonNull(inputStream); img = ImageIO.read(inputStream); } - + ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(img, "png", baos); - + // Build the request parameters byte[] bytesIn = baos.toByteArray(); String fileCaption = "Test file caption"; String fileName = "testFile2.png"; String base64Content = "data:image/png;base64," + Base64.encodeBase64String(bytesIn); Patient patient = Context.getPatientService().getPatient(2); - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", randomData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("fileCaption", fileCaption); request.addParameter("base64Content", base64Content); - + // Replay SimpleObject response = deserialize(handle(request)); - + Obs obs = Context.getObsService().getObsByUuid(response.get("uuid")); ComplexData complexData = obs.getComplexData(); byte[] bytesOut = BaseComplexData.getByteArray(complexData); - + // Verify Assert.assertEquals(obs.getComment(), fileCaption); Assert.assertTrue(complexData.getTitle().startsWith("testFile2")); Assert.assertArrayEquals(bytesIn, bytesOut); Assert.assertNull(obs.getEncounter()); } - + @Test(expected = IllegalRequestException.class) public void postAttachment_shouldThrowWhenVisitAndEncounterDoNotMatch() throws Exception { // Setup @@ -376,20 +376,20 @@ public void postAttachment_shouldThrowWhenVisitAndEncounterDoNotMatch() throws E Patient patient = Context.getPatientService().getPatient(2); Visit visit = Context.getVisitService().getVisit(1); Encounter encounter = Context.getEncounterService().getEncounter(3); - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", randomData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("visit", visit.getUuid()); request.addParameter("encounter", encounter.getUuid()); request.addParameter("fileCaption", fileCaption); - + // Replay SimpleObject response = deserialize(handle(request)); } - + @Test(expected = IllegalRequestException.class) public void postAttachment_shouldNotUploadFileAboveSizeLimit() throws Exception { // Setup @@ -397,88 +397,88 @@ public void postAttachment_shouldNotUploadFileAboveSizeLimit() throws Exception String fileName = "testFile1.dat"; Patient patient = Context.getPatientService().getPatient(2); Visit visit = Context.getVisitService().getVisit(1); - + byte[] maxData = new byte[(int) ((ctx.getMaxUploadFileSize() * 1024 * 1024) + 1)]; - + MockMultipartHttpServletRequest request = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, "application/octet-stream", maxData); - + request.addFile(file); request.addParameter("patient", patient.getUuid()); request.addParameter("visit", visit.getUuid()); request.addParameter("fileCaption", fileCaption); - + // Replay SimpleObject response = deserialize(handle(request)); } - + @Test public void getAttachmentBytes_shouldDownloadFile() throws Exception { - + // Setup String fileCaption = "Test file caption"; String uuid; String mimeType = "application/octet-stream"; String fileExtension = "dat"; String fileName = "testFile." + fileExtension; - + // Upload Test File Patient patient = Context.getPatientService().getPatient(2); MockMultipartHttpServletRequest uploadRequest = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, mimeType, randomData); - + uploadRequest.addFile(file); uploadRequest.addParameter("patient", patient.getUuid()); uploadRequest.addParameter("fileCaption", fileCaption); - + SimpleObject uploadResponse = deserialize(handle(uploadRequest)); uuid = uploadResponse.get("uuid"); fileName = "testFile_" + uuid + "." + fileExtension; - + HttpServletRequest downloadRequest = newGetRequest(getURI() + "/" + uuid + "/bytes"); - + // Replay MockHttpServletResponse downloadResponse = handle(downloadRequest); byte[] bytesContent = downloadResponse.getContentAsByteArray(); - + // Verify Assert.assertArrayEquals(randomData, bytesContent); Assert.assertEquals(downloadResponse.getContentType(), mimeType); Assert.assertEquals(downloadResponse.getHeader("File-Name"), fileName); Assert.assertEquals(downloadResponse.getHeader("File-Ext"), fileExtension); - + } - + @Test public void doSearch_shouldGetAttachmentsWithMimeTypesAndContentFamilySet() throws Exception { - + // Setup String fileCaption = "Test file caption"; String mimeType = "application/octet-stream"; String fileExtension = "dat"; String fileName = "testFile." + fileExtension; - + Patient patient = Context.getPatientService().getPatient(6); MockMultipartHttpServletRequest uploadRequest = newUploadRequest(getURI()); MockMultipartFile file = new MockMultipartFile("file", fileName, mimeType, randomData); - + uploadRequest.addFile(file); uploadRequest.addParameter("patient", patient.getUuid()); uploadRequest.addParameter("fileCaption", fileCaption); - + // Save attachment deserialize(handle(uploadRequest)); - + // Search attachments for patient MockHttpServletRequest request = request(RequestMethod.GET, getURI()); request.addParameter("patient", patient.getUuid()); SimpleObject response = deserialize(handle(request)); LinkedHashMap result = (LinkedHashMap) ((ArrayList) response - .get("results")).get(0); - + .get("results")).get(0); + // Verify Assert.assertEquals("application/octet-stream", result.get("bytesMimeType")); Assert.assertEquals(ContentFamily.OTHER.toString(), result.get("bytesContentFamily")); } - + } diff --git a/omod/src/test/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandlerTest.java b/omod/src/test/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandlerTest.java index 0794eab0..7b1c3931 100644 --- a/omod/src/test/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandlerTest.java +++ b/omod/src/test/java/org/openmrs/module/attachments/rest/ObsByConceptListSearchHandlerTest.java @@ -23,81 +23,81 @@ @SuppressWarnings("unchecked") public class ObsByConceptListSearchHandlerTest extends MainResourceControllerTest { - + private String PATIENT_UUID = "5946f880-b197-400b-9caa-a3c661d23041"; - + private String CONCEPT_1_UUID = "a09ab2c5-878e-4905-b25d-5784167d0216"; - + private String CONCEPT_2_UUID = "c607c80f-1ea9-4da3-bb88-6276ce8868dd"; - + private String CONCEPT_2_SOURCE = "CIEL"; - + private String CONCEPT_2_NUMBER = "5089"; - + private String CONCEPT_3_UUID = "96408258-000b-424e-af1a-403919332938"; - + private ObsService obsService; - + private ConceptService conceptService; - + @Autowired private AttachmentsContext context; - + @Before public void init() throws Exception { obsService = context.getObsService(); conceptService = context.getConceptService(); } - + @Test public void search_shouldReturnObsByPatientAndConceptList() throws Exception { MockHttpServletRequest req = request(RequestMethod.GET, getURI()); - + req.addParameter("patient", PATIENT_UUID); req.addParameter("conceptList", CONCEPT_1_UUID + "," + CONCEPT_2_UUID + "," + CONCEPT_3_UUID); - + SimpleObject result = deserialize(handle(req)); List hits = (List) result.get("results"); - + Assert.assertEquals(6, hits.size()); } - + @Test public void search_shouldReturnEmptyWhenPatientIsNotFound() throws Exception { MockHttpServletRequest req = request(RequestMethod.GET, getURI()); - + req.addParameter("patient", "abcd-e"); req.addParameter("conceptList", CONCEPT_1_UUID + "," + CONCEPT_2_UUID + "," + CONCEPT_3_UUID); - + SimpleObject result = deserialize(handle(req)); List hits = (List) result.get("results"); - + Assert.assertEquals(0, hits.size()); } - + @Test public void search_shouldIgnoreNonExisitingConcept() throws Exception { MockHttpServletRequest req = request(RequestMethod.GET, getURI()); - + req.addParameter("patient", PATIENT_UUID); req.addParameter("conceptList", CONCEPT_1_UUID + "," + "abc1-mks-123a" + "," + CONCEPT_3_UUID); - + SimpleObject result = deserialize(handle(req)); List hits = (List) result.get("results"); - + Assert.assertEquals(3, hits.size()); } - + @Test public void search_shouldSortByDescendingOrder() throws Exception { MockHttpServletRequest req = request(RequestMethod.GET, getURI()); - + req.addParameter("patient", PATIENT_UUID); req.addParameter("conceptList", CONCEPT_1_UUID + "," + CONCEPT_2_UUID + "," + CONCEPT_3_UUID); - + SimpleObject result = deserialize(handle(req)); List hits = (List) result.get("results"); - + for (int i = 0; i < hits.size(); i++) { Obs obs1 = obsService.getObsByUuid((String) PropertyUtils.getProperty(hits.get(i), "uuid")); if (i > 0) { @@ -106,34 +106,34 @@ public void search_shouldSortByDescendingOrder() throws Exception { } } } - + // @Ignore("The standardTestDataset.xml does not create mappings. Skipping this // test") @Test public void parseConceptList_shouldHandleMappingsAndUuids() throws Exception { - + String conceptListStr = CONCEPT_1_UUID + "," + CONCEPT_2_SOURCE + ":" + CONCEPT_2_NUMBER + "," + CONCEPT_3_UUID; - + ConceptService conceptServiceMock = mock(ConceptService.class); - + when(conceptServiceMock.getConceptByMapping(CONCEPT_2_NUMBER, CONCEPT_2_SOURCE)) - .thenReturn(conceptService.getConceptByUuid(CONCEPT_2_UUID)); + .thenReturn(conceptService.getConceptByUuid(CONCEPT_2_UUID)); when(conceptServiceMock.getConceptByUuid(CONCEPT_1_UUID)) - .thenReturn(conceptService.getConceptByUuid(CONCEPT_1_UUID)); + .thenReturn(conceptService.getConceptByUuid(CONCEPT_1_UUID)); when(conceptServiceMock.getConceptByUuid(CONCEPT_3_UUID)) - .thenReturn(conceptService.getConceptByUuid(CONCEPT_3_UUID)); - + .thenReturn(conceptService.getConceptByUuid(CONCEPT_3_UUID)); + ObsByConceptListSearchHandler searchHandler = new ObsByConceptListSearchHandler(); List conceptList = searchHandler.parseConceptList(conceptListStr, conceptServiceMock); - + Assert.assertEquals(3, conceptList.size()); } - + @Override public String getUuid() { return "be48cdcb-6a76-47e3-9f2e-2635032f3a9a"; } - + /** * @see org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceControllerTest#shouldGetAll() */ @@ -142,12 +142,12 @@ public String getUuid() { public void shouldGetAll() throws Exception { super.shouldGetAll(); } - + @Override public String getURI() { return "obs"; } - + @Override public long getAllCount() { // This method is never called since the 'shouldGetAll' test is overridden and