/*******************************************************************************
* Copyright (c) 2016 Ecole Polytechnique de Montreal, Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.segment;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
/**
* This class implements an XML Pattern Segment. This type of segment has
* content and a default timestamp, which is the start time of the segment.
*
* @author Jean-Christian Kouame
*/
public class TmfXmlPatternSegment implements ISegment {
/**
* The serial version UID
*/
private static final long serialVersionUID = 3556323761465412078L;
/* 'Byte' equivalent for state values types */
private static final byte TYPE_NULL = -1;
private static final byte TYPE_INTEGER = 0;
private static final byte TYPE_STRING = 1;
private static final byte TYPE_LONG = 2;
private final int fScale;
private final long fStart;
private final long fEnd;
private final String fSegmentName;
private transient Map<@NonNull String, @NonNull ITmfStateValue> fContent;
/**
* Constructs an XML pattern segment
*
* @param start
* Start time of the pattern segment
* @param end
* End time of the pattern segment
* @param scale
* Scale of the pattern segment
* @param segmentName
* Name of the pattern segment
* @param fields
* Fields of the pattern segment
*/
public TmfXmlPatternSegment(long start, long end, int scale, String segmentName, @NonNull Map<@NonNull String, @NonNull ITmfStateValue> fields) {
fStart = start;
fEnd = end;
fScale = scale;
fSegmentName = segmentName;
fContent = Collections.unmodifiableMap(fields);
}
/**
* Get the start timestamp of the segment
*
* @return The start timestamp
*/
public @NonNull ITmfTimestamp getTimestampStart() {
return TmfTimestamp.create(fStart, fScale);
}
/**
* Get the end timestamp of this segment
*
* @return The end timestamp
*/
public @NonNull ITmfTimestamp getTimestampEnd() {
return TmfTimestamp.create(fEnd, fScale);
}
/**
* Get the content of the pattern segment
* @return The content
*/
public Map<@NonNull String, @NonNull ITmfStateValue> getContent() {
return fContent;
}
/**
* Get the name of pattern segment
* @return The name
*/
public String getName() {
return fSegmentName;
}
/**
* Get the timestamp scale of the pattern segment
* @return The timestamp scale
*/
public int getScale() {
return fScale;
}
@Override
public int compareTo(@NonNull ISegment o) {
int ret = ISegment.super.compareTo(o);
if (ret != 0) {
return ret;
}
return toString().compareTo(o.toString());
}
@Override
public long getStart() {
return fStart;
}
@Override
public long getEnd() {
return fEnd;
}
@Override
public String toString() {
return new StringBuilder(getClass().getSimpleName())
.append(", [fTimestampStart=").append(getTimestampStart()) //$NON-NLS-1$
.append(", fTimestampEnd=").append(getTimestampEnd()) //$NON-NLS-1$
.append(", duration= ").append(getLength()) //$NON-NLS-1$
.append(", fName=").append(getName()) //$NON-NLS-1$
.append(", fContent=").append(getContent()) //$NON-NLS-1$
.append("]").toString(); //$NON-NLS-1$
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// Write the number of fields
out.writeInt(fContent.size());
// Write the fields
for (Map.Entry<String, ITmfStateValue> entry : fContent.entrySet()) {
out.writeInt(entry.getKey().length());
out.writeBytes(entry.getKey());
final ITmfStateValue value = entry.getValue();
final byte type = getByteFromType(value.getType());
out.writeByte(type);
switch (type) {
case TYPE_NULL:
break;
case TYPE_INTEGER:
out.writeInt(value.unboxInt());
break;
case TYPE_LONG:
out.writeLong(value.unboxLong());
break;
case TYPE_STRING:
final @NonNull String string = value.unboxStr();
out.writeInt(string.length());
out.writeBytes(string);
break;
default:
throw new IOException("Write object failed : Invalid data"); //$NON-NLS-1$
}
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
int contentSize = in.readInt();
final Map<@NonNull String, @NonNull ITmfStateValue> content = new HashMap<>();
for (int i = 0; i < contentSize; i++) {
int length = in.readInt();
byte[] bytes = new byte[length];
in.read(bytes, 0, length);
String name = new String(bytes).intern();
Byte type = in.readByte();
ITmfStateValue value;
switch (type) {
case TYPE_NULL:
value = TmfStateValue.nullValue();
break;
case TYPE_INTEGER:
value = TmfStateValue.newValueInt(in.readInt());
break;
case TYPE_LONG:
value = TmfStateValue.newValueLong(in.readLong());
break;
case TYPE_STRING:
length = in.readInt();
bytes = new byte[length];
in.read(bytes, 0, length);
value = TmfStateValue.newValueString(new String(bytes).intern());
break;
default:
throw new IOException("Read object failed : Invalid data"); //$NON-NLS-1$
}
content.put(name, value);
}
fContent = content;
}
/**
* Here we determine how state values "types" are written in the 8-bit field
* that indicates the value type in the file.
*/
private static byte getByteFromType(ITmfStateValue.Type type) {
switch (type) {
case NULL:
return TYPE_NULL;
case INTEGER:
return TYPE_INTEGER;
case STRING:
return TYPE_STRING;
case LONG:
return TYPE_LONG;
case DOUBLE:
case CUSTOM:
default:
/* Should not happen if the switch is fully covered */
throw new IllegalStateException("Data type " + type + " not supported"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}