1 package com.indexdata.mkjsf.pazpar2.state;
\r
3 import java.io.Serializable;
\r
4 import java.util.ArrayList;
\r
5 import java.util.Arrays;
\r
6 import java.util.HashMap;
\r
7 import java.util.List;
\r
8 import java.util.Map;
\r
10 import org.apache.log4j.Logger;
\r
12 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Command;
\r
13 import com.indexdata.mkjsf.utils.Utils;
\r
15 public class StateManager implements Serializable {
\r
17 private static final long serialVersionUID = 8152558351351730035L;
\r
19 Map<String, Pazpar2State> states = new HashMap<String, Pazpar2State>();
\r
20 String currentKey = "";
\r
21 private static List<String> allCommands = new ArrayList<String>(Arrays.asList("init","ping","settings",
\r
22 "search","stat","show","record","termlist","bytarget","info",
\r
23 /* SP extras */ "auth","categories"));
\r
24 Map<String,Boolean> pendingStateChanges = new HashMap<String,Boolean>();
\r
25 private static Logger logger = Logger.getLogger(StateManager.class);
\r
26 private List<StateListener> listeners = new ArrayList<StateListener>();
\r
28 public StateManager () {
\r
29 logger.info("Initializing a Pazpar2 state manager [" + Utils.objectId(this) + "]");
\r
30 Pazpar2State initialState = new Pazpar2State();
\r
31 states.put(initialState.getKey(), initialState);
\r
32 currentKey = initialState.getKey();
\r
33 for (String command : allCommands) {
\r
34 pendingStateChanges.put(command, new Boolean(false));
\r
38 public void addStateListener(StateListener listener) {
\r
39 listeners.add(listener);
\r
42 public void removeStateListener (StateListener listener) {
\r
43 listeners.remove(listener);
\r
46 private void updateListeners (String command) {
\r
47 for (StateListener lsnr : listeners) {
\r
48 lsnr.stateUpdated(command);
\r
53 * Registers a Pazpar2 command for execution.
\r
55 * The state manager will update current state and flag that
\r
56 * a request change was made but that it was not yet carried
\r
57 * out against Pazpar2.
\r
59 * Any command that is created or modified must be checked in
\r
60 * like this to come into effect.
\r
64 public void checkIn(Pazpar2Command command) {
\r
65 if (getCurrentState().stateMutating(command)) {
\r
66 logger.info("State changed by: " + command.getCommandName());
\r
67 Pazpar2State state = new Pazpar2State(getCurrentState(),command);
\r
68 states.put(state.getKey(), state);
\r
69 currentKey = state.getKey();
\r
70 hasPendingStateChange(command.getCommandName(),new Boolean(true));
\r
71 logger.info("Updating " + listeners.size() + " listener(s) with state change from " + command);
\r
72 updateListeners(command.getCommandName());
\r
74 logger.debug("Command " + command.getCommandName() + " not found to change the state [" + command.getEncodedQueryString() + "]");
\r
78 public Pazpar2Command getCommand (String commandName) {
\r
79 return getCurrentState().getCommand(commandName);
\r
82 public Pazpar2State getCurrentState () {
\r
83 return states.get(currentKey);
\r
87 * Changes the current state key. Invoked from the UI to have the state
\r
88 * manager switch to another state than the current one.
\r
90 * @See The state field in pz2watch.xhtml<br/>
\r
91 * The state listeners windowlocationhashListener() and StateListener()
\r
92 * in listeners.js<br/>
\r
93 * The method {@link com.indexdata.mkjsf.pazpar2.Pz2Service#handleQueryStateChanges}<br/>
\r
94 * The class {@link com.indexdata.mkjsf.pazpar2.state.Pazpar2State}<br/>
\r
95 * ... for a complete picture of browser history handling.
\r
99 public void setCurrentStateKey(String key) {
\r
100 if (currentKey.equals(key)) {
\r
101 logger.info("Ignoring request from UI to set state key, already has that key [" + key + "]");
\r
103 logger.info("Request from UI to change state key from: [" + currentKey + "] to ["+key+"]");
\r
104 if (states.get(key)==null) {
\r
105 logger.error("Have no state registered for the key ["+ key +"].");
\r
106 if (key == null || key.length()==0) {
\r
107 logger.debug("Recived an empty key, retaining currentKey [" + currentKey + "]");
\r
110 if (states.get(currentKey) != null) {
\r
111 if (key.equals("#1")) {
\r
112 logger.debug("Initial key created [" + key + "], but already got a state registered for the current key [" + currentKey + "]. Retaining current key.");
\r
115 logger.info("Current search state cached under both new key [" + key + "] and current key [" + currentKey + "]");
\r
116 states.put(key,states.get(currentKey));
\r
122 if (states.get(key).getCommand("search").equals(states.get(currentKey).getCommand("search"))) {
\r
123 logger.debug("No search change detected as a consequence of processing the key ["+key+"]");
\r
125 hasPendingStateChange("search",true);
\r
127 if (states.get(key).getCommand("record").equals(states.get(currentKey).getCommand("record"))) {
\r
128 logger.debug("No record change detected as a consequence of processing the key ["+key+"]");
\r
130 hasPendingStateChange("record",true);
\r
137 * Sets a pending-state-change flag for the given command and notifies
\r
138 * registered listeners.
\r
140 * It is up to the listener to reset the flag as needed.
\r
145 public void hasPendingStateChange(String command, boolean bool) {
\r
146 pendingStateChanges.put(command, new Boolean(bool));
\r
152 * @return true if there is a non-executed command change in this state
\r
154 public boolean hasPendingStateChange (String command) {
\r
155 return pendingStateChanges.get(command).booleanValue();
\r