io.vertx.redis.impl.Command Maven / Gradle / Ivy
/**
* Copyright 2015 Red Hat, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.redis.impl;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.streams.WriteStream;
import java.nio.charset.Charset;
import java.util.List;
public class Command {
private static final byte ARGS_PREFIX = '*';
private static final byte[] CRLF = "\r\n".getBytes();
private static final byte BYTES_PREFIX = '$';
private static final byte[] NEG_ONE = convert(-1);
// Cache 256 number conversions. That should cover a huge
// percentage of numbers passed over the wire.
private static final int NUM_MAP_LENGTH = 256;
private static final byte[][] numMap = new byte[NUM_MAP_LENGTH][];
static {
for (int i = 0; i < NUM_MAP_LENGTH; i++) {
numMap[i] = convert(i);
}
}
// Optimized for the direct to ASCII bytes case
// About 5x faster than using Long.toString.getBytes
private static byte[] numToBytes(long value) {
if (value >= 0 && value < NUM_MAP_LENGTH) {
int index = (int) value;
return numMap[index];
} else if (value == -1) {
return NEG_ONE;
}
return convert(value);
}
private static byte[] convert(long value) {
boolean negative = value < 0;
// Checked javadoc: If the argument is equal to 10^n for integer n, then the result is n.
// Also, if negative, leave another slot for the sign.
long abs = Math.abs(value);
int index = (value == 0 ? 0 : (int) Math.log10(abs)) + (negative ? 2 : 1);
byte[] bytes = new byte[index];
// Put the sign in the slot we saved
if (negative) bytes[0] = '-';
long next = abs;
while ((next /= 10) > 0) {
bytes[--index] = (byte) ('0' + (abs % 10));
abs = next;
}
bytes[--index] = (byte) ('0' + abs);
return bytes;
}
private final Context context;
private final Buffer buffer;
private final ResponseTransform transform;
private final String encoding;
private final Class returnType;
private int expectedReplies = 1;
private Handler> handler;
public Command(RedisCommand command, final List> args, Charset encoding, ResponseTransform transform, Class returnType) {
this.context = Vertx.currentContext();
this.encoding = encoding.name();
this.transform = transform;
this.returnType = returnType;
int totalArgs;
if (args == null) {
totalArgs = 0;
} else {
totalArgs = args.size();
}
String[] commandTokens = command.getTokens();
// serialize the request
buffer = Buffer.buffer();
buffer.appendByte(ARGS_PREFIX);
buffer.appendBytes(numToBytes(totalArgs + commandTokens.length));
buffer.appendBytes(CRLF);
// serialize the command
for (String token : commandTokens) {
appendToBuffer(token.getBytes(encoding), encoding, buffer);
}
// serialize arguments
for (int i = 0; i < totalArgs; i++) {
appendToBuffer(args.get(i), encoding, buffer);
}
}
// setters
public Command setExpectedReplies(int expectedReplies) {
this.expectedReplies = expectedReplies;
return this;
}
public Command handler(Handler> handler) {
this.handler = handler;
return this;
}
// getters
public int getExpectedReplies() {
return expectedReplies;
}
public ResponseTransform responseTransform() {
return transform;
}
public String encoding() {
return encoding;
}
public Class returnType() {
return returnType;
}
// methods
public void handle(AsyncResult asyncResult) {
if (handler != null) {
if (context != null) {
context.runOnContext(v -> handler.handle(asyncResult));
} else {
handler.handle(asyncResult);
}
}
}
public void writeTo(WriteStream writeStream) {
writeStream.write(buffer);
}
private void appendToBuffer(final Object value, final Charset encoding, final Buffer buffer) {
buffer.appendByte(BYTES_PREFIX);
if (value == null) {
buffer.appendByte((byte) '0');
buffer.appendBytes(CRLF);
buffer.appendBytes(CRLF);
} else {
byte[] bytes;
// Possible types are: String, JsonObject, JsonArray, JsonElement, Number, Boolean, byte[]
if (value instanceof byte[]) {
bytes = (byte[]) value;
} else if (value instanceof Buffer) {
bytes = ((Buffer) value).getBytes();
} else if (value instanceof String) {
bytes = ((String) value).getBytes(encoding);
} else if (value instanceof Byte) {
bytes = numToBytes((Byte) value);
} else if (value instanceof Short) {
bytes = numToBytes((Short) value);
} else if (value instanceof Integer) {
bytes = numToBytes((Integer) value);
} else if (value instanceof Long) {
bytes = numToBytes((Long) value);
} else {
bytes = value.toString().getBytes(encoding);
}
buffer.appendBytes(numToBytes(bytes.length));
buffer.appendBytes(CRLF);
buffer.appendBytes(bytes);
buffer.appendBytes(CRLF);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy