multiplexer.java
来自「OpenJMS是一个开源的Java Message Service API 1.」· Java 代码 · 共 814 行 · 第 1/2 页
JAVA
814 行
handshake(_out, _in); } /** * Perform handshaking on initial connection, to verify protocol. Subclasses * may extend this behaviour. * * @param out the endpoint's output stream * @param in the endpoint's input stream * @throws IOException for any I/O error */ protected void handshake(DataOutputStream out, DataInputStream in) throws IOException { out.writeInt(MAGIC); out.writeInt(VERSION); out.flush(); int magic = in.readInt(); if (magic != MAGIC) { throw new ProtocolException("Expected protocol magic=" + MAGIC + ", but received=" + magic); } int version = in.readInt(); if (version != VERSION) { throw new ProtocolException("Expected protocol version=" + VERSION + ", but received=" + version); } } /** * Perform authentication on initial connection. * * @param principal the security principal. May be <code>null</code> * @throws IOException for any I/O error * @throws java.lang.SecurityException if connection is refused by the server */ protected void authenticate(Principal principal) throws IOException, SecurityException { try { if (principal != null && !(principal instanceof BasicPrincipal)) { throw new IOException( "Cannot authenticate with principal of type " + principal.getClass().getName()); } if (principal != null) { BasicPrincipal basic = (BasicPrincipal) principal; _out.writeByte(AUTH_BASIC); _out.writeUTF(basic.getName()); _out.writeUTF(basic.getPassword()); } else { _out.writeByte(AUTH_NONE); } _out.flush(); if (_in.readByte() != AUTH_OK) { throw new SecurityException("Connection refused"); } } catch (IOException exception) { // terminate the connection _endpoint.close(); throw exception; } _principal = principal; } /** * Performs authentication on initial connection. * * @param authenticator the authenticator * @throws IOException for any I/O error * @throws ResourceException if the authenticator cannot authenticate */ protected void authenticate(Authenticator authenticator) throws IOException, ResourceException { try { Principal principal = null; byte type = _in.readByte(); switch (type) { case AUTH_BASIC: String name = _in.readUTF(); String password = _in.readUTF(); principal = new BasicPrincipal(name, password); break; case AUTH_NONE: break; default: throw new IOException("Invalid packet type: " + type); } if (authenticator.authenticate(principal)) { _out.writeByte(AUTH_OK); _out.flush(); } else { _out.writeByte(AUTH_DENIED); _out.flush(); throw new SecurityException("User " + principal + " unauthorised"); } _principal = principal; } catch (IOException exception) { // terminate the connection _endpoint.close(); throw exception; } catch (ResourceException exception) { // terminate the connection _endpoint.close(); throw exception; } } /** * Opens a new channel. * * @return a new channel * @throws IOException if a channel can't be opened */ protected Channel open() throws IOException { Channel channel; int channelId; synchronized (_channels) { channelId = getNextChannelId(); channel = addChannel(channelId); } send(OPEN, channelId); return channel; } /** * Read a packet from the endpoint. */ private void multiplex() { try { byte type = _in.readByte(); switch (type) { case OPEN: handleOpen(); break; case CLOSE: handleClose(); break; case REQUEST: handleRequest(); break; case RESPONSE: handleResponse(); break; case DATA: handleData(); break; case PING_REQUEST: handlePingRequest(); break; case PING_RESPONSE: handlePingResponse(); break; case FLOW_READ: handleFlowRead(); break; case SHUTDOWN: handleShutdown(); break; default: throw new IOException("Unrecognised message type: " + type); } } catch (Exception exception) { boolean closed = _closed; shutdown(); if (!closed) { _log.debug("Multiplexer shutting down on error", exception); // error notify the listener _listener.error(exception); } } } /** * Shuts down the multiplexer. */ private void shutdown() { // mark this as closed _closed = true; // notify the channels Channel[] channels; synchronized (_channels) { channels = (Channel[]) _channels.values().toArray(new Channel[0]); } for (int i = 0; i < channels.length; ++i) { channels[i].disconnected(); } try { _endpoint.close(); } catch (IOException exception) { _log.debug(exception); } } /** * Open a new channel. * * @throws IOException for any error */ private void handleOpen() throws IOException { int channelId = _in.readUnsignedShort(); Integer key = new Integer(channelId); synchronized (_channels) { if (_channels.get(key) != null) { throw new IOException( "A channel already exists with identifier: " + key); } addChannel(channelId); } } /** * Close a channel. * * @throws IOException for any error */ private void handleClose() throws IOException { int channelId = _in.readUnsignedShort(); Integer key = new Integer(channelId); synchronized (_channels) { Channel channel = (Channel) _channels.remove(key); if (channel == null) { throw new IOException( "No channel exists with identifier: " + key); } channel.close(); } } /** * Handle a <code>REQUEST</code> packet. * * @throws IOException if an I/O error occurs, or no channel exists matching * that read from the packet */ private void handleRequest() throws IOException { final Channel channel = handleData(); if (_log.isDebugEnabled()) { _log.debug("handleRequest() [channel=" + channel.getId() + "]"); } // todo - need to handle closed() _listener.request(channel); if (_log.isDebugEnabled()) { _log.debug("handleRequest() [channel=" + channel.getId() + "] - end"); } } /** * Handle a <code>RESPONSE</code> packet. * * @throws IOException if an I/O error occurs, or no channel exists matching * that read from the packet */ private void handleResponse() throws IOException { handleData(); } /** * Handle a <code>PING_REQUEST</code> packet. * * @throws IOException if an I/O error occurs */ private void handlePingRequest() throws IOException { int token = _in.readInt(); synchronized (_out) { _out.writeByte(PING_RESPONSE); _out.writeInt(token); _out.flush(); if (_log.isDebugEnabled()) { _log.debug("pinged(token=" + token + ")"); } } } /** * Handle a <code>PING_RESPONSE</code> packet. * * @throws IOException if an I/O error occurs */ private void handlePingResponse() throws IOException { int token = _in.readInt(); _listener.pinged(token); } /** * Handle a <code>DATA</code> packet. * * @return the channel to handle the packet * @throws IOException if an I/O error occurs, or no channel exists matching * that read from the packet */ private Channel handleData() throws IOException { Channel channel = readChannel(); int length = _in.readInt(); channel.getMultiplexInputStream().receive(_in, length); return channel; } /** * Handle a <code>FLOW_READ</code> packet. * * @throws IOException if an I/O error occurs */ private void handleFlowRead() throws IOException { Channel channel = readChannel(); int read = _in.readInt(); channel.getMultiplexOutputStream().notifyRead(read); } /** * Handle a <code>SHUTDOWN</code> packet. */ private void handleShutdown() { shutdown(); _listener.closed(); } /** * Adds a new channel. * <p/> * NOTE: Must be invoked with <code>_channels</code> synchronized * * @param channelId the channel identifier * @return the new channel */ private Channel addChannel(int channelId) { int size = BUFFER_SIZE; MultiplexOutputStream out = new MultiplexOutputStream(channelId, this, size, size); MultiplexInputStream in = new MultiplexInputStream(channelId, this, size); Channel channel = new Channel(channelId, this, in, out); _channels.put(new Integer(channelId), channel); return channel; } /** * Reads the channel identifier from the stream and returns the * corresponding channel. * * @return the channel corresponding to the read channel identifier * @throws IOException for any I/O error, or if there is no corresponding * channel */ private Channel readChannel() throws IOException { int channelId = _in.readUnsignedShort(); return getChannel(channelId); } /** * Returns a channel given its identifier. * * @param channelId the channel identifier * @return the channel corresponding to <code>channelId</code> * @throws IOException if there is no corresponding channel */ private Channel getChannel(int channelId) throws IOException { Channel channel; Integer key = new Integer(channelId); synchronized (_channels) { channel = (Channel) _channels.get(key); if (channel == null) { throw new IOException( "No channel exists with identifier: " + channelId); } } return channel; } /** * Returns the next available channel identifier. Channel identifiers * generated on the client side are in the range 0x0..0x7FFF, on the server * side, 0x8000-0xFFFF * <p/> * NOTE: Must be invoked with <code>_channels</code> synchronized * * @return the next channel identifier * @throws IOException if the connection is closed */ private int getNextChannelId() throws IOException { final int mask = 0x7fff; final int serverIdBase = 0x8000; int channelId = 0; while (!_closed) { _seed = (_seed + 1) & mask; channelId = (_client) ? _seed : _seed + serverIdBase; if (!_channels.containsKey(new Integer(channelId))) { break; } } if (_closed) { throw new IOException("Connection has been closed"); } return channelId; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?