HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Simple medical collection/database about patients visits

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplecollectiondatabasemedicalaboutvisitspatients

Problem

I am writing a system for doctors who are regularly visited by patients. The doctor adds each patient's visit to collection/database. The class can save data to an .xml file and restore it. Can you give your feedback about this code?

```
// https://github.com/veitsi/jcrf-noweb
import java.util.ArrayList;
import java.util.Date;
import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Jcrf {
@XmlElement
Jcrf jcrf;
@XmlElement
ArrayList vst = new ArrayList();

public Jcrf() {
super();
}

public static void main(String[] args) {
Jcrf jcrf = new Jcrf();
jcrf.addTestData();

System.out.println(jcrf.vst);

jcrf.toXml();
jcrf.fromXml();

System.out.println(jcrf.vst);
}

public void toXml() {
try {
File file = new File("jcrf.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); // output
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(this, file);
jaxbMarshaller.marshal(this, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}

public void fromXml() {
try {
File file = new File("jcrf.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jcrf = (Jcrf) jaxbUnmarshaller.unmarshal(file);
vst = jcrf.vst;
} catch (JAXBException e) {
e.printStackTrace();
}
}

public void addTestData() {
vst.add(new Visit(1, 1, 366));
vs

Solution

File-systems normally make poor databases because you lose the concept of 'atomicity'... let's take a worst-case example:

public void toXml() {
    try {
        File file = new File("jcrf.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); // output
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        jaxbMarshaller.marshal(this, file);
        jaxbMarshaller.marshal(this, System.out);
    } catch (JAXBException e) {
        e.printStackTrace();
    }
}


What happens if there is an IOException part-way through the jaxbMarshaller.marshal(this, file); ? You end up overwriting the old copy, and losing the new one. Your data is gone.

A more traditional way to prevent this sort of loss is to write the output to a new file, and then do an atomic 'move' operation:

public void toXml() {
    try {
        File file = new File("jcrf.xml.tmp");
        JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); // output
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        jaxbMarshaller.marshal(this, file);
        jaxbMarshaller.marshal(this, System.out);

        // move tmp file to complete output file.
        Path tmp = file.toPath();
        Path target = Paths.get("jcrf.xml");
        Files.move(tmp, target, CopyOption.REPLACE_EXISTING, CopyOption.ATOMIC_MOVE);

    } catch (JAXBException e) {
        e.printStackTrace();
    }
}


Note the use of the atomic Files.move(...)` command.

One day, when your file-system is full, and you run out of space... you will appreciate that change.

Code Snippets

public void toXml() {
    try {
        File file = new File("jcrf.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); // output
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        jaxbMarshaller.marshal(this, file);
        jaxbMarshaller.marshal(this, System.out);
    } catch (JAXBException e) {
        e.printStackTrace();
    }
}
public void toXml() {
    try {
        File file = new File("jcrf.xml.tmp");
        JAXBContext jaxbContext = JAXBContext.newInstance(Jcrf.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); // output
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        jaxbMarshaller.marshal(this, file);
        jaxbMarshaller.marshal(this, System.out);

        // move tmp file to complete output file.
        Path tmp = file.toPath();
        Path target = Paths.get("jcrf.xml");
        Files.move(tmp, target, CopyOption.REPLACE_EXISTING, CopyOption.ATOMIC_MOVE);

    } catch (JAXBException e) {
        e.printStackTrace();
    }
}

Context

StackExchange Code Review Q#86246, answer score: 2

Revisions (0)

No revisions yet.