/**
* Copyright (C) 2012 KRM Associates, Inc. healtheme@krminc.com
*
* Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.krminc.phr.api.service;
import com.krminc.phr.api.converter.UsersConverter;
import com.krminc.phr.api.service.util.ServiceUtils;
import com.krminc.phr.core.AppConfig;
import com.krminc.phr.core.UserConfig;
import com.krminc.phr.dao.PersistenceService;
import com.krminc.phr.domain.HealthRecord;
import com.krminc.phr.domain.HealthrecordRequest;
import com.krminc.phr.domain.User;
import com.sun.jersey.api.core.ResourceContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author cmccall
*/
public class CareTakerUsersResource {
final Logger logger = LoggerFactory.getLogger(CareTakerUsersResource.class);
/**
*
*/
@Context
protected UriInfo uriInfo;
/**
*
*/
@Context
protected ResourceContext resourceContext;
/**
*
*/
@Context
protected SecurityContext securityContext;
/**
*
*/
@Context
protected transient HttpServletRequest servletRequest;
private User localUser;
/**
*
*/
public CareTakerUsersResource() {
}
/**
* Get method for retrieving a collection of User instance in XML format.
*
* @param start
* @param desc
* @param max
* @param orderBy
* @param username
* @param name
* @return an instance of UsersConverter
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public UsersConverter get(
@QueryParam("start") @DefaultValue("0") int start,
@QueryParam("max") @DefaultValue("10") int max,
@QueryParam("orderBy") @DefaultValue("name") String orderBy,
@QueryParam("desc") @DefaultValue("0") int desc,
@QueryParam("u") @DefaultValue("") String username,
@QueryParam("e") @DefaultValue("") String name
) {
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
persistenceSvc.beginTx();
return new UsersConverter(
getEntities(start, max, orderBy, desc, username, name),
uriInfo.getAbsolutePath(),
Api.DEFAULT_EXPAND_LEVEL + 2); //expand deep to pull in healthrecordID
} finally {
persistenceSvc.close();
}
}
/**
* Returns a dynamic instance of UserResource used for entity navigation.
*
* @param id
* @return an instance of UserResource
*/
@Path("{userId}/")
public UserResource getUserResource(@PathParam("userId") Long id) {
UserResource resource = resourceContext.getResource(UserResource.class);
resource.setId(id);
return resource;
}
/**
* Act as in logged in as user
*
* @param healthRecord
* @return
*/
@Path("access/{hrid}/")
@GET
public Response getAccess (@PathParam ("hrid") Long healthRecord) {
if (healthRecord != null)
{
HttpSession session = servletRequest.getSession(true);
session.setAttribute("healthRecordId", healthRecord);
return Response.seeOther(uriInfo.getBaseUri().resolve("." + AppConfig.PATH_PATIENT_ROOT + "/" + healthRecord + "/dashboard")).build();
} else {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
/**
* Remove a user from your care
*
* @param healthRecordIdToRemove
* @return
*/
@Path("remove/{hrid}/")
@GET
public JSONObject removeAccess (@PathParam ("hrid") Long healthRecordIdToRemove) {
JSONObject jsonResult = new JSONObject();
Boolean returnType = false;
if (healthRecordIdToRemove != null)
{
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
EntityManager em = PersistenceService.getInstance().getEntityManager();
User self = null;
try {
persistenceSvc.beginTx();
//get user
self = getLocalUser(); //requires tx started
//find the correct hr
List<HealthRecord> healthRecords = self.getHealthRecords();
boolean shouldRemove = false;
HealthRecord toRemove = null;
for (HealthRecord hr : healthRecords) {
//prepare to remove link
if (healthRecordIdToRemove.compareTo(hr.getHealthRecordId()) == 0) {
toRemove = hr;
logger.debug("Ready to remove healthRecord {} from user {}", hr, self);
shouldRemove = true;
}
}
if (shouldRemove) {
healthRecords.remove(toRemove);
self.setHealthRecords(healthRecords);
em.flush();
persistenceSvc.commitTx();
returnType = true;
} else {
returnType = false;
persistenceSvc.rollbackTx();
}
}
catch (NoResultException ex) {
logger.error("Unable to find remove access for HRID: {}", healthRecordIdToRemove);
returnType = false;
}
}
catch (Exception ex) {
logger.error("removeAccess encountered exception: {}", ex);
returnType = false;
} finally {
persistenceSvc.close();
}
} else {
returnType = false;
}
try {
if (returnType) {
jsonResult.put("success", "Successfully removed patient from your care.");
} else {
jsonResult.put("error", "Unable to find that user. Please try again or contact an administrator if the problem persists.");
}
}
catch (JSONException ex) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
return jsonResult;
}
/**
* Ask for access to a patient's record
*
* @param username
* @param email
* @return
*/
@Path("add/")
@GET
public JSONObject requestAccess(
@QueryParam("u") @DefaultValue("") String username,
@QueryParam("e") @DefaultValue("") String email
) {
JSONObject jsonResult = new JSONObject();
User patient = null;
boolean error = false;
if (!username.isEmpty()) {
//query on username
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
EntityManager em = PersistenceService.getInstance().getEntityManager();
try {
persistenceSvc.beginTx();
patient = (User) em.createNamedQuery("User.findByUsername")
.setParameter("username", username)
.setMaxResults(1)
.getSingleResult();
persistenceSvc.commitTx();
logger.debug("Found User by username: {}", patient);
}
catch (NoResultException ex) {
logger.error("Unable to find User object for username: {}", username);
error = true;
jsonResult.put("error", "Unable to find user with that name.");
}
}
catch (Exception ex) {
logger.error("requestAccess encountered exception: {}", ex);
error = true;
try {
jsonResult.put("error", "Unable to find user with that name.");
}
catch (JSONException ex2) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
} finally {
persistenceSvc.close();
}
} else if (!email.isEmpty()) {
//query on email
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
EntityManager em = persistenceSvc.getEntityManager();
try {
persistenceSvc.beginTx();
patient = (User) em.createNamedQuery("User.findByEmail")
.setParameter("email", email)
.setMaxResults(1)
.getSingleResult();
persistenceSvc.commitTx();
logger.debug("Found User by email: {}", patient);
}
catch (NoResultException ex) {
error = true;
logger.error("Unable to find User object for email: {}", email);
jsonResult.put("error", "Unable to find user with that email address.");
}
}
catch (Exception ex) {
error = true;
logger.error("requestAccess encountered exception: {}", ex);
try {
jsonResult.put("error", "Unable to find user with that email address.");
}
catch (JSONException ex2) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
} finally {
persistenceSvc.close();
}
} else {
//no params -- cant do anything
error = true;
try {
jsonResult.put("error", "Invalid search parameters.");
}
catch (JSONException ex) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
//check that we don't already have an outstanding requests for this patient
if (!error) { //dont bother if we've already got issues
PersistenceService persistenceSvc = PersistenceService.getInstance();
List<HealthrecordRequest> requests = null;
try {
EntityManager em = persistenceSvc.getEntityManager();
try {
//grab all existing requests made by this caretaker
requests = (List<HealthrecordRequest>) em.createNamedQuery("HealthrecordRequest.findByUserIdRequestor")
.setParameter("userIdRequestor", getLocalUser().getUserId())
.getResultList();
}
catch (NoResultException ex) {
//ignore -- this is fine
}
}
catch (Exception ex) {
error = true;
logger.error("requestAccess encountered exception: {}", ex);
try {
jsonResult.put("error", "Unable to lookup current outstanding requests.");
}
catch (JSONException ex2) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
} finally {
persistenceSvc.close();
}
if ((requests != null) && (!error)) {
for (HealthrecordRequest hrr : requests) {
//check each request's requested record id - does it match the current request attempt?
if (hrr.getRecIdRequested() == patient.getPrimaryHealthRecord().getHealthRecordId()) {
error = true;
try {
jsonResult.put("error", "A request for this patient's data already exists.");
}
catch (JSONException ex2) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
}
}
}
//check patient is not already under our care
if (!error) {
for (User u : patient.getPrimaryHealthRecord().getUserList()) {
if (u.getUserId().compareTo(getLocalUser().getUserId()) == 0) {
error = true;
try {
jsonResult.put("error", "Patient is already under your care.");
}
catch (JSONException ex) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
}
}
//createDbRequest does the real work
if (!error && createDbRequest(patient.getPrimaryHealthRecord().getHealthRecordId() )) {
try {
jsonResult.put("success", "Your request has been sent.");
}
catch (JSONException ex) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
return jsonResult;
}
/**
* List requests made by current user
*
* @return JSONArray of requests, or empty JSONArray
*/
@Path("listRequests/")
@GET
public JSONArray listAccessRequests() {
List<String> users = getUsernamesRequestedByUser();
if ((users != null) && (! users.isEmpty() )) {
return new JSONArray(users);
} else {
return new JSONArray();
}
}
//helper method for requestAccess
private boolean createDbRequest(Long requestedHealthrecordId) {
HealthrecordRequest request = null;
try {
request = new HealthrecordRequest(requestedHealthrecordId.intValue(), getLocalUser().getUserId().intValue());
}
catch (Exception ex){
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
//persist request here via EM
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
persistenceSvc.beginTx();
EntityManager em = persistenceSvc.getEntityManager();
request = em.merge(request);
persistenceSvc.commitTx();
} catch (Exception ex) {
//ignored
} finally {
persistenceSvc.close();
}
return (request.getRequestId() > 0);
}
//helper method for listAccessRequests
private List<String> getUsernamesRequestedByUser() {
PersistenceService persistenceSvc = PersistenceService.getInstance();
List<HealthrecordRequest> requests = null;
List<String> usernames = new ArrayList<String>();
try {
EntityManager em = persistenceSvc.getEntityManager();
requests = em.createNamedQuery("HealthrecordRequest.findByUserIdRequestor")
.setParameter("userIdRequestor", getLocalUser().getUserId())
.getResultList();
for (HealthrecordRequest req : requests) {
HealthRecord rec = (HealthRecord) em.createNamedQuery("HealthRecord.findByHealthRecordId")
.setParameter("healthRecordId", req.getRecIdRequested())
.getSingleResult();
usernames.add(rec.getUser()
.getUsername()
); //this is not optimized at all
}
} catch (Exception ex) {
requests = null;
logger.error("ex: {}", ex);
} finally {
persistenceSvc.close();
}
return usernames;
}
/**
* Returns count of users belonging to the care taker
*
* @param username
* @param name
* @return
*/
@Path("count/")
@GET
@Produces({ MediaType.APPLICATION_JSON })
public JSONObject getCount(
@QueryParam("u") @DefaultValue("") String username,
@QueryParam("e") @DefaultValue("") String name
) {
//SELECT COUNT(DISTINCT u.user_id)
//FROM user_users_rec_healthrecord h JOIN user_users u ON h.user_id = u.user_id JOIN user_roles r ON UPPER(LTRIM(RTRIM(u.username))) = UPPER(LTRIM(RTRIM(r.username)))
//WHERE h.rec_id IN (SELECT rec_id FROM user_users_rec_healthrecord WHERE user_id = 3)
//AND r.role = "ROLE_PATIENT";
StringBuilder query = new StringBuilder("SELECT COUNT(DISTINCT u.user_id) ");
query.append("FROM user_users_rec_healthrecord h JOIN user_users u ON h.user_id = u.user_id ");
query.append("JOIN user_roles r ON UPPER(LTRIM(RTRIM(u.username))) = UPPER(LTRIM(RTRIM(r.username))) ");
query.append("WHERE h.rec_id IN (SELECT rec_id FROM user_users_rec_healthrecord WHERE user_id = ");
Long result = 0L;
Boolean hasFilterClause = true;
if (this.getLocalUser() != null) {
query.append("'" + this.getLocalUser().getUserId() + "' )");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
if (!username.isEmpty()){
if (ServiceUtils.hasValidCharacters(username)) {
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
username = "%" + username + "%";
query.append(" u.username LIKE '" +username+"'");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
if (!name.isEmpty()){
if (ServiceUtils.hasValidCharacters(name)) {
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
name = "%" + name + "%";
query.append(" (u.first_name LIKE '" +name+"'");
query.append(" OR");
query.append(" u.last_name LIKE '" +name+"')");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
//force only able to select PATIENT role users
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
query.append(" r.role IN ('"+UserConfig.ROLE_PATIENT+"')");
PersistenceService persistenceSvc = PersistenceService.getInstance();
try {
persistenceSvc.beginTx();
EntityManager em = persistenceSvc.getEntityManager();
// logger.debug("Using query caretaker patient count query: {}", query);
List resultD = (List)em.createNativeQuery(query.toString()).getSingleResult();
result = (Long)resultD.get(0);
} finally {
persistenceSvc.close();
}
JSONObject jsonResult = new JSONObject();
try {
jsonResult.put("count", result);
}
catch (JSONException ex) {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
return jsonResult;
}
/**
* Returns all the entities associated with this care taker
*
* @param start
* @param desc
* @param max
* @param username
* @param orderBy
* @param name
* @return a collection of User instances
*/
protected Collection<User> getEntities(
int start, int max, String orderBy, int desc, String username, String name) {
//SELECT DISTINCT u.*
//FROM user_users_rec_healthrecord h JOIN user_users u ON h.user_id = u.user_id JOIN user_roles r ON UPPER(LTRIM(RTRIM(u.username))) = UPPER(LTRIM(RTRIM(r.username)))
//WHERE h.rec_id IN (SELECT rec_id FROM user_users_rec_healthrecord WHERE user_id = 3)
//AND r.role = "ROLE_PATIENT";
StringBuilder query = new StringBuilder("SELECT DISTINCT u.* ");
query.append("FROM user_users_rec_healthrecord h JOIN user_users u ON h.user_id = u.user_id ");
query.append("JOIN user_roles r ON UPPER(LTRIM(RTRIM(u.username))) = UPPER(LTRIM(RTRIM(r.username))) ");
query.append("WHERE h.rec_id IN (SELECT rec_id FROM user_users_rec_healthrecord WHERE user_id = ");
Long result = 0L;
Boolean hasFilterClause = true;
if (this.getLocalUser() != null) {
query.append("'" + this.getLocalUser().getUserId() + "' )");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
if(start<0) start=0;
Boolean hasMax = true;
if( max < 1 ){
hasMax = false;
start = 0;
}
if (!username.isEmpty()){
if (ServiceUtils.hasValidCharacters(username)) {
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
username = "%" + username + "%";
query.append(" u.username LIKE '" +username+"'");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
if (!name.isEmpty()){
if (ServiceUtils.hasValidCharacters(name)) {
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
name = "%" + name + "%";
query.append(" (u.first_name LIKE '" +name+"'");
query.append(" OR");
query.append(" u.last_name LIKE '" +name+"')");
} else {
throw new WebApplicationException(Response.Status.PRECONDITION_FAILED);
}
}
//force only able to select PATIENT role users
if (!hasFilterClause){
query.append(" WHERE");
hasFilterClause = true;
} else {
query.append(" AND");
}
query.append(" r.role IN ('"+UserConfig.ROLE_PATIENT+"')");
Boolean wasOrdered = false;
if(orderBy.equalsIgnoreCase("username")){
query.append(" ORDER BY u.username");
wasOrdered = true;
} else if(orderBy.equalsIgnoreCase("name")){
query.append(" ORDER BY u.last_name, u.first_name, u.middle_name");
wasOrdered = true;
}
if (wasOrdered) {
if (desc>0) {
query.append(" DESC");
} else {
query.append(" ASC");
}
}
// logger.error("Using query caretaker patient lookup query: {}", query);
EntityManager em = PersistenceService.getInstance().getEntityManager();
Query filterQuery = em.createNativeQuery(query.toString(), User.class);
if (hasMax) filterQuery.setMaxResults(max);
List<User> users = (List<User>)filterQuery.setFirstResult(start).getResultList();
return users;
}
private User getLocalUser() {
if (localUser == null) {
//get user id from db
String localUserName = securityContext.getUserPrincipal().getName();
PersistenceService persistenceSvc = PersistenceService.getInstance();
if (localUserName != null && !localUserName.isEmpty()) {
try {
EntityManager em = PersistenceService.getInstance().getEntityManager();
//persistenceSvc.beginTx(); //not needed -- called from transaction envt
try {
localUser = (User) em.createNamedQuery("User.findByUsername")
.setParameter("username", localUserName)
.setMaxResults(1)
.getSingleResult();
logger.debug("Found User by username: {}", localUser);
}
catch (NoResultException ex) {
localUser = null;
logger.debug("Unable to find User object for: {}", localUserName);
}
}
catch (Exception ex) {
localUser = null;
logger.error("getUserId encountered exception: {}", ex);
} finally {
PersistenceService.getInstance().close();
}
} else {
//no user in security context -- should not happen
logger.error("Unable to find username from security context");
localUser = null;
}
logger.debug("Successfully returning user: {}", localUser);
return localUser;
} else {
return localUser;
}
}
}