a52e74d4bcc63a3d84dd6283e3940f8b4ef4f640
[rhynodge.git] / src / main / java / net / pterodactylus / rhynodge / states / StateManager.java
1 /*
2  * Rhynodge - StateManager.java - Copyright © 2013 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.rhynodge.states;
19
20 import static com.google.common.base.Optional.absent;
21 import static com.google.common.base.Optional.fromNullable;
22
23 import java.io.File;
24 import java.io.IOException;
25
26 import net.pterodactylus.rhynodge.State;
27
28 import com.google.common.base.Optional;
29 import org.apache.log4j.Logger;
30
31 import com.fasterxml.jackson.core.JsonGenerationException;
32 import com.fasterxml.jackson.core.JsonParseException;
33 import com.fasterxml.jackson.databind.JsonMappingException;
34 import com.fasterxml.jackson.databind.ObjectMapper;
35
36 /**
37  * Loads and saves {@link State}s.
38  *
39  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
40  */
41 public class StateManager {
42
43         /** The logger. */
44         private static final Logger logger = Logger.getLogger(StateManager.class);
45
46         /** Jackson object mapper. */
47         private final ObjectMapper objectMapper = new ObjectMapper();
48
49         /** The directory in which to store states. */
50         private final String directory;
51
52         /**
53          * Creates a new state manager. The given directory is assumed to exist.
54          *
55          * @param directory
56          *            The directory to store states in
57          */
58         public StateManager(String directory) {
59                 this.directory = directory;
60         }
61
62         //
63         // ACTIONS
64         //
65
66         /**
67          * Loads the last state with the given name.
68          *
69          * @param reactionName
70          *            The name of the reaction
71          * @return The loaded state, or {@link Optional#absent()} if the state could not be
72          *         loaded
73          */
74         public Optional<State> loadLastState(String reactionName) {
75                 return loadLastState(reactionName, false);
76         }
77
78         /**
79          * Loads the last state with the given name.
80          *
81          * @param reactionName
82          *            The name of the reaction
83          * @return The loaded state, or {@link Optional#absent()} if the state could not be
84          *         loaded
85          */
86         public Optional<State> loadLastSuccessfulState(String reactionName) {
87                 return loadLastState(reactionName, true);
88         }
89
90         /**
91          * Saves the given state under the given name.
92          *
93          * @param reactionName
94          *            The name of the reaction
95          * @param state
96          *            The state to save
97          */
98         public void saveState(String reactionName, State state) {
99                 File stateFile = null;
100                 try {
101                         stateFile = stateFile(reactionName, "last");
102                         objectMapper.writeValue(stateFile, state);
103                         if (state.success()) {
104                                 stateFile = stateFile(reactionName, "success");
105                                 objectMapper.writeValue(stateFile, state);
106                         }
107                 } catch (JsonGenerationException jge1) {
108                         logger.warn(String.format("State for Reaction “%s” could not be generated.", reactionName), jge1);
109                         stateFile.delete();
110                 } catch (JsonMappingException jme1) {
111                         logger.warn(String.format("State for Reaction “%s” could not be generated.", reactionName), jme1);
112                         stateFile.delete();
113                 } catch (IOException ioe1) {
114                         logger.warn(String.format("State for Reaction “%s” could not be written.", reactionName));
115                         stateFile.delete();
116                 }
117         }
118
119         //
120         // PRIVATE METHODS
121         //
122
123         /**
124          * Returns the file for the state with the given name.
125          *
126          * @param reactionName
127          *            The name of the reaction
128          * @param suffix
129          *            An additional suffix (may be {@code null}
130          * @return The file for the state
131          */
132         private File stateFile(String reactionName, String suffix) {
133                 return new File(directory, reactionName + ((suffix != null) ? "." + suffix : "") + ".json");
134         }
135
136         /**
137          * Load the given state for the reaction with the given name.
138          *
139          * @param reactionName
140          *            The name of the reaction
141          * @param successful
142          *            {@code true} to load the last successful state, {@code false}
143          *            to load the last state
144          * @return The loaded state, or {@link Optional#absent()} if the state could not be
145          *         loaded
146          */
147         private Optional<State> loadLastState(String reactionName, boolean successful) {
148                 File stateFile = stateFile(reactionName, successful ? "success" : "last");
149                 try {
150                         State state = objectMapper.readValue(stateFile, AbstractState.class);
151                         return fromNullable(state);
152                 } catch (JsonParseException jpe1) {
153                         logger.warn(String.format("State for Reaction “%s” could not be parsed.", reactionName), jpe1);
154                 } catch (JsonMappingException jme1) {
155                         logger.warn(String.format("State for Reaction “%s” could not be parsed.", reactionName), jme1);
156                 } catch (IOException ioe1) {
157                         logger.info(String.format("State for Reaction “%s” could not be found.", reactionName));
158                 }
159                 return absent();
160         }
161
162 }