Skip to content

Commit

Permalink
Issue #7: Added support for switching on type and format code;
Browse files Browse the repository at this point in the history
added type code to Content object,
added type- formatCode handler map in service,
type- formatCode handling for the unstructured data handler.
  • Loading branch information
hnnesv committed Jul 14, 2014
1 parent e4082df commit 554121b
Show file tree
Hide file tree
Showing 7 changed files with 440 additions and 27 deletions.
Expand Up @@ -51,11 +51,28 @@ public class UnstructuredDataHandler implements ContentHandler {
protected static final String UNSTRUCTURED_DATA_HANDLER_GLOBAL_PROP = "shr.contenthandler.unstructureddatahandler.key";

protected final String contentType;
protected final String typeCode;
protected final String formatCode;


/**
* Construct a new unstructured data handler that references content via content type
*/
public UnstructuredDataHandler(String contentType) {
this.contentType = contentType;
typeCode = formatCode = null;
}

/**
* Construct a new unstructured data handler that references content via type and format code
*/
public UnstructuredDataHandler(String typeCode, String formatCode) {
this.typeCode = typeCode;
this.formatCode = formatCode;
this.contentType = null;
}


/**
* @see ContentHandler#saveContent(Patient, Provider, EncounterRole, EncounterType, Content)
* @should create a new encounter object using the current time
Expand Down Expand Up @@ -88,7 +105,7 @@ private Encounter createEncounter(Patient patient, Provider provider, EncounterR

private Obs createUnstructuredDataObs(Content content) {
Obs res = new Obs();
ComplexData cd = new ComplexData(contentType, content);
ComplexData cd = new ComplexData(buildTitle(), content);

res.setConcept(getUnstructuredAttachmentConcept(content.getFormatCode()));
res.setComplexData(cd);
Expand Down Expand Up @@ -220,7 +237,10 @@ private void getContentFromEncounter(List<Content> dst, Encounter enc) {
continue;
}

if (((Content)data).getContentType().equals(contentType)) {
String contentTitle = contentType!=null ? (((Content)data).getContentType()) :
((Content)data).getTypeCode() + ":" + ((Content)data).getFormatCode();

if (contentTitle.equals(buildTitle())) {
dst.add((Content)data);
}
}
Expand All @@ -230,13 +250,24 @@ private void getContentFromEncounter(List<Content> dst, Encounter enc) {
private boolean isConceptAnUnstructuredDataType(Concept c) {
return c.getName().getName().startsWith(UNSTRUCTURED_ATTACHMENT_CONCEPT_BASE_NAME);
}

/**
* Build a title that's suitable for referencing the complex obs
*/
private String buildTitle() {
return contentType!=null ? contentType : typeCode + ":" + formatCode;
}

/**
* @see ContentHandler#cloneHandler()
* @should return an UnstructuredDataHandler instance with the same content type
*/
@Override
public UnstructuredDataHandler cloneHandler() {
return new UnstructuredDataHandler(contentType);
if (contentType!=null) {
return new UnstructuredDataHandler(contentType);
} else {
return new UnstructuredDataHandler(typeCode, formatCode);
}
}
}
Expand Up @@ -22,7 +22,7 @@
/**
* A text based data payload.
* <p>
* This class follows the HL7 specification for ED datatypes (Encapsulated Data), but with the addition of a format code field.
* This class follows the HL7 specification for ED datatypes (Encapsulated Data), but with the addition of both a type and format code field.
* <p>
* The format code is a globally unique code identifying the format of the content and is determined as part of the implementation
* (e.g. IHE specifies various format codes for use with XDS documents).
Expand All @@ -32,7 +32,7 @@ public final class Content implements Comparable<Content>, Serializable {
/**
*
*/
private static final long serialVersionUID = -2101280624666285488L;
private static final long serialVersionUID = 76112365244123275L;


public static enum Representation {
Expand Down Expand Up @@ -78,6 +78,7 @@ public static enum CompressionFormat {
Z
}

private final String typeCode;
private final String formatCode;
private final String contentType;
private final String encoding;
Expand All @@ -91,10 +92,10 @@ public static enum CompressionFormat {
/**
* Creates a new Content object with a simple text payload. Good if the payload is an XML document for example.
*
* @see #Content(String, boolean, String, String, String, Representation, CompressionFormat, Locale)
* @see #Content(String, boolean, String, String, String, String, Representation, CompressionFormat, Locale)
*/
public Content(String payload, String formatCode, String contentType) {
this(payload, false, formatCode, contentType, null, Representation.TXT, null, null);
public Content(String payload, String typeCode, String formatCode, String contentType) {
this(payload, false, typeCode, formatCode, contentType, null, Representation.TXT, null, null);
}

/**
Expand All @@ -103,15 +104,17 @@ public Content(String payload, String formatCode, String contentType) {
* @param payload The payload can either contain the content or a url referencing the content's location
* @param payloadIsUrl The payload contains a URL string referencing a location where the content can be retrieved from.
* Note that the other metadata (e.g. content type) applies to the data, not the payload (i.e. the url string)
* @param typeCode The content type code
* @param formatCode The content format code
* @param contentType The content MIME type
* @param encoding (Nullable) The character set used for the content
* @param representation Indicates that the content is either text or base64 encoded
* @param compressionFormat (Nullable) The compression algorithm used by the content
* @param language (Nullable) The content language
*/
public Content(String payload, boolean payloadIsUrl, String formatCode, String contentType, String encoding, Representation representation, CompressionFormat compressionFormat, Locale language) {
public Content(String payload, boolean payloadIsUrl, String typeCode, String formatCode, String contentType, String encoding, Representation representation, CompressionFormat compressionFormat, Locale language) {
this.payload = payload;
this.typeCode = typeCode;
this.formatCode = formatCode;
this.contentType = contentType;
this.encoding = encoding;
Expand All @@ -128,6 +131,10 @@ public Content(String payload, boolean payloadIsUrl, String formatCode, String c
}


public String getTypeCode() {
return typeCode;
}

public String getFormatCode() {
return formatCode;
}
Expand Down
Expand Up @@ -69,4 +69,44 @@ public interface ContentHandlerService extends OpenmrsService {
* @should Do nothing if there is an invalid content type specified
*/
void deregisterContentHandler(String contentType);

/**
* Returns a content handler for a specified type and format code.
* Will return a default handler for unknown types.
* <p>
* @see #getContentHandler(String)
*
* @return An appropriate content handler for a specified content type
* @should Get an appropriate content handler for a specified content type
* @should Return a clone of the requested handler using the handler's cloneHandler method
* @should Return the default handler (UnstructuredDataHandler) for an unknown content type
* @should Never return null
*/
ContentHandler getContentHandler(String typeCode, String formatCode);

/**
* Register a content handler for a specified type and format code.
* <p>
* @see #registerContentHandler(String, ContentHandler)
* <p>
*
* @throws AlreadyRegisteredException if a handler is already registered for a specified type and format code
* @throws InvalidContentTypeException if an invalid type or format code is specified
* @should Register the specified handler for the specified type and format code
* @should Throw an AlreadyRegisteredException if a handler is already registered for a specified type and format code
* @should Throw an InvalidContentTypeException if an invalid type or format code is specified
* @should Throw a NullPointerException if prototype is null
*/
void registerContentHandler(String typeCode, String formatCode, ContentHandler prototype) throws AlreadyRegisteredException, InvalidContentTypeException;

/**
* Deregister the current handler assigned for the specified type and format code.
* <p>
* @see #deregisterContentHandler(String)
*
* @should Deregister the handler assigned for to specified contentType
* @should Do nothing if there is no handler assigned for a specified contentType
* @should Do nothing if there is an invalid content type specified
*/
void deregisterContentHandler(String typeCode, String formatCode);
}
Expand Up @@ -32,15 +32,17 @@ public class ContentHandlerServiceImpl extends BaseOpenmrsService implements Con

protected final Log log = LogFactory.getLog(this.getClass());

protected final Map<String, ContentHandler> handlers = new HashMap<String, ContentHandler>();
protected final Map<String, ContentHandler> contentTypeHandlers = new HashMap<String, ContentHandler>();
protected final Map<TypeFormatCode, ContentHandler> typeFormatCodeHandlers = new HashMap<TypeFormatCode, ContentHandler>();


@Override
public ContentHandler getContentHandler(String contentType) {
if (contentType==null || contentType.isEmpty() || !handlers.containsKey(contentType)) {
if (contentType==null || contentType.isEmpty() || !contentTypeHandlers.containsKey(contentType)) {
return new UnstructuredDataHandler(contentType);
}

return handlers.get(contentType).cloneHandler();
return contentTypeHandlers.get(contentType).cloneHandler();
}

@Override
Expand All @@ -55,11 +57,11 @@ public void registerContentHandler(String contentType,
throw new InvalidContentTypeException();
}

if (handlers.containsKey(contentType)) {
if (contentTypeHandlers.containsKey(contentType)) {
throw new AlreadyRegisteredException();
}

handlers.put(contentType, prototype);
contentTypeHandlers.put(contentType, prototype);
}

private static boolean isValidContentType(String contentType) {
Expand All @@ -70,6 +72,88 @@ private static boolean isValidContentType(String contentType) {

@Override
public void deregisterContentHandler(String contentType) {
handlers.remove(contentType);
contentTypeHandlers.remove(contentType);
}

@Override
public ContentHandler getContentHandler(String typeCode, String formatCode) {
if (typeCode==null || typeCode.isEmpty() ||
formatCode==null || formatCode.isEmpty() ||
!typeFormatCodeHandlers.containsKey(new TypeFormatCode(typeCode, formatCode))) {
return new UnstructuredDataHandler(typeCode, formatCode);
}

return typeFormatCodeHandlers.get(new TypeFormatCode(typeCode, formatCode)).cloneHandler();
}

@Override
public void registerContentHandler(String typeCode, String formatCode,
ContentHandler prototype) throws AlreadyRegisteredException,
InvalidContentTypeException {
if (prototype==null) {
throw new NullPointerException();
}

if (typeCode==null || typeCode.isEmpty() || formatCode==null || formatCode.isEmpty()) {
throw new InvalidContentTypeException();
}

TypeFormatCode codes = new TypeFormatCode(typeCode, formatCode);

if (typeFormatCodeHandlers.containsKey(codes)) {
throw new AlreadyRegisteredException();
}

typeFormatCodeHandlers.put(codes, prototype);

}

@Override
public void deregisterContentHandler(String typeCode, String formatCode) {
typeFormatCodeHandlers.remove(new TypeFormatCode(typeCode, formatCode));

}

private static class TypeFormatCode {
String typeCode;
String formatCode;

TypeFormatCode(String typeCode, String formatCode) {
this.typeCode = typeCode;
this.formatCode = formatCode;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((formatCode == null) ? 0 : formatCode.hashCode());
result = prime * result
+ ((typeCode == null) ? 0 : typeCode.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TypeFormatCode other = (TypeFormatCode) obj;
if (formatCode == null) {
if (other.formatCode != null)
return false;
} else if (!formatCode.equals(other.formatCode))
return false;
if (typeCode == null) {
if (other.typeCode != null)
return false;
} else if (!typeCode.equals(other.typeCode))
return false;
return true;
}
}
}

0 comments on commit 554121b

Please sign in to comment.