001    /* ============================================================
002     * JRobin : Pure java implementation of RRDTool's functionality
003     * ============================================================
004     *
005     * Project Info:  http://www.jrobin.org
006     * Project Lead:  Sasa Markovic (saxon@jrobin.org);
007     *
008     * (C) Copyright 2003-2005, by Sasa Markovic.
009     *
010     * Developers:    Sasa Markovic (saxon@jrobin.org)
011     *
012     *
013     * This library is free software; you can redistribute it and/or modify it under the terms
014     * of the GNU Lesser General Public License as published by the Free Software Foundation;
015     * either version 2.1 of the License, or (at your option) any later version.
016     *
017     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
018     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
019     * See the GNU Lesser General Public License for more details.
020     *
021     * You should have received a copy of the GNU Lesser General Public License along with this
022     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
023     * Boston, MA 02111-1307, USA.
024     */
025    
026    package org.jrobin.core;
027    
028    /**
029     * Class to represent single data source definition within the RRD.
030     * Datasource definition consists of the following five elements:
031     * <p/>
032     * <ul>
033     * <li>data source name
034     * <li>data soruce type
035     * <li>heartbeat
036     * <li>minimal value
037     * <li>maximal value
038     * </ul>
039     * <p>For the complete explanation of all source definition parameters, see RRDTool's
040     * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>.</p>
041     *
042     * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a>
043     */
044    public class DsDef implements DsTypes {
045            /**
046             * array of valid source types
047             */
048            public static final String[] DS_TYPES = {DT_GAUGE, DT_COUNTER, DT_DERIVE, DT_ABSOLUTE};
049            static final String FORCE_ZEROS_FOR_NANS_SUFFIX = "!";
050    
051            private String dsName, dsType;
052            private long heartbeat;
053            private double minValue, maxValue;
054    
055            /**
056             * <p>Creates new data source definition object. This object should be passed as argument
057             * to {@link RrdDef#addDatasource(DsDef) addDatasource()}
058             * method of {@link RrdDb RrdDb} object.</p>
059             * <p/>
060             * <p>For the complete explanation of all source definition parameters, see RRDTool's
061             * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a></p>
062             * <p/>
063             * <p><b>IMPORTANT NOTE:</b> If datasource name ends with '!', corresponding archives will never
064             * store NaNs as datasource values. In that case, NaN datasource values will be silently
065             * replaced with zeros by the framework.</p>
066             *
067             * @param dsName        Data source name.
068             * @param dsType        Data source type. Valid values are "COUNTER", "GAUGE", "DERIVE"
069             *                  and "ABSOLUTE" (these string constants are conveniently defined in the
070             *                  {@link DsTypes} class).
071             * @param heartbeat Hearbeat
072             * @param minValue  Minimal value. Use <code>Double.NaN</code> if unknown.
073             * @param maxValue  Maximal value. Use <code>Double.NaN</code> if unknown.
074             * @throws RrdException Thrown if any parameter has illegal value.
075             */
076            public DsDef(String dsName, String dsType, long heartbeat,
077                                     double minValue, double maxValue) throws RrdException {
078                    this.dsName = dsName;
079                    this.dsType = dsType;
080                    this.heartbeat = heartbeat;
081                    this.minValue = minValue;
082                    this.maxValue = maxValue;
083                    validate();
084            }
085    
086            /**
087             * Returns data source name.
088             *
089             * @return Data source name.
090             */
091            public String getDsName() {
092                    return dsName;
093            }
094    
095            /**
096             * Returns source type.
097             *
098             * @return Source type ("COUNTER", "GAUGE", "DERIVE" or "ABSOLUTE").
099             */
100            public String getDsType() {
101                    return dsType;
102            }
103    
104            /**
105             * Returns source heartbeat.
106             *
107             * @return Source heartbeat.
108             */
109            public long getHeartbeat() {
110                    return heartbeat;
111            }
112    
113            /**
114             * Returns minimal calculated source value.
115             *
116             * @return Minimal value.
117             */
118            public double getMinValue() {
119                    return minValue;
120            }
121    
122            /**
123             * Returns maximal calculated source value.
124             *
125             * @return Maximal value.
126             */
127            public double getMaxValue() {
128                    return maxValue;
129            }
130    
131            private void validate() throws RrdException {
132                    if (dsName == null) {
133                            throw new RrdException("Null datasource name specified");
134                    }
135                    if (dsName.length() == 0) {
136                            throw new RrdException("Datasource name length equal to zero");
137                    }
138                    if (dsName.length() > RrdPrimitive.STRING_LENGTH) {
139                            throw new RrdException("Datasource name [" + dsName + "] to long (" +
140                                            dsName.length() + " chars found, only " + RrdPrimitive.STRING_LENGTH + " allowed");
141                    }
142                    if (!isValidDsType(dsType)) {
143                            throw new RrdException("Invalid datasource type specified: " + dsType);
144                    }
145                    if (heartbeat <= 0) {
146                            throw new RrdException("Invalid heartbeat, must be positive: " + heartbeat);
147                    }
148                    if (!Double.isNaN(minValue) && !Double.isNaN(maxValue) && minValue >= maxValue) {
149                            throw new RrdException("Invalid min/max values specified: " +
150                                            minValue + "/" + maxValue);
151                    }
152            }
153    
154            /**
155             * Checks if function argument represents valid source type.
156             *
157             * @param dsType Source type to be checked.
158             * @return <code>true</code> if <code>dsType</code> is valid type,
159             *         <code>false</code> otherwise.
160             */
161            public static boolean isValidDsType(String dsType) {
162                    for (String type : DS_TYPES) {
163                            if (type.equals(dsType)) {
164                                    return true;
165                            }
166                    }
167                    return false;
168            }
169    
170            /**
171             * Returns string representing source definition (RRDTool format).
172             *
173             * @return String containing all data source definition parameters.
174             */
175            public String dump() {
176                    return "DS:" + dsName + ":" + dsType + ":" + heartbeat +
177                                    ":" + Util.formatDouble(minValue, "U", false) +
178                                    ":" + Util.formatDouble(maxValue, "U", false);
179            }
180    
181            /**
182             * Checks if two datasource definitions are equal.
183             * Source definitions are treated as equal if they have the same source name.
184             * It is not possible to create RRD with two equal archive definitions.
185             *
186             * @param obj Archive definition to compare with.
187             * @return <code>true</code> if archive definitions are equal,
188             *         <code>false</code> otherwise.
189             */
190            public boolean equals(Object obj) {
191                    if (obj instanceof DsDef) {
192                            DsDef dsObj = (DsDef) obj;
193                            return dsName.equals(dsObj.dsName);
194                    }
195                    return false;
196            }
197    
198            boolean exactlyEqual(DsDef def) {
199                    return dsName.equals(def.dsName) && dsType.equals(def.dsType) &&
200                                    heartbeat == def.heartbeat && Util.equal(minValue, def.minValue) &&
201                                    Util.equal(maxValue, def.maxValue);
202            }
203    }