summaryrefslogtreecommitdiff
path: root/src/main/java/design/persistence/JSONPersonalDatabase.java
blob: 70aa1ab7467f92fbde5a4faa8cc9f231f105d8d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package design.persistence;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import design.model.Club;
import design.model.Course;
import design.model.Golfer;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class JSONPersonalDatabase implements PersonalDatabase {

    private static JSONPersonalDatabase INSTANCE;

    public static JSONPersonalDatabase instance() {
        if (INSTANCE == null) {
            INSTANCE = new JSONPersonalDatabase("data/personaldb.json");
        }
        return INSTANCE;
    }

    private final Map<String, Golfer> cache;
    private final ObjectMapper mapper;
    private final File file;

    private JSONPersonalDatabase(String filename) {
        this.file = new File(filename);
        this.cache = new HashMap<>();
        this.mapper = new ObjectMapper();

        // TODO: Once the saved JSON matches the model, consider removing.
        // TEMP: tolerate unknown props while the model stabilizes
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        SimpleModule module = new SimpleModule();
        module.addDeserializer(Course.class, new CourseIdDeserializer());
        module.addSerializer(Course.class, new CourseIdSerializer());
        mapper.registerModule(module);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        mapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES));
        mapper.registerModule(new JavaTimeModule());

        try {
            load();
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    private void load() throws IOException {
        Golfer[] data = mapper.readValue(file, Golfer[].class);
        cache.clear();
        for (Golfer i : data) {
            cache.put(i.getUsername(), i);
        }
    }

    private void save() throws IOException {
        Golfer[] data = cache.values().toArray(Golfer[]::new);
        mapper.writer(new CustomPrettyPrinter()).writeValue(file, data);
    }

    // turns that collection into a real array of golfers
    @Override
    public Golfer[] getGolfers() {
        return cache.values().toArray(Golfer[]::new);
    }

    @Override
    public Golfer getGolfer(String username) {
        return cache.get(username);
    }

    @Override
    public void addGolfer(Golfer golfer) throws IOException {
        cache.putIfAbsent(golfer.getUsername(), golfer);
        save();
    }

    @Override
    public void removeGolfer(Golfer golfer) throws IOException {
        cache.remove(golfer.getUsername());
        save();
    }

    @Override
    public void updateGolfer(Golfer golfer) throws IOException {
        cache.put(golfer.getUsername(), golfer);
        save();
    }

    private static class CourseIdSerializer extends JsonSerializer<Course> {
        @Override
        public void serialize(Course course, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeNumber(course.getId());
        }
    }

    private static class CourseIdDeserializer extends JsonDeserializer<Course> {
        MasterDatabase masterDB = MasterDatabase.instance();

        @Override
        public Course deserialize(JsonParser p, DeserializationContext context) throws IOException {
            int id = p.getValueAsInt();
            return masterDB.getCourse(id);
        }
    }

    private static class CustomPrettyPrinter extends DefaultPrettyPrinter {
        public CustomPrettyPrinter() {
            super._arrayIndenter = new DefaultIndenter();
            super._objectFieldValueSeparatorWithSpaces = _separators.getObjectFieldValueSeparator() + " ";
            super._arrayEmptySeparator = "";
        }

        @Override
        public CustomPrettyPrinter createInstance() {
            return new CustomPrettyPrinter();
        }
    }
}