diff --git a/.gitignore b/.gitignore index 221d8ffd83..1c5b4fa531 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ config.log config.status configure pom.xml +mavenview +src-main +src-test diff --git a/.gitignore.bak b/.gitignore.bak new file mode 100644 index 0000000000..286f880404 --- /dev/null +++ b/.gitignore.bak @@ -0,0 +1,12 @@ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +build +target +config.log +config.status +configure +pom.xml +mavenview diff --git a/core b/core new file mode 100644 index 0000000000..4ba280517a --- /dev/null +++ b/core @@ -0,0 +1 @@ +-- diff --git a/graph b/graph new file mode 100644 index 0000000000..4ba280517a --- /dev/null +++ b/graph @@ -0,0 +1 @@ +-- diff --git a/maven-view.cmd b/maven-view.cmd new file mode 100644 index 0000000000..d40358db5c --- /dev/null +++ b/maven-view.cmd @@ -0,0 +1,180 @@ +########################################### +## Script to create a fully standard maven +## project image of opentsdb linked back +## into the original +########################################### + + +:mkdirtree + IF EXIST %~1 GOTO MKDIRTREEDONE + echo "Creating DirTree %~1" + md %~1 +:MKDIRTREEDONE +GOTO:EOF + + + +:linkdir + IF EXIST %~2 GOTO LINKDIRTREEDONE + echo " Linking %~2 ---> %~1" + mklink /D %~1 %~2 +:LINKDIRTREEDONE +GOTO:EOF + + + +:domavenview + echo "" + echo "" + echo "=============================================================================" + echo "Adding Mavenized View to OpenTSDB project at %TSDB_MVN%" + echo "=============================================================================" + echo "" + echo "" + + echo "Checking mavenized view root" + + call :mkdirtree "%TSDB_MVN%" + + echo "Creating base maven source tree" + + call :mkdirtree "%TSDB_MVN%/src/main/java/net/opentsdb/tsd" + call :mkdirtree "%TSDB_MVN%/src/main/java/tsd/client" + call :mkdirtree "%TSDB_MVN%/src/main/resources/shell" + call :mkdirtree "%TSDB_MVN%/src/test/java/net/opentsdb" + call :mkdirtree "%TSDB_MVN%/src/test/resources" + + echo "Linking core source to directory tree matching package structure" + + for %%D in (%TSDB_HOME%\*) do ( + set dir=%%~nxD + + if [[ -d "%TSDB_SRC%/$dir" && ! -d $TSDB_MVN/src/main/java/net/opentsdb/$dir && $dir != "tsd" ]]; then + echo " Linking $TSDB_MVN/src/main/java/net/opentsdb/$dir ---> %TSDB_SRC%/$dir" + ln -s %TSDB_SRC%/$dir $TSDB_MVN/src/main/java/net/opentsdb/$dir + fi + ) + + echo "Linking tsd exceptions source to directory tree matching package structure" + + for dir in %TSDB_SRC%/tsd/* + do + dir=`basename $dir` + if [[ $dir != "client" ]]; then + linkdir "%TSDB_SRC%/tsd/$dir" "$TSDB_MVN/src/main/java/net/opentsdb/tsd/$dir" + fi + done + + + echo "Linking client core source to directory tree matching package structure" + + for dir in %TSDB_SRC%/tsd/client/* + do + dir=`basename $dir` + linkdir "%TSDB_SRC%/tsd/client/$dir" "$TSDB_MVN/src/main/java/tsd/client/$dir" + done + + echo "Linking client gwt.xml" + linkdir "%TSDB_SRC%/tsd/QueryUi.gwt.xml" "$TSDB_MVN/src/main/java/tsd/QueryUi.gwt.xml" + + + + echo "Linking test source to directory tree matching package structure" + + for dir in $TSDB_HOME/test/* + do + dir=`basename $dir` + if [[ -d "$TSDB_HOME/test/$dir" && $dir != "META-INF" && $dir != "test" && ! -d $TSDB_MVN/src/test/java/net/opentsdb/$dir ]]; then + echo " Linking $TSDB_MVN/src/test/java/net/opentsdb/$dir ---> $TSDB_HOME/test/$dir" + ln -s $TSDB_HOME/test/$dir $TSDB_MVN/src/test/java/net/opentsdb/$dir + fi + done + + echo "Linking main resources" + + if [ ! -e "$TSDB_MVN/src/main/resources/logback.xml" ]; then + echo " Linking $TSDB_MVN/src/main/resources/logback.xml ---> %TSDB_SRC%/logback.xml" + ln -s %TSDB_SRC%/logback.xml $TSDB_MVN/src/main/resources/logback.xml + fi + + if [ ! -e "$TSDB_MVN/src/main/resources/opentsdb.conf" ]; then + echo " Linking $TSDB_MVN/src/main/resources/opentsdb.conf ---> %TSDB_SRC%/opentsdb.conf" + ln -s %TSDB_SRC%/opentsdb.conf $TSDB_MVN/src/main/resources/opentsdb.conf + fi + + if [ ! -e "$TSDB_MVN/src/main/resources/opentsdb.conf.json" ]; then + echo " Linking $TSDB_MVN/src/main/resources/opentsdb.conf.json ---> %TSDB_SRC%/opentsdb.conf.json" + ln -s %TSDB_SRC%/opentsdb.conf.json $TSDB_MVN/src/main/resources/opentsdb.conf.json + fi + + echo "Linking shell scripts main resources" + + for shf in create_table.sh mygnuplot.sh mygnuplot.bat + do + if [ ! -e "$TSDB_MVN/src/main/resources/shell/$shf" ]; then + echo " Linking $TSDB_MVN/src/main/resources/shell/$shf ---> %TSDB_SRC%/$shf" + ln -s %TSDB_SRC%/$shf $TSDB_MVN/src/main/resources/shell/$shf + fi + done + + echo "Linking test resources" + + if [ ! -e "$TSDB_MVN/src/test/resources/META-INF" ]; then + echo " Linking $TSDB_MVN/src/test/resources/META-INF ---> $TSDB_HOME/test/META-INF" + ln -s $TSDB_HOME/test/META-INF $TSDB_MVN/src/test/resources/META-INF + fi + + echo "Linking build-aux" + + linkdir "$TSDB_HOME/build-aux" "$TSDB_MVN/build-aux" + + echo "Linking maven-view.pom.xml" + linkdir "$TSDB_HOME/maven-view.pom.xml" "$TSDB_MVN/pom.xml" + +} + + +# Automatically runs mavenview on the current dir +if [ "$1" == "-auto" ]; then + export TSDB_HOME=$(readlink -f .) + export TSDB_SRC=$TSDB_HOME/src + export TSDB_MVN=$TSDB_HOME/mavenview + echo "=============================================================================" + echo " Auto Mavenizing $TSDB_HOME --> $TSDB_MVN" + echo "=============================================================================" + domavenview + exit 0 +fi + +if [ "$1" == "" ]; then + echo "ERROR: directory specificity underflow" + echo "Please specify the TSDB Project Root" + echo "e.g. maven-view.sh /home/chappie/projects/opentsdb" + echo " or even maven-view.sh ." + exit 1 +fi + +export TSDB_HOME=$(readlink -f $1) +export TSDB_SRC=$TSDB_HOME/src +export TSDB_MVN=$TSDB_HOME/mavenview + + + +echo "" +echo "" +echo "=============================================================================" +read -p "About to mavenize TSDB at project root $TSDB_HOME. Are you sure? " -n 1 -r +echo # (optional) move to a new line +if [[ ! $REPLY =~ ^[Yy]$ ]] +then + echo " ... and we're outa here." + exit 1 +fi + +domavenview + + + + + + diff --git a/maven-view.pom.xml b/maven-view.pom.xml new file mode 100644 index 0000000000..0e6fdaca9d --- /dev/null +++ b/maven-view.pom.xml @@ -0,0 +1,518 @@ + + 4.0.0 + net.opentsdb + opentsdb + 2.0.0 + OpenTSDB + + The OpenTSDB Authors + http://opentsdb.net + + jar + + OpenTSDB is a distributed, scalable Time Series Database (TSDB) + written on top of HBase. OpenTSDB was written to address a common need: + store, index and serve metrics collected from computer systems (network + gear, operating systems, applications) at a large scale, and make this + data easily accessible and graphable. + + http://opentsdb.net + + + LGPLv2.1+ + http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html + repo + + + + scm:git:git@github.com:OpenTSDB/opentsdb.git + https://github.com/OpenTSDB/opentsdb + + + GitHub + https://github.com/OpenTSDB/opentsdb/issues + + + + User List + opentsdb@googlegroups.com + opentsdb+subscribe@googlegroups.com + opentsdb+unsubscribe@googlegroups.com + https://groups.google.com/group/opentsdb + + + + + tsuna + Benoit "tsuna" Sigoure + tsunanet@gmail.com + + developer + + -8 + + + 2010 + + + UTF-8 + 1.6 + 1.6 + + 13.0.1 + 2.1.4 + 3.6.2.Final + 1.4.0 + 3.3.6 + 1.7.2 + 1.4.1 + + 1.0.9 + + 1.3 + 3.17.1-GA + 4.11 + 1.9.5 + 1.3 + 1.5 + + 2.5.0 + + 2.5.1 + 2.4 + 2.1.2 + 2.8.1 + 2.4 + 2.9 + 2.2.1 + 2.16 + 2.5.1 + 2.1 + 1.2.1 + 1.7 + 2.12.4 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler-plugin.version} + + ${compiler-source.version} + ${compiler-target.version} + -Xlint + + + + + org.apache.maven.plugins + maven-jar-plugin + ${jar-plugin.version} + + + + true + true + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper.version} + + + add-source + generate-sources + + add-source + + + + target/generated-sources + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + -XX:PermSize=128m -XX:MaxPermSize=512m + + + + + + org.codehaus.mojo + gwt-maven-plugin + ${gwt.version} + + + compile + + true + tsd.QueryUi + + + compile + + + + + + + org.apache.maven.plugins + maven-source-plugin + ${source-plugin.version} + + + attach-sources + verify + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc-plugin.version} + + + attach-javadocs + verify + + jar + + + + + public + true + true + + Copyright © {inceptionYear}-{currentYear}, + ${project.organization.name} + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + ${eclipse-plugin.version} + + true + true + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7 + + + + + + + org.apache.maven.plugins + maven-idea-plugin + ${idea-plugin.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${shade.version} + + + package + + shade + + + true + + + + + + + net.opentsdb.tools.TSDMain + + + + + + + + + + + + com.google.guava + guava + ${guava.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + io.netty + netty + ${netty.version} + + + com.stumbleupon + async + ${async.version} + + + org.apache.zookeeper + zookeeper + ${zookeeper.version} + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + jline + jline + + + junit + junit + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.hbase + asynchbase + ${asynchbase.version} + + + + org.slf4j + log4j-over-slf4j + ${slf4j.version} + + + ch.qos.logback + logback-core + ${logback.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + org.hamcrest + hamcrest-core + ${hamcrest.version} + test + + + org.javassist + javassist + ${javassist.version} + test + + + junit + junit + ${junit.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.objenesis + objenesis + ${objenesis.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + + com.google.gwt + gwt-user + ${gwt.version} + provided + + + + + + + + + + + windows + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven.version} + + + build-data-codegen + generate-sources + + exec + + + cmd.exe + + /C + "build-aux\gen_build_data.cmd" + + + + + include-queryui + package + + exec + + + jar + + uf + ${project.build.directory}/${project.build.finalName}.jar + -C + ${project.build.directory}/${project.build.finalName} + queryui + + + + + + + + + + + Linux + + + !windows + + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven.version} + + + build-data-codegen + generate-sources + + exec + + + build-aux/gen_build_data.sh + + + target/generated-sources/net/opentsdb/BuildData.java + net.opentsdb + BuildData + + + + + include-queryui + package + + exec + + + jar + + uf + ${project.build.directory}/${project.build.finalName}.jar + -C + ${project.build.directory}/${project.build.finalName} + queryui + + + + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.16 + + + + + diff --git a/maven-view.sh b/maven-view.sh new file mode 100755 index 0000000000..2cc8be65f4 --- /dev/null +++ b/maven-view.sh @@ -0,0 +1,154 @@ +#!/bin/bash +########################################### +## Script to create a fully standard maven +## project image of opentsdb linked back +## into the original +########################################### + +if [ "$1" == "" ]; then + echo "ERROR: directory specificity underflow" + echo "Please specify the TSDB Project Root" + echo "e.g. maven-view.sh /home/chappie/projects/opentsdb" + echo " or even maven-view.sh ." + exit 1 +fi + +export TSDB_HOME=$(readlink -f $1) +export TSDB_SRC=$TSDB_HOME/src +export TSDB_MVN=$TSDB_HOME/mavenview + +function mkdirtree() { + if [ ! -d "$1" ]; then + echo "Creating DirTree $1" + mkdir -p $1 + fi +} + +function linkdir() { # target, link + if [ ! -d "$2" ]; then + echo " Linking $2 ---> $1" + ln -s $1 $2 + fi +} + + +echo "" +echo "" +echo "=============================================================================" +read -p "About to mavenize TSDB at project root $TSDB_HOME. Are you sure? " -n 1 -r +echo # (optional) move to a new line +if [[ ! $REPLY =~ ^[Yy]$ ]] +then + echo " ... and we're outa here." + exit 1 +fi + +echo "" +echo "" +echo "=============================================================================" +echo "Adding Mavenized View to OpenTSDB project at $TSDB_MVN" +echo "=============================================================================" +echo "" +echo "" + +echo "Checking mavenized view root" + +mkdirtree "$TSDB_MVN" + +echo "Creating base maven source tree" + +mkdirtree "$TSDB_MVN/src/main/java/net/opentsdb/tsd" +mkdirtree "$TSDB_MVN/src/main/java/tsd/client" +mkdirtree "$TSDB_MVN/src/main/resources/shell" +mkdirtree "$TSDB_MVN/src/test/java/net/opentsdb" +mkdirtree "$TSDB_MVN/src/test/resources" + +echo "Linking core source to directory tree matching package structure" + +for dir in $TSDB_SRC/* +do + dir=`basename $dir` + + if [[ -d "$TSDB_SRC/$dir" && ! -d $TSDB_MVN/src/main/java/net/opentsdb/$dir && $dir != "tsd" ]]; then + echo " Linking $TSDB_MVN/src/main/java/net/opentsdb/$dir ---> $TSDB_SRC/$dir" + ln -s $TSDB_SRC/$dir $TSDB_MVN/src/main/java/net/opentsdb/$dir + fi +done + +echo "Linking tsd exceptions source to directory tree matching package structure" + +for dir in $TSDB_SRC/tsd/* +do + dir=`basename $dir` + if [[ $dir != "client" ]]; then + linkdir "$TSDB_SRC/tsd/$dir" "$TSDB_MVN/src/main/java/net/opentsdb/tsd/$dir" + fi +done + + +echo "Linking client core source to directory tree matching package structure" + +for dir in $TSDB_SRC/tsd/client/* +do + dir=`basename $dir` + linkdir "$TSDB_SRC/tsd/client/$dir" "$TSDB_MVN/src/main/java/tsd/client/$dir" +done + +echo "Linking client gwt.xml" +linkdir "$TSDB_SRC/tsd/QueryUi.gwt.xml" "$TSDB_MVN/src/main/java/tsd/QueryUi.gwt.xml" + + + +echo "Linking test source to directory tree matching package structure" + +for dir in $TSDB_HOME/test/* +do + dir=`basename $dir` + if [[ -d "$TSDB_HOME/test/$dir" && $dir != "META-INF" && $dir != "test" && ! -d $TSDB_MVN/src/test/java/net/opentsdb/$dir ]]; then + echo " Linking $TSDB_MVN/src/test/java/net/opentsdb/$dir ---> $TSDB_HOME/test/$dir" + ln -s $TSDB_HOME/test/$dir $TSDB_MVN/src/test/java/net/opentsdb/$dir + fi +done + +echo "Linking main resources" + +if [ ! -e "$TSDB_MVN/src/main/resources/logback.xml" ]; then + echo " Linking $TSDB_MVN/src/main/resources/logback.xml ---> $TSDB_SRC/logback.xml" + ln -s $TSDB_SRC/logback.xml $TSDB_MVN/src/main/resources/logback.xml +fi + +if [ ! -e "$TSDB_MVN/src/main/resources/opentsdb.conf" ]; then + echo " Linking $TSDB_MVN/src/main/resources/opentsdb.conf ---> $TSDB_SRC/opentsdb.conf" + ln -s $TSDB_SRC/opentsdb.conf $TSDB_MVN/src/main/resources/opentsdb.conf +fi + + +echo "Linking shell scripts main resources" + +for shf in create_table.sh mygnuplot.sh mygnuplot.bat +do + if [ ! -e "$TSDB_MVN/src/main/resources/shell/$shf" ]; then + echo " Linking $TSDB_MVN/src/main/resources/shell/$shf ---> $TSDB_SRC/$shf" + ln -s $TSDB_SRC/$shf $TSDB_MVN/src/main/resources/shell/$shf + fi +done + +echo "Linking test resources" + +if [ ! -e "$TSDB_MVN/src/test/resources/META-INF" ]; then + echo " Linking $TSDB_MVN/src/test/resources/META-INF ---> $TSDB_HOME/test/META-INF" + ln -s $TSDB_HOME/test/META-INF $TSDB_MVN/src/test/resources/META-INF +fi + +echo "Linking build-aux" + +linkdir "$TSDB_HOME/build-aux" "$TSDB_MVN/build-aux" + +echo "Linking maven-view.pom.xml" +linkdir "$TSDB_HOME/maven-view.pom.xml" "$TSDB_MVN/pom.xml" + + + + + + diff --git a/maven-view2.cmd b/maven-view2.cmd new file mode 100644 index 0000000000..8cd06dff0b --- /dev/null +++ b/maven-view2.cmd @@ -0,0 +1,80 @@ +:: ########################################### +:: ## Script to create a standard maven +:: ## project image of opentsdb linked back +:: ## into the original +:: ########################################### +@echo off +GOTO:starthere + +:mkdirtree + IF EXIST %~1 GOTO MKDIRTREEDONE + echo "Creating DirTree %~1" + md %~1 +:MKDIRTREEDONE +GOTO:EOF + + + +:linkdir + IF EXIST %~2 GOTO LINKDIRTREEDONE + echo " Linking Dir %~2 ---> %~1" + mklink /D %~2 %~1 +:LINKDIRTREEDONE +GOTO:EOF + +:linkfile + IF EXIST %~2 GOTO LINKFILEDONE + echo " Linking File %~2 ---> %~1" + mklink %~2 %~1 +:LINKFILEDONE +GOTO:EOF + + + + +:starthere +set TSDB_HOME=%~dp0 +REM +REM +echo ============================================================================= +echo Adding Mavenized View to OpenTSDB project at %TSDB_HOME% +echo ============================================================================= +REM +REM + +set SRCMAIN=%TSDB_HOME%src-main +CALL :mkdirtree %SRCMAIN% +CALL :mkdirtree %SRCMAIN%\net +CALL :mkdirtree %SRCMAIN%\tsd + +pushd . +cd %SRCMAIN%\net +CALL :linkdir %TSDB_HOME%src %SRCMAIN%\net\opentsdb +popd + +pushd . +cd %SRCMAIN%\tsd +CALL :linkfile %TSDB_HOME%src\tsd\QueryUi.gwt.xml %SRCMAIN%\tsd\QueryUi.gwt.xml +CALL :linkdir %TSDB_HOME%\src\tsd\client %SRCMAIN%\tsd\client +popd + +set SRCTEST=%TSDB_HOME%src-test +CALL :mkdirtree %SRCTEST%\net +pushd . +cd %SRCTEST%\net + CALL :linkdir %TSDB_HOME%test %SRCTEST%\net\opentsdb +popd + +echo ============================================================================= +echo DONE +echo ============================================================================= + + + +:: domavenview + + + + + + diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index afdf436952..0000000000 --- a/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -BuildData.java diff --git a/src/core/DataPointsIterator.java b/src/core/DataPointsIterator.java deleted file mode 100644 index aaf870b113..0000000000 --- a/src/core/DataPointsIterator.java +++ /dev/null @@ -1,132 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.core; - -import java.util.NoSuchElementException; - -/** Default iterator for simple implementations of {@link DataPoints}. */ -final class DataPointsIterator implements SeekableView, DataPoint { - - /** Instance to iterate on. */ - private final DataPoints dp; - - /** Where are we in the iteration. */ - private short index = -1; - - /** - * Ctor. - * @param dp The data points to iterate on. - */ - DataPointsIterator(final DataPoints dp) { - this.dp = dp; - } - - // ------------------ // - // Iterator interface // - // ------------------ // - - public boolean hasNext() { - return index < dp.size() - 1; - } - - public DataPoint next() { - if (hasNext()) { - index++; - return this; - } - throw new NoSuchElementException("no more elements in " + this); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - // ---------------------- // - // SeekableView interface // - // ---------------------- // - - public void seek(final long timestamp) { - if ((timestamp & 0xFFFFFFFF00000000L) != 0) { // negative or not 32 bits - throw new IllegalArgumentException("invalid timestamp: " + timestamp); - } - // Do a binary search to find the timestamp given or the one right before. - short lo = 0; - short hi = (short) dp.size(); - - while (lo <= hi) { - index = (short) ((lo + hi) >>> 1); - long cmp = dp.timestamp(index) - timestamp; - - if (cmp < 0) { - lo = (short) (index + 1); - } else if (cmp > 0) { - hi = (short) (index - 1); - } else { - index--; // 'index' is exactly on the timestamp wanted. - return; // So let's go right before that for next(). - } - } - // We found the timestamp right before as there was no exact match. - // We take that position - 1 so the next call to next() returns it. - index = (short) (lo - 1); - // If the index we found was not the first or the last point, let's - // do a small extra sanity check to ensure the position we found makes - // sense: the timestamp we're at must not be >= what we're looking for. - if (0 < index && index < dp.size() && dp.timestamp(index) >= timestamp) { - throw new AssertionError("seeked after the time wanted!" - + " timestamp=" + timestamp - + ", index=" + index - + ", dp.timestamp(index)=" + dp.timestamp(index) - + ", this=" + this); - } - } - - /** Package-private helper to find the current index of this iterator. */ - int index() { - return index; - } - - // ------------------- // - // DataPoint interface // - // ------------------- // - - public long timestamp() { - return dp.timestamp(index); - } - - public boolean isInteger() { - return dp.isInteger(index); - } - - public long longValue() { - return dp.longValue(index); - } - - public double doubleValue() { - return dp.doubleValue(index); - } - - public double toDouble() { - return isInteger() ? longValue() : doubleValue(); - } - - public String toString() { - return "DataPointsIterator(index=" + index - + (index >= 0 - ? ", current type: " + (isInteger() ? "long" : "float") - + ", current value=" + (isInteger() ? longValue() : doubleValue()) - : " (iteration not started)") - + ", dp=" + dp + ')'; - } - -} diff --git a/src/core/IllegalDataException.java b/src/core/IllegalDataException.java deleted file mode 100644 index f0b6b4d915..0000000000 --- a/src/core/IllegalDataException.java +++ /dev/null @@ -1,40 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2011-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.core; - -/** - * Some illegal / malformed / corrupted data has been found in HBase. - */ -public final class IllegalDataException extends IllegalStateException { - - /** - * Constructor. - * - * @param msg Message describing the problem. - */ - public IllegalDataException(final String msg) { - super(msg); - } - - /** - * Constructor. - * - * @param msg Message describing the problem. - */ - public IllegalDataException(final String msg, final Throwable cause) { - super(msg, cause); - } - - static final long serialVersionUID = 1307719142; - -} diff --git a/src/core/SeekableView.java b/src/core/SeekableView.java deleted file mode 100644 index 7e7411038f..0000000000 --- a/src/core/SeekableView.java +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.core; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Provides a zero-copy view to iterate through data points. - *

- * The iterator returned by classes that implement this interface must return - * each {@link DataPoint} in {@code O(1)} and does not support {@link #remove}. - *

- * Because no data is copied during iteration and no new object gets created, - * the {@link DataPoint} returned must not be stored and gets - * invalidated as soon as {@link #next} is called on the iterator (actually it - * doesn't get invalidated but rather its contents changes). If you want to - * store individual data points, you need to copy the timestamp and value out - * of each {@link DataPoint} into your own data structures. - *

- * In the vast majority of cases, the iterator will be used to go once through - * all the data points, which is why it's not a problem if the iterator acts - * just as a transient "view". Iterating will be very cheap since no memory - * allocation is required (except to instantiate the actual iterator at the - * beginning). - */ -public interface SeekableView extends Iterator { - - /** - * Returns {@code true} if this view has more elements. - */ - boolean hasNext(); - - /** - * Returns a view on the next data point. - * No new object gets created, the referenced returned is always the same - * and must not be stored since its internal data structure will change the - * next time {@code next()} is called. - * @throws NoSuchElementException if there were no more elements to iterate - * on (in which case {@link #hasNext} would have returned {@code false}. - */ - DataPoint next(); - - /** - * Unsupported operation. - * @throws UnsupportedOperationException always. - */ - void remove(); - - /** - * Advances the iterator to the given point in time. - *

- * This allows the iterator to skip all the data points that are strictly - * before the given timestamp. - * @param timestamp A strictly positive 32 bit UNIX timestamp (in seconds). - * @throws IllegalArgumentException if the timestamp is zero, or negative, - * or doesn't fit on 32 bits (think "unsigned int" -- yay Java!). - */ - void seek(long timestamp); - -} diff --git a/src/core/WritableDataPoints.java b/src/core/WritableDataPoints.java deleted file mode 100644 index 671405263b..0000000000 --- a/src/core/WritableDataPoints.java +++ /dev/null @@ -1,118 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.core; - -import java.util.Map; - -import com.stumbleupon.async.Deferred; - -import org.hbase.async.HBaseException; - -/** - * Represents a mutable sequence of continuous data points. - *

- * Implementations of this interface aren't expected to be synchronized. - */ -public interface WritableDataPoints extends DataPoints { - - /** - * Sets the metric name and tags of the series. - *

- * This method can be called multiple times on the same instance to start - * adding data points to another time series without having to create a new - * instance. - * @param metric A non-empty string. - * @param tags The tags on this series. This map must be non-empty. - * @throws IllegalArgumentException if the metric name is empty or contains - * illegal characters. - * @throws IllegalArgumentException if the tags list is empty or one of the - * elements contains illegal characters. - */ - void setSeries(String metric, Map tags); - - /** - * Adds a {@code long} data point to the TSDB. - *

- * The data point is immediately persisted unless {@link #setBufferingTime} - * is used. Data points must be added in chronological order. - * @param timestamp The timestamp associated with the value. - * @param value The value of the data point. - * @return A deferred object that indicates the completion of the request. - * The {@link Object} has not special meaning and can be {@code null} (think - * of it as {@code Deferred}). But you probably want to attach at - * least an errback to this {@code Deferred} to handle failures. - * @throws IllegalArgumentException if the timestamp is less than or equal - * to the previous timestamp added or 0 for the first timestamp, or if the - * difference with the previous timestamp is too large. - * @throws HBaseException (deferred) if there was a problem while persisting - * data. - */ - Deferred addPoint(long timestamp, long value); - - /** - * Appends a {@code float} data point to this sequence. - *

- * The data point is immediately persisted unless {@link #setBufferingTime} - * is used. Data points must be added in chronological order. - * @param timestamp The timestamp associated with the value. - * @param value The value of the data point. - * @return A deferred object that indicates the completion of the request. - * The {@link Object} has not special meaning and can be {@code null} (think - * of it as {@code Deferred}). But you probably want to attach at - * least an errback to this {@code Deferred} to handle failures. - * @throws IllegalArgumentException if the timestamp is less than or equal - * to the previous timestamp added or 0 for the first timestamp, or if the - * difference with the previous timestamp is too large. - * @throws IllegalArgumentException if the value is {@code NaN} or - * {@code Infinite}. - * @throws HBaseException (deferred) if there was a problem while persisting - * data. - */ - Deferred addPoint(long timestamp, float value); - - /** - * Specifies for how long to buffer edits, in milliseconds. - *

- * By calling this method, you're allowing new data points to be buffered - * before being sent to HBase. {@code 0} (the default) means data points - * are persisted immediately. - *

- * Buffering improves performance, reduces the number of RPCs sent to HBase, - * but can cause data loss if we die before we get a chance to send buffered - * edits to HBase. It also entails that buffered data points aren't visible - * to other applications using the TSDB until they're flushed to HBase. - * @param time The approximate maximum number of milliseconds for which data - * points should be buffered before being sent to HBase. This deadline will - * be honored on a "best effort" basis. - */ - void setBufferingTime(short time); - - /** - * Specifies whether or not this is a batch import. - *

- * It is preferred that this method be called for anything importing a batch - * of data points (as opposed to streaming in new data points in real time). - *

- * Calling this method changes a few important things: - *

    - *
  • Data points may not be persisted immediately. In the event of an - * outage in HBase during or slightly after the import, un-persisted data - * points will be lost.
  • - *
  • {@link #setBufferingTime} may be called with an argument - * chosen by the implementation.
  • - *
- * @param batchornot if true, then this is a batch import. - */ - void setBatchImport(boolean batchornot); - -} diff --git a/src/logback.xml b/src/logback.xml deleted file mode 100644 index b06776504a..0000000000 --- a/src/logback.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - %d{ISO8601} %-5level [%thread] %logger{0}: %msg%n - - - - - 1024 - - - - - - - - - - diff --git a/src/mygnuplot.sh b/src/mygnuplot.sh deleted file mode 100755 index a3723cedfe..0000000000 --- a/src/mygnuplot.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# Because !@#$%^ Java can't fucking do this without a bazillion lines of codes. -set -e -stdout=$1 -shift -stderr=$1 -shift -exec nice gnuplot "$@" >"$stdout" 2>"$stderr" diff --git a/src/stats/Histogram.java b/src/stats/Histogram.java deleted file mode 100644 index ad665f2c85..0000000000 --- a/src/stats/Histogram.java +++ /dev/null @@ -1,271 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.stats; - -import java.util.Arrays; - -/** - * A histogram to keep track of the approximation of a distribution of values. - *

- * This is not a general purpose implementation of histogram. It's - * specifically designed for "small" values (close to 0) as the primary - * use case is latency histograms. - *

- * All values must be positive ({@code >= 0}). - *

- * The histogram is linear (fixed size buckets) up to a given cutoff - * point. Beyond that point, the histogram becomes exponential (each - * bucket is twice as large as the previous one). This gives good - * granularity for lower values while still allowing a rough - * classification for the "long tail" of larger values. - *

- * Note that this implementation doesn't allow you to directly control - * the number of buckets in the histogram. The number will depend on - * the arguments given to the constructor. - *

- * This class is not synchronized. - */ -public final class Histogram { - - /** Interval between each bucket for the linear part of the histogram. */ - private final short interval; - - /** Inclusive value beyond which we switch to exponential buckets. */ - private final int cutoff; - - /** - * How many linear buckets we have. - * Technically we don't need to store this value but we do in order to - * avoid having to re-compute it in the fast path each time we add a - * new value. - */ - private final short num_linear_buckets; - - /** - * The power of 2 used by the first exponential bucket. - * Technically we don't need to store this value but we do in order to - * avoid having to re-compute it in the fast path each time we add a - * new value. - */ - private final short exp_bucket_shift; - - /** Buckets where we actually store the values. */ - private final int[] buckets; - - /** - * Constructor. - * @param max The maximum value of the histogram. Any value greater - * than this will be considered to be "infinity". - * @param interval The interval (size) of each linear bucket. - * @param cutoff The value beyond which to switch to exponential - * buckets. The histogram may actually use this value or a value up - * to {@code interval} greater. - * @throws IllegalArgumentException if any of following conditions are - * not met: - *

-   *   0 < interval <= max
-   *   0 <= cutoff <= max
-   * 
- */ - public Histogram(final int max, - final short interval, final int cutoff) { - if (interval > max) { - throw new IllegalArgumentException("interval > max! interval=" - + interval + ", max=" + max); - } else if (cutoff > max) { - throw new IllegalArgumentException("cutoff > max! cutoff=" - + cutoff + ", max=" + max); - } else if (interval < 1) { - throw new IllegalArgumentException("interval < 1! interval=" + interval); - } else if (cutoff < 0) { - throw new IllegalArgumentException("cutoff < 0! interval=" + cutoff); - } - this.interval = interval; - // One linear bucket every `interval' up to `cutoff'. - num_linear_buckets = (short) (cutoff / interval); - this.cutoff = num_linear_buckets * interval; - this.exp_bucket_shift = (short) log2rounddown(interval); - this.buckets = new int[num_linear_buckets - // Find how many exponential buckets we need, starting from the - // first power of 2 that's less than or equal to `interval'. - + log2roundup((max - cutoff) >> exp_bucket_shift) - // Add an extra overflow bucket at the end. - + 1]; - } - - /** - * Computes the logarithm base 2 (rounded up) of an integer. - *

- * This is essentially equivalent to - * {@code Math.ceil(Math.log(n) / Math.log(2))} - * except it's 3 times faster. - * @param n A strictly positive integer. - * @return The logarithm base 2. As a special case, if the integer - * given in argument is 0, this function returns 0. If the integer - * given in argument is negative, the return value is undefined. - * @see #log2rounddown - */ - static final int log2roundup(final int n) { - int log2 = 0; - while (n > 1 << log2) { - log2++; - } - return log2; - } - - /** - * Computes the logarithm base 2 (rounded down) of an integer. - *

- * This is essentially equivalent to - * {@code Math.floor(Math.log(n) / Math.log(2))} - * except it's 4.5 times faster. This function is also almost 70% - * faster than {@link #log2roundup}. - * @param n A strictly positive integer. - * @return The logarithm base 2. As a special case, if the integer - * given in argument is 0, this function returns 0. If the integer - * given in argument is negative, the return value is undefined. - * @see #log2roundup - */ - static final int log2rounddown(int n) { - int log2 = 0; - while (n > 1) { - n >>>= 1; - log2++; - } - return log2; - } - - /** Returns the number of buckets in this histogram. */ - public int buckets() { - return buckets.length; - } - - /** - * Adds a value to the histogram. - *

- * This method works in {@code O(1)}. - * @param value The value to add. - * @throws IllegalArgumentException if the value given is negative. - */ - public void add(final int value) { - if (value < 0) { - throw new IllegalArgumentException("negative value: " + value); - } - buckets[bucketIndexFor(value)]++; - } - - /** - * Returns the value of the pth percentile in this histogram. - *

- * This method works in {@code O(N)} where {@code N} is the number of - * {@link #buckets buckets}. - * @param p A strictly positive integer in the range {@code [1; 100]} - * @throws IllegalArgumentException if {@code p} is not valid. - */ - public int percentile(int p) { - if (p < 1 || p > 100) { - throw new IllegalArgumentException("invalid percentile: " + p); - } - int count = 0; // Count of values in the histogram. - for (int i = 0; i < buckets.length; i++) { - count += buckets[i]; - } - if (count == 0) { // Empty histogram. Need to special-case it, otherwise - return 0; // the `if (count <= p)' below will be erroneously true. - } - // Find the number of elements at or below which the pth percentile is. - p = count * p / 100; - // Now walk the array backwards and decrement the count until it reaches p. - for (int i = buckets.length - 1; i >= 0; i--) { - count -= buckets[i]; - if (count <= p) { - return bucketHighInterval(i); - } - } - return 0; - } - - /** - * Prints this histogram in a human readable ASCII format. - *

- * This is equivalent to calling {@link #printAsciiBucket} on every - * bucket. - * @param out The buffer to which to write the output. - */ - public void printAscii(final StringBuilder out) { - for (int i = 0; i < buckets.length; i++) { - printAsciiBucket(out, i); - } - } - - /** - * Prints a bucket of this histogram in a human readable ASCII format. - * @param out The buffer to which to write the output. - * @see #printAscii - */ - final void printAsciiBucket(final StringBuilder out, final int i) { - out.append('[') - .append(bucketLowInterval(i)) - .append('-') - .append(i == buckets.length - 1 ? "Inf" : bucketHighInterval(i)) - .append("): ") - .append(buckets[i]) - .append('\n'); - } - - /** Helper for unit tests that returns the value in the given bucket. */ - final int valueInBucket(final int index) { - return buckets[index]; - } - - /** Finds the index of the bucket in which the given value should be. */ - private int bucketIndexFor(final int value) { - if (value < cutoff) { - return value / interval; - } - int bucket = num_linear_buckets // Skip all linear buckets. - // And find which bucket the rest (after `cutoff') should be in. - // Reminder: the first exponential bucket ends at 2^exp_bucket_shift. - + log2rounddown((value - cutoff) >> exp_bucket_shift); - if (bucket >= buckets.length) { - return buckets.length - 1; - } - return bucket; - } - - /** Returns the low interval (inclusive) of the given bucket. */ - private int bucketLowInterval(final int index) { - if (index <= num_linear_buckets) { - return index * interval; - } else { - return cutoff + (1 << (index - num_linear_buckets + exp_bucket_shift)); - } - } - - /** Returns the high interval (exclusive) of the given bucket. */ - private int bucketHighInterval(final int index) { - if (index == buckets.length - 1) { - return Integer.MAX_VALUE; - } else { - return bucketLowInterval(index + 1); - } - } - - public String toString() { - return "Histogram(interval=" + interval + ", cutoff=" + cutoff - + ", num_linear_buckets=" + num_linear_buckets - + ", exp_bucket_shift=" + exp_bucket_shift - + ", buckets=" + Arrays.toString(buckets) + ')'; - } - -} diff --git a/src/tsd/GnuplotException.java b/src/tsd/GnuplotException.java deleted file mode 100644 index 5e0933224f..0000000000 --- a/src/tsd/GnuplotException.java +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.tsd; - -/** - * Exception thrown when Gnuplot fails. - */ -final class GnuplotException extends RuntimeException { - - public GnuplotException(final int gnuplot_return_value) { - super("Gnuplot returned " + gnuplot_return_value); - } - - public GnuplotException(final String gnuplot_stderr) { - super("Gnuplot stderr:\n" + gnuplot_stderr); - } - - static final long serialVersionUID = 1287770642; - -} diff --git a/src/tsd/HttpRpc.java b/src/tsd/HttpRpc.java deleted file mode 100644 index fc1e3f0bcb..0000000000 --- a/src/tsd/HttpRpc.java +++ /dev/null @@ -1,29 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.tsd; - -import java.io.IOException; - -import net.opentsdb.core.TSDB; - -/** Base interface for all HTTP query handlers. */ -interface HttpRpc { - - /** - * Executes this RPC. - * @param tsdb The TSDB to use. - * @param query The HTTP query to execute. - */ - void execute(TSDB tsdb, HttpQuery query) throws IOException; - -} diff --git a/src/tsd/LineBasedFrameDecoder.java b/src/tsd/LineBasedFrameDecoder.java deleted file mode 100644 index f0ff859b5c..0000000000 --- a/src/tsd/LineBasedFrameDecoder.java +++ /dev/null @@ -1,98 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.tsd; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.frame.FrameDecoder; -import org.jboss.netty.handler.codec.frame.TooLongFrameException; - -/** - * Decodes telnet-style frames delimited by new-lines. - *

- * Both "\n" and "\r\n" are handled. - *

- * This decoder is stateful and is thus NOT shareable. - */ -final class LineBasedFrameDecoder extends FrameDecoder { - - /** Maximum length of a frame we're willing to decode. */ - private final int max_length; - /** True if we're discarding input because we're already over max_length. */ - private boolean discarding; - - /** - * Creates a new decoder. - * @param max_length Maximum length of a frame we're willing to decode. - * If a frame is longer than that, a {@link TooLongFrameException} will - * be fired on the channel causing it. - */ - public LineBasedFrameDecoder(final int max_length) { - this.max_length = max_length; - } - - @Override - protected Object decode(final ChannelHandlerContext ctx, - final Channel channel, - final ChannelBuffer buffer) throws Exception { - final int eol = findEndOfLine(buffer); - if (eol != -1) { - final ChannelBuffer frame; - final int length = eol - buffer.readerIndex(); - assert length >= 0: "WTF? length=" + length; - if (discarding) { - frame = null; - buffer.skipBytes(length); - } else { - frame = buffer.readBytes(length); - } - final byte delim = buffer.readByte(); - if (delim == '\r') { - buffer.skipBytes(1); // Skip the \n. - } - return frame; - } - - final int buffered = buffer.readableBytes(); - if (!discarding && buffered > max_length) { - discarding = true; - Channels.fireExceptionCaught(ctx.getChannel(), - new TooLongFrameException("Frame length exceeds " + max_length + " (" - + buffered + " bytes buffered already)")); - } - if (discarding) { - buffer.skipBytes(buffer.readableBytes()); - } - return null; - } - - /** - * Returns the index in the buffer of the end of line found. - * Returns -1 if no end of line was found in the buffer. - */ - private static int findEndOfLine(final ChannelBuffer buffer) { - final int n = buffer.writerIndex(); - for (int i = buffer.readerIndex(); i < n; i ++) { - final byte b = buffer.getByte(i); - if (b == '\n') { - return i; - } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') { - return i; // \r\n - } - } - return -1; // Not found. - } - -} diff --git a/src/tsd/QueryUi.gwt.xml b/src/tsd/QueryUi.gwt.xml deleted file mode 100644 index 0bf3faf297..0000000000 --- a/src/tsd/QueryUi.gwt.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/tsd/TelnetRpc.java b/src/tsd/TelnetRpc.java deleted file mode 100644 index c2fabce7f4..0000000000 --- a/src/tsd/TelnetRpc.java +++ /dev/null @@ -1,33 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.tsd; - -import com.stumbleupon.async.Deferred; - -import org.jboss.netty.channel.Channel; - -import net.opentsdb.core.TSDB; - -/** Base interface for all telnet-style RPC handlers. */ -interface TelnetRpc { - - /** - * Executes this RPC. - * @param tsdb The TSDB to use. - * @param chan The channel on which the RPC was received. - * @param command The command received, split. - * @return A deferred result. - */ - Deferred execute(TSDB tsdb, Channel chan, String[] command); - -} diff --git a/src/tsd/WordSplitter.java b/src/tsd/WordSplitter.java deleted file mode 100644 index fbd9cf4b98..0000000000 --- a/src/tsd/WordSplitter.java +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package net.opentsdb.tsd; - -import java.nio.charset.Charset; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; - -import net.opentsdb.core.Tags; - -/** - * Splits a ChannelBuffer in multiple space separated words. - */ -final class WordSplitter extends OneToOneDecoder { - - private static final Charset CHARSET = Charset.forName("ISO-8859-1"); - - /** Constructor. */ - public WordSplitter() { - } - - @Override - protected Object decode(final ChannelHandlerContext ctx, - final Channel channel, - final Object msg) throws Exception { - return Tags.splitString(((ChannelBuffer) msg).toString(CHARSET), ' '); - } - -} diff --git a/src/tsd/client/DateTimeBox.java b/src/tsd/client/DateTimeBox.java deleted file mode 100644 index 0959fc59df..0000000000 --- a/src/tsd/client/DateTimeBox.java +++ /dev/null @@ -1,357 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -import java.util.Date; - -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.i18n.client.DateTimeFormat; -import com.google.gwt.user.client.ui.Grid; -import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.InlineHTML; -import com.google.gwt.user.client.ui.InlineLabel; -import com.google.gwt.user.client.ui.PushButton; -import com.google.gwt.user.client.ui.TextBox; -import com.google.gwt.user.client.ui.VerticalPanel; -import com.google.gwt.user.datepicker.client.DateBox; -import com.google.gwt.user.datepicker.client.DatePicker; - -/** - * A {@link DateBox} with support for time. - *

- * This class is unnecessarily complicated because {@link DateBox} wasn't - * designed in an extensible way (semi-purposefully). A thread gwt-contrib - * titled "DatePicker DatePickerComponent protected ?" from 2008 shows that - * back then they were working on an extensible {@link DateBox} and - * {@link DatePicker} for GWT 2, but as of Sep 2010 this hasn't happened. - * Their suggestion to copy-paste-hack the code is unacceptable so instead - * we go through a few hoops to make this work. - */ -final class DateTimeBox extends DateBox { - - private static final DateTimeFormat HHMM_FORMAT = - DateTimeFormat.getFormat("HH:mm"); - - private static final DefaultFormat DATE_FORMAT = - new DefaultFormat(DateTimeFormat.getFormat("yyyy/MM/dd-HH:mm:ss")) { - /** Adds support for some human readable dates ("1d ago", "10:30"). */ - @Override - public Date parse(final DateBox box, - final String text, - final boolean report_error) { - if (text.endsWith(" ago") || text.endsWith("-ago")) { // e.g. "1d ago". - int interval; - final int lastchar = text.length() - 5; - try { - interval = Integer.parseInt(text.substring(0, lastchar)); - } catch (NumberFormatException e) { - setError(box); - return null; - } - if (interval <= 0) { - setError(box); - return null; - } - switch (text.charAt(lastchar)) { - case 's': break; // seconds - case 'm': interval *= 60; break; // minutes - case 'h': interval *= 3600; break; // hours - case 'd': interval *= 3600 * 24; break; // days - case 'w': interval *= 3600 * 24 * 7; break; // weeks - case 'y': interval *= 3600 * 24 * 365; break; // years - } - final Date d = new Date(); - d.setTime(d.getTime() - interval * 1000L); - return d; - } else if (text.length() == 5) { // "HH:MM" - try { - return HHMM_FORMAT.parse(text); - } catch (IllegalArgumentException ignored) { - setError(box); - return null; - } - } - return super.parse(box, text, report_error); - } - - private void setError(final DateBox box) { - box.addStyleName("dateBoxFormatError"); - } - }; - - public DateTimeBox() { - super(new DateTimePicker(), null, DATE_FORMAT); - ((DateTimePicker) getDatePicker()).setDateTimeBox(this); - final TextBox textbox = getTextBox(); - // Chrome 7.0.5xx versions, Safari 5.0.x and similar render a text box - // that's too small for 19 characters (WTF?). So we ask for space for - // an extra 2 characters. On Firefox the text box's width is computed - // properly, so it simply appears slightly wider than necessary. - textbox.setVisibleLength(19 + 2); - textbox.setMaxLength(19); - } - - /** - * A {@link DatePicker} with a customized UI for time support. - */ - private static final class DateTimePicker extends DatePicker { - - /** DateTimeBox this picker belongs to. */ - private DateTimeBox box; - /** A grid in which we put some buttons we may need to update. */ - private Grid hours_minutes; - - public DateTimePicker() { - } - - /** - * Sets the {@link DateTimeBox} this {@link DateTimePicker} belongs to. - * This must be called before using this object. - */ - void setDateTimeBox(final DateTimeBox box) { - this.box = box; - } - - /** - * Sets the date of the {@link DateBox} to the given {@link Date}. - */ - private void setDate(final Date d) { - refreshAll(); - box.setValue(d); - // Put the focus back on the text box to make it easier for the - // user to manually edit the field. - box.getTextBox().setFocus(true); - } - - /** - * Returns a new button that shifts the date when clicked. - * @param seconds How many seconds to shift. - * @param label The label to put on the button. - */ - private PushButton newShiftDateButton(final int seconds, - final String label) { - final PushButton button = new PushButton(label); - button.setStyleName(seconds < 0 ? "datePickerPreviousButton" - : "datePickerNextButton"); - button.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - Date d = box.getValue(); - if (d == null) { - if (seconds >= 0) { - return; - } - d = new Date(); - } - d.setTime(d.getTime() + seconds * 1000L); - d.setSeconds(0); - setDate(d); - } - }); - return button; - } - - /** - * Returns a new button that sets the hours when clicked. - * @param hours An hour of the day (0-23). - * @param label The label to put on the button. - */ - private PushButton newSetHoursButton(final int hours) { - final PushButton button = new PushButton(Integer.toString(hours)); - button.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - @SuppressWarnings(/* GWT requires us to use Date */{"deprecation"}) - Date d = box.getValue(); - if (d == null) { - d = new Date(); - d.setMinutes(0); - } - d.setHours(hours); - d.setSeconds(0); - setDate(d); - } - }); - return button; - } - - /** - * Returns a new button that sets the minutes when clicked. - * @param minutes A value for minutes (0-59). - * @param label The label to put on the button. - */ - private PushButton newSetMinutesButton(final int minutes, - final String label) { - final PushButton button = new PushButton(label); - button.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - @SuppressWarnings(/* GWT requires us to use Date */{"deprecation"}) - Date d = box.getValue(); - if (d == null) { - d = new Date(); - } - d.setMinutes(minutes); - d.setSeconds(0); - setDate(d); - } - }); - return button; - } - - /** Rebuilds parts of the UI with buttons to set AM hours. */ - private void setupAmUI() { - hours_minutes.setWidget(0, 1, newSetHoursButton(0)); - hours_minutes.setWidget(0, 2, newSetHoursButton(1)); - hours_minutes.setWidget(0, 3, newSetHoursButton(2)); - hours_minutes.setWidget(0, 4, newSetHoursButton(3)); - hours_minutes.setWidget(0, 5, newSetHoursButton(4)); - hours_minutes.setWidget(0, 6, newSetHoursButton(5)); - hours_minutes.setWidget(1, 1, newSetHoursButton(6)); - hours_minutes.setWidget(1, 2, newSetHoursButton(7)); - hours_minutes.setWidget(1, 3, newSetHoursButton(8)); - hours_minutes.setWidget(1, 4, newSetHoursButton(9)); - hours_minutes.setWidget(1, 5, newSetHoursButton(10)); - hours_minutes.setWidget(1, 6, newSetHoursButton(11)); - } - - /** Rebuilds parts of the UI with buttons to set PM hours. */ - private void setupPmUI() { - hours_minutes.setWidget(0, 1, newSetHoursButton(12)); - hours_minutes.setWidget(0, 2, newSetHoursButton(13)); - hours_minutes.setWidget(0, 3, newSetHoursButton(14)); - hours_minutes.setWidget(0, 4, newSetHoursButton(15)); - hours_minutes.setWidget(0, 5, newSetHoursButton(16)); - hours_minutes.setWidget(0, 6, newSetHoursButton(17)); - hours_minutes.setWidget(1, 1, newSetHoursButton(18)); - hours_minutes.setWidget(1, 2, newSetHoursButton(19)); - hours_minutes.setWidget(1, 3, newSetHoursButton(20)); - hours_minutes.setWidget(1, 4, newSetHoursButton(21)); - hours_minutes.setWidget(1, 5, newSetHoursButton(22)); - hours_minutes.setWidget(1, 6, newSetHoursButton(23)); - } - - /** Sets up the custom UI of the date picker. */ - @Override - protected void setup() { - final HorizontalPanel panel = new HorizontalPanel(); - initWidget(panel); - setStyleName(panel.getElement(), "gwt-DatePicker"); - - { - final VerticalPanel vbox = new VerticalPanel(); - setStyleName("gwt-DatePicker"); - vbox.add(super.getMonthSelector()); - vbox.add(super.getView()); - - panel.add(vbox); - } - - { - // This vbox contains all of the "extra" panel on the side - // of the calendar view. - final VerticalPanel vbox = new VerticalPanel(); - setStyleName(vbox.getElement(), "datePickerMonthSelector"); - - final PushButton now = new PushButton("now"); - now.setStyleName("datePickerNextButton"); - now.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - box.setValue(new Date()); - } - }); - - { - final Grid grid = new Grid(2, 9); - grid.setWidget(0, 0, newShiftDateButton(-3600, "1h")); - grid.setWidget(0, 1, newShiftDateButton(-600, "10m")); - grid.setWidget(0, 2, newShiftDateButton(-60, "1m")); - grid.setWidget(0, 3, new InlineHTML("‹")); - grid.setWidget(0, 4, now); - grid.setWidget(0, 5, new InlineHTML("›")); - grid.setWidget(0, 6, newShiftDateButton(+60, "1m")); - grid.setWidget(0, 7, newShiftDateButton(+600, "10m")); - grid.setWidget(0, 8, newShiftDateButton(+3600, "1h")); - grid.setWidget(1, 0, newShiftDateButton(-86400 * 30, "30d")); - grid.setWidget(1, 1, newShiftDateButton(-86400 * 7, "1w")); - grid.setWidget(1, 2, newShiftDateButton(-86400, "1d")); - grid.setWidget(1, 3, new InlineHTML("«")); - grid.setWidget(1, 4, new InlineHTML(" ")); - grid.setWidget(1, 5, new InlineHTML("»")); - grid.setWidget(1, 6, newShiftDateButton(+86400, "1d")); - grid.setWidget(1, 7, newShiftDateButton(+86400 * 7, "1w")); - grid.setWidget(1, 8, newShiftDateButton(+86400 * 30, "30d")); - final CellFormatter formatter = grid.getCellFormatter(); - formatter.setWidth(0, 4, "100%"); - formatter.setWidth(1, 4, "100%"); - vbox.add(grid); - } - - { - hours_minutes = new Grid(4, 8); - setupAmUI(); - hours_minutes.setWidget(0, 0, new InlineLabel("HH")); - final PushButton set_am = new PushButton("AM"); - set_am.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - setupAmUI(); - } - }); - hours_minutes.setWidget(0, 7, set_am); - - final PushButton set_pm = new PushButton("PM"); - set_pm.addClickHandler(new ClickHandler() { - public void onClick(final ClickEvent event) { - setupPmUI(); - } - }); - hours_minutes.setWidget(1, 7, set_pm); - - hours_minutes.setWidget(2, 0, new InlineLabel("MM")); - hours_minutes.setWidget(2, 1, newSetMinutesButton(0, "00")); - hours_minutes.setWidget(2, 2, newSetMinutesButton(10, "10")); - hours_minutes.setWidget(2, 3, newSetMinutesButton(20, "20")); - hours_minutes.setWidget(2, 4, newSetMinutesButton(30, "30")); - hours_minutes.setWidget(2, 5, newSetMinutesButton(40, "40")); - hours_minutes.setWidget(2, 6, newSetMinutesButton(50, "50")); - vbox.add(hours_minutes); - } - - { - final HorizontalPanel hbox = new HorizontalPanel(); - hbox.add(new InlineLabel("UNIX timestamp:")); - final ValidatedTextBox ts = new ValidatedTextBox(); - ts.setValidationRegexp("^(|[1-9][0-9]{0,9})$"); - ts.setVisibleLength(10); - ts.setMaxLength(10); - final EventsHandler handler = new EventsHandler() { - protected void onEvent(final DomEvent event) { - final Date d = new Date(Integer.parseInt(ts.getValue()) * 1000L); - box.setValue(d, true); - } - }; - ts.addBlurHandler(handler); - ts.addKeyPressHandler(handler); - hbox.add(ts); - vbox.add(hbox); - } - vbox.setHeight("100%"); - panel.add(vbox); - panel.setCellHeight(vbox, "100%"); - } - } - - } - -} diff --git a/src/tsd/client/EventsHandler.java b/src/tsd/client/EventsHandler.java deleted file mode 100644 index abd5bc7dc8..0000000000 --- a/src/tsd/client/EventsHandler.java +++ /dev/null @@ -1,81 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.ChangeHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyPressHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DeferredCommand; - -/** - * Handler for multiple events that indicate that the widget may have changed. - *

- * This handler is just a convenient 4-in-1 handler that can be re-used on a - * wide range of widgets such as {@code TextBox} and its derivative, - * {@code CheckBox}, {@code ListBox} etc. - */ -abstract class EventsHandler implements BlurHandler, ChangeHandler, - ClickHandler, KeyPressHandler { - - /** - * Called after one of the events (click, blur, change or "enter" - * is pressed) occurs. - *

- * This method is NOT called while the event is happening. It's invoked via - * a {@link DeferredCommand deferred command}. This entails that the event - * can't be cancelled as it has already executed. The reason the call is - * deferred is that this way, things like {@code SuggestBox}s will have - * already done their auto-completion by the time this method is called, and - * thus the handler will see the suggested text instead of the partial input - * being typed by the user. - * @param event The event that occurred. - */ - protected abstract void onEvent(DomEvent event); - - public final void onClick(final ClickEvent event) { - scheduleEvent(event); - } - - public final void onBlur(final BlurEvent event) { - scheduleEvent(event); - } - - public final void onChange(final ChangeEvent event) { - scheduleEvent(event); - } - - public final void onKeyPress(final KeyPressEvent event) { - if (event.getCharCode() == KeyCodes.KEY_ENTER) { - scheduleEvent(event); - } - } - - /** Executes the event using a deferred command. */ - private void scheduleEvent(final DomEvent event) { - DeferredCommand.addCommand(new Command() { - public void execute() { - onEvent(event); - } - }); - } - -} diff --git a/src/tsd/client/GotJsonCallback.java b/src/tsd/client/GotJsonCallback.java deleted file mode 100644 index 2bd1e06687..0000000000 --- a/src/tsd/client/GotJsonCallback.java +++ /dev/null @@ -1,21 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -import com.google.gwt.json.client.JSONValue; - -interface GotJsonCallback { - - void got(JSONValue json); - -} diff --git a/src/tsd/client/QueryString.java b/src/tsd/client/QueryString.java deleted file mode 100644 index 8652850e44..0000000000 --- a/src/tsd/client/QueryString.java +++ /dev/null @@ -1,90 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -// I (tsuna) originally wrote this code for Netty. Surprisingly, GWT has -// nothing to manually parse query string parameters... - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * Splits an HTTP query string into a path string and key-value parameter pairs. - */ -public final class QueryString extends HashMap> { - - /** - * Returns the decoded key-value parameter pairs of the URI. - */ - public static QueryString decode(final String s) { - final QueryString params = new QueryString(); - String name = null; - int pos = 0; // Beginning of the unprocessed region - int i; // End of the unprocessed region - for (i = 0; i < s.length(); i++) { - final char c = s.charAt(i); - if (c == '=' && name == null) { - if (pos != i) { - name = s.substring(pos, i); - } - pos = i + 1; - } else if (c == '&') { - if (name == null && pos != i) { - // We haven't seen an `=' so far but moved forward. - // Must be a param of the form '&a&' so add it with - // an empty value. - params.add(s.substring(pos, i), ""); - } else if (name != null) { - params.add(name, s.substring(pos, i)); - name = null; - } - pos = i + 1; - } - } - - if (pos != i) { // Are there characters we haven't dealt with? - if (name == null) { // Yes and we haven't seen any `='. - params.add(s.substring(pos, i), ""); - } else { // Yes and this must be the last value. - params.add(name, s.substring(pos, i)); - } - } else if (name != null) { // Have we seen a name without value? - params.add(name, ""); - } - - return params; - } - - /** - * Adds a query string element. - * @param name The name of the element. - * @param value The value of the element. - */ - public void add(final String name, final String value) { - ArrayList values = super.get(name); - if (values == null) { - values = new ArrayList(1); // Often there's only 1 value. - super.put(name, values); - } - values.add(value); - } - - /** - * Returns the first value for the given key, or {@code null}. - */ - public String getFirst(final String key) { - final ArrayList values = super.get(key); - return values == null ? null : values.get(0); - } - -} diff --git a/src/tsd/client/RemoteOracle.java b/src/tsd/client/RemoteOracle.java deleted file mode 100644 index 971b42a489..0000000000 --- a/src/tsd/client/RemoteOracle.java +++ /dev/null @@ -1,237 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -import java.util.HashMap; - -import com.google.gwt.http.client.RequestBuilder; -import com.google.gwt.http.client.RequestCallback; -import com.google.gwt.http.client.RequestException; -import com.google.gwt.json.client.JSONArray; -import com.google.gwt.json.client.JSONParser; -import com.google.gwt.json.client.JSONValue; -import com.google.gwt.user.client.ui.HasText; -import com.google.gwt.user.client.ui.MultiWordSuggestOracle; -import com.google.gwt.user.client.ui.SuggestBox; -import com.google.gwt.user.client.ui.SuggestOracle; -import com.google.gwt.user.client.ui.TextBoxBase; - -/** - * An oracle that gets suggestions through an AJAX call and provides caching. - * - * The oracle builds up a local cache of known suggestions and tries to avoid - * unnecessary requests when the cache can be used (which is fairly frequent - * given the typing pattern) or when we know for sure there won't be any - * results. - * - * The oracle is given a type. Every instance that share the same type also - * share the same caches under the hood. This is convenient when you want to - * have multiple text boxes with the same type of suggestions. - */ -final class RemoteOracle extends SuggestOracle { - - private static final String SUGGEST_URL = "/suggest?type="; // + type&q=foo - - /** - * Maps an oracle type to its suggestion cache. - * The cache is in fact a {@link MultiWordSuggestOracle}, which we re-use as - * its implementation is good (it uses a trie, handles HTML formatting etc.). - */ - private static final HashMap caches = - new HashMap(); - - /** Maps an oracle type to the queries recently seen for this type. */ - private static final HashMap all_queries_seen = - new HashMap(); - - private final String type; - private final MultiWordSuggestOracle cache; - private final QueriesSeen queries_seen; - - /** Which widget are we wrapping to provide suggestions. */ - private HasText requester; - /** Current ongoing request, or null. */ - private Callback current; - - /** - * Pending request that arrived while we were still processing `current'. - * If requests keep coming in while we're processing `current', the last - * pending one will overwrite the previous pending one. - */ - private Request pending_req; - private Callback pending_cb; - - /** Used to guess whether we need to fetch more suggestions. */ - private String last_query; - private String last_suggestion; - - /** - * Factory method to use in order to get a {@link RemoteOracle} instance. - * @param suggest_type The type of suggestion wanted. - * @param textbox The text box to wrap to provide suggestions to. - */ - public static SuggestBox newSuggestBox(final String suggest_type, - final TextBoxBase textbox) { - final RemoteOracle oracle = new RemoteOracle(suggest_type); - final SuggestBox box = new SuggestBox(oracle, textbox); - oracle.requester = box; - return box; - } - - /** Private constructor, use {@link #newSuggestBox} instead. */ - private RemoteOracle(final String suggest_type) { - type = suggest_type; - MultiWordSuggestOracle cache = caches.get(type); - QueriesSeen queries_seen; - if (cache == null) { - cache = new MultiWordSuggestOracle("."); - queries_seen = new QueriesSeen(); - caches.put(type, cache); - all_queries_seen.put(type, queries_seen); - } else { - queries_seen = all_queries_seen.get(type); - } - this.cache = cache; - this.queries_seen = queries_seen; - } - - @Override - public boolean isDisplayStringHTML() { - return true; - } - - @Override - public void requestSuggestions(final Request request, final Callback callback) { - if (current != null) { - pending_req = request; - pending_cb = callback; - return; - } - current = callback; - { - final String this_query = request.getQuery(); - // Check if we can serve this from our local cache, without even talking - // to the server. This is possible if either of those is true: - // 1. We've already seen this query recently. - // 2. This new query precedes another one and the user basically just - // typed another letter, so if the new query is "less than" the last - // result we got from the server, we know we already cached the full - // range of results covering the new request. - if ((last_query != null - && last_query.compareTo(this_query) <= 0 - && this_query.compareTo(last_suggestion) < 0) - || queries_seen.check(this_query)) { - current = null; - cache.requestSuggestions(request, callback); - return; - } - last_query = this_query; - } - - final RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, - SUGGEST_URL + type + "&q=" + last_query); - try { - builder.sendRequest(null, new RequestCallback() { - public void onError(final com.google.gwt.http.client.Request r, - final Throwable e) { - current = null; // Something bad happened, drop the current request. - if (pending_req != null) { // But if we have another waiting... - requestSuggestions(pending_req, pending_cb); // ... try it now. - } - } - - // Need to use fully-qualified names as this class inherits already - // from a pair of inner classes called Request / Response :-/ - public void onResponseReceived(final com.google.gwt.http.client.Request r, - final com.google.gwt.http.client.Response response) { - if (response.getStatusCode() == com.google.gwt.http.client.Response.SC_OK) { - final JSONValue json = JSONParser.parse(response.getText()); - // In case this request returned nothing, we pretend the last - // suggestion ended with the largest character possible, so we - // won't send more requests to the server if the user keeps - // adding extra characters. - last_suggestion = last_query + "\377"; - if (json != null && json.isArray() != null) { - final JSONArray results = json.isArray(); - final int n = Math.min(request.getLimit(), results.size()); - for (int i = 0; i < n; i++) { - final JSONValue suggestion = results.get(i); - if (suggestion == null || suggestion.isString() == null) { - continue; - } - final String suggestionstr = suggestion.isString().stringValue(); - last_suggestion = suggestionstr; - cache.add(suggestionstr); - } - // Is this response still relevant to what the requester wants? - if (requester.getText().startsWith(last_query)) { - cache.requestSuggestions(request, callback); - pending_req = null; - pending_cb = null; - } - } - } - current = null; // Regardless of what happened above, this is done. - if (pending_req != null) { - final Request req = pending_req; - final Callback cb = pending_cb; - pending_req = null; - pending_cb = null; - requestSuggestions(req, cb); - } - } - }); - } catch (RequestException ignore) { - } - } - - /** Small circular buffer of queries already typed by the user. */ - private static final class QueriesSeen { - - /** - * A circular buffer containing the last few requests already served. - * It would be awesome if {@code gwt.user.client.ui.PrefixTree} wasn't - * package-private, so we could use that instead. - */ - private final String[] already_requested = new String[128]; - private int already_index; // Index into already_index. - - /** - * Checks whether or not we've already seen that query. - */ - boolean check(final String query) { - // Check most recent queries first, as they're the most likely to match - // if the user goes back and forth by typing a few characters, removing - // some, typing some more, etc. - for (int i = already_index - 1; i >= 0; i--) { - if (query.equals(already_requested[i])) { - return true; - } - } - for (int i = already_requested.length - 1; i >= already_index; i--) { - if (query.equals(already_requested[i])) { - return true; - } - } - - // First time we see this query, let's record it. - already_requested[already_index++] = query; - if (already_index == already_requested.length) { - already_index = 0; - } - return false; - } - - } - -} diff --git a/src/tsd/client/ValidatedTextBox.java b/src/tsd/client/ValidatedTextBox.java deleted file mode 100644 index 4ca05e6fc2..0000000000 --- a/src/tsd/client/ValidatedTextBox.java +++ /dev/null @@ -1,59 +0,0 @@ -// This file is part of OpenTSDB. -// Copyright (C) 2010-2012 The OpenTSDB Authors. -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 2.1 of the License, or (at your -// option) any later version. This program is distributed in the hope that it -// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. You should have received a copy -// of the GNU Lesser General Public License along with this program. If not, -// see . -package tsd.client; - -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DeferredCommand; -import com.google.gwt.user.client.ui.TextBox; - -class ValidatedTextBox extends TextBox implements BlurHandler { - - private String regexp; - - public ValidatedTextBox() { - } - - public void setValidationRegexp(final String regexp) { - if (this.regexp == null) { // First call to this method. - super.addBlurHandler(this); - } - this.regexp = regexp; - } - - public String getValidationRegexp() { - return regexp; - } - - public void onBlur(final BlurEvent event) { - final String interval = getText(); - if (!interval.matches(regexp)) { - // Steal the dateBoxFormatError :) - addStyleName("dateBoxFormatError"); - event.stopPropagation(); - DeferredCommand.addCommand(new Command() { - public void execute() { - // TODO(tsuna): Understand why this doesn't work as expected, even - // though we cancel the onBlur event and we put the focus afterwards - // using a deferred command. - //setFocus(true); - selectAll(); - } - }); - } else { - removeStyleName("dateBoxFormatError"); - } - } - -} diff --git a/src/tsd/static/favicon.ico b/src/tsd/static/favicon.ico deleted file mode 100644 index 954d3c335e..0000000000 Binary files a/src/tsd/static/favicon.ico and /dev/null differ diff --git a/stats b/stats new file mode 100644 index 0000000000..4ba280517a --- /dev/null +++ b/stats @@ -0,0 +1 @@ +-- diff --git a/test.cmd b/test.cmd new file mode 100644 index 0000000000..06bbcd4c26 --- /dev/null +++ b/test.cmd @@ -0,0 +1,21 @@ +@echo off +set TSDB_HOME=%~dp0 +set TSDB_SRC=%TSDB_HOME%\src + +echo = +echo ================================================== +echo TSDB HOME: %TSDB_HOME% +echo ================================================== +echo = + + +set CURRRDIR=%%~dp0 +echo "CURRRDIR: %~dp0" + +:: for /D %%D in (%TSDB_HOME%\*) do ( +:: SETLOCAL +:: SET FD=%TSDB_HOME%\%%~nxD +:: echo %FD% +:: ENDLOCAL +:: ) + diff --git a/test/core/TestTSDB.java b/test/core/TestTSDB.java index 5bcf9cf1ee..624c06258e 100644 --- a/test/core/TestTSDB.java +++ b/test/core/TestTSDB.java @@ -30,6 +30,7 @@ import net.opentsdb.uid.UniqueId; import net.opentsdb.uid.UniqueId.UniqueIdType; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import org.hbase.async.AtomicIncrementRequest; import org.hbase.async.Bytes; @@ -38,7 +39,9 @@ import org.hbase.async.KeyValue; import org.hbase.async.PutRequest; import org.hbase.async.Scanner; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; @@ -67,6 +70,29 @@ public final class TestTSDB { private CompactionQueue compactionq = mock(CompactionQueue.class); private MockBase storage; + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + + @Before public void before() throws Exception { config = new Config(false); diff --git a/test/meta/TestAnnotation.java b/test/meta/TestAnnotation.java index 0751d621d0..7f4b87716d 100644 --- a/test/meta/TestAnnotation.java +++ b/test/meta/TestAnnotation.java @@ -42,7 +42,7 @@ @PowerMockIgnore({"javax.management.*", "javax.xml.*", "ch.qos.*", "org.slf4j.*", - "com.sum.*", "org.xml.*"}) + "com.sum.*", "org.xml.*", "com.sun.org.apache.xerces.internal.jaxp.*"}) @RunWith(PowerMockRunner.class) @PrepareForTest({TSDB.class, Config.class, UniqueId.class, HBaseClient.class, GetRequest.class, PutRequest.class, DeleteRequest.class, KeyValue.class, diff --git a/test/search/TestSearchPlugin.java b/test/search/TestSearchPlugin.java index 193088ccdd..1ea82df151 100644 --- a/test/search/TestSearchPlugin.java +++ b/test/search/TestSearchPlugin.java @@ -16,29 +16,55 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mock; - import net.opentsdb.core.TSDB; import net.opentsdb.meta.Annotation; import net.opentsdb.meta.TSMeta; import net.opentsdb.meta.UIDMeta; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import net.opentsdb.utils.PluginLoader; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.stumbleupon.async.Callback; +@PowerMockIgnore({"com.sun.org.apache.xerces.internal.jaxp.*"}) @RunWith(PowerMockRunner.class) @PrepareForTest({TSDB.class, Config.class}) public final class TestSearchPlugin { private TSDB tsdb= mock(TSDB.class); private Config config = mock(Config.class); private SearchPlugin search; + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + @Before public void before() throws Exception { diff --git a/test/tsd/TestHttpJsonSerializer.java b/test/tsd/TestHttpJsonSerializer.java index 4d4c355d62..7d7486bdc6 100644 --- a/test/tsd/TestHttpJsonSerializer.java +++ b/test/tsd/TestHttpJsonSerializer.java @@ -22,9 +22,12 @@ import net.opentsdb.core.TSDB; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import org.jboss.netty.buffer.ChannelBuffer; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -39,6 +42,29 @@ @PrepareForTest({TSDB.class, Config.class, HttpQuery.class}) public final class TestHttpJsonSerializer { private TSDB tsdb = null; + + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + @Before public void before() throws Exception { diff --git a/test/tsd/TestHttpQuery.java b/test/tsd/TestHttpQuery.java index 5227c26326..871eb1e2a9 100644 --- a/test/tsd/TestHttpQuery.java +++ b/test/tsd/TestHttpQuery.java @@ -29,6 +29,7 @@ import net.opentsdb.core.TSDB; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import net.opentsdb.utils.PluginLoader; import org.jboss.netty.buffer.ChannelBuffer; @@ -40,7 +41,9 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.jboss.netty.util.CharsetUtil; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -51,6 +54,30 @@ public final class TestHttpQuery { private TSDB tsdb = null; final static private Method guessMimeTypeFromUri; + + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + + static { try { guessMimeTypeFromUri = HttpQuery.class.getDeclaredMethod( @@ -81,6 +108,7 @@ public final class TestHttpQuery { } } + @Before public void before() throws Exception { tsdb = NettyMocks.getMockedHTTPTSDB(); diff --git a/test/tsd/TestRTPublisher.java b/test/tsd/TestRTPublisher.java index ec66a7a9e4..2075147eef 100644 --- a/test/tsd/TestRTPublisher.java +++ b/test/tsd/TestRTPublisher.java @@ -18,9 +18,12 @@ import static org.powermock.api.mockito.PowerMockito.mock; import net.opentsdb.core.TSDB; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import net.opentsdb.utils.PluginLoader; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; @@ -36,6 +39,29 @@ public final class TestRTPublisher { private TSDB tsdb= mock(TSDB.class); private Config config = mock(Config.class); private RTPublisher rt_publisher; + + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + @Before public void before() throws Exception { diff --git a/test/tsd/TestRpcPlugin.java b/test/tsd/TestRpcPlugin.java index 60cdbc18aa..279c5533d4 100644 --- a/test/tsd/TestRpcPlugin.java +++ b/test/tsd/TestRpcPlugin.java @@ -18,9 +18,12 @@ import static org.powermock.api.mockito.PowerMockito.mock; import net.opentsdb.core.TSDB; import net.opentsdb.utils.Config; +import net.opentsdb.utils.PluginJARFactory; import net.opentsdb.utils.PluginLoader; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; @@ -37,6 +40,29 @@ public final class TestRpcPlugin { private Config config = mock(Config.class); private RpcPlugin rpc_plugin; + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + + @Before public void before() throws Exception { // setups a good default for the config diff --git a/test/utils/PluginJARFactory.java b/test/utils/PluginJARFactory.java new file mode 100644 index 0000000000..af862775c7 --- /dev/null +++ b/test/utils/PluginJARFactory.java @@ -0,0 +1,242 @@ +// This file is part of OpenTSDB. +// Copyright (C) 2010-2012 The OpenTSDB Authors. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2.1 of the License, or (at your +// option) any later version. This program is distributed in the hope that it +// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. You should have received a copy +// of the GNU Lesser General Public License along with this program. If not, +// see . + +package net.opentsdb.utils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +/** + *

Title: PluginJARFactory

+ *

Description: Creates an OpenTSDB plugin jar on the fly

+ * @author Whitehead (nwhitehead AT heliosdev DOT org) + *

net.opentsdb.utils.PluginJARFactory

+ */ + +public class PluginJARFactory { + /** The stack of created files, in a thread local so we can run tests in parallel */ + private static final ThreadLocal> jarFileStack = new ThreadLocal>() { + @Override + protected Stack initialValue() { + return new Stack(); + } + }; + + /** + * Creates the plugin jar with the Services sub-folder + * @param jarFile The file the jar content will be written to + * @param classPairs A map of sets of impl classes keyed by the iface + * @param deleteOnExit If true, file will be marked to be deleted on exit + */ + private static void pluginJar(File jarFile, Map> classPairs, boolean deleteOnExit) { + FileOutputStream fos = null; + JarOutputStream jos = null; + try { + jarFileStack.get().push(jarFile); + if(deleteOnExit) jarFile.deleteOnExit(); + StringBuilder manifest = new StringBuilder(); + manifest.append("Manifest-Version: 1.0\n"); + ByteArrayInputStream bais = new ByteArrayInputStream(manifest.toString().getBytes()); + Manifest mf = new Manifest(bais); + fos = new FileOutputStream(jarFile, false); + jos = new JarOutputStream(fos, mf); + for(Map.Entry> entry: classPairs.entrySet()) { + String iface = entry.getKey(); + jos.putNextEntry(new ZipEntry("META-INF/services/" + iface)); + for(String impl: entry.getValue()) { + jos.write((impl + "\n").getBytes()); + } + } + jos.flush(); + jos.closeEntry(); + jos.close(); + fos.flush(); + fos.close(); + } catch (Exception e) { + throw new RuntimeException("Failed to Plugin Jar for [" + jarFile.getAbsolutePath() + "]", e); + } finally { + if(jos!=null) try { jos.close(); } catch (Exception e) {} + if(fos!=null) try { fos.close(); } catch (Exception e) {} + } + + } + + + + /** + * Pops the file off the top of the stack and deletes it + */ + public static void popAndDel() { + if(jarFileStack.get().isEmpty()) return; + try { + jarFileStack.get().pop().delete(); + } catch (Exception ex) { /* No Op */ } + } + + /** + * Pops the file off the top of the stack and deletes it if it's name is the same as the passed name + * @param name The expected name of the file on the top of the stack + */ + public static void popAndDel(String name) { + if(jarFileStack.get().isEmpty()) return; + if(jarFileStack.get().peek().getName().equals(name)) { + jarFileStack.get().pop().delete(); + } + if(jarFileStack.get().isEmpty()) { + jarFileStack.remove(); + } + } + + /** + * Clears the stack + */ + public static void purge() { + while(!jarFileStack.get().isEmpty()) { + popAndDel(); + } + jarFileStack.remove(); + } + + /** + * Creates a new SpecBuilder + * @param fileName The file name to write the spec as + * @return a new SpecBuilder + */ + public static SpecBuilder newBuilder(String fileName) { + return new SpecBuilder(fileName); + } + + /** + * No Ctor + */ + private PluginJARFactory() {} + + /** + *

Title: SpecBuilder

+ *

Description: A builder for prepping the creation of a service jar

+ * @author Whitehead (nwhitehead AT heliosdev DOT org) + *

net.opentsdb.utils.PluginJARFactory.SpecBuilder

+ */ + public static class SpecBuilder { + /** The array lists the builder stores the iface and impl when building */ + private final Map> classDefs = new HashMap>(); + /** The file name to write the spec as */ + private final File specFile; + /** Indicates if we should mark the jar for delete-on-exit. Defaults to true. */ + private boolean deleteOnExit = true; + /** + * Creates a new SpecBuilder + */ + private SpecBuilder(String fileName) { + this.specFile = new File(fileName); + } + + /** + * Builds and writes the configured jar file + */ + public void build() { + pluginJar(specFile, classDefs, deleteOnExit); + } + + /** + * Sets the delete on exit for the jar file created from this builder + * @param del true to enable, false to disable + * @return this builder + */ + public SpecBuilder deleteOnExit(boolean del) { + deleteOnExit = del; + return this; + } + + /** + * Adds an interface/parent and implementation pair to include in the Service spec + * @param iface The class name of the parent class or interface + * @param impl The class name[s] of the service implementation + * @return this builder + */ + public SpecBuilder service(String iface, String...impl) { + if(iface==null || iface.trim().isEmpty()) throw new IllegalArgumentException("The passed iface was null or empty"); + + Set impls = classDefs.get(iface.trim()); + if(impls==null) { + impls = new LinkedHashSet(); + classDefs.put(iface.trim(), impls); + } + for(String s: impl) { + if(s!=null) { + impls.add(s.trim()); + } + } + return this; + } + + /** + * Adds an interface/parent and implementation pair to include in the Service spec + * @param iface The class of the parent class or interface + * @param impl The class[es] of the service implementation + * @return this builder + */ + public SpecBuilder service(Class iface, Class...impl) { + if(iface==null) throw new IllegalArgumentException("The passed iface was null"); + if(impl==null) throw new IllegalArgumentException("The passed impl was null"); + return service(iface.getClass().getName(), classNameArr(impl)); + } + + /** + * Adds an interface/parent and implementation pair to include in the Service spec + * @param iface The class name of the parent class or interface + * @param impl The class[es] of the service implementation + * @return this builder + */ + public SpecBuilder service(String iface, Class...impl) { + if(impl==null) throw new IllegalArgumentException("The passed impl was null"); + return service(iface, classNameArr(impl)); + } + + /** + * Adds an interface/parent and implementation pair to include in the Service spec + * @param iface The class of the parent class or interface + * @param impl The class name[s] of the service implementation + * @return this builder + */ + public SpecBuilder service(Class iface, String...impl) { + if(iface==null) throw new IllegalArgumentException("The passed iface was null"); + return service(iface.getClass().getName(), impl); + } + + /** + * Converts an array of classes to an array of class names + * @param classes The classes + * @return the array of names + */ + private static String[] classNameArr(Class...classes) { + Set names = new LinkedHashSet(); + for(Class cl: classes) { + if(cl!=null) { + names.add(cl.getName()); + } + } + return names.toArray(new String[names.size()]); + } + } + +} diff --git a/test/utils/TestPluginLoader.java b/test/utils/TestPluginLoader.java index ea9596a06b..12fe874aad 100644 --- a/test/utils/TestPluginLoader.java +++ b/test/utils/TestPluginLoader.java @@ -22,10 +22,34 @@ import net.opentsdb.plugin.DummyPlugin; import net.opentsdb.utils.PluginLoader; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; public final class TestPluginLoader { + /** + * Creates the plugin jar + */ + @BeforeClass + public static void initPluginJar() { + PluginJARFactory.newBuilder("plugin_test.jar") + .service("net.opentsdb.plugin.DummyPlugin", "net.opentsdb.plugin.DummyPluginA", "net.opentsdb.plugin.DummyPluginB") + .service("net.opentsdb.search.SearchPlugin", "net.opentsdb.search.DummySearchPlugin") + .service("net.opentsdb.tsd.HttpSerializer", "net.opentsdb.tsd.DummyHttpSerializer") + .service("net.opentsdb.tsd.RpcPlugin", "net.opentsdb.tsd.DummyRpcPlugin") + .service("net.opentsdb.tsd.RTPublisher", "net.opentsdb.tsd.DummyRTPublisher") + .build(); + } + + /** + * Clears the created plugin jar + */ + @AfterClass + public static void clearPluginJar() { + PluginJARFactory.purge(); + } + @Test public void loadJar() throws Exception { PluginLoader.loadJAR("plugin_test.jar"); diff --git a/tsd b/tsd new file mode 100644 index 0000000000..4ba280517a --- /dev/null +++ b/tsd @@ -0,0 +1 @@ +-- diff --git a/uid b/uid new file mode 100644 index 0000000000..4ba280517a --- /dev/null +++ b/uid @@ -0,0 +1 @@ +--