Creates read-only command for optimization
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / pz2utils4jsf / pazpar2 / state / StateManager.java
1 package com.indexdata.pz2utils4jsf.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 javax.enterprise.context.SessionScoped;\r
11 \r
12 import org.apache.log4j.Logger;\r
13 \r
14 import com.indexdata.pz2utils4jsf.pazpar2.commands.CommandReadOnly;\r
15 import com.indexdata.pz2utils4jsf.pazpar2.commands.Pazpar2Command;\r
16 import com.indexdata.pz2utils4jsf.utils.Utils;\r
17 \r
18 @SessionScoped\r
19 public class StateManager implements Serializable {\r
20   \r
21   private static final long serialVersionUID = 8152558351351730035L;\r
22 \r
23   Map<String, Pazpar2State> states = new HashMap<String, Pazpar2State>();\r
24   String currentKey = "";\r
25   private static List<String> allCommands = new ArrayList<String>(Arrays.asList("init","ping","settings","search","stat","show","record","termlist","bytarget"));\r
26   Map<String,Boolean> pendingStateChanges = new HashMap<String,Boolean>();\r
27   private static Logger logger = Logger.getLogger(StateManager.class);\r
28   private List<StateListener> listeners = new ArrayList<StateListener>();\r
29   \r
30   public StateManager () {\r
31     logger.info("Initializing a Pazpar2 state manager [" + Utils.objectId(this) + "]");\r
32     Pazpar2State initialState = new Pazpar2State(this);\r
33     states.put(initialState.getKey(), initialState);\r
34     currentKey = initialState.getKey();\r
35     for (String command : allCommands) {\r
36       pendingStateChanges.put(command, new Boolean(false));\r
37     }\r
38   }\r
39   \r
40   public void addStateListener(StateListener listener) {\r
41     listeners.add(listener);\r
42   }\r
43   \r
44   public void removeStateListener (StateListener listener) {\r
45     listeners.remove(listener);\r
46   }\r
47   \r
48   private void updateListeners (String command) {\r
49     for (StateListener lsnr : listeners) {\r
50       lsnr.stateUpdate(command);\r
51     }\r
52   }\r
53   \r
54   /**\r
55    * Registers a Pazpar2 command for execution.\r
56    * \r
57    * The state manager will update current state and flag that\r
58    * a request change was made but that it was not yet carried \r
59    * out against Pazpar2.\r
60    * \r
61    * Any command that is created or modified must be checked in\r
62    * like this to come into effect.\r
63    * \r
64    * @param command\r
65    */\r
66   public void checkIn(Pazpar2Command command) {\r
67     if (getCurrentState().stateMutating(command)) {\r
68       logger.debug("State changed by: " + command.getName());\r
69       Pazpar2State state = new Pazpar2State(getCurrentState(),command);\r
70       states.put(state.getKey(), state);\r
71       currentKey = state.getKey();\r
72       hasPendingStateChange(command.getName(),new Boolean(true));\r
73     } else {\r
74       logger.debug("Command " + command.getName() + " not found to change the state [" + command.getEncodedQueryString() + "]");\r
75     }\r
76   }\r
77   \r
78   /**\r
79    * Gets a detached copy of a command. For the change manager\r
80    * to become aware of any changes to the copy it must be \r
81    * checked back in with 'checkIn(Pazpar2Command)'\r
82    * \r
83    * @param commandName\r
84    * @return Copy this state's instance of the given command\r
85    */\r
86   public Pazpar2Command checkOut (String commandName) {\r
87     logger.debug("Getting " + commandName + " from state manager.");\r
88     return getCurrentState().getCommand(commandName).copy();\r
89   }\r
90   \r
91   public CommandReadOnly getCommand (String commandName) {\r
92     return getCurrentState().getCommand(commandName);\r
93   }\r
94   \r
95   public Pazpar2State getCurrentState () {\r
96     return states.get(currentKey);\r
97   }\r
98     \r
99   /**\r
100    * Changes the current state key. Invoked from the UI to have the state \r
101    * manager switch to another state than the current one. \r
102    * \r
103    * @param key\r
104    */\r
105   public void setCurrentStateKey(String key) {    \r
106     if (currentKey.equals(key)) {\r
107       logger.debug("setCurrentStateKey: no key change detected");\r
108     } else {\r
109       logger.debug("State key change. Was: [" + currentKey + "]. Will be ["+key+"]");\r
110       if (states.get(key).getCommand("search").equals(states.get(currentKey).getCommand("search"))) {\r
111         logger.debug("No search change detected");\r
112       } else {\r
113         hasPendingStateChange("search",true);\r
114       }\r
115       if (states.get(key).getCommand("record").equals(states.get(currentKey).getCommand("record"))) {\r
116         logger.debug("No record change detected");\r
117       } else {\r
118         hasPendingStateChange("record",true);\r
119       }\r
120       currentKey = key;\r
121     }\r
122   }\r
123 \r
124   /**\r
125    * Sets a pending-state-change flag for the given command and notifies\r
126    * registered listeners. \r
127    * \r
128    * It is up to the listener to reset the flag as needed.\r
129    * \r
130    * @param command\r
131    * @param bool\r
132    */\r
133   public void hasPendingStateChange(String command, boolean bool) {\r
134     pendingStateChanges.put(command, new Boolean(bool));\r
135     if (bool) {\r
136       logger.debug("Updating listeners with state change from " + command);\r
137       updateListeners(command);\r
138     }\r
139   }\r
140   \r
141   /**\r
142    * \r
143    * @param command\r
144    * @return true if there is a non-executed command change in this state\r
145    */\r
146   public boolean hasPendingStateChange (String command) {\r
147     return pendingStateChanges.get(command).booleanValue();\r
148   }\r
149 \r
150 }\r