X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2Fcontext%2FContextInfoSerializer.java;fp=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2Fcontext%2FContextInfoSerializer.java;h=0000000000000000000000000000000000000000;hb=9d4c8b2d907edb9ebc9bfde55602598e7ba0832e;hp=ae65060789eccd44f95b82df8d0530b8a464c91b;hpb=6ba6fd60507f8e045bdc4f1be14e9d99c6a15f7f;p=lttng-ust.git diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java deleted file mode 100644 index ae650607..00000000 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (C) 2016 EfficiOS Inc. - * Copyright (C) 2016 Alexandre Montplaisir - */ - -package org.lttng.ust.agent.context; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.Charset; -import java.util.Collection; -import java.util.Map; - -import org.lttng.ust.agent.utils.LttngUstAgentLogger; - -/** - * This class is used to serialize the list of "context info" objects to pass - * through JNI. - * - * The protocol expects two byte array parameters, which are contained here in - * the {@link SerializedContexts} inner class. - * - * The first byte array is called the "entries array", and contains fixed-size - * entries, one per context element. - * - * The second one is the "strings array", it is of variable length and used to - * hold the variable-length strings. Each one of these strings is formatted as a - * UTF-8 C-string, meaning in will end with a "\0" byte to indicate its end. - * Entries in the first array may refer to offsets in the second array to point - * to relevant strings. - * - * The fixed-size entries in the entries array contain the following elements - * (size in bytes in parentheses): - * - * - * - * The context value type will indicate how many bytes are used for the value. - * If the it is of String type, then we use 4 bytes to represent the offset in - * the strings array. - * - * So the total size of each entry is 13 bytes. All unused bytes (for context - * values shorter than 8 bytes for example) will be zero'ed. - * - * @author Alexandre Montplaisir - */ -public class ContextInfoSerializer { - - private enum DataType { - NULL(0), - INTEGER(1), - LONG(2), - DOUBLE(3), - FLOAT(4), - BYTE(5), - SHORT(6), - BOOLEAN(7), - STRING(8); - - private final byte value; - - private DataType(int value) { - this.value = (byte) value; - } - - public byte getValue() { - return value; - } - } - - /** - * Class used to wrap the two byte arrays returned by - * {@link #queryAndSerializeRequestedContexts}. - */ - public static class SerializedContexts { - - private final byte[] contextEntries; - private final byte[] contextStrings; - - /** - * Constructor - * - * @param entries - * Arrays for the fixed-size context entries. - * @param strings - * Arrays for variable-length strings - */ - public SerializedContexts(byte[] entries, byte[] strings) { - contextEntries = entries; - contextStrings = strings; - } - - /** - * @return The entries array - */ - public byte[] getEntriesArray() { - return contextEntries; - } - - /** - * @return The strings array - */ - public byte[] getStringsArray() { - return contextStrings; - } - } - - private static final String UST_APP_CTX_PREFIX = "$app."; - private static final int ENTRY_LENGTH = 13; - private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); - private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); - private static final SerializedContexts EMPTY_CONTEXTS = new SerializedContexts(new byte[0], new byte[0]); - - /** - * From the list of requested contexts in the tracing session, look them up - * in the {@link ContextInfoManager}, retrieve the available ones, and - * serialize them into a byte array. - * - * @param enabledContexts - * The contexts that are enabled in the tracing session (indexed - * first by retriever name, then by index names). Should come - * from the LTTng Agent. - * @return The byte array representing the intersection of the requested and - * available contexts. - */ - public static SerializedContexts queryAndSerializeRequestedContexts(Collection>> enabledContexts) { - if (enabledContexts.isEmpty()) { - /* Early return if there is no requested context information */ - return EMPTY_CONTEXTS; - } - - ContextInfoManager contextManager; - try { - contextManager = ContextInfoManager.getInstance(); - } catch (IOException e) { - /* - * The JNI library is not available, do not send any context - * information. No retriever could have been defined anyways. - */ - return EMPTY_CONTEXTS; - } - - /* Compute the total number of contexts (flatten the map) */ - int totalArraySize = 0; - for (Map.Entry> contexts : enabledContexts) { - totalArraySize += contexts.getValue().size() * ENTRY_LENGTH; - } - - /* Prepare the ByteBuffer that will generate the "entries" array */ - ByteBuffer entriesBuffer = ByteBuffer.allocate(totalArraySize); - entriesBuffer.order(NATIVE_ORDER); - entriesBuffer.clear(); - - /* Prepare the streams that will generate the "strings" array */ - ByteArrayOutputStream stringsBaos = new ByteArrayOutputStream(); - DataOutputStream stringsDos = new DataOutputStream(stringsBaos); - - try { - for (Map.Entry> entry : enabledContexts) { - String requestedRetrieverName = entry.getKey(); - Map requestedContexts = entry.getValue(); - - IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName); - - for (String requestedContext : requestedContexts.keySet()) { - Object contextInfo; - if (retriever == null) { - contextInfo = null; - } else { - contextInfo = retriever.retrieveContextInfo(requestedContext); - /* - * 'contextInfo' can still be null here, which would - * indicate the retriever does not supply this context. - * We will still write this information so that the - * tracer can know about it. - */ - } - - /* Serialize the result to the buffers */ - // FIXME Eventually pass the retriever name only once? - String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext); - byte[] strArray = fullContextName.getBytes(UTF8_CHARSET); - - entriesBuffer.putInt(stringsDos.size()); - stringsDos.write(strArray); - stringsDos.writeChar('\0'); - - LttngUstAgentLogger.log(ContextInfoSerializer.class, - "ContextInfoSerializer: Context to be sent through JNI: " + fullContextName + '=' + - (contextInfo == null ? "null" : contextInfo.toString())); - - serializeContextInfo(entriesBuffer, stringsDos, contextInfo); - } - } - - stringsDos.flush(); - stringsBaos.flush(); - - } catch (IOException e) { - /* - * Should not happen because we are wrapping a - * ByteArrayOutputStream, which writes to memory - */ - e.printStackTrace(); - } - - byte[] entriesArray = entriesBuffer.array(); - byte[] stringsArray = stringsBaos.toByteArray(); - return new SerializedContexts(entriesArray, stringsArray); - } - - private static final int CONTEXT_VALUE_LENGTH = 8; - - private static void serializeContextInfo(ByteBuffer entriesBuffer, DataOutputStream stringsDos, Object contextInfo) throws IOException { - int remainingBytes; - if (contextInfo == null) { - entriesBuffer.put(DataType.NULL.getValue()); - remainingBytes = CONTEXT_VALUE_LENGTH; - - } else if (contextInfo instanceof Integer) { - entriesBuffer.put(DataType.INTEGER.getValue()); - entriesBuffer.putInt(((Integer) contextInfo).intValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - - } else if (contextInfo instanceof Long) { - entriesBuffer.put(DataType.LONG.getValue()); - entriesBuffer.putLong(((Long) contextInfo).longValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 8; - - } else if (contextInfo instanceof Double) { - entriesBuffer.put(DataType.DOUBLE.getValue()); - entriesBuffer.putDouble(((Double) contextInfo).doubleValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 8; - - } else if (contextInfo instanceof Float) { - entriesBuffer.put(DataType.FLOAT.getValue()); - entriesBuffer.putFloat(((Float) contextInfo).floatValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - - } else if (contextInfo instanceof Byte) { - entriesBuffer.put(DataType.BYTE.getValue()); - entriesBuffer.put(((Byte) contextInfo).byteValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 1; - - } else if (contextInfo instanceof Short) { - entriesBuffer.put(DataType.SHORT.getValue()); - entriesBuffer.putShort(((Short) contextInfo).shortValue()); - remainingBytes = CONTEXT_VALUE_LENGTH - 2; - - } else if (contextInfo instanceof Boolean) { - entriesBuffer.put(DataType.BOOLEAN.getValue()); - boolean b = ((Boolean) contextInfo).booleanValue(); - /* Converted to one byte, write 1 for true, 0 for false */ - entriesBuffer.put((byte) (b ? 1 : 0)); - remainingBytes = CONTEXT_VALUE_LENGTH - 1; - - } else { - /* Also includes the case of Character. */ - /* - * We'll write the object as a string, into the strings array. We - * will write the corresponding offset to the entries array. - */ - String str = contextInfo.toString(); - byte[] strArray = str.getBytes(UTF8_CHARSET); - - entriesBuffer.put(DataType.STRING.getValue()); - - entriesBuffer.putInt(stringsDos.size()); - stringsDos.write(strArray); - stringsDos.writeChar('\0'); - - remainingBytes = CONTEXT_VALUE_LENGTH - 4; - } - entriesBuffer.position(entriesBuffer.position() + remainingBytes); - } -}