/*
* Copyright to the original author or authors.
*
* 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.
*/
package org.rioproject.examples.hospital.service;
import org.rioproject.associations.Association;
import org.rioproject.associations.AssociationServiceListener;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.examples.hospital.*;
import org.rioproject.examples.hospital.Doctor.Status;
import org.rioproject.impl.watch.CounterWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Implementation of a {@link Hospital}
*/
public class HospitalImpl implements Hospital {
private Iterable<Doctor> doctors;
private Iterable<Bed> beds;
private CounterWatch availableBeds;
private ServiceBeanContext context;
private final List<Patient> waitingRoom = new ArrayList<Patient>();
private final static Logger logger = LoggerFactory.getLogger(HospitalImpl.class.getName());
@SuppressWarnings("unused") /* Injection point for Rio */
public void setServiceBeanContext(final ServiceBeanContext context) {
this.context = context;
availableBeds = new CounterWatch("availableBeds");
context.getWatchRegistry().register(availableBeds);
}
@PostConstruct
@SuppressWarnings("unused") /* Injection point for Rio */
public void started() {
Association<Bed> association = context.getAssociationManagement().getAssociation(Bed.class,
"Beds",
"Hospital");
association.registerAssociationServiceListener(new AssociationServiceListener<Bed>() {
public void serviceAdded(Bed b) {
availableBeds.increment();
synchronized(waitingRoom) {
if(waitingRoom.size()>0) {
Patient p = waitingRoom.get(0);
try {
doAdmitWithBed(p, b);
waitingRoom.remove(p);
logger.info("Removed {} from the waiting room, waiting room size is now: {}",
p.getPatientInfo().getName(), waitingRoom.size());
} catch (AdmissionException e) {
logger.debug("Unable to assign patient {}", p.getPatientInfo().getName());
}
}
}
}
public void serviceRemoved(Bed b) {
availableBeds.decrement();
}
});
}
public Patient admit(final Patient p) throws AdmissionException {
Bed bed = getEmptyBed();
return doAdmitWithBed(p, bed);
}
public Patient release(final Patient p) throws AdmissionException {
Patient released = null;
try {
Patient removedPatient = p.getBed().removePatient();
if(removedPatient!=null) {
availableBeds.increment();
removedPatient.getDoctor().removePatient(removedPatient);
released = removedPatient;
}
} catch (IOException e) {
throw new AdmissionException(String.format("Patient %s could not be released", p.getPatientInfo().getName()),
e);
}
return released;
}
private Patient doAdmitWithBed(final Patient p, final Bed bed) throws AdmissionException {
if(bed==null) {
addToWaitingRoom(p);
throw new AdmissionException(String.format("No available beds for %s", p.getPatientInfo().getName()));
}
Doctor d = getAvailableDoctor();
if(d==null) {
addToWaitingRoom(p);
throw new AdmissionException(String.format("No available Doctor for %s", p.getPatientInfo().getName()));
}
p.setDoctor(d);
try {
d.assignPatient(p);
} catch(IOException e) {
p.setDoctor(null);
throw new AdmissionException("Could not get the patient a doctor", e);
}
try {
p.setBed(bed);
bed.setPatient(p);
} catch(IOException e) {
p.setDoctor(null);
throw new AdmissionException("Could not get the patient into a bed", e);
}
availableBeds.decrement();
return p;
}
private Doctor getAvailableDoctor() {
Doctor d = null;
List<Doctor> onDuty = get(Status.ON_DUTY, false);
if(onDuty.size()>0) {
if(onDuty.size()>1)
Collections.sort(onDuty, new DoctorComparator());
d = onDuty.get(0);
}
return d;
}
private Bed getEmptyBed() {
Bed bed = null;
for(Bed b : beds) {
try {
if(b.getPatient()==null) {
bed = b;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return bed;
}
public List<Bed> getBeds() {
List<Bed> bs = new ArrayList<Bed>();
for(Bed b : beds)
bs.add(b);
return Collections.unmodifiableList(bs);
}
@SuppressWarnings("unused") /* Injection point for Rio */
public void setDoctors(final Iterable<Doctor> drs) {
doctors = drs;
}
@SuppressWarnings("unused") /* Injection point for Rio */
public void setBeds(final Iterable<Bed> bs) {
beds = bs;
}
public List<Doctor> getDoctors() {
return get(null, true);
}
public List<Doctor> getDoctorsOnCall() {
return get(Status.ON_CALL, true);
}
public List<Doctor> getDoctorsOnDuty() {
return get(Status.ON_DUTY, true);
}
public List<Patient> getWaitingRoom() {
return getWaitingRoomList();
}
private void addToWaitingRoom(final Patient p) {
synchronized(waitingRoom) {
if(waitingRoom.add(p)) {
logger.info("Added {} to the waiting room, waiting room size is now: {}",
p.getPatientInfo().getName(), waitingRoom.size());
} else {
logger.info("Did not add {} to the waiting room, must already be waiting", p.getPatientInfo().getName());
}
}
}
public List<Patient> getAdmittedPatients() {
List<Patient> l = new ArrayList<Patient>();
for(Bed b : getBeds()) {
try {
Patient p = b.getPatient();
if(p!=null)
l.add(p);
} catch (IOException e) {
logger.warn("Could not get Patient from Bed", e);
}
}
return Collections.unmodifiableList(l);
}
private List<Patient> getWaitingRoomList() {
List<Patient> l = new ArrayList<Patient>();
synchronized(waitingRoom) {
l.addAll(waitingRoom);
}
return Collections.unmodifiableList(l);
}
private List<Doctor> get(final Status status, final boolean immutable) {
List<Doctor> list = new ArrayList<Doctor>();
for(Doctor d : doctors) {
if(status==null) {
list.add(d);
} else {
try {
if(d.getStatus().equals(status)) {
list.add(d);
}
} catch (IOException e) {
logger.warn("Could not get Doctor's Status", e);
}
}
}
return immutable?Collections.unmodifiableList(list):list;
}
class DoctorComparator implements Comparator<Doctor> {
public int compare(final Doctor dr1, final Doctor dr2) {
int dr1Patients = getPatientCount(dr1);
int dr2Patients = getPatientCount(dr2);
if(dr1Patients==dr2Patients)
return 0;
return dr1Patients<dr2Patients?-1:1;
}
int getPatientCount(final Doctor d) {
int count = 0;
try {
List<Patient> l = d.getPatients();
count = l.size();
} catch (IOException e) {
logger.warn("Getting patient count from a Doctor", e);
/* */
}
return count;
}
}
}