/******************************************************************************* * Copyright (c) 2009, 2014 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 * * Contributors: * Francois Chouinard - Initial API and implementation * Francois Chouinard - Updated as per TMF Event Model 1.0 * Alexandre Montplaisir - Removed Cloneable, made immutable *******************************************************************************/ package fr.inria.linuxtools.tmf.core.event; import java.util.Collection; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; /** * A basic implementation of ITmfEventField. * <p> * Non-value fields are structural (i.e. used to represent the event structure * including optional fields) while the valued fields are actual event fields. * * @version 1.0 * @author Francois Chouinard * * @see ITmfEvent * @see ITmfEventType */ public class TmfEventField implements ITmfEventField { // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ private final @NonNull String fName; private final @Nullable Object fValue; private final @NonNull ImmutableMap<String, ITmfEventField> fFields; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Full constructor * * @param name * the event field id * @param value * the event field value * @param fields * the list of subfields * @throws IllegalArgumentException * If 'name' is null, or if 'fields' has duplicate field names. */ @SuppressWarnings("null") /* ImmutableMap methods do not return @NonNull */ public TmfEventField(String name, @Nullable Object value, @Nullable ITmfEventField[] fields) { if (name == null) { throw new IllegalArgumentException(); } fName = name; fValue = value; if (fields == null) { fFields = ImmutableMap.of(); } else { /* Java 8 streams will make this even more simple! */ ImmutableMap.Builder<String, ITmfEventField> mapBuilder = new ImmutableMap.Builder<>(); for (ITmfEventField field : fields) { final String curName = field.getName(); mapBuilder.put(curName, field); } fFields = mapBuilder.build(); } } /** * Copy constructor * * @param field the other event field */ public TmfEventField(final TmfEventField field) { if (field == null) { throw new IllegalArgumentException(); } fName = field.fName; fValue = field.fValue; fFields = field.fFields; } // ------------------------------------------------------------------------ // ITmfEventField // ------------------------------------------------------------------------ @Override public String getName() { return fName; } @Override public Object getValue() { return fValue; } /** * @since 3.0 */ @Override public Collection<String> getFieldNames() { return fFields.keySet(); } /** * @since 3.0 */ @Override public Collection<ITmfEventField> getFields() { return fFields.values(); } @Override public ITmfEventField getField(final String name) { return fFields.get(name); } /** * @since 3.0 */ @Override public ITmfEventField getSubField(final String... names) { ITmfEventField field = this; for (String name : names) { field = field.getField(name); if (field == null) { return null; } } return field; } // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ /** * Create a root field from a list of labels. * * @param labels the list of labels * @return the (flat) root list */ public final static ITmfEventField makeRoot(final String[] labels) { final ITmfEventField[] fields = new ITmfEventField[labels.length]; for (int i = 0; i < labels.length; i++) { fields[i] = new TmfEventField(labels[i], null, null); } // Return a new root field; return new TmfEventField(ITmfEventField.ROOT_FIELD_ID, null, fields); } // ------------------------------------------------------------------------ // Object // ------------------------------------------------------------------------ @Override public int hashCode() { Object value = fValue; final int prime = 31; int result = 1; result = prime * result + fName.hashCode(); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof TmfEventField)) { return false; } final TmfEventField other = (TmfEventField) obj; if (!fName.equals(other.fName)) { return false; } Object value = this.fValue; if (value == null) { if (other.fValue != null) { return false; } } else if (!value.equals(other.fValue)) { return false; } return true; } @Override public String toString() { StringBuilder ret = new StringBuilder(); if (fName.equals(ITmfEventField.ROOT_FIELD_ID)) { /* * If this field is a top-level "field container", we will print its * sub-fields directly. */ appendSubFields(ret); } else { /* The field has its own values */ ret.append(fName); ret.append('='); ret.append(fValue); if (!fFields.isEmpty()) { /* * In addition to its own name/value, this field also has * sub-fields. */ ret.append(" ["); //$NON-NLS-1$ appendSubFields(ret); ret.append(']'); } } return ret.toString(); } private void appendSubFields(StringBuilder sb) { Joiner joiner = Joiner.on(", ").skipNulls(); //$NON-NLS-1$ sb.append(joiner.join(getFields())); } /** * @since 2.0 */ @Override public String getFormattedValue() { return getValue().toString(); } }