package open.dolphin.ejb;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import open.dolphin.dto.PatientVisitSpec;
import open.dolphin.infomodel.AppointmentModel;
import open.dolphin.infomodel.HealthInsuranceModel;
import open.dolphin.infomodel.IInfoModel;
import open.dolphin.infomodel.KarteBean;
import open.dolphin.infomodel.KarteState;
import open.dolphin.infomodel.ModelUtils;
import open.dolphin.infomodel.PatientModel;
import open.dolphin.infomodel.PatientVisitModel;
import org.apache.log4j.Logger;
import org.jboss.ejb3.annotation.SecurityDomain;
/**
* RemotePvtServiceImpl
*
* @author Minagawa,Kazushi
*/
@Stateless
@SecurityDomain("openDolphin")
@RolesAllowed("user")
@Remote({RemotePvtService.class})
public class RemotePvtServiceImpl extends DolphinService implements RemotePvtService {
private static final long serialVersionUID = -3889943133781444449L;
private Logger logger = Logger.getLogger("CONSOLE");
@Resource
private SessionContext ctx;
@PersistenceContext
private EntityManager em;
/**
* 患者来院情報を登録する。
* @param spec 来院情報を保持する DTO オブジェクト
* @return 登録個数
*/
@Override
@PermitAll // MBean からの呼び出し対応
public int addPvt(PatientVisitModel pvt) {
PatientModel patient = pvt.getPatient();
String facilityId = DEFAULT_FACILITY_OID;
// MBean からの呼び出しの場合は ctx.getCallerPrincipal().getName() が "anonymous" を返す
String callerId = ctx.getCallerPrincipal().getName();
if (callerId.contains(IInfoModel.COMPOSITE_KEY_MAKER)) {
// 施設IDを認証にパスしたユーザがある場合は facilityId を更新する
facilityId = getCallersFacilityId(ctx);
}
pvt.setFacilityId(facilityId);
patient.setFacilityId(facilityId);
PatientModel exist = null;
// 既存の患者かどうか調べる
try {
exist = (PatientModel) em
.createQuery("from PatientModel p where p.facilityId = :fid and p.patientId = :pid")
.setParameter("fid", facilityId)
.setParameter("pid", patient.getPatientId())
.getSingleResult();
//
// 健康保険情報を更新する
//
Collection<HealthInsuranceModel> ins = patient.getHealthInsurances();
if (ins != null && ins.size() > 0) {
// 健康保険を更新する
Collection old = em.createQuery("from HealthInsuranceModel h where h.patient.id = :pk")
.setParameter("pk", exist.getId())
.getResultList();
// 現在の保険情報を削除する
for (Iterator iter = old.iterator(); iter.hasNext(); ) {
HealthInsuranceModel model = (HealthInsuranceModel) iter.next();
em.remove(model);
}
// 新しい健康保険情報を登録する
Collection<HealthInsuranceModel> newOne = patient.getHealthInsurances();
for (HealthInsuranceModel model : newOne) {
model.setPatient(exist);
em.persist(model);
}
}
// 名前を更新する 2007-04-12
exist.setFamilyName(patient.getFamilyName());
exist.setGivenName(patient.getGivenName());
exist.setFullName(patient.getFullName());
exist.setKanaFamilyName(patient.getKanaFamilyName());
exist.setKanaGivenName(patient.getKanaGivenName());
exist.setKanaName(patient.getKanaName());
exist.setRomanFamilyName(patient.getRomanFamilyName());
exist.setRomanGivenName(patient.getRomanGivenName());
exist.setRomanName(patient.getRomanName());
// 性別
exist.setGender(patient.getGender());
exist.setGenderDesc(patient.getGenderDesc());
exist.setGenderCodeSys(patient.getGenderCodeSys());
// Birthday
exist.setBirthday(patient.getBirthday());
// 住所、電話を更新する
exist.setAddress(patient.getAddress());
exist.setTelephone(patient.getTelephone());
//exist.setMobilePhone(patient.getMobilePhone());
// PatientVisit との関係を設定する
pvt.setPatient(exist);
// トータルの病名数をセット
pvt.setByomeiCount(getByomeiCount(exist.getId()));
// 今日の病名数をセット
pvt.setByomeiCountToday(getByomeiCountToday(exist.getId()));
} catch (NoResultException e) {
// 新規患者であれば登録する
// 患者属性は cascade=PERSIST で自動的に保存される
em.persist(patient);
// この患者のカルテを生成する
KarteBean karte = new KarteBean();
karte.setPatient(patient);
karte.setCreated(new Date());
em.persist(karte);
}
// 来院情報を登録する
// CLAIM の仕様により患者情報のみを登録し、来院情報はない場合がある
// それを pvtDate の属性で判断している
// 同じ pvt がすでに登録されていないかどうかチェック
if (!samePvtExists(pvt)) {
em.persist(pvt);
} else if (exist != null) {
em.merge(exist);
}
broadcast(pvt); // pvt broadcaster
logger.info("pvt broadcasted at addPvt [" + patient.getPatientId() + "]");
return 1;
}
/**
* 同じ pvt がすでに登録されていないかどうかチェック by masuda-sensei
* @param pvtTest
* @return
*/
private boolean samePvtExists(PatientVisitModel pvtTest) {
String ptId = pvtTest.getPatientId();
String fid = pvtTest.getFacilityId();
String pvtDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
Collection<PatientVisitModel> result = em.createQuery(
"from PatientVisitModel p where p.facilityId = :fid and p.patient.patientId = :ptId and p.pvtDate >= :date")
.setParameter("fid", fid)
.setParameter("ptId", ptId)
.setParameter("date", pvtDate)
.getResultList();
for (PatientVisitModel pvt : result) {
// ひとつでも生きている pvt があれば,存在するということ
//if (pvt.getState() != KarteState.CANCEL_PVT) { return true; }
return true;
}
return false; // 全部 cancel なら存在しない
}
/**
* トータル病名数を返す
* @param patientPk
* @param fromDate
* @return
*/
private int getByomeiCount(long patientPk) {
String byomeiCountQuery = "select count(*) from RegisteredDiagnosisModel r "
+ "where r.karte.id = (select k.id from KarteBean k where k.patient.id = :pk)";
int totalCount = ((Long) em.createQuery(byomeiCountQuery)
.setParameter("pk", patientPk)
.getSingleResult()).intValue();
return totalCount;
}
/**
* 今日の病名数を返す
* @param patientPk
* @param fromDate
* @return
*/
private int getByomeiCountToday(long patientPk) {
String byomeiCountQuery = "select count(*) from RegisteredDiagnosisModel r "
+ "where r.karte.id = (select k.id from KarteBean k where k.patient.id = :pk)"
+ "and r.started >= :fromDate";
GregorianCalendar yesterday = new GregorianCalendar();
yesterday.add(GregorianCalendar.DATE, -1);
yesterday.set(Calendar.HOUR_OF_DAY, 23);
int todayCount = ((Long)em.createQuery(byomeiCountQuery)
.setParameter("pk", patientPk)
.setParameter("fromDate", yesterday.getTime())
.getSingleResult()).intValue();
return todayCount;
}
/**
* 施設の患者来院情報を取得する。
* @param spec 検索仕様DTOオブジェクト
* @return 来院情報のCollection
*/
@SuppressWarnings("unchecked")
@Override
public Collection<PatientVisitModel> getPvt(PatientVisitSpec spec) {
//System.out.println("getPvt start at " + new Date());
String date = spec.getDate();
if (!date.endsWith("%")) {
date += "%";
}
int index = date.indexOf('%');
Date theDate = ModelUtils.getDateAsObject(date.substring(0, index));
int firstResult = spec.getSkipCount();
String fid = getCallersFacilityId(ctx);
String appoDateFrom = spec.getAppodateFrom();
String appoDateTo = spec.getAppodateTo();
boolean searchAppo = (appoDateFrom != null && appoDateTo != null) ? true : false;
// PatientVisitModelを施設IDで検索する
Collection result = em.createQuery("from PatientVisitModel p where p.facilityId = :fid and p.pvtDate >= :date order by p.pvtDate")
.setFirstResult(firstResult)
.setParameter("fid", fid)
.setParameter("date", date)
.getResultList();
// 患者の基本データを取得する
// 来院情報と患者は ManyToOne の関係である
for (Iterator iter = result.iterator(); iter.hasNext(); ) {
PatientVisitModel pvt = (PatientVisitModel) iter.next();
PatientModel patient = pvt.getPatient();
// 健康保険はカルテオープン時に取得,病名数は addPvt で取得
// 患者の健康保険を取得する
//Collection insurances = em.createQuery("from HealthInsuranceModel h where h.patient.id = :pk")
//.setParameter("pk", patient.getId()).getResultList();
//patient.setHealthInsurances(insurances);
// トータルの病名数をセット
//pvt.setByomeiCount(getByomeiCount(patient.getId()));
// 今日の病名数をセット
//pvt.setByomeiCountToday(getByomeiCountToday(patient.getId()));
// 予約を検索する
if (searchAppo) {
List c = em.createQuery("from AppointmentModel a where a.date = :date "
+ "and a.karte.id = (select k.id from KarteBean k where k.patient.id = :pk)")
.setParameter("pk", patient.getId())
.setParameter("date", theDate)
.getResultList();
if (c != null && c.size() > 0) {
AppointmentModel appo = (AppointmentModel) c.get(0);
pvt.setAppointment(appo.getName());
}
}
}
//System.out.println("getPvt end at " + new Date());
return result;
}
/**
* 受付情報を削除する。
* @param id 受付レコード
* @return 削除件数
*/
@Override
public int removePvt(long id) {
try {
PatientVisitModel exist = em.find(PatientVisitModel.class, id);
em.remove(exist);
return 1;
} catch (Exception e) {
}
return 0;
}
/**
* 診察終了情報を書き込む。
* @param pk レコードID
* @param state 診察終了の時 1
*/
@Override
public int updatePvtState(long pk, int state) {
PatientVisitModel exist = em.find(PatientVisitModel.class, pk);
exist.setState(state);
broadcast(exist); // pvt broadcaster
//logger.info("pvt broadcasted at updatePvtState [" + exist.getPatientId() + "]");
return 1;
}
/**
* 付いている病名数を書き込む
* @param pk
* @param total 総病名数
* @param today 今日付いた病名数
* @return
*/
@Override
public int setByomeiCount(long pk, int total, int today) {
PatientVisitModel exist = em.find(PatientVisitModel.class, pk);
exist.setByomeiCount(total);
exist.setByomeiCountToday(today);
return 1;
}
/**
* pvt state だけスピーディーにとってくる by pns
* @return
*/
public final int BYOMEI_COUNT_MASK = 100;
public final int BYOMEI_COUNT_TODAY_MASK = 10000;
@Override
public ArrayList<Integer> getPvtState() {
ArrayList<Integer> list = new ArrayList<Integer>();
String fid = getCallersFacilityId(ctx);
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
Collection result = em.createQuery("from PatientVisitModel p where p.facilityId = :fid and p.pvtDate >= :date order by p.pvtDate")
.setParameter("fid", fid)
.setParameter("date", date)
.getResultList();
for (Iterator iter = result.iterator(); iter.hasNext(); ) {
PatientVisitModel pvt = (PatientVisitModel) iter.next();
Integer state = pvt.getState();
state += pvt.getByomeiCount() * BYOMEI_COUNT_MASK;
state += pvt.getByomeiCountToday() * BYOMEI_COUNT_TODAY_MASK;
list.add(state);
}
return list;
}
/**
* pk の state を取ってくる
* @param pk
* @return
*/
@Override
public int getPvtState(long pk) {
PatientVisitModel exist = em.find(PatientVisitModel.class, pk);
return exist.getState();
}
/**
* PatientModel をもつ今日の PatientVisitModel があれば取ってくる
* @param patient
* @return
*/
@Override
public PatientVisitModel getPvt(PatientModel patient) {
String fid = getCallersFacilityId(ctx);
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
Collection result = em.createQuery("from PatientVisitModel p where p.facilityId = :fid and p.pvtDate >= :date and p.patient = :patient")
.setParameter("fid", fid)
.setParameter("date", date)
.setParameter("patient", patient)
.getResultList();
if (result.isEmpty()) { return null; }
return (PatientVisitModel) result.iterator().next();
}
/**
* jms pvt broadcaster
* addPvt, updatePvtState のタイミングで pvt を broadcast する
*/
private void broadcast(PatientVisitModel pvt) {
TopicConnection connection = null;
try {
InitialContext ic = new InitialContext();
TopicConnectionFactory cf = (TopicConnectionFactory) ic.lookup("/ConnectionFactory");
Topic topic = (Topic) ic.lookup("topic/pvt");
connection = cf.createTopicConnection();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer publisher = session.createProducer(topic);
connection.start();
ObjectMessage message = session.createObjectMessage(pvt);
publisher.send(message);
} catch (NamingException ex) {
logger.error("RemotePvtService broadcast error: " + ex.getMessage());
} catch (JMSException ex) {
logger.error("RemotePvtService broadcast error: " + ex.getMessage());
} finally {
if (connection != null) {
try {
connection.close();
//logger.info("TopicConnection closed");
} catch (JMSException ex) {
logger.error("RemotePvtService broadcast error: " + ex.getMessage());
}
}
}
}
}