package open.dolphin.session;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.AsyncContext;
import open.dolphin.infomodel.*;
import open.dolphin.mbean.ServletContextHolder;
import open.dolphin.rest.ChartEventResource;
/**
* ChartEventServiceBean
* @author masuda, Masuda Naika
*/
@Stateless
public class ChartEventServiceBean {
//private static final Logger logger = Logger.getLogger(ChartEventServiceBean.class.getSimpleName());
@Inject
private ServletContextHolder contextHolder;
@PersistenceContext
private EntityManager em;
private boolean DEBUG = false;
public void notifyEvent(ChartEventModel evt) {
String fid = evt.getFacilityId();
if (fid == null) {
warn("Facility id is null.");
return;
}
List<AsyncContext> acList = contextHolder.getAsyncContextList();
synchronized (acList) {
for (Iterator<AsyncContext> itr = acList.iterator(); itr.hasNext();) {
AsyncContext ac = itr.next();
String acFid = (String) ac.getRequest().getAttribute(ChartEventResource.FID);
String acUUID = (String) ac.getRequest().getAttribute(ChartEventResource.CLIENT_UUID);
String issuerUUID = evt.getIssuerUUID();
// 同一施設かつChartEventModelの発行者でないクライアントに通知する
if (fid.equals(acFid) && !acUUID.equals(issuerUUID)) {
itr.remove();
try {
ac.getRequest().setAttribute(ChartEventResource.KEY_NAME, evt);
ac.dispatch(ChartEventResource.DISPATCH_URL);
//minagawa^
if (true) {
StringBuilder sb = new StringBuilder();
sb.append(acFid).append(":").append(acUUID);
sb.append(" did notified by ").append(issuerUUID);
debug(sb.toString());
}
//minagawa$
} catch (Exception ex) {
warn("Exception in ac.dispatch.");
}
}
}
}
}
public String getServerUUID() {
return contextHolder.getServerUUID();
}
public List<PatientVisitModel> getPvtList(String fid) {
return contextHolder.getPvtList(fid);
}
/**
* ChartEventModelを処理する
*/
public int processChartEvent(ChartEventModel evt) {
int eventType = evt.getEventType();
if (DEBUG) {
StringBuilder sb = new StringBuilder();
sb.append("ChartEventServiceBean: ").append(eventType).append(" will issue");
debug(sb.toString());
}
boolean sendEvent = true;
switch(eventType) {
case ChartEventModel.PVT_DELETE:
processPvtDeleteEvent(evt);
break;
case ChartEventModel.PVT_STATE:
sendEvent = processPvtStateEvent(evt);
break;
//s.oh^ 2014/10/14 診察終了後のメモ対応
case ChartEventModel.PVT_MEMO:
sendEvent = processPvtMemoEvent(evt);
break;
//s.oh$
default:
return 0;
}
// クライアントに通知
if(sendEvent) notifyEvent(evt);
return 1;
}
private void processPvtDeleteEvent(ChartEventModel evt) {
long pvtPk = evt.getPvtPk();
String fid = evt.getFacilityId();
// データベースから削除
PatientVisitModel exist = em.find(PatientVisitModel.class, pvtPk);
// WatingListから開いていないとexist = nullなので。
if (exist != null) {
PatientModel pm = exist.getPatientModel();
if(pm != null) {
log("processPvtDeleteEvent : pvtPk = " + String.valueOf(pvtPk) + ", ptId = " + pm.getPatientId() + ", pvtDate = " + exist.getPvtDate());
}
em.remove(exist);
}
// pvtListから削除
List<PatientVisitModel> pvtList = getPvtList(fid);
PatientVisitModel toRemove = null;
for (PatientVisitModel model : pvtList) {
if (model.getId() == pvtPk) {
toRemove = model;
break;
}
}
if (toRemove != null) {
pvtList.remove(toRemove);
}
}
private boolean processPvtStateEvent(ChartEventModel evt) {
// msgからパラメーターを取得
String fid = evt.getFacilityId();
long pvtId = evt.getPvtPk();
int state = evt.getState();
int byomeiCount = evt.getByomeiCount();
int byomeiCountToday = evt.getByomeiCountToday();
String memo = evt.getMemo();
String ownerUUID = evt.getOwnerUUID();
long ptPk = evt.getPtPk();
if((state & (1 << PatientVisitModel.BIT_NOTUPDATE)) > 0) {
return false;
}
List<PatientVisitModel> pvtList = getPvtList(fid);
// データベースのPatientVisitModelを更新
PatientVisitModel pvt = em.find(PatientVisitModel.class, pvtId);
if (pvt != null) {
//s.oh^ 2013/08/29
//pvt.setState(state);
if(state <= 1 && pvt.getState() >= 2) {
if((state & (1 << PatientVisitModel.BIT_CANCEL)) == 0 && (pvt.getState() & (1 << PatientVisitModel.BIT_CANCEL)) > 0) {
int status = pvt.getState();
status &= ~(1 << PatientVisitModel.BIT_CANCEL);
pvt.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_TREATMENT)) == 0 && (pvt.getState() & (1 << PatientVisitModel.BIT_TREATMENT)) > 0) {
int status = pvt.getState();
status &= ~(1 << PatientVisitModel.BIT_TREATMENT);
pvt.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_GO_OUT)) == 0 && (pvt.getState() & (1 << PatientVisitModel.BIT_GO_OUT)) > 0) {
int status = pvt.getState();
status &= ~(1 << PatientVisitModel.BIT_GO_OUT);
pvt.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_HURRY)) == 0 && (pvt.getState() & (1 << PatientVisitModel.BIT_HURRY)) > 0) {
int status = pvt.getState();
status &= ~(1 << PatientVisitModel.BIT_HURRY);
pvt.setState(status);
}else{
log("state <= 1 && pvt.getState() >= 2 && pvt.getState() != BIT_CANCEL/BIT_TREATMENT/BIT_GO_OUT/BIT_HURRY");
}
// 正しい情報で通知するように設定
evt.setState(pvt.getState());
}else{
pvt.setState(state);
}
//s.oh$
pvt.setByomeiCount(byomeiCount);
pvt.setByomeiCountToday(byomeiCountToday);
pvt.setMemo(memo);
}
// データベースのPatientModelを更新
PatientModel pm = em.find(PatientModel.class, ptPk);
if (pm != null) {
log("processPvtStateEvent : owner = " + ownerUUID + ", pvtPk = " + String.valueOf(pvtId) + ", ptId = " + pm.getPatientId() + ", state = " + String.valueOf(state));
pm.setOwnerUUID(ownerUUID);
}
// pvtListを更新
for (PatientVisitModel model : pvtList) {
if (model.getId() == pvtId) {
//s.oh^ 2013/08/29
//model.setState(state);
if(state <= 1 && model.getState() >= 2) {
if((state & (1 << PatientVisitModel.BIT_CANCEL)) == 0 && (model.getState() & (1 << PatientVisitModel.BIT_CANCEL)) > 0) {
int status = model.getState();
status &= ~(1 << PatientVisitModel.BIT_CANCEL);
model.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_TREATMENT)) == 0 && (model.getState() & (1 << PatientVisitModel.BIT_TREATMENT)) > 0) {
int status = model.getState();
status &= ~(1 << PatientVisitModel.BIT_TREATMENT);
model.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_GO_OUT)) == 0 && (model.getState() & (1 << PatientVisitModel.BIT_GO_OUT)) > 0) {
int status = model.getState();
status &= ~(1 << PatientVisitModel.BIT_GO_OUT);
model.setState(status);
}else if((state & (1 << PatientVisitModel.BIT_HURRY)) == 0 && (model.getState() & (1 << PatientVisitModel.BIT_HURRY)) > 0) {
int status = model.getState();
status &= ~(1 << PatientVisitModel.BIT_HURRY);
model.setState(status);
}else{
log("state <= 1 && model.getState() >= 2 && model.getState() != BIT_CANCEL/BIT_TREATMENT/BIT_GO_OUT/BIT_HURRY");
}
// 正しい情報で通知するように設定
evt.setState(model.getState());
}else{
model.setState(state);
}
//s.oh$
model.setByomeiCount(byomeiCount);
model.setByomeiCountToday(byomeiCountToday);
model.setMemo(memo);
model.getPatientModel().setOwnerUUID(ownerUUID);
break;
}
}
//s.oh^ 2013/08/13
for (PatientVisitModel model : pvtList) {
if (model.getPatientModel().getId() == ptPk) {
model.setStateBit(PatientVisitModel.BIT_OPEN, ownerUUID != null);
model.getPatientModel().setOwnerUUID(ownerUUID);
}
}
//s.oh$
return true;
}
//s.oh^ 2014/10/14 診察終了後のメモ対応
private boolean processPvtMemoEvent(ChartEventModel evt) {
String fid = evt.getFacilityId();
long pvtId = evt.getPvtPk();
int state = evt.getState();
String memo = evt.getMemo();
if((state & (1 << PatientVisitModel.BIT_NOTUPDATE)) > 0) {
return false;
}
List<PatientVisitModel> pvtList = getPvtList(fid);
PatientVisitModel pvt = em.find(PatientVisitModel.class, pvtId);
if(pvt != null) {
pvt.setMemo(memo);
}
log("processPvtMemoEvent : pvtPk = " + String.valueOf(pvtId) + ", memo = " + memo);
for(PatientVisitModel model : pvtList) {
if(model.getId() == pvtId) {
model.setMemo(memo);
break;
}
}
return true;
}
//s.oh$
public void start() {
log("ChartEventServiceBean: start did call");
setupServerUUID();
initializePvtList();
}
// serverUUIDを設定する
private void setupServerUUID() {
String uuid = UUID.randomUUID().toString();
contextHolder.setServerUUID(uuid);
log("ServerUUID="+uuid);
}
// 起動後最初のPvtListを作る
private void initializePvtList() {
contextHolder.setToday();
// サーバーの「今日」で管理する
final SimpleDateFormat frmt = new SimpleDateFormat(IInfoModel.DATE_WITHOUT_TIME);
String fromDate = frmt.format(contextHolder.getToday().getTime());
String toDate = frmt.format(contextHolder.getTomorrow().getTime());
// PatientVisitModelを施設IDで検索する
final String sql =
"from PatientVisitModel p " +
"where p.pvtDate >= :fromDate and p.pvtDate < :toDate " +
"order by p.id";
@SuppressWarnings("unchecked")
List<PatientVisitModel> result =
em.createQuery(sql)
.setParameter("fromDate", fromDate)
.setParameter("toDate", toDate)
.getResultList();
// 患者の基本データを取得する
// 来院情報と患者は ManyToOne の関係である
//int counter = 0;
for (PatientVisitModel pvt : result) {
String fid = pvt.getFacilityId();
contextHolder.getPvtList(fid).add(pvt);
PatientModel patient = pvt.getPatientModel();
// 患者の健康保険を取得する
@SuppressWarnings("unchecked")
List<HealthInsuranceModel> insurances =
em.createQuery("from HealthInsuranceModel h where h.patient.id = :pk")
.setParameter("pk", patient.getId())
.getResultList();
patient.setHealthInsurances(insurances);
KarteBean karte = (KarteBean)
em.createQuery("from KarteBean k where k.patient.id = :pk")
.setParameter("pk", patient.getId())
.getSingleResult();
// カルテの PK を得る
long karteId = karte.getId();
// 予約を検索する
@SuppressWarnings("unchecked")
List<AppointmentModel> list =
em.createQuery("from AppointmentModel a where a.karte.id = :karteId and a.date = :date")
.setParameter("karteId", karteId)
.setParameter("date", contextHolder.getToday().getTime())
.getResultList();
if (list != null && !list.isEmpty()) {
AppointmentModel appo = list.get(0);
pvt.setAppointment(appo.getName());
}
// 病名数をチェックする
setByomeiCount(karteId, pvt);
// 受付番号セット
//pvt.setNumber(++counter);
}
log("ChartEventService: initializePvtList did done");
}
// データベースを調べてpvtに病名数を設定する
public void setByomeiCount(long karteId, PatientVisitModel pvt) {
// byomeiCountがすでに0でないならば、byomeiCountは設定済みであろう
//if (pvt.getByomeiCount() != 0) {
// return;
//}
int byomeiCount = 0;
int byomeiCountToday = 0;
Date pvtDate = ModelUtils.getCalendar(pvt.getPvtDate()).getTime();
// データベースから検索
final String sql = "from RegisteredDiagnosisModel r where r.karte.id = :karteId";
List<RegisteredDiagnosisModel> rdList =
em.createQuery(sql)
.setParameter("karteId", karteId)
.getResultList();
for (RegisteredDiagnosisModel rd : rdList) {
Date start = ModelUtils.getStartDate(rd.getStarted()).getTime();
Date ended = ModelUtils.getEndedDate(rd.getEnded()).getTime();
if (start.getTime() == pvtDate.getTime()) {
byomeiCountToday++;
}
if (ModelUtils.isDateBetween(start, ended, pvtDate)) {
byomeiCount++;
}
}
pvt.setByomeiCount(byomeiCount);
pvt.setByomeiCountToday(byomeiCountToday);
}
// 0時にpvtListをリニューアルする
public void renewPvtList() {
contextHolder.setToday();
Map<String, List<PatientVisitModel>> map = contextHolder.getPvtListMap();
//s.oh^ 受付リストのクリア 2013/08/15
Properties config = new Properties();
StringBuilder sb = new StringBuilder();
sb.append(System.getProperty("jboss.home.dir"));
sb.append(File.separator);
sb.append("custom.properties");
File f = new File(sb.toString());
String pvtListClear = null;
try {
FileInputStream fin = new FileInputStream(f);
InputStreamReader r = new InputStreamReader(fin, "JISAutoDetect");
config.load(r);
r.close();
pvtListClear = config.getProperty("pvtlist.clear", "false");
} catch (FileNotFoundException ex) {
Logger.getLogger(ChartEventServiceBean.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(ChartEventServiceBean.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ChartEventServiceBean.class.getName()).log(Level.SEVERE, null, ex);
}
if(pvtListClear != null && pvtListClear.equals("true")) {
List<String> fidList = new ArrayList<String>();
for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry) itr.next();
List<PatientVisitModel> pvtList = (List<PatientVisitModel>) entry.getValue();
pvtList.clear();
fidList.add((String)entry.getKey());
log("ChartEventService: fid = " + (String)entry.getKey());
}
initializePvtList();
for(int i = 0; i < fidList.size(); i++) {
String fid = fidList.get(i);
String uuid = contextHolder.getServerUUID();
ChartEventModel msg = new ChartEventModel(uuid);
msg.setFacilityId(fid);
msg.setEventType(ChartEventModel.PVT_RENEW);
notifyEvent(msg);
}
log("ChartEventService: ServerUUID = " + contextHolder.getServerUUID());
}else{
//s.oh$
for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry) itr.next();
List<PatientVisitModel> pvtList = (List<PatientVisitModel>) entry.getValue();
List<PatientVisitModel> toRemove = new ArrayList<PatientVisitModel>();
for (PatientVisitModel pvt : pvtList) {
// BIT_SAVE_CLAIMとBIT_MODIFY_CLAIMは削除する
if (pvt.getStateBit(PatientVisitModel.BIT_SAVE_CLAIM)
|| pvt.getStateBit(PatientVisitModel.BIT_MODIFY_CLAIM)
|| pvt.getStateBit(PatientVisitModel.BIT_CANCEL)) {
toRemove.add(pvt);
}
}
pvtList.removeAll(toRemove);
// クライアントに伝える。
String fid = (String) entry.getKey();
String uuid = contextHolder.getServerUUID();
ChartEventModel msg = new ChartEventModel(uuid);
msg.setFacilityId(fid);
msg.setEventType(ChartEventModel.PVT_RENEW);
notifyEvent(msg);
}
}
log("ChartEventService: renewPvtList did done");
}
//minagawa^
private void log(String msg) {
Logger.getLogger("open.dolphin").info(msg);
}
private void debug(String msg) {
if (DEBUG) {
Logger.getLogger("open.dolphin").info(msg);
}
}
private void warn(String msg) {
Logger.getLogger("open.dolphin").info(msg);
}
//minagawa$
}