/*
* The contents of this file are subject to the OpenMRS Public License
* Version 2.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.
*/
package org.openmrs.module.webservices.rest.resource;
import java.lang.reflect.ParameterizedType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.OpenmrsMetadata;
import org.openmrs.api.context.Context;
import org.openmrs.module.openhmis.commons.api.PagingInfo;
import org.openmrs.module.openhmis.commons.api.entity.IMetadataDataService;
import org.openmrs.module.openhmis.commons.api.exception.PrivilegeException;
import org.openmrs.module.webservices.rest.web.RequestContext;
import org.openmrs.module.webservices.rest.web.annotation.PropertyGetter;
import org.openmrs.module.webservices.rest.web.representation.DefaultRepresentation;
import org.openmrs.module.webservices.rest.web.representation.FullRepresentation;
import org.openmrs.module.webservices.rest.web.representation.RefRepresentation;
import org.openmrs.module.webservices.rest.web.representation.Representation;
import org.openmrs.module.webservices.rest.web.resource.api.PageableResult;
import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription;
import org.openmrs.module.webservices.rest.web.resource.impl.MetadataDelegatingCrudResource;
import org.springframework.dao.DataIntegrityViolationException;
/**
* REST resource for {@link org.openmrs.OpenmrsMetadata} entities.
* @param <E> The model class
*/
public abstract class BaseRestMetadataResource<E extends OpenmrsMetadata> extends MetadataDelegatingCrudResource<E>
implements IMetadataDataServiceResource<E> {
private static final Log LOG = LogFactory.getLog(BaseRestMetadataResource.class);
private Class<E> entityClass = null;
/**
* Instantiates a new entity instance.
* @return The new instance
*/
@Override
public abstract E newDelegate();
@Override
public abstract Class<? extends IMetadataDataService<E>> getServiceClass();
/**
* Saves the entity.
* @param entity The entity to save
* @return The saved entity
*/
@Override
public E save(E entity) {
try {
return getService().save(entity);
} catch (PrivilegeException p) {
LOG.error("Exception occured when trying to save entity <" + entity.getName() + "> as privilege is missing", p);
throw new PrivilegeException("Can't save entity with name <" + entity.getName() + "> as privilege is missing");
}
}
/**
* Gets the {@link DelegatingResourceDescription} for the specified {@link Representation}.
* @param rep The representation
* @return The resource description
*/
@Override
public DelegatingResourceDescription getRepresentationDescription(Representation rep) {
DelegatingResourceDescription description = new DelegatingResourceDescription();
description.addProperty("uuid");
description.addProperty("name");
description.addProperty("description");
description.addProperty("retired");
if (!(rep instanceof RefRepresentation)) {
description.addProperty("retireReason");
if (rep instanceof FullRepresentation) {
description.addProperty("auditInfo", findMethod("getAuditInfo"));
}
}
return description;
}
/**
* Gets a description of the properties that can be created.
* @return The resource description
*/
@Override
public DelegatingResourceDescription getCreatableProperties() {
DelegatingResourceDescription description = getRepresentationDescription(new DefaultRepresentation());
description.removeProperty("uuid");
description.removeProperty("retireReason");
return description;
}
/**
* Gets an entity by the UUID or {@code null} if not found.
* @param uniqueId The UUID for the entity
* @return The entity or null if not found
*/
@Override
public E getByUniqueId(String uniqueId) {
if (StringUtils.isEmpty(uniqueId)) {
return null;
}
E result = null;
// Ensure that a service is found for this resource. This is a fix for changes to the RESTWS module as of v2.12.
IMetadataDataService<E> service = getService();
if (service != null) {
try {
result = service.getByUuid(uniqueId);
} catch (PrivilegeException p) {
LOG.error("Exception occured when trying to get entity with ID <" + uniqueId
+ "> as privilege is missing", p);
throw new PrivilegeException("Can't get entity with ID <" + uniqueId + "> as privilege is missing");
}
}
return result;
}
/**
* Purges the entity from the database.
* @param entity The entity to purge
* @param context The request context
*/
@Override
public void purge(E entity, RequestContext context) {
try {
getService().purge(entity);
} catch (PrivilegeException p) {
LOG.error("Exception occured when trying to purge entity <" + entity.getName() + "> as privilege is missing", p);
throw new PrivilegeException("Can't purge entity with name <" + entity.getName() + "> as privilege is missing");
} catch (DataIntegrityViolationException e) {
LOG.error("Exception occured when trying to purge entity <" + entity.getName() + ">", e);
throw new DataIntegrityViolationException("Can't purge entity with name <" + entity.getName()
+ "> as it is still in use");
}
}
/**
* Gets all entities from the database using paging if specified in the context.
* @param context The request context
* @return A paged list of the entities
*/
@Override
protected PageableResult doGetAll(RequestContext context) {
PagingInfo pagingInfo = PagingUtil.getPagingInfoFromContext(context);
return new AlreadyPagedWithLength<E>(context, getService().getAll(context.getIncludeAll(), pagingInfo),
pagingInfo.hasMoreResults(), pagingInfo.getTotalRecordCount());
}
/**
* Finds all entities with a name that starts with the specified search query ('q' parameter).
* @param context The request context
* @return The paged results
*/
@Override
protected PageableResult doSearch(RequestContext context) {
context.setRepresentation(Representation.REF);
String query = context.getParameter("q");
return new MetadataSearcher<E>(getServiceClass()).searchByName(query, context);
}
/**
* Gets whether the specified entity is retired.
* @param entity The entity
* @return {@code true} if the entity is retired; otherwise, {@code false}
*/
@PropertyGetter("retired")
public Boolean getRetired(E entity) {
return entity.isRetired();
}
/**
* Gets the entity data service for this resource.
* @return The entity data service
*/
protected IMetadataDataService<E> getService() {
// Ensure that the service class is not null. This is a fix for changes to the RESTWS module as of v2.12.
Class<? extends IMetadataDataService<E>> cls = getServiceClass();
if (cls == null) {
return null;
} else {
return Context.getService(cls);
}
}
/**
* Gets a usable instance of the actual class of the generic type E defined by the implementing sub-class.
* @return The class object for the entity.
*/
@SuppressWarnings("unchecked")
public Class<E> getEntityClass() {
if (entityClass == null) {
ParameterizedType parameterizedType = (ParameterizedType)getClass().getGenericSuperclass();
entityClass = (Class)parameterizedType.getActualTypeArguments()[0];
}
return entityClass;
}
}