1 /*******************************************************************************
2 * Copyright (c) 2016 École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.provisional
.statesystem
.core
.statevalue
;
12 import java
.nio
.BufferOverflowException
;
14 import org
.eclipse
.jdt
.annotation
.Nullable
;
15 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.Activator
;
16 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
18 import com
.google
.common
.annotations
.VisibleForTesting
;
21 * This allows to define custom state values.
23 * Each sub-class should define a {@link CustomStateValueFactory} that has to be
24 * registered, for example by the analysis using this state value type, through
26 * {@link CustomStateValue#registerCustomFactory(byte, CustomStateValueFactory)}
29 * Note to implementers: These state values are meant to be used in data
30 * structures that save information on objects that varies in time, like a state
31 * system. It will often be made persistent on disk at some point, so it is
32 * suggested to make the child classes immutable.
34 * Data structures using these custom values will often keep the values in a
35 * transient state before they are sent to be persisted. For persistence, it
36 * will request the size of the value, then write its bytes to a buffer. Once
37 * the size is requested, the value is about to be saved, so it is important
38 * that its value and size do not change after that, as it may get in an
39 * incoherent state, or, worse throw runtime exceptions.
41 * @author Geneviève Bastien
44 public abstract class CustomStateValue
extends TmfStateValue
{
46 /* Minimum size of the state value */
47 private static final int MIN_SIZE
= Byte
.BYTES
;
50 * Custom value factory interface. Each custom state value should have a
51 * corresponding factory to re-create the object from a ByteBuffer
54 public interface CustomStateValueFactory
{
57 * Get the custom state value from a byte buffer
61 * @return the custom state value
63 CustomStateValue
readCustomValue(ISafeByteBufferReader buffer
);
66 private static final CustomStateValueFactory
[] CUSTOM_FACTORIES
= new CustomStateValueFactory
[256];
69 * Register the custom factory that will be reused to create instances of
70 * custom state value objects
73 * The ID of this custom type. For possible values of this ID,
74 * see {@link #getCustomTypeId()}
76 * The factory used to create a new custom type object of this ID
78 public static void registerCustomFactory(byte customId
, CustomStateValueFactory factory
) {
79 if (customId
>= 0 && customId
<= 20) {
80 throw new IllegalArgumentException("State value IDs between 0 and 20 are reserved for built-in state value types"); //$NON-NLS-1$
82 CustomStateValueFactory currentFactory
= CUSTOM_FACTORIES
[customId
- Byte
.MIN_VALUE
];
83 if (currentFactory
== null) {
84 CUSTOM_FACTORIES
[customId
- Byte
.MIN_VALUE
] = factory
;
85 } else if (currentFactory
!= factory
) {
86 throw new IllegalStateException("Already a custom factory registered for " + Byte
.toString(customId
)); //$NON-NLS-1$
91 * Unregisters the custom factory
94 * The ID of this custom type
97 protected static void unregisterCustomFactory(byte customId
) {
98 CUSTOM_FACTORIES
[customId
- Byte
.MIN_VALUE
] = null;
102 * Get the custom factory for a byte
105 * the custom factory key
106 * @return the custom factory or null if none is registered for the key
108 public static @Nullable CustomStateValueFactory
getCustomFactory(byte customId
) {
109 return CUSTOM_FACTORIES
[customId
- Byte
.MIN_VALUE
];
113 * Read a serialized value (obtained with the
114 * {@link #serialize(ISafeByteBufferWriter)} method) into a real
115 * {@link CustomStateValue} object.
118 * The byte buffer to read from
119 * @return The state value object
121 public static TmfStateValue
readSerializedValue(ISafeByteBufferReader buffer
) {
122 /* the first byte = the custom type id */
123 byte customType
= buffer
.get();
124 CustomStateValueFactory customFactory
= CustomStateValue
.getCustomFactory(customType
);
125 if (customFactory
== null) {
126 Activator
.getDefault().logWarning("Custom factory for type " + customType
+ " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
127 return TmfStateValue
.nullValue();
130 return customFactory
.readCustomValue(buffer
);
134 * Get custom type id. The value should be between {@link Byte#MIN_VALUE}
135 * and {@link Byte#MAX_VALUE}, but not between {@code 0} and {@code 20} that
136 * are reserved for built-in state value types.
138 * @return the custom type ID
140 protected abstract Byte
getCustomTypeId();
143 * Serialize this state value into the byte buffer. This method should only
144 * write the payload of the state value and should match what will be read
145 * by the factory when deserializing.
147 * This serialized value must contain all the payload of the state value
150 * The ByteBuffer to write the values to
152 protected abstract void serializeValue(ISafeByteBufferWriter buffer
);
155 * Get the serialized size of this state value. The size must not exceed
156 * {@link Short#MAX_VALUE - MIN_SIZE}, otherwise serialization might throw a
157 * {@link BufferOverflowException}
159 * @return The serialized size of this state value
161 protected abstract int getSerializedValueSize();
164 * Serialize this custom state value into a byte buffer. It calls the
165 * serialization of the state value itself and adds the specific fields to
166 * interpret that byte array.
168 * The format of the value is [custom type (byte)][payload]
170 * The total serialized size should never exceed {@link Short#MAX_VALUE}
173 * The ByteBuffer to write the values to
175 * @throws BufferOverflowException
176 * If the serialized size of the value ends up larger than the
177 * maximum of {@link Short#MAX_VALUE} and the implementation has
178 * no way of handling it
180 public final void serialize(ISafeByteBufferWriter buffer
) {
181 buffer
.put(getCustomTypeId());
182 serializeValue(buffer
);
186 * Get the serialized size of this state value. This size will be used to
187 * allow the buffer that will be sent to the
188 * {@link #serialize(ISafeByteBufferWriter)} method
190 * @return The size of the serialized value
192 public final int getSerializedSize() {
193 int size
= getSerializedValueSize();
194 if (size
> Short
.MAX_VALUE
- MIN_SIZE
) {
195 throw new ArrayIndexOutOfBoundsException("Serialized state value is larger than the maximum allowed size of " + (Short
.MAX_VALUE
- MIN_SIZE
) + ": " + size
); //$NON-NLS-1$ //$NON-NLS-2$
197 return size
+ MIN_SIZE
;
201 public final Type
getType() {
206 public boolean isNull() {