| /* |
| * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/StatusVariable.java,v 1.14 2006/06/16 16:31:25 hargrave Exp $ |
| * |
| * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.osgi.service.monitor; |
| |
| import java.io.UnsupportedEncodingException; |
| import java.util.Date; |
| |
| /** |
| * A <code>StatusVariable</code> object represents the value of a status |
| * variable taken with a certain collection method at a certain point of time. |
| * The type of the <code>StatusVariable</code> can be <code>int</code>, |
| * <code>float</code>, <code>boolean</code> or <code>String</code>. |
| * <p> |
| * A <code>StatusVariable</code> is identified by an ID string that is unique |
| * within the scope of a <code>Monitorable</code>. The ID must be a non- |
| * <code>null</code>, non-empty string that conforms to the "symbolic-name" |
| * definition in the OSGi core specification. This means that only the |
| * characters [-_.a-zA-Z0-9] may be used. The length of the ID must not exceed |
| * 32 bytes when UTF-8 encoded. |
| */ |
| public final class StatusVariable { |
| //----- Public constants -----// |
| /** |
| * Constant for identifying <code>int</code> data type. |
| */ |
| public static final int TYPE_INTEGER = 0; |
| |
| /** |
| * Constant for identifying <code>float</code> data type. |
| */ |
| public static final int TYPE_FLOAT = 1; |
| |
| /** |
| * Constant for identifying <code>String</code> data type. |
| */ |
| public static final int TYPE_STRING = 2; |
| |
| /** |
| * Constant for identifying <code>boolean</code> data type. |
| */ |
| public static final int TYPE_BOOLEAN = 3; |
| |
| /** |
| * Constant for identifying 'Cumulative Counter' data collection method. |
| */ |
| public static final int CM_CC = 0; |
| |
| /** |
| * Constant for identifying 'Discrete Event Registration' data collection |
| * method. |
| */ |
| public static final int CM_DER = 1; |
| |
| /** |
| * Constant for identifying 'Gauge' data collection method. |
| */ |
| public static final int CM_GAUGE = 2; |
| |
| /** |
| * Constant for identifying 'Status Inspection' data collection method. |
| */ |
| public static final int CM_SI = 3; |
| |
| //----- Package private constants -----// |
| |
| static final String SYMBOLIC_NAME_CHARACTERS = |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + |
| "-_."; // a subset of the characters allowed in DMT URIs |
| |
| static final int MAX_ID_LENGTH = 32; |
| |
| //----- Private fields -----// |
| private String id; |
| private Date timeStamp; |
| private int cm; |
| private int type; |
| |
| private int intData; |
| private float floatData; |
| private String stringData; |
| private boolean booleanData; |
| |
| |
| //----- Constructors -----// |
| /** |
| * Constructor for a <code>StatusVariable</code> of <code>int</code> |
| * type. |
| * |
| * @param id the identifier of the <code>StatusVariable</code> |
| * @param cm the collection method, one of the <code>CM_</code> constants |
| * @param data the <code>int</code> value of the |
| * <code>StatusVariable</code> |
| * @throws java.lang.IllegalArgumentException if the given <code>id</code> |
| * is not a valid <code>StatusVariable</code> name, or if |
| * <code>cm</code> is not one of the collection method constants |
| * @throws java.lang.NullPointerException if the <code>id</code> |
| * parameter is <code>null</code> |
| */ |
| public StatusVariable(String id, int cm, int data) { |
| setCommon(id, cm); |
| type = TYPE_INTEGER; |
| intData = data; |
| } |
| |
| /** |
| * Constructor for a <code>StatusVariable</code> of <code>float</code> |
| * type. |
| * |
| * @param id the identifier of the <code>StatusVariable</code> |
| * @param cm the collection method, one of the <code>CM_</code> constants |
| * @param data the <code>float</code> value of the |
| * <code>StatusVariable</code> |
| * @throws java.lang.IllegalArgumentException if the given <code>id</code> |
| * is not a valid <code>StatusVariable</code> name, or if |
| * <code>cm</code> is not one of the collection method constants |
| * @throws java.lang.NullPointerException if the <code>id</code> parameter |
| * is <code>null</code> |
| */ |
| public StatusVariable(String id, int cm, float data) { |
| setCommon(id, cm); |
| type = TYPE_FLOAT; |
| floatData = data; |
| } |
| |
| /** |
| * Constructor for a <code>StatusVariable</code> of <code>boolean</code> |
| * type. |
| * |
| * @param id the identifier of the <code>StatusVariable</code> |
| * @param cm the collection method, one of the <code>CM_</code> constants |
| * @param data the <code>boolean</code> value of the |
| * <code>StatusVariable</code> |
| * @throws java.lang.IllegalArgumentException if the given <code>id</code> |
| * is not a valid <code>StatusVariable</code> name, or if |
| * <code>cm</code> is not one of the collection method constants |
| * @throws java.lang.NullPointerException if the <code>id</code> parameter |
| * is <code>null</code> |
| */ |
| public StatusVariable(String id, int cm, boolean data) { |
| setCommon(id, cm); |
| type = TYPE_BOOLEAN; |
| booleanData = data; |
| } |
| |
| /** |
| * Constructor for a <code>StatusVariable</code> of <code>String</code> |
| * type. |
| * |
| * @param id the identifier of the <code>StatusVariable</code> |
| * @param cm the collection method, one of the <code>CM_</code> constants |
| * @param data the <code>String</code> value of the |
| * <code>StatusVariable</code>, can be <code>null</code> |
| * @throws java.lang.IllegalArgumentException if the given <code>id</code> |
| * is not a valid <code>StatusVariable</code> name, or if |
| * <code>cm</code> is not one of the collection method constants |
| * @throws java.lang.NullPointerException if the <code>id</code> parameter |
| * is <code>null</code> |
| */ |
| public StatusVariable(String id, int cm, String data) { |
| setCommon(id, cm); |
| type = TYPE_STRING; |
| stringData = data; |
| } |
| |
| |
| // ----- Public methods -----// |
| /** |
| * Returns the ID of this <code>StatusVariable</code>. The ID is unique |
| * within the scope of a <code>Monitorable</code>. |
| * |
| * @return the ID of this <code>StatusVariable</code> |
| */ |
| public String getID() { |
| return id; |
| } |
| |
| /** |
| * Returns information on the data type of this <code>StatusVariable</code>. |
| * |
| * @return one of the <code>TYPE_</code> constants indicating the type of |
| * this <code>StatusVariable</code> |
| */ |
| public int getType() { |
| return type; |
| } |
| |
| /** |
| * Returns the timestamp associated with the <code>StatusVariable</code>. |
| * The timestamp is stored when the <code>StatusVariable</code> instance is |
| * created, generally during the {@link Monitorable#getStatusVariable} |
| * method call. |
| * |
| * @return the time when the <code>StatusVariable</code> value was |
| * queried, cannot be <code>null</code> |
| * |
| */ |
| public Date getTimeStamp() { |
| return timeStamp; |
| } |
| |
| /** |
| * Returns the <code>StatusVariable</code> value if its type is |
| * <code>String</code>. |
| * |
| * @return the <code>StatusVariable</code> value as a <code>String</code> |
| * @throws java.lang.IllegalStateException if the type of the |
| * <code>StatusVariable</code> is not <code>String</code> |
| */ |
| public String getString() throws IllegalStateException { |
| if (type != TYPE_STRING) |
| throw new IllegalStateException( |
| "This StatusVariable does not contain a String value."); |
| return stringData; |
| } |
| |
| /** |
| * Returns the <code>StatusVariable</code> value if its type is |
| * <code>int</code>. |
| * |
| * @return the <code>StatusVariable</code> value as an <code>int</code> |
| * @throws java.lang.IllegalStateException if the type of this |
| * <code>StatusVariable</code> is not <code>int</code> |
| */ |
| public int getInteger() throws IllegalStateException { |
| if (type != TYPE_INTEGER) |
| throw new IllegalStateException( |
| "This StatusVariable does not contain an integer value."); |
| return intData; |
| } |
| |
| /** |
| * Returns the <code>StatusVariable</code> value if its type is |
| * <code>float</code>. |
| * |
| * @return the <code>StatusVariable</code> value as a <code>float</code> |
| * @throws java.lang.IllegalStateException if the type of this |
| * <code>StatusVariable</code> is not <code>float</code> |
| */ |
| public float getFloat() throws IllegalStateException { |
| if (type != TYPE_FLOAT) |
| throw new IllegalStateException( |
| "This StatusVariable does not contain a float value."); |
| return floatData; |
| } |
| |
| /** |
| * Returns the <code>StatusVariable</code> value if its type is |
| * <code>boolean</code>. |
| * |
| * @return the <code>StatusVariable</code> value as a <code>boolean</code> |
| * @throws java.lang.IllegalStateException if the type of this |
| * <code>StatusVariable</code> is not <code>boolean</code> |
| */ |
| public boolean getBoolean() throws IllegalStateException { |
| if (type != TYPE_BOOLEAN) |
| throw new IllegalStateException( |
| "This StatusVariable does not contain a boolean value."); |
| return booleanData; |
| } |
| |
| /** |
| * Returns the collection method of this <code>StatusVariable</code>. See |
| * section 3.3 b) in [ETSI TS 132 403] |
| * |
| * @return one of the <code>CM_</code> constants |
| */ |
| public int getCollectionMethod() { |
| return cm; |
| } |
| |
| /** |
| * Compares the specified object with this <code>StatusVariable</code>. |
| * Two <code>StatusVariable</code> objects are considered equal if their |
| * full path, collection method and type are identical, and the data |
| * (selected by their type) is equal. |
| * |
| * @param obj the object to compare with this <code>StatusVariable</code> |
| * @return <code>true</code> if the argument represents the same |
| * <code>StatusVariable</code> as this object |
| */ |
| public boolean equals(Object obj) { |
| if (!(obj instanceof StatusVariable)) |
| return false; |
| |
| StatusVariable other = (StatusVariable) obj; |
| |
| if (!equals(id, other.id) || cm != other.cm || type != other.type) |
| return false; |
| |
| switch (type) { |
| case TYPE_INTEGER: return intData == other.intData; |
| case TYPE_FLOAT: return floatData == other.floatData; |
| case TYPE_STRING: return equals(stringData, other.stringData); |
| case TYPE_BOOLEAN: return booleanData == other.booleanData; |
| } |
| |
| return false; // never reached |
| } |
| |
| /** |
| * Returns the hash code value for this <code>StatusVariable</code>. The |
| * hash code is calculated based on the full path, collection method and |
| * value of the <code>StatusVariable</code>. |
| * |
| * @return the hash code of this object |
| */ |
| public int hashCode() { |
| int hash = hashCode(id) ^ cm; |
| |
| switch (type) { |
| case TYPE_INTEGER: return hash ^ intData; |
| case TYPE_FLOAT: return hash ^ hashCode(new Float(floatData)); |
| case TYPE_BOOLEAN: return hash ^ hashCode(new Boolean(booleanData)); |
| case TYPE_STRING: return hash ^ hashCode(stringData); |
| } |
| |
| return 0; // never reached |
| } |
| |
| // String representation: StatusVariable(path, cm, time, type, value) |
| /** |
| * Returns a <code>String</code> representation of this |
| * <code>StatusVariable</code>. The returned <code>String</code> |
| * contains the full path, collection method, timestamp, type and value |
| * parameters of the <code>StatusVariable</code> in the following format: |
| * <pre>StatusVariable(<path>, <cm>, <timestamp>, <type>, <value>)</pre> |
| * The collection method identifiers used in the string representation are |
| * "CC", "DER", "GAUGE" and "SI" (without the quotes). The format of the |
| * timestamp is defined by the <code>Date.toString</code> method, while the |
| * type is identified by one of the strings "INTEGER", "FLOAT", "STRING" and |
| * "BOOLEAN". The final field contains the string representation of the |
| * value of the status variable. |
| * |
| * @return the <code>String</code> representation of this |
| * <code>StatusVariable</code> |
| */ |
| public String toString() { |
| String cmName = null; |
| switch (cm) { |
| case CM_CC: cmName = "CC"; break; |
| case CM_DER: cmName = "DER"; break; |
| case CM_GAUGE: cmName = "GAUGE"; break; |
| case CM_SI: cmName = "SI"; break; |
| } |
| |
| String beg = "StatusVariable(" + id + ", " + cmName + ", " |
| + timeStamp + ", "; |
| |
| switch (type) { |
| case TYPE_INTEGER: return beg + "INTEGER, " + intData + ")"; |
| case TYPE_FLOAT: return beg + "FLOAT, " + floatData + ")"; |
| case TYPE_STRING: return beg + "STRING, " + stringData + ")"; |
| case TYPE_BOOLEAN: return beg + "BOOLEAN, " + booleanData + ")"; |
| } |
| |
| return null; // never reached |
| } |
| |
| //----- Private methods -----// |
| |
| private void setCommon(String id, int cm) |
| throws IllegalArgumentException, NullPointerException { |
| checkId(id, "StatusVariable ID"); |
| |
| if (cm != CM_CC && cm != CM_DER && cm != CM_GAUGE && cm != CM_SI) |
| throw new IllegalArgumentException( |
| "Unknown data collection method constant '" + cm + "'."); |
| |
| this.id = id; |
| this.cm = cm; |
| timeStamp = new Date(); |
| } |
| |
| |
| private boolean equals(Object o1, Object o2) { |
| return o1 == null ? o2 == null : o1.equals(o2); |
| } |
| |
| private int hashCode(Object o) { |
| return o == null ? 0 : o.hashCode(); |
| } |
| |
| private static void checkId(String id, String idName) |
| throws IllegalArgumentException, NullPointerException { |
| if (id == null) |
| throw new NullPointerException(idName + " is null."); |
| if(id.length() == 0) |
| throw new IllegalArgumentException(idName + " is empty."); |
| |
| byte[] nameBytes; |
| try { |
| nameBytes = id.getBytes("UTF-8"); |
| } catch (UnsupportedEncodingException e) { |
| // never happens, "UTF-8" must always be supported |
| throw new IllegalStateException(e.getMessage()); |
| } |
| if(nameBytes.length > MAX_ID_LENGTH) |
| throw new IllegalArgumentException(idName + " is too long " + |
| "(over " + MAX_ID_LENGTH + " bytes in UTF-8 encoding)."); |
| |
| if(id.equals(".") || id.equals("..")) |
| throw new IllegalArgumentException(idName + " is invalid."); |
| |
| if(!containsValidChars(id)) |
| throw new IllegalArgumentException(idName + |
| " contains invalid characters."); |
| } |
| |
| private static boolean containsValidChars(String name) { |
| char[] chars = name.toCharArray(); |
| for(int i = 0; i < chars.length; i++) |
| if(SYMBOLIC_NAME_CHARACTERS.indexOf(chars[i]) == -1) |
| return false; |
| |
| return true; |
| } |
| } |