1 20 21 package org.jivesoftware.whack; 22 23 import org.dom4j.DocumentException; 24 import org.dom4j.Element; 25 import org.dom4j.io.XMLWriter; 26 import org.dom4j.io.XPPPacketReader; 27 import org.jivesoftware.whack.util.StringUtils; 28 import org.xmlpull.v1.XmlPullParser; 29 import org.xmlpull.v1.XmlPullParserException; 30 import org.xmlpull.v1.XmlPullParserFactory; 31 import org.xmpp.component.Component; 32 import org.xmpp.component.ComponentException; 33 import org.xmpp.component.ComponentManager; 34 import org.xmpp.packet.JID; 35 import org.xmpp.packet.Packet; 36 import org.xmpp.packet.StreamError; 37 38 import javax.net.SocketFactory; 39 import java.io.*; 40 import java.net.Socket ; 41 import java.net.UnknownHostException ; 42 import java.util.concurrent.LinkedBlockingQueue ; 43 import java.util.concurrent.ThreadPoolExecutor ; 44 import java.util.concurrent.TimeUnit ; 45 46 54 public class ExternalComponent implements Component { 55 56 59 private static String CHARSET = "UTF-8"; 60 61 private Component component; 62 private ExternalComponentManager manager; 63 64 private Socket socket; 65 private XMLWriter xmlSerializer; 66 private XmlPullParserFactory factory = null; 67 private XPPPacketReader reader = null; 68 private Writer writer = null; 69 private boolean shutdown = false; 70 71 private String connectionID; 72 77 private String domain; 78 83 private String subdomain; 84 87 private String host; 88 private int port; 89 private SocketFactory socketFactory; 90 91 94 private ThreadPoolExecutor threadPool; 95 99 private SocketReadThread readerThread; 100 101 public ExternalComponent(Component component, ExternalComponentManager manager) { 102 this(component, manager, 25); 104 } 105 106 public ExternalComponent(Component component, ExternalComponentManager manager, int maxThreads) { 107 this.component = component; 108 this.manager = manager; 109 110 threadPool = new ThreadPoolExecutor (1, maxThreads, 15, TimeUnit.SECONDS, 113 new LinkedBlockingQueue <Runnable >(), new ThreadPoolExecutor.CallerRunsPolicy ()); 114 } 115 116 126 public void connect(String host, int port, SocketFactory socketFactory, String subdomain) 127 throws ComponentException { 128 try { 129 this.socket = socketFactory.createSocket(host, port); 131 this.domain = subdomain + "." + manager.getServerName(); 132 this.subdomain = subdomain; 133 this.host= host; 135 this.port = port; 136 this.socketFactory = socketFactory; 137 138 try { 139 factory = XmlPullParserFactory.newInstance(); 140 reader = new XPPPacketReader(); 141 reader.setXPPFactory(factory); 142 143 reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), 144 CHARSET)); 145 146 writer = 148 new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), 149 CHARSET)); 150 StringBuilder stream = new StringBuilder (); 152 stream.append("<stream:stream"); 153 stream.append(" xmlns=\"jabber:component:accept\""); 154 stream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\""); 155 stream.append(" to=\"" + domain + "\">"); 156 writer.write(stream.toString()); 157 writer.flush(); 158 stream = null; 159 160 XmlPullParser xpp = reader.getXPPParser(); 162 for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { 163 eventType = xpp.next(); 164 } 165 166 connectionID = xpp.getAttributeValue("", "id"); 168 if (xpp.getAttributeValue("", "from") != null) { 169 this.domain = xpp.getAttributeValue("", "from"); 170 } 171 xmlSerializer = new XMLWriter(writer); 172 173 stream = new StringBuilder (); 175 stream.append("<handshake>"); 176 stream.append(StringUtils.hash(connectionID + manager.getSecretKey(subdomain))); 177 stream.append("</handshake>"); 178 writer.write(stream.toString()); 179 writer.flush(); 180 stream = null; 181 182 try { 184 Element doc = reader.parseDocument().getRootElement(); 185 if ("error".equals(doc.getName())) { 186 StreamError error = new StreamError(doc); 187 socket.close(); 189 socket = null; 190 throw new ComponentException(error); 192 } 193 } catch (DocumentException e) { 195 try { socket.close(); } catch (IOException ioe) {} 196 throw new ComponentException(e); 197 } catch (XmlPullParserException e) { 198 try { socket.close(); } catch (IOException ioe) {} 199 throw new ComponentException(e); 200 } 201 } catch (XmlPullParserException e) { 202 try { socket.close(); } catch (IOException ioe) {} 203 throw new ComponentException(e); 204 } 205 } 206 catch (UnknownHostException uhe) { 207 try { if (socket != null) socket.close(); } catch (IOException e) {} 208 throw new ComponentException(uhe); 209 } 210 catch (IOException ioe) { 211 try { if (socket != null) socket.close(); } catch (IOException e) {} 212 throw new ComponentException(ioe); 213 } 214 } 215 216 public Component getComponent() { 217 return component; 218 } 219 220 public String getName() { 221 return component.getName(); 222 } 223 224 public String getDescription() { 225 return component.getDescription(); 226 } 227 228 235 public String getDomain() { 236 return domain; 237 } 238 239 244 public String getSubdomain() { 245 return subdomain; 246 } 247 248 253 ExternalComponentManager getManager() { 254 return manager; 255 } 256 257 public void processPacket(final Packet packet) { 258 threadPool.execute(new Runnable () { 259 public void run() { 260 component.processPacket(packet); 261 } 262 }); 263 } 264 265 public void send(Packet packet) { 266 synchronized (writer) { 267 try { 268 xmlSerializer.write(packet.getElement()); 269 xmlSerializer.flush(); 270 } 271 catch (IOException e) { 272 manager.getLog().error(e); 274 try { 276 manager.removeComponent(subdomain); 277 } catch (ComponentException e1) { 278 manager.getLog().error(e); 279 } 280 } 281 } 282 } 283 284 public void initialize(JID jid, ComponentManager componentManager) throws ComponentException { 285 component.initialize(jid, componentManager); 286 } 287 288 public void start() { 289 readerThread = new SocketReadThread(this, reader); 291 readerThread.setDaemon(true); 292 readerThread.start(); 293 component.start(); 295 } 296 297 public void shutdown() { 298 shutdown = true; 299 disconnect(); 300 } 301 302 private void disconnect() { 303 if (readerThread != null) { 304 readerThread.shutdown(); 305 } 306 threadPool.shutdown(); 307 if (socket != null && !socket.isClosed()) { 308 try { 309 synchronized (writer) { 310 try { 311 writer.write("</stream:stream>"); 312 xmlSerializer.flush(); 313 } 314 catch (IOException e) {} 315 } 316 } 317 catch (Exception e) { 318 } 320 try { 321 socket.close(); 322 } 323 catch (Exception e) { 324 manager.getLog().error(e); 325 } 326 } 327 } 328 329 334 public void connectionLost() { 335 readerThread = null; 336 boolean isConnected = false; 337 while (!isConnected && !shutdown) { 338 try { 339 connect(host, port, socketFactory, subdomain); 340 isConnected = true; 341 if (shutdown) { 345 disconnect(); 346 } 347 } catch (ComponentException e) { 348 manager.getLog().error("Error trying to reconnect with the server", e); 349 try { 351 Thread.sleep(5000); 352 } catch (InterruptedException e1) {} 353 } 354 } 355 } 356 } 357 | Popular Tags |