/** * Creates a {@link Connection} with {@link Connection.Modality#Synchronous} semantics suitable * for use by synchronous (blocking) JRedis clients. * * <p>[TODO: this method should be using connection spec!] * * @param host * @param port * @param redisVersion * @return */ protected Connection createSynchConnection(String host, int port, RedisVersion redisVersion) { InetAddress address = null; Connection synchConnection = null; try { address = InetAddress.getByName(host); synchConnection = new SynchConnection(address, port, redisVersion); Assert.notNull(synchConnection, "connection delegate", ClientRuntimeException.class); } catch (NotSupportedException e) { Log.log("Can not support redis protocol '%s'", redisVersion); throw e; } catch (ProviderException e) { Log.bug("Couldn't create the handler delegate. => " + e.getLocalizedMessage()); throw e; } catch (ClientRuntimeException e) { String msg = e.getMessage() + "\nMake sure your server is running."; Log.error("Error creating connection -> " + e.getLocalizedMessage()); setConnection(new FaultedConnection(msg)); } catch (UnknownHostException e) { String msg = "Couldn't obtain InetAddress for " + host; Log.problem(msg + " => " + e.getLocalizedMessage()); throw new ClientRuntimeException(msg, e); } return synchConnection; }
/** * Keeps processing the {@link PendingRequest}s in the pending {@link Queue} until a QUIT is * encountered in the pending queue. Thread will stop after processing the QUIT response (which * is expected to be a {@link VirtualResponse}. * * <p>TODO: not entirely clear what is the best way to handle exceptions. * * <p>TODO: socket Reconnect in the context of pipelining is non-trivial, and maybe not even * practically possible. (e.g. request n is sent but pipe breaks on some m (m!=n) response. non * trivial. */ public void run() { Log.log("AsyncConnection processor thread <%s> started.", Thread.currentThread().getName()); /** Response handler thread specific protocol handler -- optimize fencing */ Protocol protocol = Assert.notNull( newProtocolHandler(), "the delegate protocol handler", ClientRuntimeException.class); PendingRequest pending = null; while (true) { try { pending = pendingQueue.take(); try { Request request = Assert.notNull( protocol.createRequest(pending.cmd, pending.args), "request object from handler", ProviderException.class); request.write(getOutputStream()); pending.response = protocol.createResponse(pending.cmd); pending.response.read(getInputStream()); pending.completion.signal(); if (pending.response.getStatus().isError()) { Log.error( "(Asynch) Error response for " + pending.cmd.code + " => " + pending.response.getStatus().message()); } } catch (ProviderException bug) { Log.error("ProviderException: " + bug.getLocalizedMessage()); bug.printStackTrace(); pending.setCRE(bug); } catch (ClientRuntimeException cre) { Log.error("ClientRuntimeException: " + cre.getLocalizedMessage()); cre.printStackTrace(); pending.setCRE(cre); } catch (RuntimeException e) { Log.error("Unexpected RuntimeException ", e); e.printStackTrace(); pending.setCRE( new ProviderException("Unexpected runtime exception in response handler")); pending.setResponse(null); break; } // redis (1.00) simply shutsdown connection even if pending responses // are expected, so quit is NOT sent. we simply close connection on this // end. if (pending.cmd == Command.QUIT) { AsyncConnection.this.disconnect(); break; } } catch (InterruptedException e1) { e1.printStackTrace(); } } Log.log("AsyncConnection processor thread <%s> stopped.", Thread.currentThread().getName()); }