Wiring of pazpar2 info command and response
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / state / StateManager.java
1 package com.indexdata.mkjsf.pazpar2.state;\r
2 \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
9 \r
10 import org.apache.log4j.Logger;\r
11 \r
12 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Command;\r
13 import com.indexdata.mkjsf.utils.Utils;\r
14 \r
15 public class StateManager implements Serializable {\r
16   \r
17   private static final long serialVersionUID = 8152558351351730035L;\r
18 \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
27   \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
35     }    \r
36   }\r
37   \r
38   public void addStateListener(StateListener listener) {\r
39     listeners.add(listener);\r
40   }\r
41   \r
42   public void removeStateListener (StateListener listener) {\r
43     listeners.remove(listener);\r
44   }\r
45   \r
46   private void updateListeners (String command) {\r
47     for (StateListener lsnr : listeners) {\r
48       lsnr.stateUpdated(command);\r
49     }\r
50   }\r
51   \r
52   /**\r
53    * Registers a Pazpar2 command for execution.\r
54    * \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
58    * \r
59    * Any command that is created or modified must be checked in\r
60    * like this to come into effect.\r
61    * \r
62    * @param command\r
63    */\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
73     } else {\r
74       logger.debug("Command " + command.getCommandName() + " not found to change the state [" + command.getEncodedQueryString() + "]");\r
75     }\r
76   }\r
77       \r
78   public Pazpar2Command getCommand (String commandName) {\r
79     return getCurrentState().getCommand(commandName);\r
80   }\r
81   \r
82   public Pazpar2State getCurrentState () {\r
83     return states.get(currentKey);\r
84   }\r
85     \r
86   /**\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
89    * \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
96    * \r
97    * @param key\r
98    */\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
102     } else {\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
108           key = currentKey;\r
109         } else {\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
113               key = currentKey;\r
114             } else {\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
117             }\r
118           }\r
119         }\r
120       }\r
121       \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
124       } else {\r
125         hasPendingStateChange("search",true);\r
126       }\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
129       } else {\r
130         hasPendingStateChange("record",true);\r
131       }\r
132       currentKey = key;            \r
133     }\r
134   }\r
135 \r
136   /**\r
137    * Sets a pending-state-change flag for the given command and notifies\r
138    * registered listeners. \r
139    * \r
140    * It is up to the listener to reset the flag as needed.\r
141    * \r
142    * @param command\r
143    * @param bool\r
144    */\r
145   public void hasPendingStateChange(String command, boolean bool) {\r
146     pendingStateChanges.put(command, new Boolean(bool));\r
147   }\r
148   \r
149   /**\r
150    * \r
151    * @param command\r
152    * @return true if there is a non-executed command change in this state\r
153    */\r
154   public boolean hasPendingStateChange (String command) {\r
155     return pendingStateChanges.get(command).booleanValue();\r
156   }\r
157 \r
158 }\r