View Javadoc

1   /*
2    *  XNap
3    *
4    *  A pure java file sharing client.
5    *
6    *  See AUTHORS for copyright information.
7    *
8    *  This program is free software; you can redistribute it and/or modify
9    *  it under the terms of the GNU General Public License as published by
10   *  the Free Software Foundation; either version 2 of the License, or
11   *  (at your option) any later version.
12   *
13   *  This program is distributed in the hope that it will be useful,
14   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   *  GNU General Public License for more details.
17   *
18   *  You should have received a copy of the GNU General Public License
19   *  along with this program; if not, write to the Free Software
20   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21   *
22   */
23  package org.xnap.plugin.joscar;
24  
25  import java.io.IOException;
26  import java.util.Hashtable;
27  import java.util.Observable;
28  import java.util.Observer;
29  
30  import org.apache.log4j.Logger;
31  import org.xnap.event.StateListener;
32  import org.xnap.event.StateSupport;
33  import org.xnap.plugin.joscar.msg.JOscarMessageQueue;
34  import org.xnap.plugin.joscar.msg.JOscarMessageSender;
35  import org.xnap.util.FiniteStateMachine;
36  import org.xnap.util.State;
37  import org.xnap.XNap;
38  
39  import JOscarLib.Core.OscarConnection;
40  import JOscarLib.Integration.Event.MessagingListener;
41  import JOscarLib.Integration.Event.StatusListener;
42  import JOscarLib.Setting.Enum.StatusModeEnum;
43  import JOscarLib.Tool.OscarInterface;
44  
45  public class JOscarConnection implements Observer
46  {
47  	//--- Constant(s) ---
48  	
49  	//--- Data field(s) ---
50  
51  	/***
52  	 * The connection to the oscar server.
53  	 */
54      private OscarConnection connection = null;
55  	/***
56  	 * Provides listener support for state listeners.
57  	 */
58  	private StateSupport listeners = new StateSupport(this);
59  	
60  	private StateMachine sm = new StateMachine();
61  	/***
62  	 * Queue for messages to be sent out. This is necessary since the joscar
63  	 * library doesn't use a thread itself for sending out messages, so we
64  	 * have to do this in order to prevent the GUI from blocking.
65  	 */
66  	private JOscarMessageQueue queue = new JOscarMessageQueue();
67  	/***
68  	 * Sends out the messages in the queue.
69  	 */
70  	private JOscarMessageSender sender = new JOscarMessageSender(queue);
71  
72  	private static Logger logger = Logger.getLogger(JOscarConnection.class);
73  
74  	private static JOscarPreferences prefs = JOscarPreferences.getInstance();
75  
76  	private static final Hashtable TRANSITION_TABLE;
77  	static {
78  		State[][] table = new State[][] {
79  			{ State.DISCONNECTED, State.CONNECTING, },
80  			{ State.CONNECTING, State.CONNECTED, State.DISCONNECTED },
81  			{ State.CONNECTED, State.DISCONNECTING, State.DISCONNECTED },
82  			{ State.DISCONNECTING, State.DISCONNECTED }
83  		};
84  		TRANSITION_TABLE = FiniteStateMachine.createStateTable(table);
85  	}
86  	
87  	//--- Constructor(s) ---
88  
89      public JOscarConnection()
90  	{
91  		
92  	}
93  
94      //--- Method(s) ---
95  
96  	public void addMessagingListener(MessagingListener l)
97  	{
98  		if (connection != null) {
99  			connection.addMessagingListener(l);
100 		}
101 	}
102 
103 	public void addStatusListener(StatusListener l)
104 	{
105 		if (connection != null) {
106 			connection.addStatusListener(l);
107 		}
108 	}
109 
110 	/***
111 	 * Adds message to its internal message queue {@link JOscarMessageQueue}
112 	 * which is emptied by the {@link JOscarMessageSender}.
113 	 */
114 	public void sendMessage(String uin, String message)
115 	{
116 		queue.addMessage(uin, message);
117 	}
118 
119 	/***
120 	 * Adds SMS message to its internal message queue {@link
121 	 * JOscarMessageQueue} which is emptied by the {@link
122 	 * JOscarMessageSender}.
123 	 */
124 	public void sendSMS(String uin, String message)
125 	{
126 		queue.addSMS(uin, message);
127 	}
128 
129 	public void addUser(String uin)
130 	{
131 		queue.addUser(uin);
132 	}
133 
134 	public void connect()
135 	{
136 		setState(State.CONNECTING);
137 	}
138 
139 	public void disconnect()
140 	{
141 		setState(State.DISCONNECTING);
142 	}
143 
144 	public State getState()
145 	{
146 		return sm.getState();
147 	}
148 
149 	private void setState(State newState)
150 	{
151 		sm.setState(newState);
152 		listeners.fireStateChanged();
153 	}
154 
155 	private void setState(State newState, String message)
156 	{
157 		sm.setState(newState, message);
158 		listeners.fireStateChanged();
159 	}
160 
161 	public void addStateListener(StateListener listener) 
162     {
163         listeners.addStateListener(listener);
164     }
165 
166     public void removeStateListener(StateListener listener) 
167     {
168         listeners.removeStateListener(listener);
169     }
170 
171 	/***
172 	 * Implements the {@link Observer} interface.
173 	 *
174 	 * The <code>connection</code> notifies us when it's connected.
175 	 */
176 	public void update(Observable obs, Object obj) 
177 	{
178 		if (connection.isLogged()) {
179 			OscarInterface.changeStatus
180 				(connection,new StatusModeEnum(StatusModeEnum.ONLINE));
181 			setState(State.CONNECTED);
182 		}
183 		else {
184 			// this is never the case yet
185 			setState(State.DISCONNECTED);
186 		}
187 	}		
188 
189 
190 	private class StateMachine extends FiniteStateMachine
191 	{
192 		public StateMachine()
193 		{
194 			super(State.DISCONNECTED, TRANSITION_TABLE);
195 		}
196 
197 		protected synchronized void stateChanged(State oldState,
198 												 State newState)
199 		{
200 			if (newState == State.CONNECTING) {
201 				createConnection();
202 			}
203 			else if (newState == State.CONNECTED) {
204 				sender.setConnection(connection);
205 				sender.start();
206 			}
207 			else if (newState == State.DISCONNECTING) {
208 				closeConnection();
209 			}
210 			else if (newState == State.DISCONNECTED) {
211 				sender.stop();
212 				queue.clear();
213 			}
214 		}
215 
216 		/***
217 		 * Connect to the oscar server.
218 		 */
219 		private void createConnection()
220 		{
221 			connection = new OscarConnection(prefs.getServerHost(), 
222 											 prefs.getServerPort(),
223 											 prefs.getUsername(),
224 											 prefs.getPassword());
225 			if (XNap.isRunFromCvs()) {
226 				connection.getPacketAnalyser().setDebug(true);
227 			}
228 			connection.addObserver(JOscarConnection.this);
229 		}
230 		
231 		/***
232 		 * Closes the connection.
233 		 */
234 		private void closeConnection()
235 		{
236 			try {
237 				connection.getClient().disconnect();
238 			}
239 			catch (IOException ie) {
240 				logger.debug("Error stopping connection", ie);
241 			}
242 			connection = null;
243 			JOscarConnection.this.setState(State.DISCONNECTED);
244 		}
245 	}
246 	
247 }