All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mysql.cj.protocol.x.SyncMessageReader Maven / Gradle / Ivy

There is a newer version: 8.0.33
Show newest version
/*
 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, version 2.0, as published by the
 * Free Software Foundation.
 *
 * This program is also distributed with certain software (including but not
 * limited to OpenSSL) that is licensed under separate terms, as designated in a
 * particular file or component or in included license documentation. The
 * authors of MySQL hereby grant you an additional permission to link the
 * program and your derivative works with the separately licensed software that
 * they have included with MySQL.
 *
 * Without limiting anything contained in the foregoing, this file, which is
 * part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
 * version 1.0, a copy of which can be found at
 * http://oss.oracle.com/licenses/universal-foss-exception.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 */

package com.mysql.cj.protocol.x;

import java.io.IOException;
import java.util.Optional;

import com.google.protobuf.GeneratedMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Parser;
import com.mysql.cj.exceptions.CJCommunicationsException;
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.protocol.FullReadInputStream;
import com.mysql.cj.protocol.MessageReader;
import com.mysql.cj.x.protobuf.Mysqlx.Error;

/**
 * Synchronous-only implementation of {@link MessageReader}. This implementation wraps an {@link java.io.InputStream}.
 */
public class SyncMessageReader implements MessageReader {
    /** Stream as a source of messages. */
    private FullReadInputStream inputStream;
    /** Have we already read the header for the next message? */
    private boolean hasReadHeader = false;
    private XMessageHeader header;

    public SyncMessageReader(FullReadInputStream inputStream) {
        this.inputStream = inputStream;
    }

    /**
     * Read the header for the next message.
     *
     * 

* Note that the "header" per-se is the size of all data following the header. This currently includes the message type tag (1 byte) and the message * bytes. However since we know the type tag is present we also read it as part of the header. This may change in the future if session multiplexing is * supported by the protocol. The protocol will be able to accommodate it but we will have to separate reading data after the header (size). * * @throws IOException * in case of reading error */ private void readMessageHeader() throws IOException { byte[] len = new byte[5]; this.inputStream.readFully(len); this.header = new XMessageHeader(len); this.hasReadHeader = true; } /** * Clear the stored header. */ private void clearHeader() { this.hasReadHeader = false; this.header = null; } @SuppressWarnings("unchecked") @Override public XMessageHeader readHeader() throws IOException { if (!this.hasReadHeader) { try { readMessageHeader(); } catch (IOException ex) { throw new CJCommunicationsException("Cannot read packet header", ex); } } int type = this.header.getMessageType(); // forces header read if necessary Class messageClass = MessageConstants.getMessageClassForType(type); if (messageClass == Error.class) { // throw an error/exception if receive an Error message throw new XProtocolError(readAndParse((Parser) MessageConstants.MESSAGE_CLASS_TO_PARSER.get(Error.class))); } return this.header; } private T readAndParse(Parser parser) { byte[] packet = new byte[this.header.getMessageSize()]; try { // for debugging // System.err.println("Initiating read of message (size=" + this.payloadSize + ", tag=" + ServerMessages.Type.valueOf(this.messageType) + ")"); this.inputStream.readFully(packet); } catch (IOException ex) { throw new CJCommunicationsException("Cannot read packet payload", ex); } try { return parser.parseFrom(packet); } catch (InvalidProtocolBufferException ex) { // wrap the protobuf exception. No further information is available throw new WrongArgumentException(ex); } finally { // this must happen if we *successfully* read a packet. CJCommunicationsException will be thrown above if not clearHeader(); } } @Override public XMessage readMessage(Optional reuse, XMessageHeader hdr) throws IOException { Class messageClass = MessageConstants.getMessageClassForType(hdr.getMessageType()); return new XMessage(readAndParse(messageClass)); } @Override public XMessage readMessage(Optional reuse, int expectedType) throws IOException { try { Class messageClass = MessageConstants.getMessageClassForType(readHeader().getMessageType()); Class expectedClass = MessageConstants.getMessageClassForType(expectedType); // ensure that parsed message class matches incoming tag if (expectedClass != messageClass) { throw new WrongArgumentException("Unexpected message class. Expected '" + expectedClass.getSimpleName() + "' but actually received '" + messageClass.getSimpleName() + "'"); } return new XMessage(readAndParse(messageClass)); } catch (IOException e) { throw new XProtocolError(e.getMessage(), e); } } @SuppressWarnings("unchecked") private T readAndParse(Class messageClass) { return readAndParse((Parser) MessageConstants.MESSAGE_CLASS_TO_PARSER.get(messageClass)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy