Imported Upstream version 1.5.1

This commit is contained in:
Mario Fetka
2020-09-22 02:25:22 +02:00
commit 434d6067d9
2103 changed files with 928962 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="Foundation" default="default" basedir=".">
<description>Builds, tests, and runs the project Foundation as part of the XtreemFS project.</description>
<import file="nbproject/build-impl-1.6.5.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="XtreemFS-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="Foundation" default="default" basedir=".">
<description>Builds, tests, and runs the project Foundation as part of the XtreemFS project.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="XtreemFS-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

89
java/foundation/build.xml Normal file
View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="Foundation" default="default" basedir=".">
<description>Builds, tests, and runs the project Foundation as part of the XtreemFS project.</description>
<import file="nbproject/build-impl.xml"/>
<import file="nbproject/profiler-build-impl.xml"/> <!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="XtreemFS-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
<!--
This target is required by the BabuDB replication plugin which uses only a subset
of the foundation code (the PBRPC communication infrastructure).
The generated .jar file contains the required files of the subset.
-->
<target name="pbrpc-jar" depends="compile">
<echo level="info">Creating PBRPC.jar.</echo>
<!-- Create a new JAR. -->
<jar destfile="dist/PBRPC.jar" basedir="build/classes">
<include name="org/xtreemfs/foundation/pbrpc/**/*.class"/>
<zipfileset dir="../../" includes="LICENSE" fullpath="/LICENSE"/>
</jar>
</target>
</project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="../lib/protobuf-java-2.5.0.jar"/>
<classpathentry kind="lib" path="../lib/test/junit-4.11.jar"/>
<classpathentry kind="lib" path="../lib/test/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="../lib/commons-codec-1.3.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>xtreemfs_foundation</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,682 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="XtreemFS-foundation-impl">
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="${empty.dir}" name="sourcepath"/>
<attribute default="${empty.dir}" name="gensrcdir"/>
<element name="customize" optional="true"/>
<sequential>
<property location="${build.dir}/empty" name="empty.dir"/>
<mkdir dir="${empty.dir}"/>
<mkdir dir="@{gensrcdir}"/>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<src>
<dirset dir="@{gensrcdir}">
<include name="*"/>
</dirset>
</src>
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<attribute default="${run.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<pathconvert property="build.generated.subdirs">
<dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="*"/>
</dirset>
</pathconvert>
<j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="libs.CopyLibs.classpath" name="-do-jar-with-libraries-without-manifest" unless="manifest.available+main.class">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
</copylibs>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-do-jar-with-libraries-without-manifest,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single" name="run-test-with-main">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
<fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,687 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="XtreemFS-foundation-impl">
<fail message="Please build using Ant 1.7.1 or higher.">
<condition>
<not>
<antversion atleast="1.7.1"/>
</not>
</condition>
</fail>
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="${empty.dir}" name="sourcepath"/>
<attribute default="${empty.dir}" name="gensrcdir"/>
<element name="customize" optional="true"/>
<sequential>
<property location="${build.dir}/empty" name="empty.dir"/>
<mkdir dir="${empty.dir}"/>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<src>
<dirset dir="@{gensrcdir}" erroronmissingdir="false">
<include name="*"/>
</dirset>
</src>
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<attribute default="${run.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<pathconvert property="build.generated.subdirs">
<dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="*"/>
</dirset>
</pathconvert>
<j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="libs.CopyLibs.classpath" name="-do-jar-with-libraries-without-manifest" unless="manifest.available+main.class">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
</copylibs>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-do-jar-with-libraries-without-manifest,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single" name="run-test-with-main">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
<fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,11 @@
build.xml.data.CRC32=4a9eff70
build.xml.script.CRC32=ce2ddeb0
build.xml.stylesheet.CRC32=958a1d3e
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=beaaf17a
nbproject/build-impl.xml.script.CRC32=3e4625c6
nbproject/build-impl.xml.stylesheet.CRC32=78c6a6ee@1.38.1.45
nbproject/profiler-build-impl.xml.data.CRC32=4a9eff70
nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
nbproject/profiler-build-impl.xml.stylesheet.CRC32=42cb6bcf

View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- profiling
- applet profiling
-->
<project name="-profiler-impl" default="profile" basedir="..">
<target name="default" depends="profile" description="Build and profile the project."/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="profile-init" depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check"/>
<target name="-profile-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target name="-profile-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target name="-profile-init-macrodef-profile">
<macrodef name="resolve">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${env.@{value}}"/>
</sequential>
</macrodef>
<macrodef name="profile">
<attribute name="classname" default="${main.class}"/>
<element name="customize" optional="true"/>
<sequential>
<property environment="env"/>
<resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
<java fork="true" classname="@{classname}" dir="${profiler.info.dir}" jvm="${profiler.info.jvm}">
<jvmarg value="${profiler.info.jvmargs.agent}"/>
<jvmarg line="${profiler.info.jvmargs}"/>
<env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
<arg line="${application.args}"/>
<classpath>
<path path="${run.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper type="glob" from="run-sys-prop.*" to="*"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-profile-init-check" depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile">
<fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
<fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
</target>
<!--
=================
PROFILING SECTION
=================
-->
<target name="profile" if="netbeans.home" depends="profile-init,compile" description="Profile a project in the IDE.">
<nbprofiledirect>
<classpath>
<path path="${run.classpath}"/>
</classpath>
</nbprofiledirect>
<profile/>
</target>
<target name="profile-single" if="netbeans.home" depends="profile-init,compile-single" description="Profile a selected class in the IDE.">
<fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
<nbprofiledirect>
<classpath>
<path path="${run.classpath}"/>
</classpath>
</nbprofiledirect>
<profile classname="${profile.class}"/>
</target>
<!--
=========================
APPLET PROFILING SECTION
=========================
-->
<target name="profile-applet" if="netbeans.home" depends="profile-init,compile-single">
<nbprofiledirect>
<classpath>
<path path="${run.classpath}"/>
</classpath>
</nbprofiledirect>
<profile classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</profile>
</target>
<!--
=========================
TESTS PROFILING SECTION
=========================
-->
<target name="profile-test-single" if="netbeans.home" depends="profile-init,compile-test-single">
<nbprofiledirect>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
</nbprofiledirect>
<junit showoutput="true" fork="true" dir="${profiler.info.dir}" jvm="${profiler.info.jvm}" failureproperty="tests.failed" errorproperty="tests.failed">
<env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
<jvmarg value="${profiler.info.jvmargs.agent}"/>
<jvmarg line="${profiler.info.jvmargs}"/>
<test name="${profile.class}"/>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper type="glob" from="test-sys-prop.*" to="*"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
</junit>
</target>
</project>

View File

@@ -0,0 +1,82 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.run.all.processors=true
application.args=
application.title=Foundation
application.vendor=flangner
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/Foundation.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.bcprov-jdk16-139.jar=lib/bcprov-jdk16-139.jar
file.reference.cdaclient.jar=lib/cdaclient.jar
file.reference.junit-4.11.jar=../lib/test/junit-4.11.jar
file.reference.config.jar=lib/config.jar
file.reference.je-3.2.13.jar=lib/je-3.2.13.jar
file.reference.protobuf-java-2.5.0.jar=../lib/protobuf-java-2.5.0.jar
file.reference.xbean.jar=lib/xbean.jar
file.reference.commons-codec-1.3.jar=../lib/commons-codec-1.3.jar
includes=**
jar.compress=true
javac.classpath=\
${file.reference.commons-codec-1.3.jar}:\
${file.reference.protobuf-java-2.5.0.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.6
javac.target=1.6
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
jnlp.codebase.type=local
jnlp.enabled=false
jnlp.offline-allowed=false
jnlp.signed=false
main.class=
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=-ea
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
src.dir=src
test.src.dir=test

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">
<extension file="protobuf-build.xml" id="protobuf">
<dependency dependsOn="protobuf-code-generation" target="-pre-pre-compile"/>
</extension>
</buildExtensions>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>XtreemFS-foundation</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
<references xmlns="http://www.netbeans.org/ns/ant-project-references/1"/>
</configuration>
</project>

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2010 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
/**
*
* @author bjko
*/
public final class ClientLease implements Cloneable {
/**
* Default time span for the client lease validity.
* Must be smaller than a intra-OSD lease, if replication is
* active!
*/
public static final long LEASE_VALIDITY = 15000;
/**
* Indicates that a lease spans to EOF "append lease".
* a lease from 0 to -1 spans the whole file, even if data is appended.
*/
public static final long TO_EOF = -1;
/**
* timestamp when the lease expires
*/
private long firstObject;
/**
* last object the lease is valid for
*/
private long lastObject;
/**
* UUID of the client owning the lease
*/
private String clientId;
/**
* timestamp when the lease expires (in seconds since 01/01/70)
* must be XtreemFS global time!
*/
private long expires;
/**
* fileId this lease was issued for
*/
private final String fileId;
/**
* sequenceNo, used to generate unique leaseId = fileId+"/"+sequenceNo
*/
private long sequenceNo;
/**
* lease type/operation
*/
private String operation;
public static final String EXCLUSIVE_LEASE = "w";
public ClientLease(final String fileId) {
this.fileId = fileId;
}
/**
* Checks if two leases have conflicting (i.e. overlapping ranges)
* @param other other lease for the same file
* @return true, if there is an overlap in the ranges
*/
public boolean isConflicting(ClientLease other) {
//checks
if ( ((this.lastObject < other.firstObject) && (this.lastObject != TO_EOF)) ||
((other.lastObject < this.firstObject) && (other.lastObject != TO_EOF)) ) {
return false;
} else {
return true;
}
}
@Override
public ClientLease clone() {
ClientLease l = new ClientLease(this.fileId);
l.clientId = this.clientId;
l.expires = this.expires;
l.firstObject = this.firstObject;
l.lastObject = this.lastObject;
l.operation = this.operation;
l.sequenceNo = this.sequenceNo;
return l;
}
public long getFirstObject() {
return firstObject;
}
public void setFirstObject(long firstObject) {
this.firstObject = firstObject;
}
public long getLastObject() {
return lastObject;
}
public void setLastObject(long lastObject) {
this.lastObject = lastObject;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public long getExpires() {
return expires;
}
public void setExpires(long expires) {
this.expires = expires;
}
public String getFileId() {
return fileId;
}
public long getSequenceNo() {
return sequenceNo;
}
public void setSequenceNo(long sequenceNo) {
this.sequenceNo = sequenceNo;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2010 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import java.util.Map;
/**
*
* @author bjko
*/
public class CrashReporter {
public static void reportXtreemFSCrash(String report) {
/*try {
URL u = new URL("http://www.xtreemfs.org/dump/dump.php?srv=server");
HttpURLConnection con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("PUT");
con.setDoOutput(true);
con.connect();
OutputStream os = con.getOutputStream();
os.write(report.getBytes());
os.flush();
os.close();
InputStream is = con.getInputStream();
is.available();
is.close();
} catch (Throwable th) {
System.out.println("cannot send crash report: "+th);
}*/
}
public static String createCrashReport(String service, String version, Throwable cause) {
try {
StringBuilder report = new StringBuilder();
report.append("----------------------------------------------------------------\n");
report.append("We are sorry, but your "+service+" has crashed. To report this bug\n");
report.append("please go to http://www.xtreemfs.org and file an issue and attach\n");
report.append("this crash report.\n\n");
report.append("service: ");
report.append(service);
report.append(" version: ");
report.append(version);
report.append("\n");
report.append("JVM version: ");
report.append(System.getProperty("java.version"));
report.append(" ");
report.append(System.getProperty("java.vendor"));
report.append(" on ");
report.append(System.getProperty("os.name"));
report.append(" ");
report.append(System.getProperty("os.version"));
report.append("\n");
report.append("exception: ");
report.append(cause.toString());
report.append("\n");
for (StackTraceElement elem : cause.getStackTrace()) {
report.append(elem.toString());
report.append("\n");
}
if (cause.getCause() != null) {
report.append("\nroot cause: ");
report.append(cause.getCause());
report.append("\n");
for (StackTraceElement elem : cause.getCause().getStackTrace()) {
report.append(elem.toString());
report.append("\n");
}
}
reportThreadStates(report);
report.append("----------------------------------------------------------------\n");
return report.toString();
} catch (Exception ex) {
ex.printStackTrace();
return "Could not write crash report for: "+service+","+version+","+cause+" due to "+ex;
}
}
/** Logs the stack trace of each thread into {@code report}. */
public static void reportThreadStates(StringBuilder report) {
report.append("\n--- THREAD STATES ---\n");
final Map<Thread,StackTraceElement[]> traces = Thread.getAllStackTraces();
for (Thread t : traces.keySet()) {
report.append("thread: ");
report.append(t.getName());
report.append("\n");
for (StackTraceElement e : traces.get(t)) {
report.append(e.toString());
report.append("\n");
}
report.append("\n");
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2008-2010 by Jan Stender, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* This class implements a LRU cache
*
* @author jmalo
*/
public class LRUCache<K,V> extends LinkedHashMap<K,V> {
private static final long serialVersionUID = -4673214355284364245L;
private int maximumSize;
/** Creates a new instance of LRUCache */
public LRUCache(int size) {
super(size, (float)0.75, true);
maximumSize = size;
}
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maximumSize;
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2010 by Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
/**
* Notifies a process of a life cycle event.
*
* @author stender
*
*/
public interface LifeCycleListener {
public void startupPerformed();
public void shutdownPerformed();
public void crashPerformed(Throwable cause);
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2008-2010 by Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
/**
* A base class for threads representing a life cycle. It offers methods for
* blocking other threads until a certain life cycle event has occurred. It
* currently supports two life cycle-related events: startup and shutdown.
*
* @author stender
*
*/
public class LifeCycleThread extends Thread {
private final Object startLock;
private final Object stopLock;
private boolean started;
private boolean stopped;
private Exception exc;
private LifeCycleListener listener;
public LifeCycleThread(String name) {
super(name);
startLock = new Object();
stopLock = new Object();
}
/**
* This method should be invoked by subclasses when the startup procedure
* has been completed.
*/
protected void notifyStarted() {
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.lifecycle, this, "Thread %s started", Thread
.currentThread().getName());
synchronized (startLock) {
started = true;
startLock.notifyAll();
if (listener != null)
listener.startupPerformed();
}
}
/**
* This method should be invoked by subclasses when the shutdown procedure
* has been completed.
*/
protected void notifyStopped() {
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.lifecycle, this, "Thread %s terminated", Thread
.currentThread().getName());
synchronized (stopLock) {
stopped = true;
stopLock.notifyAll();
if (listener != null)
listener.shutdownPerformed();
}
}
/**
* This method should be invoked by subclasses when the thread has crashed.
*/
protected void notifyCrashed(Throwable exc) {
Logging.logMessage(Logging.LEVEL_CRIT, this, "service ***CRASHED***, shutting down");
Logging.logError(Logging.LEVEL_CRIT, this, exc);
synchronized (startLock) {
this.exc = exc instanceof Exception ? (Exception) exc : new Exception(exc);
started = true;
startLock.notifyAll();
}
synchronized (stopLock) {
this.exc = exc instanceof Exception ? (Exception) exc : new Exception(exc);
stopped = true;
stopLock.notifyAll();
}
if (listener != null)
listener.crashPerformed(exc);
}
/**
* Synchronously waits for a notification indicating that the startup
* procedure has been completed.
*
* @throws Exception
* if an error occurred during the startup procedure
*/
public void waitForStartup() throws Exception {
synchronized (startLock) {
while (!started)
startLock.wait();
if (exc != null && listener == null)
throw exc;
}
}
/**
* Synchronously waits for a notification indicating that the shutdown
* procedure has been completed.
*
* @throws Exception
* if an error occurred during the shutdown procedure
*/
public void waitForShutdown() throws Exception {
synchronized (stopLock) {
if (!started)
return;
while (!stopped)
try {
stopLock.wait();
} catch (InterruptedException e) {
// In case this thread executes notifyCrashed(), he will
// probably interrupt itself. However, this should not
// interfere with the notifyCrashed() procedure and
// therefore we swallow this exception.
if (listener == null) {
throw e;
}
}
if (exc != null && listener == null)
throw exc;
}
}
/**
* Terminates the thread. This method should be overridden in subclasses.
* @throws Exception if an error occurred
*/
public void shutdown() throws Exception {
}
/**
* Sets a listener waiting for life cycle events.
*
* @param listener
* the listener
*/
public void setLifeCycleListener(LifeCycleListener listener) {
this.listener = listener;
}
}

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender, Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.util.OutputUtils;
/**
* Encapsulates the SSLOptions for the connections of pinky and speedy
*
* @author clorenz
*/
public class SSLOptions {
/**
* a Java JKS Keystore
*/
public final static String JKS_CONTAINER = "JKS";
/**
* a PKCS12 Keystore
*/
public final static String PKCS12_CONTAINER = "PKCS12";
/**
* Default SSL/TLS Protocol to use when no or an invalid protocol was specified
*/
public final static String DEFAULT_SSL_PROTOCOL = "TLS";
/**
* file with the private key and the public cert for the server
*/
private final InputStream serverCredentialFile;
/**
* file with trusted public certs
*/
private final InputStream trustedCertificatesFile;
/**
* passphrase of the server credential file
*/
private final char[] serverCredentialFilePassphrase;
/**
* passphrase of the trusted certificates file
*/
private final char[] trustedCertificatesFilePassphrase;
/**
* using symmetric encryption or only authenticating via certs
*/
private boolean authenticationWithoutEncryption;
/**
* file format of the server credential file
*/
private final String serverCredentialFileContainer;
/**
* file format of the trusted certificates file
*/
private final String trustedCertificatesFileContainer;
/**
* knows the used certs and more
*/
private final SSLContext sslContext;
private final boolean useFakeSSLMode;
public SSLOptions(InputStream serverCredentialFile, String serverCredentialFilePassphrase,
String serverCredentialFileContainer, InputStream trustedCertificatesFile,
String trustedCertificatesFilePassphrase, String trustedCertificatesFileContainer,
boolean authenticationWithoutEncryption, boolean useFakeSSLMode, String sslProtocolString,
TrustManager trustManager) throws IOException {
this.serverCredentialFile = serverCredentialFile;
this.trustedCertificatesFile = trustedCertificatesFile;
if (serverCredentialFilePassphrase != null)
this.serverCredentialFilePassphrase = serverCredentialFilePassphrase.toCharArray();
else
this.serverCredentialFilePassphrase = null;
if (trustedCertificatesFilePassphrase != null)
this.trustedCertificatesFilePassphrase = trustedCertificatesFilePassphrase.toCharArray();
else
this.trustedCertificatesFilePassphrase = null;
this.serverCredentialFileContainer = serverCredentialFileContainer;
this.trustedCertificatesFileContainer = trustedCertificatesFileContainer;
this.authenticationWithoutEncryption = authenticationWithoutEncryption;
this.useFakeSSLMode = useFakeSSLMode;
sslContext = createSSLContext(sslProtocolStringToProtocol(sslProtocolString), trustManager);
}
/**
* Create/initialize the SSLContext with key material
*
* @param trustManager
* the trust manager for the SSL context (may be
* <code>null</code>)
* @return the created and initialized SSLContext
* @throws IOException
*/
private SSLContext createSSLContext(String sslProtocol, TrustManager trustManager) throws IOException {
SSLContext sslContext = null;
try {
// First initialize the key and trust material.
KeyStore ksKeys = KeyStore.getInstance(serverCredentialFileContainer);
ksKeys.load(serverCredentialFile, serverCredentialFilePassphrase);
// KeyManager's decide which key material to use.
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ksKeys, serverCredentialFilePassphrase);
// There are quite a few issues with the OpenJDK PKCS11 provider in combination with NSS,
// so remove it no matter what the OpenJDK version is.
if ("OpenJDK Runtime Environment".equals(System.getProperty("java.runtime.name"))) {
try {
Security.removeProvider("SunPKCS11-NSS");
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Successfully removed faulty security provider 'SunPKCS11-NSS'.");
}
} catch(SecurityException e) {
Logging.logMessage(Logging.LEVEL_WARN, this,
"Could not remove security provider 'SunPKCS11-NSS'. This might cause TLS connections to time out. " +
"Known to affect multiple OpenJDK / NSS version combinations.");
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "%s:\n%s", e.getMessage(), OutputUtils.stackTraceToString(e));
}
}
}
// Re-enable disabled algorithms if the user requests it.
final String defaultDisabledAlgorithms = Security.getProperty("jdk.tls.disabledAlgorithms");
removeDisabledEntailedProtocolSupportForProtocol(sslProtocol);
try {
sslContext = SSLContext.getInstance(sslProtocol);
} catch (NoSuchAlgorithmException e) {
Logging.logMessage(Logging.LEVEL_WARN, this, "Unsupported algorithm '%s', defaulting to '%s'.",
sslProtocol, DEFAULT_SSL_PROTOCOL);
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "%s:\n%s", e.getMessage(), OutputUtils.stackTraceToString(e));
}
// Reset disabled algorithms because the context could not be created.
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Trying to reset disabled algorithms.");
}
try {
Security.setProperty("jdk.tls.disabledAlgorithms", defaultDisabledAlgorithms);
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Successfully reset disabled algorithms.");
}
} catch (SecurityException e1) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Could not reset disabled algorithms: %s", OutputUtils.stackTraceToString(e1));
}
}
// Setup everything anew for the default SSL protocol.
removeDisabledEntailedProtocolSupportForProtocol(DEFAULT_SSL_PROTOCOL);
sslContext = SSLContext.getInstance(DEFAULT_SSL_PROTOCOL);
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Disabling the following algorithms: %s", Security.getProperty("jdk.tls.disabledAlgorithms"));
}
if (trustManager != null) {
// if a user-defined trust manager is set ...
trustManager.init(trustedCertificatesFileContainer, trustedCertificatesFile,
trustedCertificatesFilePassphrase);
sslContext.init(kmf.getKeyManagers(), new TrustManager[] { trustManager }, null);
} else if (trustedCertificatesFileContainer.equals("none")) {
TrustManager[] myTMs = new TrustManager[] { new NoAuthTrustStore() };
sslContext.init(kmf.getKeyManagers(), myTMs, null);
} else {
// TrustManager's decide whether to allow connections.
KeyStore ksTrust = null;
if (trustedCertificatesFileContainer.equals("none")) {
ksTrust = KeyStore.getInstance(KeyStore.getDefaultType());
} else {
ksTrust = KeyStore.getInstance(trustedCertificatesFileContainer);
ksTrust.load(trustedCertificatesFile, trustedCertificatesFilePassphrase);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ksTrust);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
}
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
return sslContext;
}
public boolean isAuthenticationWithoutEncryption() {
return this.authenticationWithoutEncryption;
}
public void setAuthenticationWithoutEncryption(boolean authenticationWithoutEncryption) {
this.authenticationWithoutEncryption = authenticationWithoutEncryption;
}
public InputStream getServerCredentialFile() {
return this.serverCredentialFile;
}
public String getServerCredentialFileContainer() {
return this.serverCredentialFileContainer;
}
public String getServerCredentialFilePassphrase() {
return this.serverCredentialFilePassphrase.toString();
}
public InputStream getTrustedCertificatesFile() {
return this.trustedCertificatesFile;
}
public String getTrustedCertificatesFileContainer() {
return this.trustedCertificatesFileContainer;
}
public String getTrustedCertificatesFilePassphrase() {
return this.trustedCertificatesFilePassphrase.toString();
}
public SSLContext getSSLContext() {
return this.sslContext;
}
public boolean isFakeSSLMode() {
return this.useFakeSSLMode;
}
public String getSSLProtocol() {
return sslContext.getProtocol();
}
public boolean isSSLEngineProtocolSupported(String sslEngineProtocol) {
// Protocol names in JDK 5, 6: SSLv2Hello, SSLv3, TLSv1
// Additionally in JDK 7, 8: TLSv1.2
// TLSv1.1 seems to depend on the vendor
String sslProtocol = getSSLProtocol();
if ("SSLv3".equals(sslProtocol)) {
return "SSLv3".equals(sslEngineProtocol);
} else if ("TLS".equals(sslProtocol)) {
return "SSLv3".equals(sslEngineProtocol) ||
"TLSv1".equals(sslEngineProtocol) ||
"TLSv1.1".equals(sslEngineProtocol) ||
"TLSv1.2".equals(sslEngineProtocol);
} else if ("TLSv1".equals(sslProtocol)) {
return "TLSv1".equals(sslEngineProtocol);
} else if ("TLSv1.1".equals(sslProtocol)) {
return "TLSv1.1".equals(sslEngineProtocol);
} else if ("TLSv1.2".equals(sslProtocol)) {
return "TLSv1.2".equals(sslEngineProtocol);
} else {
return false;
}
}
private String sslProtocolStringToProtocol(String sslProtocolString) {
// SSL Context Protocol Strings:
// JDK 6: SSL, SSLv2, SSLv3, TLS, TLSv1
// additionally in JDK 7: TLSv1.2
// TLSv1.1 seems to depend on the vendor
if ("sslv3".equals(sslProtocolString)) {
return "SSLv3";
} else if ("ssltls".equals(sslProtocolString)) {
return "TLS";
} else if ("tlsv1".equals(sslProtocolString)) {
return "TLSv1";
} else if ("tlsv11".equals(sslProtocolString)) {
return "TLSv1.1";
} else if ("tlsv12".equals(sslProtocolString)) {
return "TLSv1.2";
} else {
if (sslProtocolString != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"Unknown SSL Context Protocol: '%s', defaulting to '%s'.",
sslProtocolString, DEFAULT_SSL_PROTOCOL);
}
return DEFAULT_SSL_PROTOCOL;
}
}
/**
* Removes all protocols that should be supported when using {@code sslProtocol} from the disabled
* algorithms list that is set as system default, e.g. in /usr/lib/jvm/default-java/jre/lib/security/java.security.
*
* @param sslProtocol
*/
private void removeDisabledEntailedProtocolSupportForProtocol(String sslProtocol) {
if (Security.getProperty("jdk.tls.disabledAlgorithms") == null) {
return; // no disabled algorithms, everything is allowed by default
}
String[] entailedSupportedProtocols = new String[] {};
if ("SSLv3".equals(sslProtocol)) {
entailedSupportedProtocols = new String[] { "SSLv3" };
} else if ("TLS".equals(sslProtocol)) {
entailedSupportedProtocols = new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" };
} else if ("TLSv1".equals(sslProtocol)) {
entailedSupportedProtocols = new String[] { "TLSv1" };
} else if ("TLSv1.1".equals(sslProtocol)) {
entailedSupportedProtocols = new String[] { "TLSv1.1" };
} else if ("TLSv1.2".equals(sslProtocol)) {
entailedSupportedProtocols = new String[] { "TLSv1.2" };
}
// For each protocol whose support is entailed by the requested protocol,
// remove it from the disabled algorithms list if possible.
for (String supportedSSLProtocol : entailedSupportedProtocols) {
if (Security.getProperty("jdk.tls.disabledAlgorithms").contains(supportedSSLProtocol)) {
Logging.logMessage(Logging.LEVEL_WARN, this,
"Algorithm '%s' is disabled in your java.security configuration file (see key 'jdk.tls.disabledAlgorithms'). " +
"Trying to enable algorithm '%s' manually as specified in your configuration file (see key 'ssl.protocol'). " +
"Consider using a newer SSL/TLS algorithm for your setup, " +
"as algorithm '%s' has been disabled by default because of security issues.",
supportedSSLProtocol, supportedSSLProtocol, supportedSSLProtocol);
try {
Security.setProperty("jdk.tls.disabledAlgorithms",
Security.getProperty("jdk.tls.disabledAlgorithms").replace(supportedSSLProtocol, "").replace(" ", ""));
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Successfully removed algorithm '%s' from disabled algorithms.",
supportedSSLProtocol);
}
} catch (SecurityException e) {
Logging.logMessage(Logging.LEVEL_WARN, this, "Could not remove algorithm '%s' from disabled algorithm. " +
"This might cause SSL Handshake exceptions. For SSLv3 this is known to affect all JDKs fixing issue CVE-2014-3566.",
supportedSSLProtocol);
}
}
}
}
private static class NoAuthTrustStore implements TrustManager, X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// ignore
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// ignore
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
@Override
public void init(String trustedCertificatesFileContainer, InputStream trustedCertificatesFile,
char[] trustedCertificatesFilePassphrase) {
// ignore
}
}
public static interface TrustManager extends javax.net.ssl.TrustManager {
public void init(String trustedCertificatesFileContainer, InputStream trustedCertificatesFile,
char[] trustedCertificatesFilePassphrase);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2010 by Felix Langner,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import java.net.InetSocketAddress;
import org.xtreemfs.foundation.pbrpc.client.RPCResponse;
/**
* Provides methods to synchronize with a XtreemFS TimeServer, usually provided
* by a DIR service.
*
* @author flangner
* @since 03/01/2010
*/
public interface TimeServerClient {
/**
* Requests the global time at the given server.
*
* @param server - if null, the default will be used.
* @return a {@link RPCResponse} future for an UNIX time-stamp.
*/
public long xtreemfs_global_time_get(InetSocketAddress server);
}

View File

@@ -0,0 +1,464 @@
/*
* Copyright (c) 2008-2010 by Jan Stender, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
/**
* A class that offers a local time w/ adjustable granularity and a global time
* based on the time reported by the DIR. Global time is adjusted periodically.
* This class should be used to minimize the number of calls to
* System.currentTimeMillis which is a costly system call on Linux. Moreover it
* offers a system-global time.
*
* @author bjko
*/
public final class TimeSync extends LifeCycleThread {
public enum ExtSyncSource {
XTREEMFS_DIR, GPSD, LOCAL_CLOCK
};
/**
* The maximum round trip time for a clock synchronization message between
* the <code>TimeSync</code> and the DIR. If the round trip time of a
* synchronization message exceeds this value, the message will be ignored.
*/
private static final int MAX_RTT = 1000;
/**
* A client used to synchronize clocks
*/
private TimeServerClient timeServerClient;
/**
* interval in ms to wait between to synchronizations.
*/
private volatile int timeSyncInterval;
/**
* interval between updates of the local system clock.
*
* If it's set to 0, the local renew by the thread is disabled and the time
* is read from the system on demand.
*/
private volatile int localTimeRenew;
private volatile ExtSyncSource syncSource;
private InetSocketAddress gpsdAddr;
/**
* local sys time as of last update
*/
private volatile long localSysTime;
/**
* drift between local clock and global time as of last resync() operation.
*/
private volatile long currentDrift;
/**
* set to true to stop thread
*/
private volatile boolean quit;
/**
* timestamp of last resync operation
*/
private volatile long lastSuccessfulSync;
/**
* Timestamp of the last resync attempt.
*
* @note No need to specify it as volatile since it's only used by run().
*/
private long lastSyncAttempt;
private volatile int syncRTT;
private volatile boolean syncSuccess;
private static TimeSync theInstance;
private final Pattern gpsdDatePattern;
private Socket gpsdSocket;
/**
* Creates a new instance of TimeSync
*
* @dir a directory server to use for synchronizing clocks, can be null for
* test setups only
*/
private TimeSync(ExtSyncSource source, TimeServerClient dir, InetSocketAddress gpsd, int timeSyncInterval, int localTimeRenew) {
super("TSync Thr");
setDaemon(true);
this.syncSuccess = false;
this.gpsdDatePattern = Pattern.compile("GPSD,D=(....)-(..)-(..)T(..):(..):(..)\\.(.+)Z");
init(source, dir, gpsd, timeSyncInterval, localTimeRenew);
}
/**
* Initializes the TimeSync with new parameters.
*
* @param source
* @param dir
* @param gpsd
* @param timeSyncInterval
* @param localTimeRenew
*/
public synchronized void init(ExtSyncSource source, TimeServerClient dir, InetSocketAddress gpsd, int timeSyncInterval, int localTimeRenew) {
this.localTimeRenew = localTimeRenew;
this.timeSyncInterval = timeSyncInterval;
this.timeServerClient = dir;
this.syncSource = source;
this.gpsdAddr = gpsd;
if (this.timeServerClient != null && this.timeSyncInterval != 0 && this.localTimeRenew != 0) {
this.localTimeRenew = 0;
Logging.logMessage(Logging.LEVEL_DEBUG, this,
"Disabled the periodic local time renew (set local_clock_renewal to 0)" +
" and using always the current system time as base since the time will be corrected by synchronizing with the DIR service.");
}
if (source == ExtSyncSource.GPSD) {
try {
if (gpsdSocket != null)
gpsdSocket.close();
gpsdSocket = new Socket();
gpsdSocket.setSoTimeout(2000);
gpsdSocket.setTcpNoDelay(true);
gpsdSocket.connect(gpsdAddr,2000);
} catch (IOException ex) {
Logging.logMessage(Logging.LEVEL_ERROR, this,"cannot connect to GPSd: "+ex);
gpsdSocket = null;
}
}
}
/**
* main loop
*/
@Override
public void run() {
TimeSync.theInstance = this;
notifyStarted();
String tsStatus;
if (localTimeRenew == 0) {
tsStatus = "using the local clock";
} else {
tsStatus = "using the local clock (precision is " + this.localTimeRenew + " ms)";
}
if (this.timeServerClient != null && timeSyncInterval != 0) {
tsStatus += " and remote sync every " + this.timeSyncInterval + " ms";
}
Logging.logMessage(Logging.LEVEL_INFO, Category.lifecycle, this, "TimeSync is running %s", tsStatus);
while (!quit) {
// Renew cached local time.
final long previousLocalSysTime = localSysTime;
localSysTime = System.currentTimeMillis();
if (localTimeRenew > 0 && previousLocalSysTime != 0) {
final long timeBetweenUpdates = Math.abs(localSysTime - previousLocalSysTime);
if (timeBetweenUpdates > 4 * localTimeRenew) {
Logging.logMessage(Logging.LEVEL_WARN, this,
"The granularity of the renewed local time could not be guaranteed" +
" since it took longer to retrieve the latest local time (%d ms) than configured (local_clock_renewal = %d)." +
" Maybe the system is under high I/O load and therefore scheduling threads takes longer than usual?",
timeBetweenUpdates,
localTimeRenew);
}
}
// Remote sync time.
if (timeSyncInterval != 0 && localSysTime - lastSyncAttempt > timeSyncInterval) {
resync();
}
if (!quit) {
//
try {
// If local refresh was disabled, use timeSyncInterval as sleep time.
long sleepTimeMs = localTimeRenew != 0 ? localTimeRenew : timeSyncInterval;
if (sleepTimeMs == 0) {
// If there is no need to run this thread at all, let it sleep for 10 minutes.
sleepTimeMs = 600000;
}
TimeSync.sleep(sleepTimeMs);
} catch (InterruptedException ex) {
break;
}
}
}
notifyStopped();
syncSuccess = false;
theInstance = null;
}
/**
* Initializes the time synchronizer. Note that only the first invocation of
* this method has an effect, any further invocations will be ignored.
*
* @param dir
* @param timeSyncInterval
* @param localTimeRenew
* @param dirAuthStr
*/
public static TimeSync initialize(TimeServerClient dir, int timeSyncInterval, int localTimeRenew) throws Exception {
if (theInstance != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.lifecycle, null, "time sync already running",
new Object[0]);
return theInstance;
}
TimeSync s = new TimeSync(ExtSyncSource.XTREEMFS_DIR, dir, null, timeSyncInterval, localTimeRenew);
s.start();
s.waitForStartup();
return s;
}
public static TimeSync initializeLocal(int localTimeRenew) {
if (theInstance != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.lifecycle, null, "time sync already running",
new Object[0]);
return theInstance;
}
TimeSync s = new TimeSync(ExtSyncSource.LOCAL_CLOCK, null, null, 0, localTimeRenew);
s.start();
return s;
}
public static TimeSync initializeGPSD(InetSocketAddress gpsd, int timeSyncInterval, int localTimeRenew) {
if (theInstance != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.lifecycle, null, "time sync already running",
new Object[0]);
return theInstance;
}
TimeSync s = new TimeSync(ExtSyncSource.GPSD, null, gpsd, timeSyncInterval, localTimeRenew);
s.start();
return s;
}
public void close() {
shutdown();
try {
waitForShutdown();
} catch (Exception e) {
Logging.logError(Logging.LEVEL_ERROR, null, e);
}
}
/**
* stop the thread
*/
public void shutdown() {
quit = true;
this.interrupt();
if (gpsdSocket != null) {
try {
gpsdSocket.close();
} catch (IOException ex) {
}
}
}
/**
* returns the current value of the local system time variable. Has a
* resolution of localTimeRenew ms.
*/
public static long getLocalSystemTime() {
TimeSync ts = getInstance();
if (ts.localTimeRenew == 0 || ts.localSysTime == 0) {
return System.currentTimeMillis();
} else {
return ts.localSysTime;
}
}
/**
* returns the current value of the local system time adjusted to global
* time. Has a resolution of localTimeRenew ms.
*/
public static long getGlobalTime() {
TimeSync ts = getInstance();
if (ts.localTimeRenew == 0 || ts.localSysTime == 0) {
return System.currentTimeMillis() + ts.currentDrift;
} else {
return ts.localSysTime + ts.currentDrift;
}
}
public static long getLocalRenewInterval() {
return getInstance().localTimeRenew;
}
public static int getTimeSyncInterval() {
return getInstance().timeSyncInterval;
}
public static int getSyncRTT() {
return getInstance().syncRTT;
}
public static boolean lastSyncWasSuccessful() {
return getInstance().syncSuccess;
}
/**
*
* @return the timestamp (local time) when the drift
* was successfully calculated
*/
public static long getLastSuccessfulSyncTimestamp() {
return getInstance().lastSuccessfulSync;
}
/**
* returns the current clock drift.
*/
public long getDrift() {
return this.currentDrift;
}
/**
* resynchronizes with the global time obtained from the DIR
*/
@SuppressWarnings("deprecation")
private void resync() {
switch (syncSource) {
case LOCAL_CLOCK : return;
case XTREEMFS_DIR : {
try {
long tStart = System.currentTimeMillis();
lastSyncAttempt = tStart;
long oldDrift = currentDrift;
long globalTime = timeServerClient.xtreemfs_global_time_get(null);
if (globalTime <= 0) {
//error
return;
}
long tEnd = System.currentTimeMillis();
// add half a roundtrip to estimate the delay
syncRTT = (int)(tEnd - tStart);
if (syncRTT > MAX_RTT) {
Logging.logMessage(Logging.LEVEL_WARN, Category.misc, this,
"Ignored time synchronization message because DIR took too long to respond (%d ms)",
syncRTT);
syncSuccess = false;
return;
}
globalTime += syncRTT / 2;
syncSuccess = true;
currentDrift = globalTime - tEnd;
lastSuccessfulSync = tEnd;
if (Math.abs(oldDrift - currentDrift) > 5000 && oldDrift != 0) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.misc, this,
"STRANGE DRIFT CHANGE from %d to %d", oldDrift, currentDrift);
}
} catch (Exception ex) {
syncSuccess = false;
ex.printStackTrace();
}
break;
}
case GPSD : {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(gpsdSocket.getInputStream()));
OutputStream os = gpsdSocket.getOutputStream();
long tStart = System.currentTimeMillis();
lastSyncAttempt = tStart;
os.write(new byte[]{'d','\n'});
os.flush();
long oldDrift = currentDrift;
String response = br.readLine();
long tEnd = System.currentTimeMillis();
Matcher m = gpsdDatePattern.matcher(response);
Calendar c = Calendar.getInstance();
if (m.matches()) {
c.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
c.set(Calendar.MONTH, Integer.parseInt(m.group(2))-1);
c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(3)));
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4)));
c.set(Calendar.MINUTE, Integer.parseInt(m.group(5)));
c.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
//c.set(Calendar.MILLISECOND, Integer.parseInt(m.group(7))*10);
} else {
Logging.logMessage(Logging.LEVEL_WARN, this,"cannot parse GPSd response: %s",response);
syncSuccess = false;
return;
}
long globalTime = c.getTimeInMillis();
Date d = new Date(globalTime);
Logging.logMessage(Logging.LEVEL_DEBUG, this,"global GPSd time: %d (%d:%d:%d)",c.getTimeInMillis(),d.getHours(),
d.getMinutes(),d.getSeconds());
// add half a roundtrip to estimate the delay
syncRTT = (int)(tEnd - tStart);
Logging.logMessage(Logging.LEVEL_DEBUG, this,"sync RTT: %d ms",syncRTT);
globalTime += syncRTT / 2;
syncSuccess = true;
currentDrift = globalTime - tEnd;
lastSuccessfulSync = tEnd;
Logging.logMessage(Logging.LEVEL_DEBUG, Category.misc, this,
"resync success, drift: %d ms", Math.abs(oldDrift-currentDrift));
if (Math.abs(oldDrift - currentDrift) > 5000 && oldDrift != 0) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.misc, this,
"STRANGE DRIFT CHANGE from %d to %d", oldDrift, currentDrift);
}
} catch (Exception ex) {
syncSuccess = false;
ex.printStackTrace();
}
}
}
}
public static TimeSync getInstance() {
if (theInstance == null)
throw new RuntimeException("TimeSync not initialized!");
return theInstance;
}
public static boolean isInitialized() {
return theInstance != null;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2008-2010 by Jan Stender, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation;
/**
* This class is meant to maintain version numbers for different components used
* in XtreemFS, in order to be able to detect possible incompatibilities between
* different versions.
*
* When a new version of the protocol, database, etc. has been implemented, the
* corresponding version number should be replaced. XtreemFS will rely on this
* class to find out what the current version numbers are.
*
*/
public class VersionManagement {
public static final String RELEASE_VERSION = "1.5.1 (Wonderful Waffles)";
private static final long mrcDataVersion = 10;
private static final long osdDataVersion = 1;
private static final long foundationVersion = 2;
public static long getMrcDataVersion() {
return mrcDataVersion;
}
public static long getOsdDataVersion() {
return osdDataVersion;
}
public static long getFoundationVersion() {
return foundationVersion;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.buffer;
import java.io.Serializable;
/**
*
* @author bjko
*/
public final class ASCIIString implements Serializable {
private static final long serialVersionUID = 4633232360908659139L;
private byte[] data;
private int hash;
protected ASCIIString() {
}
/**
* Creates a new instance of ASCIIString
*/
public ASCIIString(String str) {
this.data = str.getBytes();
}
/**
* Creates a new instance of ASCIIString
*/
protected ASCIIString(byte[] data) {
this.data = data;
}
public String toString() {
return new String(data);
}
public char charAt(int index) {
return (char)data[index];
}
public boolean equals(Object o) {
if (o == null) return false;
try {
ASCIIString other = (ASCIIString)o;
if (other.length() != this.length())
return false;
for (int i = 0; i < data.length; i++) {
if (data[i] != other.data[i])
return false;
}
return true;
} catch (ClassCastException ex) {
return false;
}
}
public void marshall(ReusableBuffer target) {
target.putInt(data.length);
target.put(data);
}
public static ASCIIString unmarshall(ReusableBuffer target) {
int length = target.getInt();
if (length < 0)
return null;
byte[] tmp = new byte[length];
target.get(tmp);
return new ASCIIString(tmp);
}
public int hashCode() {
int h = hash;
if (h == 0) {
for (int i = 0; i < data.length; i++) {
h = 31*h + data[i];
}
hash = h;
}
return h;
}
public int length() {
return data.length;
}
public int getSerializedSize() {
return length()+Integer.SIZE/8;
}
}

View File

@@ -0,0 +1,324 @@
/*
* Copyright (c) 2008-2011 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.buffer;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* A concurrent pool for buffer recycling.
*
* @author bjko
*/
public final class BufferPool {
/**
* size of buffers for each class.
*/
public static final int[] BUFF_SIZES = { 8192, 65536, 131072, 524288,
2097152 };
/**
* max pool size for each class
*/
public static final int[] MAX_POOL_SIZES = { 2000, 200, 100, 10, 5 };
/**
* queues to store buffers in
*/
private final ConcurrentLinkedQueue<ByteBuffer>[] pools;
/**
* pool sizes to avoid counting elements on each access
*/
private final AtomicInteger[] poolSizes;
/**
* stats for num requests and creates of buffers per class
*/
private final AtomicLong[] requests, creates, deletes;
/**
* singleton pattern.
*/
private static final BufferPool instance = new BufferPool();
/**
* if true all allocate/free operations record the stack trace. Useful to
* find memory leaks but slow.
*/
protected static boolean recordStackTraces = false;
/**
* Creates a new instance of BufferPool
*/
@SuppressWarnings("unchecked")
private BufferPool() {
pools = new ConcurrentLinkedQueue[BUFF_SIZES.length];
creates = new AtomicLong[BUFF_SIZES.length];
for (int i = 0; i < creates.length; i++) {
creates[i] = new AtomicLong();
}
requests = new AtomicLong[BUFF_SIZES.length + 1];
deletes = new AtomicLong[BUFF_SIZES.length + 1];
for (int i = 0; i < BUFF_SIZES.length + 1; i++) {
requests[i] = new AtomicLong();
deletes[i] = new AtomicLong();
}
poolSizes = new AtomicInteger[BUFF_SIZES.length];
for (int i = 0; i < BUFF_SIZES.length; i++) {
pools[i] = new ConcurrentLinkedQueue<ByteBuffer>();
poolSizes[i] = new AtomicInteger(0);
}
}
/**
* Get a new buffer. The Buffer is taken from the pool or created if none is
* available or the size exceedes the largest class.
*
* @param size
* the buffer's size in bytes
* @return a buffer of requested size
* @throws OutOfMemoryError
* if a buffer cannot be allocated
*/
public static ReusableBuffer allocate(int size) {
ReusableBuffer tmp = instance.getNewBuffer(size);
assert (tmp.refCount.get() == 1): "newly allocated buffer has invalid reference count: " + tmp.refCount.get();
if (recordStackTraces) {
tmp.allocStack = "\n";
for (StackTraceElement elem : new Exception().getStackTrace())
tmp.allocStack += elem.toString() + "\n";
}
return tmp;
}
/**
* Returns a buffer to the pool, if the buffer is reusable. Other buffers
* are ignored.
*
* @param buf
* the buffer to return
*/
public static void free(ReusableBuffer buf) {
if (buf != null) {
instance.returnBuffer(buf);
}
}
/**
* Returns a buffer which has at least size bytes.
*
* @attention The returned buffer can be larger than requested!
*/
private ReusableBuffer getNewBuffer(int size) {
try {
// if there is a pooled buffer with sufficient capacity ...
for (int i = 0; i < BUFF_SIZES.length; i++) {
if (size <= BUFF_SIZES[i]) {
ByteBuffer buf = pools[i].poll();
// if no free buffer is available in the pool ...
if (buf == null) {
// ... create
// - a direct buffer if the pool is not full yet,
// - a non-direct buffer if the pool is full
//
// Thus, the first MAX_POOL_SIZES[i] buffers will be
// pooled, whereas any additional buffers will be
// allocated on demand and freed by the garbage
// collector.
buf = creates[i].get() < MAX_POOL_SIZES[i] ? ByteBuffer.allocateDirect(BUFF_SIZES[i])
: ByteBuffer.allocate(BUFF_SIZES[i]);
creates[i].incrementAndGet();
}
// otherwise, decrement the pool size to indicate that the
// pooled buffer was handed out to the application
else {
poolSizes[i].decrementAndGet();
}
requests[i].incrementAndGet();
return new ReusableBuffer(buf, size);
}
}
// ... otherwise, create an unpooled buffer
requests[BUFF_SIZES.length].incrementAndGet();
ByteBuffer buf = ByteBuffer.allocate(size);
return new ReusableBuffer(buf, size);
} catch (OutOfMemoryError ex) {
System.out.println(getStatus());
throw ex;
}
}
private void returnBuffer(ReusableBuffer buffer) {
returnBuffer(buffer, false);
}
/**
* return a buffer to the pool
*/
private void returnBuffer(ReusableBuffer buffer, boolean callFromView) {
if (!buffer.isReusable())
return;
if (buffer.viewParent != null) {
// view buffer
if (recordStackTraces) {
if (buffer.freeStack == null)
buffer.freeStack = "";
buffer.freeStack += "\n";
StackTraceElement[] stackTrace = new Exception().getStackTrace();
for (int i = 0; i < stackTrace.length; i++)
buffer.freeStack += stackTrace[i].toString() + "\n";
}
assert (!buffer.returned) : "buffer was already released: " + buffer.freeStack;
buffer.returned = true;
returnBuffer(buffer.viewParent, true);
} else {
assert (!buffer.returned || callFromView) : "buffer was already released: " + buffer.freeStack;
if (recordStackTraces) {
if (buffer.freeStack == null)
buffer.freeStack = "";
buffer.freeStack += "\n";
StackTraceElement[] stackTrace = new Exception().getStackTrace();
for (int i = 0; i < stackTrace.length; i++)
buffer.freeStack += stackTrace[i].toString() + "\n";
}
if (!callFromView) {
buffer.returned = true;
}
if (buffer.refCount.getAndDecrement() > 1) {
return;
}
ByteBuffer buf = buffer.getParent();
buf.clear();
// determine the pool to which the buffer is supposed to be
// returned
// ...
for (int i = 0; i < BUFF_SIZES.length; i++) {
if (buf.capacity() == BUFF_SIZES[i]) {
// return direct buffers to the pool
if (buf.isDirect()) {
poolSizes[i].incrementAndGet();
pools[i].add(buf);
// since only direct buffers will be returned to the
// pool, which have been counted on allocation, there is
// no need to check the pool size here
return;
}
// if the buffer is non-direct, increment the delete counter
// and implicitly make the buffer subject to garbage
// collection
else {
deletes[i].incrementAndGet();
return;
}
}
}
assert (!buf.isDirect()) : "encountered direct buffer that does not fit in any of the pools (size="
+ buf.capacity() + "): " + buffer.freeStack;
// if the buffer did not fit in any of the pools,
// increment the delete counter for the unpooled buffers
deletes[deletes.length - 1].incrementAndGet();
}
}
/**
* Get the current pool size for a specific buffer size.
*
* @throws IllegalArgumentException
* when bufferSize is not in the pool
*/
public static int getPoolSize(int bufferSize) {
for (int i = 0; i < BUFF_SIZES.length; i++) {
if (BUFF_SIZES[i] == bufferSize) {
return instance.poolSizes[i].get();
}
}
throw new IllegalArgumentException("Specified buffer size is not pooled. Check BufferPool configuration.");
}
/**
* Returns a textual representation of the pool status.
*
* @return a textual representation of the pool status.
*/
public static String getStatus() {
String str = "";
for (int i = 0; i < BUFF_SIZES.length; i++) {
str += String.format(
"%8d: poolSize = %5d numRequests = %8d creates = %8d deletes = %8d\n",
BUFF_SIZES[i], instance.poolSizes[i].get(), instance.requests[i].get(), instance.creates[i]
.get(), instance.deletes[i].get());
}
str += String.format("unpooled (> %8d) numRequests = creates = %8d deletes = %8d",
BUFF_SIZES[BUFF_SIZES.length - 1], instance.requests[instance.requests.length - 1].get(),
instance.deletes[instance.deletes.length - 1].get());
return str;
}
/**
* Specifies whether stack traces shall be recorded when allocating and
* freeing buffers. Since recording stack traces leads to some overhead, it
* should only be enabled for debugging purposes.
*
* @param record
*/
public static void enableStackTraceRecording(boolean record) {
recordStackTraces = record;
}
}

View File

@@ -0,0 +1,724 @@
/*
* Copyright (c) 2008-2011 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.buffer;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicInteger;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
/**
*
* @author bjko
*/
public final class ReusableBuffer {
private static final Charset ENC_UTF8 = Charset.forName("utf-8");
/**
* A view buffer of parentBuffer with the requested size. For non-reusable
* buffers this is the buffer itself
*/
private ByteBuffer buffer;
/**
* A parent buffer which is returned to the pool
*/
private final ByteBuffer parentBuffer;
/**
* True if the buffer can be returned to the pool
*/
private final boolean reusable;
/**
* set to true after a buffer was returned to the pool
*/
protected volatile boolean returned;
/**
* size (as requested), might be smaller than parentBuffer size but is
* always equal to the (view) buffer size.
*/
private int size;
protected ReusableBuffer viewParent;
protected String freeStack, allocStack;
/**
* reference count
*/
AtomicInteger refCount;
/**
* Creates a new instance of ReusableBuffer. A view buffer of size is created.
*
* @param buffer
* the parent buffer
* @param size
* the requested size
*/
protected ReusableBuffer(ByteBuffer buffer, int size) {
buffer.position(0);
buffer.limit(size);
this.buffer = buffer.slice();
this.parentBuffer = buffer;
this.size = size;
this.reusable = true;
this.refCount = new AtomicInteger(1);
returned = false;
viewParent = null;
}
/**
* A wrapper for a non-reusable buffer. The buffer is not used by the pool
* when returned.
*/
public ReusableBuffer(ByteBuffer nonManaged) {
this.buffer = nonManaged;
this.size = buffer.limit();
this.reusable = false;
this.parentBuffer = null;
returned = false;
this.refCount = new AtomicInteger(1);
viewParent = null;
}
/**
* Creates a non-reusable buffer around a byte array. Uses the
* ByteBuffer.wrap method.
*
* @param data
* the byte arry containing the data
* @return
*/
public static ReusableBuffer wrap(byte[] data) {
return new ReusableBuffer(ByteBuffer.wrap(data));
}
public static ReusableBuffer wrap(byte[] data, int offset, int length) {
assert (offset >= 0);
assert (length >= 0);
if (offset + length > data.length)
throw new IllegalArgumentException("offset+length > buffer size (" + offset + "+" + length
+ " > " + data.length);
ByteBuffer tmp = ByteBuffer.wrap(data);
tmp.position(offset);
tmp.limit(offset + length);
return new ReusableBuffer(tmp.slice());
}
/**
* Creates a new view buffer. This view buffer shares the same data (i.e.
* backing byte buffer) but has independent position, limit etc.
*/
public ReusableBuffer createViewBuffer() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
if (this.viewParent == null) {
if (parentBuffer == null) {
// wraped buffers
ReusableBuffer view = new ReusableBuffer(this.buffer.slice());
view.viewParent = this;
return view;
} else {
// regular buffer
ReusableBuffer view = new ReusableBuffer(this.parentBuffer, this.size);
view.viewParent = this;
this.refCount.incrementAndGet();
if (BufferPool.recordStackTraces) {
view.allocStack = "\n";
StackTraceElement[] stackTrace = new Exception().getStackTrace();
for (int i = 0; i < stackTrace.length; i++)
view.allocStack += stackTrace[i].toString() + (i < stackTrace.length - 1 ? "\n" : "");
}
return view;
}
} else {
if (parentBuffer == null) {
// wraped buffers
ReusableBuffer view = new ReusableBuffer(this.buffer.slice());
view.viewParent = this.viewParent;
return view;
} else {
// regular buffer: use the parent to create a view buffer
ReusableBuffer view = new ReusableBuffer(this.buffer, this.size);
view.viewParent = this.viewParent;
this.viewParent.refCount.incrementAndGet();
if (BufferPool.recordStackTraces) {
view.allocStack = "\n";
StackTraceElement[] stackTrace = new Exception().getStackTrace();
for (int i = 0; i < stackTrace.length; i++)
view.allocStack += stackTrace[i].toString() + (i < stackTrace.length - 1 ? "\n" : "");
}
return view;
}
}
}
/**
* @see java.nio.Buffer#capacity
*/
public int capacity() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return this.size;
}
/**
* May be higher than {@link #capacity()} if the parent buffer is from the {@link BufferPool} which may
* have returned a larger buffer.
*/
public int capacityUnderlying() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return parentBuffer != null ? parentBuffer.capacity() : this.size;
}
/**
* @see java.nio.ByteBuffer#hasArray
*/
public boolean hasArray() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.hasArray();
}
/**
* Returns the byte array of the buffer, creating a copy if the buffer is
* not backed by an array
*
* @return a byte array with a copy of the data
*/
public byte[] array() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
byte[] array = null;
if (this.hasArray() && (this.viewParent == null)) {
array = buffer.array();
} else {
array = new byte[this.limit()];
final int oldPos = this.position();
this.position(0);
this.get(array);
this.position(oldPos);
}
return array;
}
/**
* @see java.nio.Buffer#flip
*/
public void flip() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.flip();
}
/**
* @see java.nio.Buffer#compact
*/
public void compact() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.compact();
}
/**
* @see java.nio.Buffer#limit(int)
*/
public void limit(int l) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.limit(l);
}
/**
* @see java.nio.Buffer#limit()
*/
public int limit() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.limit();
}
/**
* @see java.nio.Buffer#position(int)
*/
public void position(int p) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.position(p);
}
/**
* @see java.nio.Buffer#position()
*/
public int position() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.position();
}
/**
* @see java.nio.Buffer#hasRemaining
*/
public boolean hasRemaining() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.hasRemaining();
}
/**
* Returns the view buffer encapsulated by this ReusableBuffer.
*
* @return the view buffer
*/
public ByteBuffer getBuffer() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return this.buffer;
}
/**
* Returns true, if this buffer is re-usable and can be returned to the
* pool.
*
* @return true, if this buffer is re-usable
*/
public boolean isReusable() {
// assert(!returned) :
// "Buffer was already freed and cannot be used anymore"+this.freeStack;
return this.reusable;
}
/**
* Returns the parent buffer.
*
* @return the parent buffer
*/
protected ByteBuffer getParent() {
return this.parentBuffer;
}
/**
* @see java.nio.ByteBuffer#get()
*/
public byte get() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.get();
}
public byte get(int index) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.get(index);
}
/**
* @see java.nio.ByteBuffer#get(byte[])
*/
public ReusableBuffer get(byte[] dst) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.get(dst);
return this;
}
/**
* @see java.nio.ByteBuffer#get(byte[], int offset, int length)
*/
public ReusableBuffer get(byte[] dst, int offset, int length) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.get(dst, offset, length);
return this;
}
/**
* @see java.nio.ByteBuffer#put(byte)
*/
public ReusableBuffer put(byte b) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(b);
return this;
}
/**
* @see java.nio.ByteBuffer#put(byte[])
*/
public ReusableBuffer put(byte[] src) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(src);
return this;
}
/**
* @see java.nio.ByteBuffer#put(byte[],int,int)
*/
public ReusableBuffer put(byte[] src, int offset, int len) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(src, offset, len);
return this;
}
/**
* @see java.nio.ByteBuffer#put(ByteBuffer)
*/
public ReusableBuffer put(ByteBuffer src) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(src);
return this;
}
/**
* Writes the content of src into this buffer.
*
* @param src
* the buffer to read from
* @return this ReusableBuffer after reading
* @see java.nio.ByteBuffer#put(ByteBuffer)
*/
public ReusableBuffer put(ReusableBuffer src) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(src.buffer);
return this;
}
/**
* @see java.nio.ByteBuffer#getInt
*/
public int getInt() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.getInt();
}
/**
* @see java.nio.ByteBuffer#putInt(int)
*/
public ReusableBuffer putInt(int i) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.putInt(i);
return this;
}
public long getLong() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.getLong();
}
public ReusableBuffer putLong(long l) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.putLong(l);
return this;
}
public double getDouble() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.getDouble();
}
public ReusableBuffer putDouble(double d) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.putDouble(d);
return this;
}
public String getString() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
int length = buffer.getInt();
if (length > 0) {
byte[] bytes = new byte[length];
buffer.get(bytes);
return new String(bytes, ENC_UTF8);
} else if (length == 0) {
return "";
} else {
return null;
}
}
public ReusableBuffer putString(String str) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
if (str != null) {
byte[] bytes = str.getBytes(ENC_UTF8);
buffer.putInt(bytes.length);
buffer.put(bytes);
} else {
buffer.putInt(-1);
}
return this;
}
public ReusableBuffer putShortString(String str) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
assert (str.length() <= Short.MAX_VALUE);
if (str != null) {
byte[] bytes = str.getBytes(ENC_UTF8);
buffer.putShort((short) bytes.length);
buffer.put(bytes);
} else {
buffer.putInt(-1);
}
return this;
}
public ASCIIString getBufferBackedASCIIString() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return ASCIIString.unmarshall(this);
}
public ReusableBuffer putBufferBackedASCIIString(ASCIIString str) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
if (str != null) {
str.marshall(this);
} else {
buffer.putInt(-1);
}
return this;
}
public ReusableBuffer putShort(short s) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.putShort(s);
return this;
}
public short getShort() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.getShort();
}
/**
* @see java.nio.ByteBuffer#isDirect
*/
public boolean isDirect() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.isDirect();
}
/**
* @see java.nio.Buffer#remaining
*/
public int remaining() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.remaining();
}
/**
* @see java.nio.Buffer#clear
*/
public void clear() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.clear();
}
public byte[] getData() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
byte[] array = new byte[this.limit()];
this.position(0);
this.get(array);
return array;
}
public void shrink(int newSize) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
if (newSize > size) {
throw new IllegalArgumentException("new size must not be larger than old size");
}
this.size = newSize;
int oldPos = buffer.position();
if (oldPos > newSize)
oldPos = 0;
// save parent position and limit
ByteBuffer originalBuffer;
if (parentBuffer != null) {
originalBuffer = parentBuffer;
} else {
originalBuffer = buffer;
}
int position = originalBuffer.position();
int limit = originalBuffer.limit();
originalBuffer.position(0);
originalBuffer.limit(newSize);
this.buffer = originalBuffer.slice();
buffer.position(oldPos);
// restore parent position and limit
originalBuffer.position(position);
originalBuffer.limit(limit);
}
/*
* Increases the capacity of this buffer. Returns false if {@code newSize} is bigger than the capacity of
* the underlying buffer.
*
* The underlying buffer can be a reusable buffer (parentBuffer != 0) or non-reusable buffer (viewParent
* != 0).
*/
public boolean enlarge(int newSize) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
if (newSize == this.size) {
return true;
}
if (parentBuffer == null && viewParent == null) {
return false;
}
ByteBuffer underlyingBuffer = parentBuffer != null ? parentBuffer : viewParent.getBuffer();
if (newSize > underlyingBuffer.capacity()) {
return false;
} else {
this.size = newSize;
int oldPos = buffer.position();
if (oldPos > newSize)
oldPos = 0;
// save parent position and limit
int position = underlyingBuffer.position();
int limit = underlyingBuffer.limit();
underlyingBuffer.position(0);
underlyingBuffer.limit(newSize);
this.buffer = underlyingBuffer.slice();
buffer.position(oldPos);
// restore parent position and limit
underlyingBuffer.position(position);
underlyingBuffer.limit(limit);
return true;
}
}
/*
* Sets the new range of the buffer starting from {@code offset} going for {@code length} bytes.
*
* The new position of the buffer will be 0 and the size/capacity will equal {@code length}.
*/
public void range(int offset, int length) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
// useless call!
if ((offset == 0) && (length == this.size))
return;
if (offset >= size) {
throw new IllegalArgumentException("offset must be < size. offset=" + offset + " size=" + size);
}
if (offset + length > size) {
throw new IllegalArgumentException("offset+length must be <= size. size=" + size + " offset="
+ offset + " length=" + length);
}
this.size = length;
// save parent position and limit
ByteBuffer originalBuffer;
if (parentBuffer != null) {
originalBuffer = parentBuffer;
} else {
originalBuffer = buffer;
}
int position = originalBuffer.position();
int limit = originalBuffer.limit();
// ensure that the subsequent 'position' does not fail
if (offset > limit)
originalBuffer.limit(offset);
originalBuffer.position(offset);
originalBuffer.limit(offset + length);
this.buffer = originalBuffer.slice();
assert (this.buffer.capacity() == length);
// restore parent position and limit
originalBuffer.position(position);
originalBuffer.limit(limit);
}
public ReusableBuffer putBoolean(boolean bool) {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
buffer.put(bool ? (byte) 1 : (byte) 0);
return this;
}
public boolean getBoolean() {
assert (!returned) : "Buffer was already freed and cannot be used anymore" + this.freeStack;
return buffer.get() == 1;
}
public int getRefCount() {
if (this.viewParent == null) {
return this.refCount.get();
} else {
return this.viewParent.refCount.get();
}
}
@Override
protected void finalize() {
if (!returned && reusable) {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this,
"buffer was finalized but not freed before! buffer = %s, refCount=%d", this.toString(), getRefCount());
if (allocStack != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "stacktrace: %s", allocStack);
if (this.viewParent != null)
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "parent stacktrace: %s",
viewParent.allocStack);
}
if (freeStack != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "freed at: %s", freeStack);
} else if (viewParent != null && viewParent.freeStack != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "freed at: %s", viewParent.freeStack);
}
if (Logging.isDebug()) {
byte[] data = new byte[(this.capacity() > 128) ? 128 : this.capacity()];
this.position(0);
this.limit(this.capacity());
this.get(data);
String content = new String(data);
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "content: %s", content);
if (this.viewParent != null) {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "view parent: %s",
this.viewParent.toString());
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "ref count: %d",
this.viewParent.refCount.get());
} else {
Logging.logMessage(Logging.LEVEL_WARN, Category.buffer, this, "ref count: %d",
this.refCount.get());
}
}
BufferPool.free(this);
}
}
@Override
public String toString() {
return "ReusableBuffer( capacity=" + this.capacity() + " limit=" + this.limit() + " position="
+ this.position() + ")";
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums;
import java.nio.ByteBuffer;
/**
* An interface which must be implemented by checksum algorithms for XtreemFS.
*
* 19.08.2008
*
* @author clorenz
*/
public interface ChecksumAlgorithm extends Cloneable {
/**
* Returns a string that identifies the algorithm, independent of
* implementation details.
*
* @return name of algorithm
*/
public String getName();
/**
* Returns checksum value (as Hex-String) and resets the Algorithm.
*
* @return checksum
*/
public long getValue();
/**
* Resets checksum to initial value.
*
* @return
*/
public void reset();
/**
* Updates checksum with specified data.
*
* @param data
*/
public void update(ByteBuffer data);
/**
* returns a new instance of the checksum algorithm
*
* @return
*/
public ChecksumAlgorithm clone();
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* A Factory for getting checksum algorithms from checksum provider. Implemented
* as a Singleton.
*
* 19.08.2008
*
* @author clorenz
*/
public class ChecksumFactory {
/**
* amount of cached instances/algorithm
*/
private static int MAX_CACHE_SIZE = 20;
private static ChecksumFactory self;
/**
* Contains all available checksum algorithms (only one instance).
*/
private HashMap<String, ChecksumAlgorithm> algorithms;
/**
* Contains all known checksum provider
*/
private HashMap<String, ChecksumProvider> knownProvider;
/**
* Contains cached instances for all available checksum algorithms.
*/
private HashMap<String, ConcurrentLinkedQueue<ChecksumAlgorithm>> pool;
/**
* creates a new ChecksumFactory
*/
private ChecksumFactory() {
super();
this.algorithms = new HashMap<String, ChecksumAlgorithm>();
this.pool = new HashMap<String, ConcurrentLinkedQueue<ChecksumAlgorithm>>();
this.knownProvider = new HashMap<String, ChecksumProvider>();
}
/**
* Get the instance of ChecksumFactory.
*
* @return the instance
*/
public static ChecksumFactory getInstance() {
if (self == null) {
self = new ChecksumFactory();
}
return self;
}
/**
* Get an instance of a specific checksum algorithm, if supported.
*
* @param name
* of the algorithm
* @return algorithm object or null, if algorithm is not supported
*/
public ChecksumAlgorithm getAlgorithm(String name)
throws NoSuchAlgorithmException {
ConcurrentLinkedQueue<ChecksumAlgorithm> cache = pool.get(name);
if (cache == null)
throw new NoSuchAlgorithmException("algorithm " + name
+ " not supported");
ChecksumAlgorithm algorithm = cache.poll();
if (algorithm == null) { // cache is empty
return algorithms.get(name).clone(); // create new instance
} else {
return algorithm; // return caches instance
}
}
/**
* Returns an instance of a specific checksum algorithm for caching.
*
* @param instance
* of the algorithm
*/
public void returnAlgorithm(ChecksumAlgorithm algorithm) {
ConcurrentLinkedQueue<ChecksumAlgorithm> cache = pool.get(algorithm
.getName());
if (cache.size() < MAX_CACHE_SIZE) {
algorithm.reset();
cache.add(algorithm);
}
}
/**
* Adds a new provider to factory and adds all supported algorithms from the
* provider to the algorithms-list. NOTE: Existing algorithms will be
* overridden when the new provider contains the same algorithm (maybe
* another implementation).
*
* @param provider
*/
public void addProvider(ChecksumProvider provider) {
knownProvider.put(provider.getName(), provider);
for (ChecksumAlgorithm algorithm : provider.getSupportedAlgorithms()) {
addAlgorithm(algorithm);
}
}
/**
* Adds a new Algorithm to factory. NOTE: The same existing algorithm will
* be overridden.
*
* @param algorithm
*/
public void addAlgorithm(ChecksumAlgorithm algorithm) {
algorithms.put(algorithm.getName(), algorithm);
pool.put(algorithm.getName(),
new ConcurrentLinkedQueue<ChecksumAlgorithm>());
}
/**
* Removes a provider, but not the added algorithms.
*
* @param provider
*/
public void removeProvider(ChecksumProvider provider) {
knownProvider.remove(provider.getName());
}
/**
* Removes an algorithm.
*
* @param algorithm
*/
public void removeAlgorithm(String algorithm) {
algorithms.remove(algorithm);
pool.remove(algorithm);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums;
import java.util.Collection;
import java.util.HashMap;
/**
* An abstract class which must be implemented by a checksum provider for
* XtreemFS.
*
* 19.08.2008
*
* @author clorenz
*/
public abstract class ChecksumProvider {
/**
* contains the supported algorithms
*/
protected HashMap<String, ChecksumAlgorithm> algorithms;
protected ChecksumProvider() {
super();
this.algorithms = new HashMap<String, ChecksumAlgorithm>();
}
/**
* Returns the name of the provider.
*
* @return name
*/
public abstract String getName();
/**
* Returns all from this provider supported checksum algorithms.
*
* @return a collection with ChecksumAlgorithms
*/
public Collection<ChecksumAlgorithm> getSupportedAlgorithms() {
return algorithms.values();
}
/**
* adds an algorithm to the map
*
* @param newAlgorithm
*/
protected void addAlgorithm(ChecksumAlgorithm newAlgorithm) {
this.algorithms.put(newAlgorithm.getName(), newAlgorithm);
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums;
/**
* An interface for checksum algorithms, which are based on computations on
* strings.
*
* 02.09.2008
*
* @author clorenz
*/
public interface StringChecksumAlgorithm extends ChecksumAlgorithm {
/**
* Updates checksum with specified data.
*
* @param data
*/
public void digest(String data);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.algorithms;
/**
* The Adler32 algorithm. It uses the Java internal implementation.
*
* 19.08.2008
*
* @author clorenz
*/
@SuppressWarnings("unchecked")
public class Adler32 extends JavaChecksumAlgorithm {
public Adler32() {
super(new java.util.zip.Adler32(), "Adler32");
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#clone()
*/
@Override
public Adler32 clone() {
return new Adler32();
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.algorithms;
/**
* The CRC32 algorithm. It uses the Java internal implementation.
*
* 19.08.2008
*
* @author clorenz
*/
@SuppressWarnings("unchecked")
public class CRC32 extends JavaChecksumAlgorithm {
public CRC32() {
super(new java.util.zip.CRC32(), "CRC32");
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#clone()
*/
@Override
public CRC32 clone() {
return new CRC32();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.algorithms;
import java.nio.ByteBuffer;
import java.util.zip.Checksum;
import org.xtreemfs.foundation.checksums.ChecksumAlgorithm;
/**
* An abstract wrapper for Java internal checksums.
*
* 19.08.2008
*
* @author clorenz
*/
abstract public class JavaChecksumAlgorithm<RealJavaAlgorithm extends Checksum>
implements ChecksumAlgorithm {
/**
* the class, which really implements the selected algorithm
*/
protected RealJavaAlgorithm realAlgorithm;
protected String name;
public JavaChecksumAlgorithm(RealJavaAlgorithm realAlgorithm, String name) {
super();
this.realAlgorithm = realAlgorithm;
this.name = name;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#digest(java.nio.ByteBuffer)
*/
@Override
public void update(ByteBuffer data) {
byte[] array;
if (data.hasArray()) {
array = data.array();
} else {
array = new byte[data.capacity()];
final int oldPos = data.position();
data.position(0);
data.get(array);
data.position(oldPos);
}
realAlgorithm.update(array, 0, array.length);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#getName()
*/
@Override
public String getName() {
return name;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#getValue()
*/
@Override
public long getValue() {
final long tmp = realAlgorithm.getValue();
realAlgorithm.reset();
return tmp;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#reset()
*/
@Override
public void reset() {
realAlgorithm.reset();
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#clone()
*/
@Override
public abstract JavaChecksumAlgorithm<?> clone();
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.algorithms;
import java.nio.ByteBuffer;
import org.xtreemfs.foundation.checksums.StringChecksumAlgorithm;
/**
* The Java algorithm, which is used for string.hashCode(). It uses the Java
* internal implementation.
*
* 02.09.2008
*
* @author clorenz
*/
public class JavaHash implements StringChecksumAlgorithm {
private Long hash = null;
private String name = "Java-Hash";
/**
* Updates checksum with specified data.
*
* @param data
*/
public void digest(String data) {
this.hash = Long.valueOf(data.hashCode());
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#digest(java.nio.ByteBuffer)
*/
@Override
public void update(ByteBuffer data) {
byte[] array;
if (data.hasArray()) {
array = data.array();
} else {
array = new byte[data.capacity()];
final int oldPos = data.position();
data.position(0);
data.get(array);
data.position(oldPos);
}
this.hash = (long)new String(array).hashCode();
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#getName()
*/
@Override
public String getName() {
return this.name;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#getValue()
*/
@Override
public long getValue() {
long value;
if (this.hash != null)
value = this.hash;
else
value = 0;
reset();
return value;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#reset()
*/
@Override
public void reset() {
hash = null;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#clone()
*/
@Override
public JavaHash clone() {
return new JavaHash();
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.algorithms;
import java.nio.ByteBuffer;
import org.xtreemfs.foundation.checksums.StringChecksumAlgorithm;
/**
* The SDBM algorithm.
*
* 02.09.2008
*
* @author clorenz
*/
public class SDBM implements StringChecksumAlgorithm {
private Long hash = null;
private String name = "SDBM";
/**
* Updates checksum with specified data.
*
* @param data
*/
public void digest(String data) {
this.hash = sdbmHash(data);
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#digest(java.nio.ByteBuffer)
*/
@Override
public void update(ByteBuffer data) {
byte[] array;
if (data.hasArray()) {
array = data.array();
} else {
array = new byte[data.capacity()];
final int oldPos = data.position();
data.position(0);
data.get(array);
data.position(oldPos);
}
this.hash = sdbmHash(new String(array));
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#getName()
*/
@Override
public String getName() {
return this.name;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#getValue()
*/
@Override
public long getValue() {
long value;
if (this.hash != null)
value = this.hash;
else
value = 0;
reset();
return value;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumAlgorithm#reset()
*/
@Override
public void reset() {
hash = null;
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.common.checksum.ChecksumAlgorithm#clone()
*/
@Override
public SDBM clone() {
return new SDBM();
}
/**
* SDBM algorithm
*
* @param str
* @return
*/
protected static long sdbmHash(String str) {
long hash = 0;
for (int c : str.toCharArray()) {
hash = c + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.checksums.provider;
import org.xtreemfs.foundation.checksums.ChecksumProvider;
/**
* A provider for Java internal checksums. offers the following algorithms:
* Adler32, CRC32, MD5, Java-Hash
*
* 19.08.2008
*
* @author clorenz
*/
public class JavaChecksumProvider extends ChecksumProvider {
private static String NAME = "Java Checksum Provider";
/**
* creates a new JavaChecksumProvider
*/
public JavaChecksumProvider() {
super();
addAlgorithm(new org.xtreemfs.foundation.checksums.algorithms.Adler32());
addAlgorithm(new org.xtreemfs.foundation.checksums.algorithms.CRC32());
/*try {
addAlgorithm(new org.xtreemfs.foundation.checksums.algorithms.JavaMessageDigestAlgorithm(
"MD5", "MD5"));
addAlgorithm(new org.xtreemfs.foundation.checksums.algorithms.JavaMessageDigestAlgorithm(
"SHA1", "SHA-1"));
} catch (NoSuchAlgorithmException e) {
Logging.logMessage(Logging.LEVEL_WARN, this, e.getMessage()
+ " in your java-installation");
}*/
addAlgorithm(new org.xtreemfs.foundation.checksums.algorithms.JavaHash());
}
/*
* (non-Javadoc)
*
* @see org.xtreemfs.foundation.checksums.ChecksumProvider#getName()
*/
@Override
public String getName() {
return NAME;
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.json;
import java.nio.BufferUnderflowException;
import java.nio.CharBuffer;
/**
*
* @author bjko
*/
public class JSONCharBufferString implements JSONInput {
CharBuffer cb;
/** Creates a new instance of JSONCharBufferString */
public JSONCharBufferString(CharBuffer cb) {
assert (cb != null);
this.cb = cb;
this.cb.position(0);
}
public char read() throws JSONException {
try {
return cb.get();
} catch(BufferUnderflowException ex) {
throw new JSONException("Reached end of buffer");
}
}
public int skip(int skip) {
try {
cb.position(cb.position()+skip);
return skip;
} catch (IllegalArgumentException e) {
return 0;
}
}
public String toString() {
return "JSONCharBufferString backed by "+cb.toString();
}
public boolean hasMore() {
return cb.hasRemaining();
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.json;
/**
* Thrown by the JSON parser and writer.
*
* @author bjko
*/
public class JSONException extends java.lang.Exception {
/***/
private static final long serialVersionUID = 2422241603599209392L;
/**
* Creates a new instance of <code>JSONException</code> without detail
* message.
*/
public JSONException() {
}
/**
* Constructs an instance of <code>JSONException</code> with the specified
* detail message.
*
* @param msg
* the detail message.
*/
public JSONException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.json;
/**
*
* @author bjko
*/
public interface JSONInput {
/**
* reads a single char
*
* @return the character at the current position is returned
*/
public char read() throws JSONException;
/**
* It checks if there are more characters
*/
public boolean hasMore();
/**
* Skips skip characters
*
* @param skip
* num characters to skip
* @return the number of characters skipped
*/
public int skip(int skip);
/**
* Get a string representation.
*
* @return A string representation of the this JSONString.
*/
public String toString();
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.json;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* JSON Parser routines. This parser accepts any value as top level element, not
* just an object or array.
*
* @author bjko
*/
public class JSONParser {
/**
* Creates a new instance of JSONParser
*/
public JSONParser() {
}
private static String parseString(JSONInput input) throws JSONException {
boolean nonEscaped = true;
StringBuilder str = new StringBuilder();
while (input.hasMore()) {
char ch = input.read();
if (nonEscaped) {
if (ch == '\\') {
nonEscaped = false;
continue;
}
else if (ch == '"') {
return str.toString();
}
else {
str.append(ch);
}
}
else {
if (ch == 'n') {
str.append('\n');
} else if (ch == 'r') {
str.append('\r');
} else if (ch == 't') {
str.append('\t');
} else {
str.append(ch);
}
}
nonEscaped = true;
}
throw new JSONException("[ E | JSONParser ] Unexpected end while parsing string");
}
private static Object parseNumber(JSONInput input) throws JSONException {
StringBuilder str = new StringBuilder();
input.skip(-1);
boolean isFP = false;
while (input.hasMore()) {
char ch = input.read();
if ((ch == '-') || (ch >= '0') && (ch <= '9')) {
str.append(ch);
} else if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
str.append(ch);
isFP = true;
} else {
input.skip(-1);
if (isFP)
return new BigDecimal(str.toString());
else
return Long.valueOf(str.toString());
}
}
if (isFP)
return new BigDecimal(str.toString());
else
return Long.valueOf(str.toString());
}
private static Object parseArray(JSONInput input) throws JSONException {
LinkedList<Object> arr = new LinkedList<Object>();
while (input.hasMore()) {
char ch = input.read();
if (ch == ']') {
return arr;
} else if (ch == ',') {
arr.add(parseJSON(input));
} else if ((ch == ' ') || (ch == '\t')) {
continue;
} else {
input.skip(-1);
arr.add(parseJSON(input));
}
}
throw new JSONException("[ E | JSONParser ] Unexpected end while parsing array");
}
private static Object parseObject(JSONInput input) throws JSONException {
HashMap<String, Object> map = new HashMap<String, Object>();
while (input.hasMore()) {
char ch = input.read();
if (ch == '}') {
return map;
}
// skip all ws
if ((ch == ' ') || (ch == '\t')) {
continue;
}
String name = parseString(input);
ch = input.read();
while ((ch == ' ') || (ch == '\t')) {
ch = input.read();
}
if (ch != ':') {
throw new JSONException("[ E | JSONParser ] Unexpected token '"
+ ((char) ch) + "' or EOF. Expected : in Object.");
}
while ((ch == ' ') || (ch == '\t')) {
ch = input.read();
}
Object value = parseJSON(input);
map.put(name, value);
ch = input.read();
while ((ch == ' ') || (ch == '\t')) {
ch = input.read();
}
if (ch == '}') {
return map;
}
if (ch != ',') {
throw new JSONException("[ E | JSONParser ] Unexpected token '"
+ ((char) ch) + "' or EOF. Expected , or } in Object.");
}
}
throw new JSONException("[ E | JSONParser ] Unexpected end while parsing object");
}
/**
* Parses a JSON message.
*
* @return the objects encoded in input.
* @attention This routine may cause a StackOverflow exception when parsing
* incorrect, very deep or maliciously malformed JSON messages.
* @param input
* the JSON string
* @throws org.xtreemos.wp34.mrc.utils.JSONException
* if input is not valid JSON
*/
public static Object parseJSON(JSONInput input) throws JSONException {
while (input.hasMore()) {
char ch = input.read();
if (ch == '[') {
return parseArray(input);
} else if (ch == '{') {
return parseObject(input);
} else if (ch == '"') {
return parseString(input);
} else if ((ch == '-') || ((ch >= '0') && (ch <= '9'))) {
return parseNumber(input);
} else if (ch == 't') {
input.skip(3);
return Boolean.valueOf(true);
} else if (ch == 'f') {
input.skip(4);
return Boolean.valueOf(false);
} else if (ch == 'n') {
input.skip(3);
return null;
} else if ((ch == ' ') || (ch == '\t')) {
continue;
} else {
throw new JSONException("[ E | JSONParser ] Unexpected token '"
+ ((char) ch) + "' expected Object, Array or Value.");
}
}
throw new JSONException("[ E | JSONParser ] Unexpected end while parsing root element");
}
/**
* Creates a JSON encoded message from an object. Can handle Boolean,
* Integer, Long, BigDecimal, List and Map.
*
* @param input
* object to encode, objects can be nested.
* @return a JSON encoded message
* @throws org.xtreemos.wp34.mrc.utils.JSONException
* if there are one or more objects it cannot encode
*/
public static String writeJSON(Object input) throws JSONException {
return writeJSON(input,new StringBuilder()).toString();
}
/**
* Creates a JSON encoded message from an object. Can handle Boolean,
* Integer, Long, BigDecimal, List and Map.
*
* @param input
* object to encode, objects can be nested.
* @return a JSON encoded message
* @throws org.xtreemos.wp34.mrc.utils.JSONException
* if there are one or more objects it cannot encode
*/
@SuppressWarnings("unchecked")
public static StringBuilder writeJSON(Object input, StringBuilder result) throws JSONException {
if (input == null) {
return result.append("null");
} else if (input instanceof Boolean) {
return result.append(((Boolean) input).booleanValue() ? "true" : "false");
} else if (input instanceof BigDecimal) {
return result.append(((BigDecimal) input).toString());
} else if (input instanceof Integer) {
return result.append((Integer) input);
} else if (input instanceof Long) {
return result.append((Long) input);
} else if (input instanceof String) {
return writeJSONString(input,result);
} else if (input instanceof Map) {
return writeJSONObject(input,result);
} else if (input instanceof Collection) {
return writeJSONArray(input,result);
} else {
throw new JSONException(
"[ E | JSONParser ] Unexpected Object type: "
+ input.getClass().getName());
}
}
@SuppressWarnings("unchecked")
private static StringBuilder writeJSONObject(Object input, StringBuilder result) throws JSONException {
Map<Object, Object> map = (Map) input;
result.append("{");
int i = 1;
for (Object key : map.keySet()) {
writeJSONString(key.toString(),result);
result.append(":");
writeJSON(map.get(key),result);
if (i < map.size())
result.append(",");
i++;
}
return result.append("}");
}
@SuppressWarnings("unchecked")
private static StringBuilder writeJSONArray(Object input, StringBuilder result) throws JSONException {
Collection<Object> arr = (Collection<Object>) input;
result.append("[");
int i = 1;
for (Object obj : arr) {
writeJSON(obj,result);
if (i < arr.size())
result.append(",");
i++;
}
return result.append("]");
}
private static StringBuilder writeJSONString(Object input, StringBuilder result) {
/*
* This is 10 times faster than using str.replace
*/
final String str = input.toString();
result.append("\"");
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
switch (ch) {
case '\n' : result.append("\\n"); break;
case '\r' : result.append("\\r"); break;
case '\t' : result.append("\\t"); break;
case '"' : result.append("\\\""); break;
case '\\' : result.append("\\\\"); break;
case '/' : result.append("\\/"); break;
default: result.append(ch);
}
}
result.append("\"");
return result;
}
public static String toJSON(Object... args) throws JSONException {
List<Object> argList = new ArrayList<Object>(args.length);
for (Object arg : args)
argList.add(arg);
return writeJSON(argList);
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck, Jan Stender,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.json;
/**
* This class is necessary because the StringReader cannot skip back once the
* end is reached.
*
* @author bjko
*/
public class JSONString implements JSONInput {
String str;
int position;
/**
* Creates a new instance of JSONString
*
* @param str
* the JSON message
*/
public JSONString(String str) {
this.str = str;
position = 0;
}
/**
* reads a single char
*
* @return the character at the current position is returned
*/
public char read() throws JSONException {
try {
return str.charAt(position++);
}
catch (StringIndexOutOfBoundsException ex) {
throw new JSONException("Reach the end of the string");
}
}
/**
*/
public boolean hasMore() {
return position < str.length();
}
/**
* Skips skip characters
*
* @param skip
* num characters to skip
* @return the number of characters skipped
*/
public int skip(int skip) {
if (((position + skip) < 0) || ((position + skip) >= str.length())) {
return 0;
} else {
position = position + skip;
return skip;
}
}
/**
* Get a string representation.
*
* @return A string representation of the this JSONString.
*/
public String toString() {
return "JSONString pos=" + position + " str=" + str;
}
}

View File

@@ -0,0 +1,274 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.logging;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* @author bjko
*/
public class Logging {
public enum Category {
/**
* enable logging for all categories (no real category)
*/
all,
/**
* logs messages pertaining to buffers
*/
buffer,
/**
* log messaages pertaining to service lifecycles (threads)
*/
lifecycle,
/**
* network-related log messages
*/
net,
/**
* authorization-related log messages
*/
auth,
/**
* log messages pertaining to the request flow through the stages
*/
stage,
/**
* log messages pertaining to any kind of request processing
*/
proc,
/**
*
*/
misc,
/**
* log messages pertaining storage on OSD or database access on MRC/DIR
*/
storage,
/**
* logs messages pertaining to replication
*/
replication,
/**
* logs messages from additional tools
*/
tool,
/**
* logs messages from tests
*/
test
}
protected static final char ABBREV_LEVEL_INFO = 'I';
protected static final char ABBREV_LEVEL_DEBUG = 'D';
protected static final char ABBREV_LEVEL_WARN = 'W';
protected static final char ABBREV_LEVEL_ERROR = 'E';
protected static final char ABBREV_LEVEL_TRACE = 'T';
public static final int LEVEL_EMERG = 0;
public static final int LEVEL_ALERT = 1;
public static final int LEVEL_CRIT = 2;
public static final int LEVEL_ERROR = 3;
public static final int LEVEL_WARN = 4;
public static final int LEVEL_NOTICE = 5;
public static final int LEVEL_INFO = 6;
public static final int LEVEL_DEBUG = 7;
public static final String FORMAT_PATTERN = "[ %c | %-20s | %-15s | %3d | %15s ] %s";
private static PrintStream out = System.out;
protected static Logging instance;
protected static boolean tracingEnabled = false;
private final int level;
private final int catMask;
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss");
/**
* Creates a new instance of Logging
*/
private Logging(int level, int catMask) {
if (level < 0)
this.level = 0;
else
this.level = level;
this.catMask = catMask;
instance = this;
System.currentTimeMillis();
}
public static void redirect(PrintStream out) {
Logging.out = out;
}
public static String truncateString(String string, int maxLength) {
return (string.length() > maxLength) ?
(string.substring(0, maxLength - 3) + "...") : string;
}
public static void logMessage(int level, Category cat, Object me, String formatPattern, Object... args) {
checkIfInitializedOrThrow();
// if the level is appropriate as well as the category, or the category
// is 'all', log the message
if (level <= instance.level && (cat == Category.all || (2 << cat.ordinal() & instance.catMask) > 0)) {
char levelName = getLevelName(level);
out.println(String.format(FORMAT_PATTERN, levelName,
me == null ? "-" : truncateString(me instanceof Class ? ((Class) me).getSimpleName(): me.getClass().getSimpleName(), 20),
truncateString(Thread.currentThread().getName(), 15),
Thread.currentThread().getId(),
getTimeStamp(),
String.format(formatPattern, args)));
}
}
private static void checkIfInitializedOrThrow() {
if (instance == null) {
throw new RuntimeException(
"Cannot log message because the logging is not initialized yet. Did you forget to call Logging.start(...) in your code?");
}
}
public static void logMessage(int level, Object me, String formatPattern, Object... args) {
logMessage(level, Category.all, me, formatPattern, args);
}
public static void logError(int level, Object me, Throwable msg) {
checkIfInitializedOrThrow();
// if the level is appropriate, log the message
if (level <= instance.level) {
char levelName = getLevelName(level);
out.println(String.format(FORMAT_PATTERN, levelName,
me == null ? "-" : (me instanceof Class ? ((Class) me).getSimpleName(): me.getClass().getSimpleName()),
Thread.currentThread().getName(), Thread.currentThread().getId(),
getTimeStamp(), msg.toString()));
for (StackTraceElement elem : msg.getStackTrace()) {
out.println(" ... " + elem.toString());
}
if (msg.getCause() != null) {
out.println(String.format(FORMAT_PATTERN, levelName, me == null ? "-" : me.getClass()
.getSimpleName(), Thread.currentThread().getName(), Thread.currentThread().getId(),
getTimeStamp(), "root cause: " + msg.getCause()));
for (StackTraceElement elem : msg.getCause().getStackTrace()) {
out.println(" ... " + elem.toString());
}
}
}
}
public static void logUserError(int level, Category cat, Object me, Throwable msg) {
checkIfInitializedOrThrow();
// if the level is appropriate as well as the category, or the category
// is 'all', log the message
if (level <= instance.level && (cat == Category.all || (2 << cat.ordinal() & instance.catMask) > 0)) {
char levelName = getLevelName(level);
out.println(String.format(FORMAT_PATTERN, levelName, me == null ? "-" : me.getClass()
.getSimpleName(), Thread.currentThread().getName(), Thread.currentThread().getId(),
getTimeStamp(), msg.toString()));
for (StackTraceElement elem : msg.getStackTrace()) {
out.println(" ... " + elem.toString());
}
}
}
public static char getLevelName(int level) {
switch (level) {
case LEVEL_EMERG:
case LEVEL_ALERT:
case LEVEL_CRIT:
case LEVEL_ERROR:
return ABBREV_LEVEL_ERROR;
case LEVEL_WARN:
return ABBREV_LEVEL_WARN;
case LEVEL_NOTICE:
case LEVEL_INFO:
return ABBREV_LEVEL_INFO;
case LEVEL_DEBUG:
return ABBREV_LEVEL_DEBUG;
default:
return '?';
}
}
public synchronized static void start(int level, Category... categories) {
if (instance == null) {
int catMask = 0;
for (Category cat : categories) {
if (cat == Category.all)
catMask = -1;
catMask |= 2 << cat.ordinal();
}
if(categories.length == 0)
catMask = -1;
instance = new Logging(level, catMask);
}
}
public static boolean isDebug() {
if (instance == null)
return false;
else
return instance.level >= LEVEL_DEBUG;
}
public static boolean isInfo() {
if (instance == null)
return false;
else
return instance.level >= LEVEL_INFO;
}
public static boolean isNotice() {
if (instance == null)
return false;
else
return instance.level >= LEVEL_NOTICE;
}
private static String getTimeStamp() {
return dateFormat.format(new Date());
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2008-2010 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.logging;
/**
*
* @author bjko
*/
public class Utils {
public static final char LEVEL_INFO = 'I';
public static final char LEVEL_DEBUG = 'D';
public static final char LEVEL_WARN = 'W';
public static final char LEVEL_ERROR = 'E';
public static void logMessage(char level, Object me, String msg) {
if (me == null) {
System.out.println(String.format("[ %c | %-20s | %3d ] %s",
level,"?",Thread.currentThread().getId(),
msg));
} else {
System.out.println(String.format("[ %c | %-20s | %3d ] %s",
level,me.getClass().getSimpleName(),Thread.currentThread().getId(),
msg));
}
}
/** Creates a new instance of Utils */
public Utils() {
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2009-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.monitoring;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* The class provides the ability to monitor data. It could monitor multiple data for each key.<br>
* NOTE: This class is thread-safe. <br>
* 22.07.2009
*/
public class ListMonitoring<V> extends Monitoring<List<V>> {
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2009-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.monitoring;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* The class provides the ability to monitor data. The data must be added via push (put-method). For getting the
* contained data poll (get-method) and push (via listeners) is supported.<br>
* NOTE: This class is thread-safe. <br>
* 22.07.2009
*/
public class Monitoring<V> {
/**
* contains the monitored data
*/
protected ConcurrentHashMap<String, V> datasets;
/**
* contains the registered listeners
*/
protected ConcurrentHashMap<String, List<MonitoringListener<V>>> listeners;
/**
*
*/
public Monitoring() {
datasets = new ConcurrentHashMap<String, V>();
listeners = new ConcurrentHashMap<String, List<MonitoringListener<V>>>();
}
/**
* Adds the value to the given key and overwrites the old value. Notifies all associated listeners.
*
* @param key
* @param value
* @return
* @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
*/
public V put(String key, V value) {
assert (key != null && value != null);
V oldValue = datasets.put(key, value);
// check if listeners are registered
if (listeners.containsKey(key)) {
MonitoringEvent<V> event = new MonitoringEvent<V>(this, key, value);
for (MonitoringListener<V> listener : listeners.get(key))
listener.valueAddedOrChanged(event);
}
return oldValue;
}
/**
* @param key
* @return
* @see java.util.HashMap#get(java.lang.Object)
*/
public V get(String key) {
return datasets.get(key);
}
/**
* @param key
* @return
* @see java.util.HashMap#containsKey(java.lang.Object)
*/
public boolean containsKey(String key) {
return datasets.containsKey(key);
}
/**
* @return
* @see java.util.HashMap#entrySet()
*/
public Set<Entry<String, V>> entrySet() {
return datasets.entrySet();
}
/**
* @param key
* @return
* @see java.util.HashMap#remove(java.lang.Object)
*/
public V remove(String key) {
return datasets.remove(key);
}
/**
* @return
* @see java.util.HashMap#size()
*/
public int size() {
return datasets.size();
}
/**
* @return
* @see java.util.AbstractMap#toString()
*/
public String toString() {
return datasets.toString();
}
/**
* Registers a listener for the specified key. If the value of the key changes, the associated listeners
* will be notified.
*
* @param key
* @param listener
*/
public void registerListener(String key, MonitoringListener<V> listener) {
List<MonitoringListener<V>> list = listeners.get(key);
if (list == null) {
list = new CopyOnWriteArrayList<MonitoringListener<V>>();
listeners.put(key, list);
}
list.add(listener);
}
/**
* Unregisters the given listener for the given key.
*
* @param key
* @param listener
*/
public void unregisterListener(String key, MonitoringListener<V> listener) {
List<MonitoringListener<V>> list = listeners.get(key);
if (list != null) {
int index = list.indexOf(listener);
if (index != -1)
list.remove(index);
}
}
/*
* system-wide stuff
*/
private static boolean monitoringEnabled = false;
/**
* enables monitoring for the whole system
*/
public static void enable() {
monitoringEnabled = true;
}
/**
* @return the monitoringEnabled
*/
public static boolean isEnabled() {
return monitoringEnabled;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2009-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.monitoring;
import java.util.EventObject;
/**
* An event which is created, when a value has changed. It piggybacks the key and new value, too. <br>
* 22.07.2009
*/
public class MonitoringEvent<V> extends EventObject {
private static final long serialVersionUID = 1L;
/**
* the key of the changed value
*/
String key;
/**
* the changed value
*/
V newValue;
/**
* Creates a new instance of this class.
*
* @param source
* @param key
* @param newValue
*/
public MonitoringEvent(Object source, String key, V newValue) {
super(source);
this.key = key;
this.newValue = newValue;
}
/**
* @return the key
*/
public String getKey() {
return key;
}
/**
* @return the value
*/
public V getNewValue() {
return newValue;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2009-2010, Konrad-Zuse-Zentrum fuer Informationstechnik Berlin
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of the Konrad-Zuse-Zentrum fuer Informationstechnik Berlin
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* AUTHORS: Christian Lorenz (ZIB)
*/
package org.xtreemfs.foundation.monitoring;
import java.util.EventListener;
/**
* A simple listener for notification, if the value of the target has changed. <br>
* 22.07.2009
*/
public interface MonitoringListener<V> extends EventListener {
/**
* Invoked when a value of the monitored data has changed.
*
* @param event
*/
public void valueAddedOrChanged(MonitoringEvent<V> event);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2009-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.monitoring;
import java.io.IOException;
/**
*
* <br>
* 17.08.2009
*/
public class MonitoringLog implements MonitoringListener<Double> {
private static MonitoringLog instance;
private long monitoringStartTime;
public static synchronized void initialize(String filepath) throws IOException {
if (instance == null) {
instance = new MonitoringLog();
instance.monitoringStartTime = System.currentTimeMillis();
// file to write to
// (new File(filepath)).getParentFile().mkdirs();
// instance.out = new FileWriter(filepath);
}
}
@Override
public void valueAddedOrChanged(MonitoringEvent<Double> event) {
monitor(event.getKey(), event.getNewValue().toString());
}
public static synchronized void monitor(String key, String value) {
long time = (System.currentTimeMillis() - instance.monitoringStartTime) / 1000;
System.out.println("[" + time + "s]\t" + key + "\t:\t" + value);
}
@SuppressWarnings("unchecked")
public static void registerFor(Monitoring monitoring, String... keys) {
for (String key : keys)
monitoring.registerListener(key, instance);
}
}

View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2009-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.monitoring;
/**
* The class provides the ability to monitor numeric data. It also provides methods some methods for special
* cases than only overwriting the old value.<br>
* NOTE: This class is thread-safe. <br>
* 22.07.2009
*/
public class NumberMonitoring extends Monitoring<Double> {
/**
* Saves the value only if the new value is smaller than the old one.
*
* @param key
* @param value
* @return
*/
public Double putSmaller(String key, Double value) {
Double oldValue = super.get(key);
if (oldValue != null) {
if (oldValue > value)
return super.put(key, value);
else
return value;
} else
return super.put(key, value);
}
/**
* Saves the value only if the new value is larger than the old one.
*
* @param key
* @param value
* @return
*/
public Double putLarger(String key, Double value) {
Double oldValue = super.get(key);
if (oldValue != null) {
if (oldValue < value)
return super.put(key, value);
else
return value;
} else
return super.put(key, value);
}
/**
* Saves the average of the old and new value.
*
* @param key
* @param value
* @return
*/
public Double putAverage(String key, Double value) {
Double oldValue = super.get(key);
if (oldValue != null) {
return super.put(key, (oldValue + value) / 2);
} else
return super.put(key, value);
}
/**
* Increases the old value about new value.
*
* @param key
* @param value
* @return
*/
public Double putIncreaseFor(String key, Double value) {
Double oldValue = super.get(key);
if (oldValue != null) {
return super.put(key, oldValue + value);
} else
return super.put(key, value);
}
/**
* Decreases the old value about new value.
*
* @param key
* @param value
* @return
*/
public Double putDecreaseFor(String key, Double value) {
Double oldValue = super.get(key);
if (oldValue != null) {
return super.put(key, oldValue - value);
} else
return super.put(key, value);
}
/**
* Special method for Longs.
*
* @see org.xtreemfs.foundation.monitoring.Monitoring#put(java.lang.String, java.lang.Object)
* @param key
* @param value
* @return
*/
public Long putLong(String key, Long value) {
Double oldValue = super.put(key, value.doubleValue());
return (oldValue == null) ? null : oldValue.longValue();
}
/**
* Special method for Longs. Saves the value only if the new value is smaller than the old one.
*
* @see org.xtreemfs.foundation.monitoring.NumberMonitoring#putSmaller(java.lang.String, java.lang.Double)
* @param key
* @param value
* @return
*/
public Long putSmallerLong(String key, Long value) {
Double oldValue = this.putSmaller(key, value.doubleValue());
return (oldValue == null) ? null : oldValue.longValue();
}
/**
* Special method for Longs. Saves the value only if the new value is larger than the old one.
*
* @see org.xtreemfs.foundation.monitoring.NumberMonitoring#putLarger(java.lang.String, java.lang.Double)
* @param key
* @param value
* @return
*/
public Long putLargerLong(String key, Long value) {
Double oldValue = this.putLarger(key, value.doubleValue());
return (oldValue == null) ? null : oldValue.longValue();
}
/**
* Special method for Longs. Saves the average of the old and new value.
*
* @param key
* @param value
* @return
*/
public Long putAverageLong(String key, Long value) {
Double oldValue = super.get(key);
if (oldValue != null) {
this.put(key, (oldValue + value) / 2d).longValue();
return oldValue.longValue();
} else
return this.putLong(key, value);
}
/**
* Increases the old value about new value.
*
* @param key
* @param value
* @return
*/
public Long putIncreaseForLong(String key, Long value) {
Double oldValue = this.putIncreaseFor(key, value.doubleValue());
return (oldValue == null) ? null : oldValue.longValue();
}
/**
* Decreases the old value about new value.
*
* @param key
* @param value
* @return
*/
public Long putDecreaseForLong(String key, Long value) {
Double oldValue = this.putDecreaseFor(key, value.doubleValue());
return (oldValue == null) ? null : oldValue.longValue();
}
/**
*
* @param key
* @return
*/
public Long getLong(String key) {
Double value = super.get(key);
return (value == null) ? null : value.longValue();
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc;
/**
*
* @author bjko
*/
public class Schemes {
public static final String SCHEME_PBRPC = "pbrpc";
public static final String SCHEME_PBRPCG = "pbrpcg";
public static final String SCHEME_PBRPCS = "pbrpcs";
public static final String SCHEME_PBRPCU = "pbrpcu";
public static String getScheme(boolean sslEnabled, boolean gridSSL) {
if (sslEnabled) {
if (gridSSL) {
return SCHEME_PBRPCG;
} else {
return SCHEME_PBRPCS;
}
} else {
return SCHEME_PBRPC;
}
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2008-2011 by Christian Lorenz, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.channels;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.security.cert.Certificate;
/**
* A abstraction of the SocketChannel
*
* @author clorenz
*/
public class ChannelIO {
protected final SocketChannel channel;
protected Certificate[] certs;
protected Object attachment;
public ChannelIO(SocketChannel channel) {
this.channel = channel;
this.certs = null;
attachment = null;
}
public SelectableChannel configureBlocking(boolean block)
throws IOException {
return channel.configureBlocking(block);
}
public boolean connect(SocketAddress remote) throws IOException {
return this.channel.connect(remote);
}
public void close() throws IOException {
channel.socket().close();
channel.close();
}
public boolean isBlocking() {
return channel.isBlocking();
}
public boolean isOpen() {
return channel.isOpen();
}
public SelectionKey keyFor(Selector sel) {
return channel.keyFor(sel);
}
public int read(ByteBuffer dst) throws IOException, NotYetConnectedException {
return channel.read(dst);
}
public SelectionKey register(Selector sel, int ops, Object att)
throws ClosedChannelException {
return channel.register(sel, ops, att);
}
public Socket socket() {
return channel.socket();
}
public String toString() {
return channel.toString();
}
public int validOps() {
return channel.validOps();
}
public int write(ByteBuffer src) throws IOException, NotYetConnectedException {
return channel.write(src);
}
public long write(ByteBuffer[] src) throws IOException, NotYetConnectedException {
return channel.write(src);
}
public boolean finishConnect() throws IOException {
return this.channel.finishConnect();
}
public boolean isConnectionPending() {
return this.channel.isConnectionPending();
}
/**
* does the handshake if needed
* @param key
* @return true, if handshake is completed
* @throws IOException
*/
public boolean doHandshake(SelectionKey key) throws IOException {
return true;
}
/**
* prepares the channel for closing
* this can take more than 1 call
* @param key
* @return true, if channel is ready for closing
* @throws IOException
*/
public boolean shutdown(SelectionKey key) throws IOException {
return true;
}
/**
* is channel in closing-procedure?
* @return
*/
public boolean isShutdownInProgress() {
return false;
}
/**
* is there remaining data in channel-buffers, which must be flushed?
* @return
*/
public boolean isFlushed() {
return true;
}
public Certificate[] getCerts() {
return certs;
}
public Object getAttachment() {
return attachment;
}
public void setAttachment(Object attachment) {
this.attachment = attachment;
}
}

View File

@@ -0,0 +1,768 @@
/*
* Copyright (c) 2008-2011 by Christian Lorenz, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.channels;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.util.OutputUtils;
/**
* A secure abstraction of the SocketChannel (by using SSL)
*
* @author clorenz
*/
public class SSLChannelIO extends ChannelIO {
/**
* Number of Threads in the ThreadPool which will be used for the
* time-consuming tasks
*/
// public static int EXECUTOR_THREADS = 4;
/**
* used SSLEngine for this channel
*/
protected final SSLEngine sslEngine;
/**
* contains the read data encrypted by ssl
*/
protected ReusableBuffer inNetBuffer, inReadBuffer;
/**
* contains the written data encrypted by ssl
*/
protected ReusableBuffer outNetBuffer;
/**
* an empty buffer for e.g. handshaking and shutdown; it will never contain
* data
*/
protected ReusableBuffer dummyBuffer;
/**
* the last SSLEngine-status
*/
protected HandshakeStatus handshakeStatus;
protected boolean handshakeComplete;
protected int keyOpsBeforeHandshake = -1;
/**
* true, if shutdown was called at least one time
*/
protected boolean shutdownInProgress;
/**
* cipher suites without symmetric encryption, wich are supported by the
* SSLEngine in Java6
*/
protected static String[] supportedCipherSuitesWithoutEncryption = null;
/**
* SSL-Channel is used by client
*/
protected boolean clientMode;
/**
* for asynchronious execution of time-consuming tasks only one executor for
* ALL SSLChannelIOs
*/
// private static ExecutorService executor = null;
private boolean closed = false;
private boolean shutdownComplete = false;
/**
* creates a SSLChannelIO
*
* @param channel
* channel, which should be protected by SSL
* @param sslOptions
* the Options for the SSL-Connection
* @param clientMode
* true, if you are a client; false, if you are a server
* @throws SSLException
*/
public SSLChannelIO(SocketChannel channel, SSLOptions sslOptions, boolean clientMode) throws SSLException {
super(channel);
// initialize SSLEngine for a server
sslEngine = sslOptions.getSSLContext().createSSLEngine();
sslEngine.setUseClientMode(clientMode);
sslEngine.setNeedClientAuth(true);
List<String> enabledProtocols = new ArrayList<String>();
for (String protocol : sslEngine.getSupportedProtocols()) {
if (sslOptions.isSSLEngineProtocolSupported(protocol) && !enabledProtocols.contains(protocol)) {
enabledProtocols.add(protocol);
}
}
String[] enabledProtocolsArray = enabledProtocols.toArray(new String[enabledProtocols.size()]);
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "Enabling the following protocols: %s",
Arrays.toString(enabledProtocolsArray));
}
sslEngine.setEnabledProtocols(enabledProtocolsArray);
if (clientMode) {
// the first call for a client is wrap()
sslEngine.beginHandshake();
handshakeStatus = HandshakeStatus.NEED_WRAP;
} else {
// the first call for a server is unwrap()
sslEngine.beginHandshake();
handshakeStatus = HandshakeStatus.NEED_UNWRAP;
}
handshakeComplete = false;
shutdownInProgress = false;
int netBufSize = sslEngine.getSession().getPacketBufferSize();
inNetBuffer = BufferPool.allocate(netBufSize);
inReadBuffer = BufferPool.allocate(sslEngine.getSession().getApplicationBufferSize() * 2);
outNetBuffer = BufferPool.allocate(netBufSize);
dummyBuffer = BufferPool.allocate(netBufSize);
if (sslOptions.isAuthenticationWithoutEncryption()) { // only
// authentication
// without
// protecting
// data?
// enable only cipher suites without encryption
if (supportedCipherSuitesWithoutEncryption == null) { // runs only
// first time
// a
// SSLChannelIO
// without Encryption is created
// find all supported cipher suites without symmetric encryption
ArrayList<String> cipherSuites = new ArrayList<String>();
for (String cipherSuite : sslEngine.getSupportedCipherSuites()) {
if (cipherSuite.contains("WITH_NULL")) {
cipherSuites.add(cipherSuite);
}
}
supportedCipherSuitesWithoutEncryption = new String[cipherSuites.size()];
supportedCipherSuitesWithoutEncryption = cipherSuites
.toArray(supportedCipherSuitesWithoutEncryption);
}
sslEngine.setEnabledCipherSuites(supportedCipherSuitesWithoutEncryption);
} else // enable all supported cipher suites
{
sslEngine.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());
}
// only initialize the first time an SSLChannelIO is created
/*
* if(executor==null) executor =
* Executors.newFixedThreadPool(EXECUTOR_THREADS);
*/
}
/**
* {@inheritDoc}
*/
@Override
public int read(ByteBuffer dst) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
if (inReadBuffer.remaining() == inReadBuffer.capacity()) {
if (channel.read(inNetBuffer.getBuffer()) == -1) {
return -1;
}
inNetBuffer.flip(); // ready for being read
inDataAvail: while (inNetBuffer.hasRemaining()) {
SSLEngineResult result = sslEngine.unwrap(inNetBuffer.getBuffer(), inReadBuffer
.getBuffer());
switch (result.getStatus()) {
case OK: {
// returnValue += result.bytesProduced();
// FIXME: if client does't close the connection
// after receiving close_notify =>
// decomment it
if (sslEngine.isInboundDone()) // received
// close_notify
{
close();
}
break;
}
case BUFFER_UNDERFLOW: {
// needed more data in inNetBuffer, maybe nexttime
// inNetBuffer.compact();
break inDataAvail;
// return returnValue;
}
case BUFFER_OVERFLOW: {
// needed more space in dst
throw new IOException(
"BufferOverflow in the SSLEngine: Destination-Buffer is too small.");
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in an undefined state.");
}
}
}
inNetBuffer.compact(); // ready for reading from channel
}
inReadBuffer.flip();
if (dst.remaining() >= inReadBuffer.remaining()) {
returnValue += inReadBuffer.remaining();
dst.put(inReadBuffer.getBuffer());
} else {
while (inReadBuffer.hasRemaining() && dst.hasRemaining()) {
dst.put(inReadBuffer.get());
returnValue++;
}
}
inReadBuffer.compact();
}
}
return returnValue;
}
/**
* {@inheritDoc} warning: maybe more bytes would be consumed from src-buffer
* than will be written to channel (returned value)
*/
@Override
public int write(ByteBuffer src) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
switch (result.getStatus()) {
case OK: {
tryFlush();
break;
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
returnValue = result.bytesConsumed();
}
}
return returnValue;
}
/**
* {@inheritDoc}
*/
/**
* {@inheritDoc} warning: maybe more bytes would be consumed from src-buffer
* than will be written to channel (returned value)
*/
@Override
public long write(ByteBuffer[] src) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
switch (result.getStatus()) {
case OK: {
tryFlush();
break;
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
returnValue = result.bytesConsumed();
}
}
return returnValue;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isShutdownInProgress() {
return this.shutdownInProgress;
}
/**
* {@inheritDoc}
*/
@Override
public boolean shutdown(SelectionKey key) throws IOException, CancelledKeyException {
if (!handshakeComplete) { // no SSL connection is established => simple
// close
shutdownInProgress = true;
return true;
}
if (shutdownComplete) {
return shutdownComplete;
}
if (!shutdownInProgress) { // initiate shutdown
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"shutdown SSL connection of %s:%d", channel.socket().getInetAddress().toString(), channel
.socket().getPort());
sslEngine.closeOutbound();
shutdownInProgress = true;
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); // don't
// wait
// for
// the
// close_notify-reply
}
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush() && sslEngine.isOutboundDone()) { // shutdown complete
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
shutdownComplete = true;
}
if (!sslEngine.isOutboundDone()) {
// Get close message
SSLEngineResult result = sslEngine.wrap(dummyBuffer.getBuffer(), outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
switch (result.getStatus()) {
case OK: {
throw new IOException("This should not happen.");
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
if (tryFlush() && sslEngine.isOutboundDone()) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
shutdownComplete = true;
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
}
return shutdownComplete;
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
try {
super.close();
try {
sslEngine.closeInbound();
sslEngine.closeOutbound();
} catch (SSLException e) {
// ignore it
}
// free buffers
BufferPool.free(inNetBuffer);
inNetBuffer = null;
BufferPool.free(inReadBuffer);
inReadBuffer = null;
BufferPool.free(outNetBuffer);
BufferPool.free(dummyBuffer);
shutdownInProgress = true;
closed = true;
} catch (Throwable th) {
System.out.println("CANNOT CLOSE DUE TO: " + th);
throw new IOException(th);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void finalize() {
if (inNetBuffer != null) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.misc, this, "buffers not freed!");
BufferPool.free(inNetBuffer);
inNetBuffer = null;
BufferPool.free(outNetBuffer);
BufferPool.free(dummyBuffer);
}
if (!closed) {
System.out.println("CONNECTION WAS NOT CLOSED PROPERLY: " + this);
}
}
/**
* Writes the outNetBuffer-data to the channel. After write, the buffer is
* empty or ready for add new data
*
* @return true, if write was successful; false, if buffer is not empty
* @throws IOException
*/
protected boolean tryFlush() throws IOException {
// if (outNetBuffer.hasRemaining()) { // flush the buffer
channel.write(outNetBuffer.getBuffer());
if (outNetBuffer.hasRemaining()) {
outNetBuffer.compact();
return false;
} else {
outNetBuffer.compact();
}
// }
return true;
}
/**
* {@inheritDoc} warning: the function manipulates the SelectionKey Ops, so
* don't do anything in your programm beetween first call of this function
* until the function returns true
*/
@Override
public boolean doHandshake(SelectionKey key) throws IOException, CancelledKeyException {
if (handshakeComplete || shutdownInProgress) { // quick return
return handshakeComplete;
}
if (keyOpsBeforeHandshake == -1) {
keyOpsBeforeHandshake = key.interestOps();
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ & ~SelectionKey.OP_WRITE);
}
if (!handshakeComplete) {
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake next step: "+handshakeStatus);
SSLEngineResult result;
switch (handshakeStatus) {
case NEED_UNWRAP: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
if (channel.read(inNetBuffer.getBuffer()) == -1) {
throw new IOException("End of stream has reached.");
}
boolean underflow = false;
do { // read all read data in buffer
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: unwrap");
inNetBuffer.flip(); // ready for being read
result = sslEngine.unwrap(inNetBuffer.getBuffer(), dummyBuffer.getBuffer());
inNetBuffer.compact(); // ready for reading from channel
handshakeStatus = result.getHandshakeStatus();
switch (result.getStatus()) {
case OK: {
analyseHandshakeStatus(key, handshakeStatus);
break;
}
case BUFFER_UNDERFLOW: {
// needed more data in inNetBuffer, maybe nexttime
underflow = true;
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
} while (bufferRemaining(inNetBuffer) != 0 && handshakeStatus == HandshakeStatus.NEED_UNWRAP
&& !underflow);
break;
}
case NEED_WRAP: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: wrap");
result = sslEngine.wrap(dummyBuffer.getBuffer(), outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
handshakeStatus = result.getHandshakeStatus();
switch (result.getStatus()) {
case OK: {
tryFlush();
analyseHandshakeStatus(key, handshakeStatus);
break;
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
break;
}
case FINISHED: {
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush()) {
handshakeFinished(key);
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
case NEED_TASK: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
doTasks(key);
break;
}
case NOT_HANDSHAKING: {
// TODO: Exception or maybe handshakeComplete = true?
throw new IOException("The SSLEngine is not handshaking.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
}
return handshakeComplete;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isFlushed() {
return bufferRemaining(outNetBuffer) == 0;
}
/**
* finishing operations for handshake
*
* @param key
*/
private void handshakeFinished(SelectionKey key) throws CancelledKeyException {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "SSL-handshake for %s:%d finished",
channel.socket().getInetAddress().toString(), channel.socket().getPort());
// all handshake-data processed and sent
handshakeComplete = true;
inNetBuffer.clear();
outNetBuffer.clear();
key.interestOps(keyOpsBeforeHandshake);
try {
this.certs = sslEngine.getSession().getPeerCertificates();
} catch (SSLPeerUnverifiedException ex) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this, OutputUtils.stackTraceToString(ex));
this.certs = null;
}
}
/**
*
* @param key
* @param handshakeStatus
* @throws IOException
*/
private void analyseHandshakeStatus(SelectionKey key, HandshakeStatus handshakeStatus) throws IOException, CancelledKeyException {
switch (handshakeStatus) {
case NEED_UNWRAP: {
key.interestOps(key.interestOps() | SelectionKey.OP_READ & ~SelectionKey.OP_WRITE);
break;
}
case NEED_WRAP: {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
case NEED_TASK: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
doTasks(key);
break;
}
case FINISHED: {
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush()) {
handshakeFinished(key);
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
case NOT_HANDSHAKING: {
// TODO: Exception or maybe handshakeComplete = true?
throw new IOException("The SSLEngine is not handshaking.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
}
/**
* checks the remaining data of the buffer (only for internal buffers)
*
* @param buffer
* @return
*/
private int bufferRemaining(ReusableBuffer buffer) {
buffer.flip(); // ready for being read
int tmp = buffer.remaining();
buffer.compact(); // ready for being read
return tmp;
}
/**
* runs the time-consuming tasks
*
* @param key
* @throws IOException
*/
protected void doTasks(final SelectionKey key) throws CancelledKeyException {
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: doing task");
final int tmp = key.interestOps();
// clear all interests, so no one other than this thread can modify the
// selector
key.interestOps(0);
/*
* executor.execute(new Runnable(){ public void run() {
*/
// TODO: running in a different thread
Runnable run;
while ((run = sslEngine.getDelegatedTask()) != null) {
run.run();
}
switch (handshakeStatus = sslEngine.getHandshakeStatus()) {
case NEED_WRAP: {
key.interestOps(tmp | SelectionKey.OP_WRITE);
break;
}
case NEED_UNWRAP: {
// need to read from channel
key.interestOps(tmp | SelectionKey.OP_READ);
break;
}
case FINISHED: {
// should not happen
handshakeFinished(key);
break;
}
case NEED_TASK: {
// should not happen
doTasks(key);
break;
}
case NOT_HANDSHAKING: {
// should not happen
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this,
"Exception in worker-thread: The SSLEngine is not handshaking.");
break;
}
default: {
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this,
"Exception in worker-thread: The SSLEngine is in a curiuos handshake-state.");
assert (false);
// throw new
// IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
/*
* key.selector().wakeup(); } });
*/
}
}

View File

@@ -0,0 +1,647 @@
/*
* Copyright (c) 2008-2011 by Christian Lorenz, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.channels;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.util.OutputUtils;
/**
* A secure abstraction of the SocketChannel (by using SSL)
*
* @author clorenz
*/
public class SSLHandshakeOnlyChannelIO extends ChannelIO {
/**
* Number of Threads in the ThreadPool which will be used for the
* time-consuming tasks
*/
// public static int EXECUTOR_THREADS = 4;
/**
* used SSLEngine for this channel
*/
protected final SSLEngine sslEngine;
/**
* contains the read data encrypted by ssl
*/
protected ReusableBuffer inNetBuffer, inReadBuffer;
/**
* contains the written data encrypted by ssl
*/
protected ReusableBuffer outNetBuffer;
/**
* an empty buffer for e.g. handshaking and shutdown; it will never contain
* data
*/
protected ReusableBuffer dummyBuffer;
/**
* the last SSLEngine-status
*/
protected HandshakeStatus handshakeStatus;
protected boolean handshakeComplete;
protected int keyOpsBeforeHandshake = -1;
/**
* true, if shutdown was called at least one time
*/
protected boolean shutdownInProgress;
/**
* cipher suites without symmetric encryption, wich are supported by the
* SSLEngine in Java6
*/
protected static String[] supportedCipherSuitesWithoutEncryption = null;
/**
* SSL-Channel is used by client
*/
protected boolean clientMode;
/**
* for asynchronious execution of time-consuming tasks only one executor for
* ALL SSLChannelIOs
*/
// private static ExecutorService executor = null;
private boolean closed = false;
private boolean shutdownComplete = false;
/**
* creates a SSLChannelIO
*
* @param channel
* channel, which should be protected by SSL
* @param sslOptions
* the Options for the SSL-Connection
* @param clientMode
* true, if you are a client; false, if you are a server
* @throws SSLException
*/
public SSLHandshakeOnlyChannelIO(SocketChannel channel, SSLOptions sslOptions, boolean clientMode) throws SSLException {
super(channel);
// initialize SSLEngine for a server
sslEngine = sslOptions.getSSLContext().createSSLEngine();
sslEngine.setUseClientMode(clientMode);
sslEngine.setNeedClientAuth(true);
if (clientMode) {
// the first call for a client is wrap()
sslEngine.beginHandshake();
handshakeStatus = HandshakeStatus.NEED_WRAP;
} else {
// the first call for a server is unwrap()
sslEngine.beginHandshake();
handshakeStatus = HandshakeStatus.NEED_UNWRAP;
}
handshakeComplete = false;
shutdownInProgress = false;
int netBufSize = sslEngine.getSession().getPacketBufferSize();
inNetBuffer = BufferPool.allocate(netBufSize);
inReadBuffer = BufferPool.allocate(sslEngine.getSession().getApplicationBufferSize() * 2);
outNetBuffer = BufferPool.allocate(netBufSize);
dummyBuffer = BufferPool.allocate(netBufSize);
sslEngine.setEnabledProtocols(sslEngine.getSupportedProtocols());
if (sslOptions.isAuthenticationWithoutEncryption()) { // only
// authentication
// without
// protecting
// data?
// enable only cipher suites without encryption
if (supportedCipherSuitesWithoutEncryption == null) { // runs only
// first time
// a
// SSLChannelIO
// without Encryption is created
// find all supported cipher suites without symmetric encryption
ArrayList<String> cipherSuites = new ArrayList<String>();
for (String cipherSuite : sslEngine.getSupportedCipherSuites()) {
if (cipherSuite.contains("WITH_NULL")) {
cipherSuites.add(cipherSuite);
}
}
supportedCipherSuitesWithoutEncryption = new String[cipherSuites.size()];
supportedCipherSuitesWithoutEncryption = cipherSuites
.toArray(supportedCipherSuitesWithoutEncryption);
}
sslEngine.setEnabledCipherSuites(supportedCipherSuitesWithoutEncryption);
} else // enable all supported cipher suites
{
sslEngine.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());
}
// only initialize the first time an SSLChannelIO is created
/*
* if(executor==null) executor =
* Executors.newFixedThreadPool(EXECUTOR_THREADS);
*/
}
/**
* {@inheritDoc}
*/
@Override
public int read(ByteBuffer dst) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
/*if (inNetBuffer.hasRemaining()) {
//read something which is still in the buffer after the handshake
while (dst.hasRemaining() && inNetBuffer.hasRemaining())
dst.put(inNetBuffer.get());
} else {*/
returnValue = channel.read(dst);
// }
}
}
return returnValue;
}
/**
* {@inheritDoc} warning: maybe more bytes would be consumed from src-buffer
* than will be written to channel (returned value)
*/
@Override
public int write(ByteBuffer src) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
return channel.write(src);
}
}
return returnValue;
}
/**
* {@inheritDoc}
*/
/**
* {@inheritDoc} warning: maybe more bytes would be consumed from src-buffer
* than will be written to channel (returned value)
*/
@Override
public long write(ByteBuffer[] src) throws IOException {
int returnValue = 0;
if (!shutdownInProgress) {
if (handshakeComplete) {
return channel.write(src);
}
}
return returnValue;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isShutdownInProgress() {
return this.shutdownInProgress;
}
/**
* {@inheritDoc}
*/
@Override
public boolean shutdown(SelectionKey key) throws IOException, CancelledKeyException {
if (!handshakeComplete) { // no SSL connection is established => simple
// close
shutdownInProgress = true;
return true;
}
if (shutdownComplete) {
return shutdownComplete;
}
if (!shutdownInProgress) { // initiate shutdown
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"shutdown SSL connection of %s:%d", channel.socket().getInetAddress().toString(), channel
.socket().getPort());
sslEngine.closeOutbound();
shutdownInProgress = true;
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); // don't
// wait
// for
// the
// close_notify-reply
}
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush() && sslEngine.isOutboundDone()) { // shutdown complete
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
shutdownComplete = true;
}
if (!sslEngine.isOutboundDone()) {
// Get close message
SSLEngineResult result = sslEngine.wrap(dummyBuffer.getBuffer(), outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
switch (result.getStatus()) {
case OK: {
throw new IOException("This should not happen.");
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
if (tryFlush() && sslEngine.isOutboundDone()) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
shutdownComplete = true;
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
}
return shutdownComplete;
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
try {
super.close();
try {
sslEngine.closeInbound();
sslEngine.closeOutbound();
} catch (SSLException e) {
// ignore it
}
// free buffers
BufferPool.free(inNetBuffer);
inNetBuffer = null;
BufferPool.free(inReadBuffer);
inReadBuffer = null;
BufferPool.free(outNetBuffer);
BufferPool.free(dummyBuffer);
shutdownInProgress = true;
closed = true;
} catch (Throwable th) {
System.out.println("CANNOT CLOSE DUE TO: " + th);
throw new IOException(th);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void finalize() {
if (inNetBuffer != null) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.misc, this, "buffers not freed!");
BufferPool.free(inNetBuffer);
inNetBuffer = null;
BufferPool.free(outNetBuffer);
BufferPool.free(dummyBuffer);
}
if (!closed) {
System.out.println("CONNECTION WAS NOT CLOSED PROPERLY: " + this);
}
}
/**
* Writes the outNetBuffer-data to the channel. After write, the buffer is
* empty or ready for add new data
*
* @return true, if write was successful; false, if buffer is not empty
* @throws IOException
*/
protected boolean tryFlush() throws IOException {
// if (outNetBuffer.hasRemaining()) { // flush the buffer
channel.write(outNetBuffer.getBuffer());
if (outNetBuffer.hasRemaining()) {
outNetBuffer.compact();
return false;
} else {
outNetBuffer.compact();
}
// }
return true;
}
/**
* {@inheritDoc} warning: the function manipulates the SelectionKey Ops, so
* don't do anything in your programm beetween first call of this function
* until the function returns true
*/
@Override
public boolean doHandshake(SelectionKey key) throws IOException, CancelledKeyException {
if (handshakeComplete || shutdownInProgress) { // quick return
return handshakeComplete;
}
if (keyOpsBeforeHandshake == -1) {
keyOpsBeforeHandshake = key.interestOps();
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ & ~SelectionKey.OP_WRITE);
}
if (!handshakeComplete) {
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake next step: "+handshakeStatus);
SSLEngineResult result;
switch (handshakeStatus) {
case NEED_UNWRAP: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
if (channel.read(inNetBuffer.getBuffer()) == -1) {
throw new IOException("End of stream has reached.");
}
boolean underflow = false;
do { // read all read data in buffer
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: unwrap");
inNetBuffer.flip(); // ready for being read
result = sslEngine.unwrap(inNetBuffer.getBuffer(), dummyBuffer.getBuffer());
inNetBuffer.compact(); // ready for reading from channel
handshakeStatus = result.getHandshakeStatus();
switch (result.getStatus()) {
case OK: {
analyseHandshakeStatus(key, handshakeStatus);
break;
}
case BUFFER_UNDERFLOW: {
// needed more data in inNetBuffer, maybe nexttime
underflow = true;
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
} while (bufferRemaining(inNetBuffer) != 0 && handshakeStatus == HandshakeStatus.NEED_UNWRAP
&& !underflow);
break;
}
case NEED_WRAP: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: wrap");
result = sslEngine.wrap(dummyBuffer.getBuffer(), outNetBuffer.getBuffer());
outNetBuffer.flip(); // ready for writing to channel
handshakeStatus = result.getHandshakeStatus();
switch (result.getStatus()) {
case OK: {
tryFlush();
analyseHandshakeStatus(key, handshakeStatus);
break;
}
case BUFFER_OVERFLOW: {
// needed more space in outNetBuffer
// two reasons for overflow:
// 1. buffer is too small
// 2. buffer is nearly full
tryFlush();
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
/*
* throw new IOException(
* "BufferOverflow in SSLEngine. Buffer for SSLEngine-generated data is too small."
* );
*/
break;
}
case CLOSED: {
throw new IOException("The SSLEngine is already closed.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos state.");
}
}
break;
}
case FINISHED: {
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush()) {
handshakeFinished(key);
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
case NEED_TASK: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
doTasks(key);
break;
}
case NOT_HANDSHAKING: {
// TODO: Exception or maybe handshakeComplete = true?
throw new IOException("The SSLEngine is not handshaking.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
}
return handshakeComplete;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isFlushed() {
return bufferRemaining(outNetBuffer) == 0;
}
/**
* finishing operations for handshake
*
* @param key
*/
private void handshakeFinished(SelectionKey key) throws CancelledKeyException {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "SSL-handshake for %s:%d finished",
channel.socket().getInetAddress().toString(), channel.socket().getPort());
// all handshake-data processed and sent
handshakeComplete = true;
inNetBuffer.clear();
outNetBuffer.clear();
key.interestOps(keyOpsBeforeHandshake);
try {
this.certs = sslEngine.getSession().getPeerCertificates();
} catch (SSLPeerUnverifiedException ex) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this, OutputUtils.stackTraceToString(ex));
this.certs = null;
}
}
/**
*
* @param key
* @param handshakeStatus
* @throws IOException
*/
private void analyseHandshakeStatus(SelectionKey key, HandshakeStatus handshakeStatus) throws IOException, CancelledKeyException {
switch (handshakeStatus) {
case NEED_UNWRAP: {
key.interestOps(key.interestOps() | SelectionKey.OP_READ & ~SelectionKey.OP_WRITE);
break;
}
case NEED_WRAP: {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
case NEED_TASK: {
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
doTasks(key);
break;
}
case FINISHED: {
outNetBuffer.flip(); // ready for writing to channel
if (tryFlush()) {
handshakeFinished(key);
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
break;
}
case NOT_HANDSHAKING: {
// TODO: Exception or maybe handshakeComplete = true?
throw new IOException("The SSLEngine is not handshaking.");
}
default: {
throw new IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
}
/**
* checks the remaining data of the buffer (only for internal buffers)
*
* @param buffer
* @return
*/
private int bufferRemaining(ReusableBuffer buffer) {
buffer.flip(); // ready for being read
int tmp = buffer.remaining();
buffer.compact(); // ready for being read
return tmp;
}
/**
* runs the time-consuming tasks
*
* @param key
* @throws IOException
*/
protected void doTasks(final SelectionKey key) throws CancelledKeyException {
// Logging.logMessage(Logging.LEVEL_DEBUG, this,
// "SSL-handshake doing: doing task");
final int tmp = key.interestOps();
// clear all interests, so no one other than this thread can modify the
// selector
key.interestOps(0);
/*
* executor.execute(new Runnable(){ public void run() {
*/
// TODO: running in a different thread
Runnable run;
while ((run = sslEngine.getDelegatedTask()) != null) {
run.run();
}
switch (handshakeStatus = sslEngine.getHandshakeStatus()) {
case NEED_WRAP: {
key.interestOps(tmp | SelectionKey.OP_WRITE);
break;
}
case NEED_UNWRAP: {
// need to read from channel
key.interestOps(tmp | SelectionKey.OP_READ);
break;
}
case FINISHED: {
// should not happen
handshakeFinished(key);
break;
}
case NEED_TASK: {
// should not happen
doTasks(key);
break;
}
case NOT_HANDSHAKING: {
// should not happen
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this,
"Exception in worker-thread: The SSLEngine is not handshaking.");
break;
}
default: {
Logging.logMessage(Logging.LEVEL_ERROR, Category.auth, this,
"Exception in worker-thread: The SSLEngine is in a curiuos handshake-state.");
assert (false);
// throw new
// IOException("The SSLEngine is in a curiuos handshake-state.");
}
}
/*
* key.selector().wakeup(); } });
*/
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import java.io.IOException;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader.ErrorResponse;
/**
*
* @author bjko
*/
public class PBRPCException extends IOException {
final ErrorResponse response;
final String message;
public PBRPCException(String ioError) {
super();
this.message = ioError;
response = null;
}
public PBRPCException(ErrorResponse response) {
super();
this.response = response;
this.message = null;
}
public RPC.ErrorType getErrorType() {
if (response != null)
return response.getErrorType();
else
return RPC.ErrorType.IO_ERROR;
}
public RPC.POSIXErrno getPOSIXErrno() {
if (response != null)
return response.getPosixErrno();
else
return RPC.POSIXErrno.POSIX_ERROR_NONE;
}
public String getErrorMessage() {
if (response != null)
return response.getErrorMessage();
else
return this.message;
}
public String getDebugInfo() {
if (response != null)
return response.getDebugInfo();
else
return "";
}
public String getRedirectToServerUUID() {
if (response != null)
return response.getRedirectToServerUuid();
else
return "";
}
public ErrorResponse getErrorResponse() {
return response;
}
@Override
public String getMessage() {
if (response != null) {
return response.getErrorType().toString()+"/"+response.getPosixErrno().toString()+": "+response.getErrorMessage()+" / "+response.getDebugInfo();
} else {
return this.message;
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.AuthType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
/**
*
* @author bjko
*/
public class RPCAuthentication {
public static final Auth authNone;
public static final UserCredentials userService;
static {
authNone = Auth.newBuilder().setAuthType(AuthType.AUTH_NONE).build();
userService = UserCredentials.newBuilder().setUsername("srv").addGroups("xtreemfs").build();
}
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.xtreemfs.foundation.TimeSync;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServerConnection.ReceiveState;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
/**
*
* @author bjko
*/
public class RPCClientConnection {
public static final int RETRY_RESET_IN_MS = 500;
/** max wait is one minute */
public static final int MAX_RETRY_WAIT_MS = 1000*60;
private ChannelIO channel;
private final Map<Integer,RPCClientRequest> requests;
private final List<RPCClientRequest> sendQueue;
private long lastUsed;
private long nextReconnectTime;
private int numConnectAttempts;
private final ByteBuffer requestRecordMarker;
private final ByteBuffer responseRecordMarker;
private ReusableBuffer[] responseBuffers;
private ByteBuffer[] requestBuffers;
private RPCClientRequest pendingRequest;
private ReceiveState receiveState;
private final InetSocketAddress endpoint;
volatile long bytesRX, bytesTX;
public RPCClientConnection(InetSocketAddress endpoint) {
requests = new HashMap<Integer, RPCClientRequest>();
lastUsed = TimeSync.getLocalSystemTime();
numConnectAttempts = 0;
nextReconnectTime = 0;
sendQueue = new LinkedList<RPCClientRequest>();
requestRecordMarker = ByteBuffer.allocateDirect(RecordMarker.HDR_SIZE);
responseRecordMarker = ByteBuffer.allocateDirect(RecordMarker.HDR_SIZE);
this.endpoint = endpoint;
receiveState = ReceiveState.RECORD_MARKER;
bytesTX = 0;
bytesRX = 0;
}
public void freeBuffers() {
if (responseBuffers != null) {
for (ReusableBuffer buf: responseBuffers)
BufferPool.free(buf);
}
for (RPCClientRequest rq : sendQueue) {
rq.freeBuffers();
}
for (RPCClientRequest rq : requests.values()) {
rq.freeBuffers();
}
}
boolean isConnected() {
return channel != null;
}
void connectFailed() {
numConnectAttempts++;
long waitt = Math.round(RETRY_RESET_IN_MS*Math.pow(2,this.numConnectAttempts));
if (waitt > MAX_RETRY_WAIT_MS) {
waitt = MAX_RETRY_WAIT_MS;
}
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"next reconnect possible after %d s, attempt = %d", (waitt / 1000), this.numConnectAttempts);
this.nextReconnectTime = System.currentTimeMillis()+waitt;
}
boolean canReconnect() {
return (this.nextReconnectTime < System.currentTimeMillis());
}
void setChannel(ChannelIO channel) {
this.channel = channel;
}
void connected() {
numConnectAttempts = 0;
lastUsed = TimeSync.getLocalSystemTime();
}
void useConnection() {
lastUsed = TimeSync.getLocalSystemTime();
}
long getLastUsed() {
return lastUsed;
}
ChannelIO getChannel() {
return channel;
}
RPCClientRequest getRequest(int callId) {
return requests.remove(callId);
}
void addRequest(int callId, RPCClientRequest rq) {
requests.put(callId,rq);
}
void removeRequest(int callId) {
requests.remove(callId);
}
Map<Integer,RPCClientRequest> getRequests() {
return this.requests;
}
List<RPCClientRequest> getSendQueue() {
return sendQueue;
}
/**
* @return the requestFragHdr
*/
ByteBuffer getRequestRecordMarker() {
return requestRecordMarker;
}
/**
* @return the responseFragHdr
*/
ByteBuffer getResponseRecordMarker() {
return responseRecordMarker;
}
public String getEndpointString() {
String endpointString = "unknown";
try {
endpointString = endpoint.toString();
} catch (Exception ex2) {
}
return endpointString;
}
/**
* @return the requestBuffers
*/
public ByteBuffer[] getRequestBuffers() {
return requestBuffers;
}
/**
* @param requestBuffers the requestBuffers to set
*/
public void setRequestBuffers(ByteBuffer[] requestBuffers) {
this.requestBuffers = requestBuffers;
}
public RPCClientRequest getPendingRequest() {
return pendingRequest;
}
public void setPendingRequest(RPCClientRequest pendingRequest) {
this.pendingRequest = pendingRequest;
}
/**
* @return the receiveState
*/
public ReceiveState getReceiveState() {
return receiveState;
}
/**
* @param receiveState the receiveState to set
*/
public void setReceiveState(ReceiveState receiveState) {
this.receiveState = receiveState;
}
/**
* @return the responseBuffers
*/
public ReusableBuffer[] getResponseBuffers() {
return responseBuffers;
}
/**
* @param responseBuffers the responseBuffers to set
*/
public void setResponseBuffers(ReusableBuffer[] responseBuffers) {
this.responseBuffers = responseBuffers;
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import com.google.protobuf.Message;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.xtreemfs.foundation.TimeSync;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferOutputStream;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
/**
*
* @author bjko
*/
public class RPCClientRequest<ReturnType extends Message> {
private final RPC.RPCHeader requestHeader;
private RPC.RPCHeader responseHeader;
final ReusableBuffer[] buffers;
final int hdrLen;
final int msgLen;
final int dataLen;
private final RPCResponse response;
private long timeQueued;
private long bytesWritten;
RPCClientRequest(Auth authHeader, UserCredentials uCreds, int callId, int interfaceId, int procId, Message message, ReusableBuffer data, RPCResponse<ReturnType> response) throws IOException {
if (uCreds == null) {
throw new IOException("No UserCredentials object given (null). Make sure it's set.");
}
if (authHeader == null) {
throw new IOException("No Auth object given (null). Make sure it's set.");
}
RPC.RPCHeader.RequestHeader rqHdr = RPC.RPCHeader.RequestHeader.newBuilder().setAuthData(authHeader).setUserCreds(uCreds).
setInterfaceId(interfaceId).setProcId(procId).build();
requestHeader = RPC.RPCHeader.newBuilder().setCallId(callId).setMessageType(RPC.MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
this.response = response;
ReusableBufferOutputStream os = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
requestHeader.writeTo(os);
hdrLen = os.length();
if (message != null) {
message.writeTo(os);
msgLen = os.length()-hdrLen;
} else {
msgLen = 0;
}
if (data != null) {
os.appendBuffer(data);
dataLen = data.limit();
} else {
dataLen = 0;
}
assert(hdrLen > 0);
assert(msgLen >= 0);
assert(dataLen >= 0);
os.flip();
buffers = os.getBuffers();
}
public ReusableBuffer[] getBuffers() {
return buffers;
}
public ByteBuffer[] packBuffers(ByteBuffer recordMarker) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "sending record marker: %d/%d/%d", hdrLen,msgLen,dataLen);
}
recordMarker.putInt(hdrLen);
recordMarker.putInt(msgLen);
recordMarker.putInt(dataLen);
recordMarker.flip();
ByteBuffer[] arr = new ByteBuffer[buffers.length+1];
arr[0] = recordMarker;
for (int i = 0; i < buffers.length; i++) {
arr[i+1] = buffers[i].getBuffer();
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, this, "send buffer #%d: %s", i+1,buffers[i]);
}
}
return arr;
}
public void freeBuffers() {
for (int i = 0; i < buffers.length; i++) {
BufferPool.free(buffers[i]);
buffers[i] = null;
}
}
/**
* duration of request from sending the request until the response
* was received completeley.
* @return duration in ns
*/
public long getDuration() {
if (RPCNIOSocketClient.ENABLE_STATISTICS) {
return 0;
} else {
return 0l;
}
}
/**
* @return the requestHeader
*/
public RPC.RPCHeader getRequestHeader() {
return requestHeader;
}
void queued() {
this.timeQueued = TimeSync.getLocalSystemTime();
}
long getTimeQueued() {
return this.timeQueued;
}
/**
* @return the responseHeader
*/
public RPC.RPCHeader getResponseHeader() {
return responseHeader;
}
/**
* @param responseHeader the responseHeader to set
*/
public void setResponseHeader(RPC.RPCHeader responseHeader) {
this.responseHeader = responseHeader;
}
public RPCResponse<ReturnType> getResponse() {
return response;
}
public void recordBytesWritten(long bytesWritten) {
this.bytesWritten += bytesWritten;
if (this.bytesWritten > RecordMarker.HDR_SIZE + hdrLen + dataLen + msgLen) {
String errorMessage = "Too many bytes written (expected: "
+ (RecordMarker.HDR_SIZE + hdrLen + dataLen + msgLen)
+ ", actual: "
+ this.bytesWritten
+ ") for message "
+ requestHeader;
Logging.logMessage(Logging.LEVEL_ERROR, this, errorMessage);
throw new IllegalStateException(errorMessage);
}
}
public void checkEnoughBytesSent() {
if (bytesWritten != RecordMarker.HDR_SIZE + hdrLen + dataLen + msgLen) {
String errorMessage = "Not enough bytes written (expected: "
+ (RecordMarker.HDR_SIZE + hdrLen + dataLen + msgLen)
+ ", actual: "
+ bytesWritten
+ ") for message "
+ requestHeader;
Logging.logMessage(Logging.LEVEL_ERROR, this, errorMessage);
throw new IllegalStateException(errorMessage);
}
}
}

View File

@@ -0,0 +1,806 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
* Copyright (c) 2013 by Bjoern Kolbeck.
* Copyright (c) 2014 by Quobyte Inc.
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.xtreemfs.foundation.LifeCycleThread;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
import org.xtreemfs.foundation.pbrpc.channels.SSLChannelIO;
import org.xtreemfs.foundation.pbrpc.channels.SSLHandshakeOnlyChannelIO;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServer;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServerConnection;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.util.OutputUtils;
import com.google.protobuf.Message;
/**
*
* @author bjko
*/
public class RPCNIOSocketClient extends LifeCycleThread {
public static boolean ENABLE_STATISTICS = false;
/**
* Maximum tries to reconnect to the server
*/
public static final int MAX_RECONNECT = 4;
/**
* milliseconds between two timeout checks
*/
public static final int TIMEOUT_GRANULARITY = 250;
private final Map<InetSocketAddress, RPCClientConnection> connections;
private final int requestTimeout;
private final int connectionTimeout;
private long lastCheck;
private final Selector selector;
private volatile boolean quit;
private final SSLOptions sslOptions;
private final AtomicInteger transactionId;
private final ConcurrentLinkedQueue<RPCClientConnection> toBeEstablished;
private final int sendBufferSize;
private final int receiveBufferSize;
private final SocketAddress localBindPoint;
/**
* on some platforms (e.g. FreeBSD 7.2 with openjdk6) Selector.select(int timeout)
* returns immediately. If this problem is detected, the thread waits 25ms after each
* invocation to avoid excessive CPU consumption. See also issue #75
*/
private boolean brokenSelect;
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout)
throws IOException {
this(sslOptions, requestTimeout, connectionTimeout, -1, -1, null, "", false);
}
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout, String threadName)
throws IOException {
this(sslOptions, requestTimeout, connectionTimeout, -1, -1, null, threadName, false);
}
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout,
int sendBufferSize, int receiveBufferSize, SocketAddress localBindPoint) throws IOException {
this(sslOptions, requestTimeout, connectionTimeout, sendBufferSize, receiveBufferSize, localBindPoint, "", false);
}
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout, String threadName, boolean startAsDaemon) throws IOException {
this(sslOptions, requestTimeout, connectionTimeout, -1, -1, null, threadName, startAsDaemon);
}
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout,
int sendBufferSize, int receiveBufferSize, SocketAddress localBindPoint, String threadName) throws IOException {
this(sslOptions, requestTimeout, connectionTimeout, sendBufferSize, receiveBufferSize, localBindPoint, threadName, false);
}
public RPCNIOSocketClient(SSLOptions sslOptions, int requestTimeout, int connectionTimeout,
int sendBufferSize, int receiveBufferSize, SocketAddress localBindPoint, String threadName, boolean startAsDaemon) throws IOException {
super(threadName);
setDaemon(startAsDaemon);
if (requestTimeout >= connectionTimeout - TIMEOUT_GRANULARITY * 2) {
throw new IllegalArgumentException(
"request timeout must be smaller than connection timeout less " + TIMEOUT_GRANULARITY * 2
+ "ms");
}
this.requestTimeout = requestTimeout;
this.connectionTimeout = connectionTimeout;
this.sendBufferSize = sendBufferSize;
this.receiveBufferSize = receiveBufferSize;
this.localBindPoint = localBindPoint;
connections = new HashMap<InetSocketAddress, RPCClientConnection>();
selector = Selector.open();
this.sslOptions = sslOptions;
quit = false;
transactionId = new AtomicInteger((int) (Math.random() * 1e6 + 1.0));
toBeEstablished = new ConcurrentLinkedQueue<RPCClientConnection>();
if (this.localBindPoint != null && Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"RPC Client '%s': Using the following address for outgoing connections: %s", threadName, this.localBindPoint);
}
}
public void sendRequest(InetSocketAddress server, Auth auth, UserCredentials uCred, int interface_id, int proc_id, Message message, ReusableBuffer data,
RPCResponse response, boolean highPriority) {
try {
RPCClientRequest rq = new RPCClientRequest(auth, uCred, transactionId.incrementAndGet(), interface_id, proc_id, message, data, response);
internalSendRequest(server, rq, highPriority);
} catch (Throwable e) { // CancelledKeyException, RuntimeException (caused by missing TimeSyncThread)
//e.printStackTrace();
response.requestFailed(e.toString());
}
}
private void internalSendRequest(InetSocketAddress server, RPCClientRequest request, boolean highPriority) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "sending request %s no %d", request
.toString(), transactionId.get());
}
// get connection
RPCClientConnection con = null;
synchronized (connections) {
con = connections.get(server);
if (con == null) {
con = new RPCClientConnection(server);
connections.put(server, con);
}
}
synchronized (con) {
boolean isEmpty = con.getSendQueue().isEmpty();
request.queued();
con.useConnection();
if (highPriority)
con.getSendQueue().add(0, request);
else
con.getSendQueue().add(request);
if (!con.isConnected()) {
establishConnection(server, con);
} else {
if (isEmpty) {
final SelectionKey key = con.getChannel().keyFor(selector);
if (key != null) {
try {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
} catch (CancelledKeyException e) {
// Ignore it since the timeout mechanism will deal with it.
}
}
selector.wakeup();
}
}
}
}
@Override
public void run() {
brokenSelect = false;
// Doesn't work properly, should be a replaced with a better way to detect
// a broken selector on FreeBSD.
/*try {
long now = System.currentTimeMillis();
int numKeys = selector.select(100);
long duration = System.currentTimeMillis()-now;
if ((duration < 10) && (numKeys == 0)) {
Logging.logMessage(Logging.LEVEL_WARN, this,"detected broken select(int timeout)!");
brokenSelect = true;
}
} catch (Throwable th) {
Logging.logMessage(Logging.LEVEL_DEBUG, this,"could not check Selector for broken select(int timeout): "+th);
}*/
notifyStarted();
lastCheck = System.currentTimeMillis();
try {
while (!quit) {
if (!toBeEstablished.isEmpty()) {
while (true) {
RPCClientConnection con = toBeEstablished.poll();
if (con == null) {
break;
}
try {
con.getChannel().register(selector,
SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE | SelectionKey.OP_READ, con);
} catch (ClosedChannelException ex) {
closeConnection(con.getChannel().keyFor(selector), ex.toString());
}
}
toBeEstablished.clear();
}
int numKeys = 0;
try {
numKeys = selector.select(TIMEOUT_GRANULARITY);
} catch (CancelledKeyException ex) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this, "Exception while selecting: %s",
ex.toString());
continue;
} catch (IOException ex) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this, "Exception while selecting: %s",
ex.toString());
continue;
}
if (numKeys > 0) {
// fetch events
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
// process all events
while (iter.hasNext()) {
try {
SelectionKey key = iter.next();
// remove key from the list
iter.remove();
if (key.isConnectable()) {
connectConnection(key);
}
if (key.isReadable()) {
readConnection(key);
}
if (key.isWritable()) {
writeConnection(key);
}
} catch (CancelledKeyException ex) {
continue;
}
}
}
if (numKeys == 0 && brokenSelect) {
try {
sleep(25);
} catch (InterruptedException ex) {
break;
}
}
try {
checkForTimers();
} catch (ConcurrentModificationException ce) {
Logging.logMessage(Logging.LEVEL_CRIT, this,
OutputUtils.getThreadDump());
}
}
} catch (Throwable thr) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.net, this, "PBRPC Client CRASHED!");
notifyCrashed(thr);
}
synchronized (connections) {
for (RPCClientConnection con : connections.values()) {
synchronized (con) {
for (RPCClientRequest rq : con.getSendQueue()) {
rq.getResponse().requestFailed("RPC cancelled due to client shutdown");
rq.freeBuffers();
}
for (RPCClientRequest rq : con.getRequests().values()) {
rq.getResponse().requestFailed("RPC cancelled due to client shutdown");
rq.freeBuffers();
}
try {
if (con.getChannel() != null)
con.getChannel().close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
notifyStopped();
}
private void establishConnection(InetSocketAddress server, RPCClientConnection con) {
if (con.canReconnect()) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "connect to %s", server
.toString());
}
ChannelIO channel;
try {
if (sslOptions == null) { // no SSL
channel = new ChannelIO(SocketChannel.open());
} else {
if (sslOptions.isFakeSSLMode()) {
channel = new SSLHandshakeOnlyChannelIO(SocketChannel.open(), sslOptions, true);
} else {
channel = new SSLChannelIO(SocketChannel.open(), sslOptions, true);
}
}
channel.configureBlocking(false);
channel.socket().setTcpNoDelay(true);
if (localBindPoint != null) {
channel.socket().bind(localBindPoint);
}
if (sendBufferSize != -1) {
channel.socket().setSendBufferSize(sendBufferSize);
if (channel.socket().getSendBufferSize() != sendBufferSize) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"could not set socket send buffer size to " + sendBufferSize
+ ", using default size of " + channel.socket().getSendBufferSize());
}
}
if (receiveBufferSize != -1) {
channel.socket().setReceiveBufferSize(receiveBufferSize);
if (channel.socket().getReceiveBufferSize() != receiveBufferSize) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"could not set socket receive buffer size to " + receiveBufferSize
+ ", using default size of " + channel.socket().getReceiveBufferSize());
}
} else {
channel.socket().setReceiveBufferSize(256 * 1024);
}
channel.connect(server);
con.setChannel(channel);
toBeEstablished.add(con);
selector.wakeup();
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "connection created");
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "socket send buffer size: %d",
channel.socket().getSendBufferSize());
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "socket receive buffer size: %d",
channel.socket().getReceiveBufferSize());
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "local bind point: %s", channel
.socket().getLocalAddress());
}
} catch (Exception ex) {
if (ex.getClass() == java.net.SocketException.class && ex.getMessage().equals("Invalid argument")) {
Logging.logMessage(
Logging.LEVEL_ERROR,
Category.net,
this,
"FAILED TO USE THE FOLLOWING ADDRESS FOR OUTGOING REQUESTS: %s. Make sure that the hostname is correctly spelled in the configuration and it resolves to the correct IP.",
localBindPoint);
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "cannot contact server %s",
con.getEndpointString());
}
con.connectFailed();
for (RPCClientRequest rq : con.getSendQueue()) {
rq.getResponse().requestFailed("sending RPC failed: server '"+con.getEndpointString()+"' not reachable ("+ex+")");
rq.freeBuffers();
}
con.getSendQueue().clear();
}
} else {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"reconnect to server still blocked locally to avoid flooding (server: %s)", con.getEndpointString());
}
synchronized (con) {
for (RPCClientRequest rq : con.getSendQueue()) {
rq.getResponse().requestFailed("sending RPC failed: reconnecting to the server '"+con.getEndpointString()+"' was blocked locally to avoid flooding");
rq.freeBuffers();
}
con.getSendQueue().clear();
}
}
}
private void readConnection(SelectionKey key) {
final RPCClientConnection con = (RPCClientConnection) key.attachment();
final ChannelIO channel = con.getChannel();
try {
if (!channel.isShutdownInProgress()) {
if (channel.doHandshake(key)) {
while (true) {
ByteBuffer buf = null;
switch (con.getReceiveState()) {
case RECORD_MARKER: {
buf = con.getResponseRecordMarker(); break;
}
case RPC_MESSAGE: {
buf = con.getResponseBuffers()[1].getBuffer(); break;
}
case RPC_HEADER: {
buf = con.getResponseBuffers()[0].getBuffer(); break;
}
case DATA: {
buf = con.getResponseBuffers()[2].getBuffer(); break;
}
}
// read fragment header
final int numBytesRead = RPCNIOSocketServer.readData(key, channel, buf);
if (numBytesRead == -1) {
// connection closed
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"client closed connection (EOF): %s", channel.socket()
.getRemoteSocketAddress().toString());
}
closeConnection(key,"server ("+channel.socket()
.getRemoteSocketAddress().toString()+") closed connection");
return;
}
if (buf.hasRemaining()) {
// not enough data...
break;
}
switch (con.getReceiveState()) {
case RECORD_MARKER: {
buf.position(0);
final int hdrLen = buf.getInt();
final int msgLen = buf.getInt();
final int dataLen = buf.getInt();
if ((hdrLen <= 0) || (hdrLen >= RPCNIOSocketServer.MAX_FRAGMENT_SIZE)
|| (msgLen < 0) || (msgLen >= RPCNIOSocketServer.MAX_FRAGMENT_SIZE)
|| (dataLen < 0) || (dataLen >= RPCNIOSocketServer.MAX_FRAGMENT_SIZE)) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.net, this,
"invalid record marker size (%d/%d/%d) received, closing connection to client %s",
hdrLen,msgLen,dataLen,channel.socket()
.getRemoteSocketAddress().toString());
closeConnection(key,"received invalid record marker from server ("+channel.socket()
.getRemoteSocketAddress().toString()+"), closed connection");
return;
}
final ReusableBuffer[] buffers = new ReusableBuffer[]{BufferPool.allocate(hdrLen),
((msgLen > 0) ? BufferPool.allocate(msgLen) : null),
((dataLen > 0) ? BufferPool.allocate(dataLen) : null) };
con.setResponseBuffers(buffers);
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RPC_HEADER);
continue;
}
case RPC_HEADER: {
if (con.getResponseBuffers()[1] != null) {
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RPC_MESSAGE);
continue;
} else if (con.getResponseBuffers()[2] != null) {
// this is necessary, because we may receive some default
// instance of a message (empty) with data attached BUG #188
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.DATA);
continue;
} else {
break;
}
}
case RPC_MESSAGE: {
if (con.getResponseBuffers()[2] != null) {
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.DATA);
continue;
} else {
break;
}
}
}
//assemble ServerRequest
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RECORD_MARKER);
con.getResponseRecordMarker().clear();
//assemble response...
assembleResponse(key, con);
}
}
}
} catch (IOException ex) {
// simply close the connection
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(ex));
}
closeConnection(key, "server closed connection ("+ex+")");
} catch (NotYetConnectedException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(e));
}
closeConnection(key, "server closed connection: "+e);
}
}
private void assembleResponse(SelectionKey key, RPCClientConnection con) throws IOException {
try {
ReusableBuffer[] receiveBuffers = con.getResponseBuffers();
receiveBuffers[0].flip();
if (receiveBuffers[1] != null)
receiveBuffers[1].flip();
if (receiveBuffers[2] != null)
receiveBuffers[2].flip();
ReusableBufferInputStream rbis = new ReusableBufferInputStream(receiveBuffers[0]);
final RPC.RPCHeader header = RPC.RPCHeader.parseFrom(rbis);
BufferPool.free(receiveBuffers[0]);
RPCClientRequest rq = con.getRequest(header.getCallId());
if (rq == null) {
// Might happen when a request timed out before a response was
// sent.
BufferPool.free(receiveBuffers[1]);
BufferPool.free(receiveBuffers[2]);
con.setResponseBuffers(null);
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"received response for unknown request callId=%d",
header.getCallId());
return;
}
RPCResponse response = rq.getResponse();
rq.setResponseHeader(header);
con.setResponseBuffers(null);
response.responseAvailable(rq, receiveBuffers[1], receiveBuffers[2]);
} catch (IOException ex) {
closeConnection(key,"invalid response received: "+ex);
}
}
private void writeConnection(SelectionKey key) {
final RPCClientConnection con = (RPCClientConnection) key.attachment();
final ChannelIO channel = con.getChannel();
try {
if (!channel.isShutdownInProgress()) {
if (channel.doHandshake(key)) {
while (true) {
ByteBuffer[] buffers = con.getRequestBuffers();
RPCClientRequest send = con.getPendingRequest();
if (buffers == null) {
assert(send == null);
synchronized (con) {
if (con.getSendQueue().isEmpty()) {
// no more responses, stop writing...
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
break;
}
send = con.getSendQueue().remove(0);
}
assert(send != null);
con.getRequestRecordMarker().clear();
buffers = send.packBuffers(con.getRequestRecordMarker());
con.setRequestBuffers(buffers);
con.setPendingRequest(send);
}
assert(buffers != null);
final long numBytesWritten = channel.write(buffers);
if (numBytesWritten == -1) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (EOF): %s", channel.socket()
.getRemoteSocketAddress().toString());
}
// connection closed
closeConnection(key, "server unexpectedly closed connection (EOF)");
return;
}
// Detect if the client writes outside of the fragment.
send.recordBytesWritten(numBytesWritten);
if (buffers[buffers.length-1].hasRemaining()) {
// not enough data...
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
//remove from queue
synchronized (con) {
con.addRequest(send.getRequestHeader().getCallId(), send);
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"sent request %d to %s", send.getRequestHeader().getCallId(), con.getEndpointString());
}
}
send.checkEnoughBytesSent();
con.setRequestBuffers(null);
con.setPendingRequest(null);
}
}
}
} catch (CancelledKeyException ex) {
// simply close the connection
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(ex));
}
closeConnection(key, "server closed connection: "+ex);
} catch (IOException ex) {
// simply close the connection
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(ex));
}
closeConnection(key, "server closed connection: "+ex);
} catch (NotYetConnectedException e) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(e));
}
closeConnection(key, "server closed connection: "+e);
}
}
private void connectConnection(SelectionKey key) {
final RPCClientConnection con = (RPCClientConnection) key.attachment();
final ChannelIO channel = con.getChannel();
try {
if (channel.isConnectionPending()) {
channel.finishConnect();
}
synchronized (con) {
if (!con.getSendQueue().isEmpty()) {
key.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ);
}
}
con.connected();
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "connected from %s to %s", con
.getChannel().socket().getLocalSocketAddress().toString(), con.getEndpointString());
}
} catch (CancelledKeyException ex) {
con.connectFailed();
closeConnection(key, "server '" + con.getEndpointString() + "' not reachable ("+ex+")");
} catch (IOException ex) {
con.connectFailed();
closeConnection(key, "server '" + con.getEndpointString() + "' not reachable ("+ex+")");
}
}
private void closeConnection(SelectionKey key, String errorMessage) {
final RPCClientConnection con = (RPCClientConnection) key.attachment();
final ChannelIO channel = con.getChannel();
List<RPCClientRequest> cancelRq = new LinkedList<RPCClientRequest>();
synchronized (con) {
// remove the connection from the selector and close socket
try {
key.cancel();
channel.close();
} catch (Exception ex) {
}
cancelRq.addAll(con.getRequests().values());
cancelRq.addAll(con.getSendQueue());
con.getRequests().clear();
con.getSendQueue().clear();
con.setChannel(null);
}
// notify listeners
for (RPCClientRequest rq : cancelRq) {
rq.getResponse().requestFailed("sending RPC failed: "+errorMessage);
rq.freeBuffers();
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "closing connection to %s", con
.getEndpointString());
}
}
private void checkForTimers() {
// poor man's timer
long now = System.currentTimeMillis();
if (now >= lastCheck + TIMEOUT_GRANULARITY) {
// check for timed out requests
synchronized (connections) {
Iterator<RPCClientConnection> conIter = connections.values().iterator();
while (conIter.hasNext()) {
final RPCClientConnection con = conIter.next();
if (con.getLastUsed() < (now - connectionTimeout)) {
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"removing idle connection");
}
try {
conIter.remove();
closeConnection(con.getChannel().keyFor(selector), null);
} catch (Exception ex) {
}
} else {
// check for request timeout
List<RPCClientRequest> cancelRq = new LinkedList<RPCClientRequest>();
synchronized (con) {
Iterator<RPCClientRequest> iter = con.getRequests().values().iterator();
while (iter.hasNext()) {
final RPCClientRequest rq = iter.next();
if (rq.getTimeQueued() + requestTimeout < now) {
cancelRq.add(rq);
iter.remove();
}
}
iter = con.getSendQueue().iterator();
while (iter.hasNext()) {
final RPCClientRequest rq = iter.next();
if (rq.getTimeQueued() + requestTimeout < now) {
cancelRq.add(rq);
iter.remove();
} else {
// requests are ordered :-)
break;
}
}
}
for (RPCClientRequest rq : cancelRq) {
rq.getResponse().requestFailed("sending RPC failed: request timed out");
rq.freeBuffers();
}
}
}
lastCheck = now;
}
}
}
@Override
public void shutdown() {
this.quit = true;
this.interrupt();
}
/**
* Returns the number of bytes received and transferred from/to a server.
* @param server
* @return an array with the number of bytes received [0] and sent [1]
*/
public long[] getTransferStats(InetSocketAddress server) {
RPCClientConnection con = null;
synchronized (connections) {
con = connections.get(server);
}
if (con == null)
return null;
else
return new long[]{con.bytesRX,con.bytesTX};
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import com.google.protobuf.Message;
import java.io.IOException;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.MessageType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader.ErrorResponse;
/**
*
* @author bjko
*/
public class RPCResponse<V extends Message> implements RPCResponseListener<V> {
private static final boolean TRACE_DUPLICATE_RESPONSES = false;
private RPCClientRequest request;
private RPCResponseAvailableListener<V> listener;
private String errorMessage;
private boolean failed;
private final V responsePrototype;
private Object attachment;
private ReusableBuffer message, data;
public RPCResponse(V responsePrototype) {
failed = false;
this.responsePrototype = responsePrototype;
}
public void freeBuffers() {
if (request != null)
request.freeBuffers();
}
public void registerListener(RPCResponseAvailableListener<V> listener) {
synchronized (this) {
this.listener = listener;
if (request != null || failed) {
//do notification
listener.responseAvailable(this);
}
}
}
public V get() throws IOException, InterruptedException {
waitForResult();
if (failed) {
throw new IOException(errorMessage);
} else {
if (request.getResponseHeader().getMessageType() == MessageType.RPC_RESPONSE_SUCCESS) {
if (responsePrototype != null) {
if (message != null) {
ReusableBufferInputStream rbis = new ReusableBufferInputStream(message);
V responseObject = (V) responsePrototype.newBuilderForType().mergeFrom(rbis).build();
assert(responseObject != null);
BufferPool.free(message);
message = null;
return responseObject;
} else {
return (V) responsePrototype.getDefaultInstanceForType();
}
} else {
if (message != null)
throw new RuntimeException("specify response prototype for null message!");
return null;
}
} else {
ErrorResponse err = request.getResponseHeader().getErrorResponse();
throw new PBRPCException(err);
}
}
}
public void setAttachment(Object attachment) {
this.attachment = attachment;
}
public Object getAttachment() {
return this.attachment;
}
public ReusableBuffer getData() throws InterruptedException {
waitForResult();
return data;
}
public void waitForResult() throws InterruptedException {
synchronized (this) {
if (request == null && !failed)
this.wait();
}
}
@Override
public void responseAvailable(RPCClientRequest<V> request, ReusableBuffer message, ReusableBuffer data) {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "response received");
synchronized (this) {
/*if (TRACE_DUPLICATE_RESPONSES) {
if (responseTrace != null) {
StringBuffer strace = new StringBuffer();
for (int i = responseTrace.length-1; i >= 0; i--) {
strace.append("\t");
strace.append(responseTrace[i].toString());
}
throw new RuntimeException("response already set:\n"+strace.toString());
} else {
responseTrace = Thread.currentThread().getStackTrace();
}
}*/
this.message = message;
this.data = data;
this.request = request;
if (listener != null)
listener.responseAvailable(this);
this.notify();
}
}
@Override
public void requestFailed(String errorMessage) {
synchronized (this) {
this.failed = true;
this.errorMessage = errorMessage;
if (listener != null)
listener.responseAvailable(this);
this.notify();
}
}
/**
* duration of request from sending the request until the response
* was received completeley.
* @return duration in ns
*/
public long getDuration() {
return request.getDuration();
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import com.google.protobuf.Message;
/**
*
* @author bjko
*/
public interface RPCResponseAvailableListener<V extends Message> {
public void responseAvailable(RPCResponse<V> r);
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.client;
import com.google.protobuf.Message;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
/**
*
* @author bjko
*/
public interface RPCResponseListener<V extends Message> {
public void responseAvailable(RPCClientRequest<V> request, ReusableBuffer message, ReusableBuffer data);
public void requestFailed(String reason);
}

View File

@@ -0,0 +1,98 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: include/PBRPC.proto
package org.xtreemfs.foundation.pbrpc.generatedinterfaces;
public final class PBRPC {
private PBRPC() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registry.add(org.xtreemfs.foundation.pbrpc.generatedinterfaces.PBRPC.procId);
registry.add(org.xtreemfs.foundation.pbrpc.generatedinterfaces.PBRPC.dataIn);
registry.add(org.xtreemfs.foundation.pbrpc.generatedinterfaces.PBRPC.dataOut);
registry.add(org.xtreemfs.foundation.pbrpc.generatedinterfaces.PBRPC.interfaceId);
}
public static final int PROC_ID_FIELD_NUMBER = 50001;
/**
* <code>extend .google.protobuf.MethodOptions { ... }</code>
*/
public static final
com.google.protobuf.GeneratedMessage.GeneratedExtension<
com.google.protobuf.DescriptorProtos.MethodOptions,
java.lang.Integer> procId = com.google.protobuf.GeneratedMessage
.newFileScopedGeneratedExtension(
java.lang.Integer.class,
null);
public static final int DATA_IN_FIELD_NUMBER = 50004;
/**
* <code>extend .google.protobuf.MethodOptions { ... }</code>
*/
public static final
com.google.protobuf.GeneratedMessage.GeneratedExtension<
com.google.protobuf.DescriptorProtos.MethodOptions,
java.lang.Boolean> dataIn = com.google.protobuf.GeneratedMessage
.newFileScopedGeneratedExtension(
java.lang.Boolean.class,
null);
public static final int DATA_OUT_FIELD_NUMBER = 50003;
/**
* <code>extend .google.protobuf.MethodOptions { ... }</code>
*/
public static final
com.google.protobuf.GeneratedMessage.GeneratedExtension<
com.google.protobuf.DescriptorProtos.MethodOptions,
java.lang.Boolean> dataOut = com.google.protobuf.GeneratedMessage
.newFileScopedGeneratedExtension(
java.lang.Boolean.class,
null);
public static final int INTERFACE_ID_FIELD_NUMBER = 50002;
/**
* <code>extend .google.protobuf.ServiceOptions { ... }</code>
*/
public static final
com.google.protobuf.GeneratedMessage.GeneratedExtension<
com.google.protobuf.DescriptorProtos.ServiceOptions,
java.lang.Integer> interfaceId = com.google.protobuf.GeneratedMessage
.newFileScopedGeneratedExtension(
java.lang.Integer.class,
null);
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\023include/PBRPC.proto\022\016xtreemfs.pbrpc\032 g" +
"oogle/protobuf/descriptor.proto:1\n\007proc_" +
"id\022\036.google.protobuf.MethodOptions\030\321\206\003 \001" +
"(\007:1\n\007data_in\022\036.google.protobuf.MethodOp" +
"tions\030\324\206\003 \001(\010:2\n\010data_out\022\036.google.proto" +
"buf.MethodOptions\030\323\206\003 \001(\010:7\n\014interface_i" +
"d\022\037.google.protobuf.ServiceOptions\030\322\206\003 \001" +
"(\007B3\n1org.xtreemfs.foundation.pbrpc.gene" +
"ratedinterfaces"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
procId.internalInit(descriptor.getExtensions().get(0));
dataIn.internalInit(descriptor.getExtensions().get(1));
dataOut.internalInit(descriptor.getExtensions().get(2));
interfaceId.internalInit(descriptor.getExtensions().get(3));
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
com.google.protobuf.DescriptorProtos.getDescriptor(),
}, assigner);
}
// @@protoc_insertion_point(outer_class_scope)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
//automatically generated from Ping.proto at Thu Dec 11 16:01:46 CET 2014
//(c) 2014. See LICENSE file for details.
package org.xtreemfs.foundation.pbrpc.generatedinterfaces;
import java.io.IOException;
import java.util.List;
import java.net.InetSocketAddress;
import com.google.protobuf.Message;
import com.google.protobuf.ByteString;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.Auth;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
import org.xtreemfs.foundation.pbrpc.client.RPCNIOSocketClient;
import org.xtreemfs.foundation.pbrpc.client.RPCResponse;
public class PingServiceClient {
private RPCNIOSocketClient client;
private InetSocketAddress defaultServer;
public PingServiceClient(RPCNIOSocketClient client, InetSocketAddress defaultServer) {
this.client = client;
this.defaultServer = defaultServer;
}
public RPCResponse<Ping.PingResponse> doPing(InetSocketAddress server, Auth authHeader, UserCredentials userCreds, Ping.PingRequest input, ReusableBuffer data) throws IOException {
if (server == null) server = defaultServer;
if (server == null) throw new IllegalArgumentException("defaultServer must be set in constructor if you want to pass null as server in calls");
RPCResponse<Ping.PingResponse> response = new RPCResponse<Ping.PingResponse>(Ping.PingResponse.getDefaultInstance());
client.sendRequest(server, authHeader, userCreds, 1, 1, input, data, response, false);
return response;
}
public RPCResponse<Ping.PingResponse> doPing(InetSocketAddress server, Auth authHeader, UserCredentials userCreds, String text, boolean sendError, ReusableBuffer data) throws IOException {
final Ping.PingRequest msg = Ping.PingRequest.newBuilder().setText(text).setSendError(sendError).build();
return doPing(server, authHeader, userCreds,msg, data);
}
public RPCResponse emptyPing(InetSocketAddress server, Auth authHeader, UserCredentials userCreds, Ping.Ping_emptyRequest input) throws IOException {
if (server == null) server = defaultServer;
if (server == null) throw new IllegalArgumentException("defaultServer must be set in constructor if you want to pass null as server in calls");
RPCResponse response = new RPCResponse(null);
client.sendRequest(server, authHeader, userCreds, 1, 2, input, null, response, false);
return response;
}
public RPCResponse emptyPing(InetSocketAddress server, Auth authHeader, UserCredentials userCreds) throws IOException {
return emptyPing(server, authHeader, userCreds,null);
}
public boolean clientIsAlive() {
return client.isAlive();
}
}

View File

@@ -0,0 +1,32 @@
//automatically generated from Ping.proto at Thu Dec 11 16:01:46 CET 2014
//(c) 2014. See LICENSE file for details.
package org.xtreemfs.foundation.pbrpc.generatedinterfaces;
import com.google.protobuf.Message;
public class PingServiceConstants {
public static final int INTERFACE_ID = 1;
public static final int PROC_ID_DOPING = 1;
public static final int PROC_ID_EMPTYPING = 2;
public static Message getRequestMessage(int procId) {
switch (procId) {
case 1: return Ping.PingRequest.getDefaultInstance();
case 2: return null;
default: throw new RuntimeException("unknown procedure id");
}
}
public static Message getResponseMessage(int procId) {
switch (procId) {
case 1: return Ping.PingResponse.getDefaultInstance();
case 2: return null;
default: throw new RuntimeException("unknown procedure id");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,787 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.xtreemfs.foundation.LifeCycleThread;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
import org.xtreemfs.foundation.pbrpc.channels.SSLChannelIO;
import org.xtreemfs.foundation.pbrpc.channels.SSLHandshakeOnlyChannelIO;
import org.xtreemfs.foundation.util.OutputUtils;
/**
*
* @author bjko
*/
public class RPCNIOSocketServer extends LifeCycleThread implements RPCServerInterface {
/**
* Maximum number of record fragments supported.
*/
public static final int MAX_FRAGMENTS = 1;
/**
* Maximum fragment size to accept. If the size is larger, the connection is
* closed.
*/
public static final int MAX_FRAGMENT_SIZE = 1024 * 1024 * 32;
/**
* the server socket
*/
private final ServerSocketChannel socket;
/**
* Selector for server socket
*/
private final Selector selector;
/**
* If set to true thei main loop will exit upon next invocation
*/
private volatile boolean quit;
/**
* The receiver that gets all incoming requests.
*/
private volatile RPCServerRequestListener receiver;
/**
* sslOptions if SSL is enabled, null otherwise
*/
private final SSLOptions sslOptions;
/**
* Connection count
*/
private final AtomicInteger numConnections;
/**
* Number of requests received but not answered
*/
private long pendingRequests;
/**
* Port on which the server listens for incoming connections.
*/
private final int bindPort;
private final List<RPCNIOSocketServerConnection> connections;
/**
* maximum number of pending client requests to allow
*/
private final int maxClientQLength;
/**
* if the Q was full we need at least CLIENT_Q_THR spaces before we start
* reading from the client again. This is to prevent it from oscillating
*/
private final int clientQThreshold;
public static final int DEFAULT_MAX_CLIENT_Q_LENGTH = 100;
public RPCNIOSocketServer(int bindPort, InetAddress bindAddr, RPCServerRequestListener rl,
SSLOptions sslOptions) throws IOException {
this(bindPort, bindAddr, rl, sslOptions, -1);
}
public RPCNIOSocketServer(int bindPort, InetAddress bindAddr, RPCServerRequestListener rl,
SSLOptions sslOptions, int receiveBufferSize) throws IOException {
this(bindPort, bindAddr, rl, sslOptions, receiveBufferSize, DEFAULT_MAX_CLIENT_Q_LENGTH);
}
public RPCNIOSocketServer(int bindPort, InetAddress bindAddr, RPCServerRequestListener rl,
SSLOptions sslOptions, int receiveBufferSize,
int maxClientQLength) throws IOException {
super("PBRPCSrv@" + bindPort);
// open server socket
socket = ServerSocketChannel.open();
socket.configureBlocking(false);
if (receiveBufferSize != -1) {
socket.socket().setReceiveBufferSize(receiveBufferSize);
try {
if (socket.socket().getReceiveBufferSize() != receiveBufferSize) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"could not set socket receive buffer size to " + receiveBufferSize
+ ", using default size of " + socket.socket().getReceiveBufferSize());
}
} catch (SocketException exc) {
Logging.logMessage(Logging.LEVEL_WARN, this,
"could not check whether receive buffer size was successfully set to %d bytes", receiveBufferSize);
}
} else {
socket.socket().setReceiveBufferSize(256 * 1024);
}
socket.socket().setReuseAddress(true);
try {
socket.socket().bind(
bindAddr == null ? new InetSocketAddress(bindPort) : new InetSocketAddress(bindAddr, bindPort));
} catch (BindException e) {
// Rethrow exception with the failed port number.
throw new BindException(e.getMessage() + ". Port number: " + bindPort);
}
this.bindPort = bindPort;
// create a selector and register socket
selector = Selector.open();
socket.register(selector, SelectionKey.OP_ACCEPT);
// server is ready to accept connections now
this.receiver = rl;
this.sslOptions = sslOptions;
this.numConnections = new AtomicInteger(0);
this.connections = new LinkedList<RPCNIOSocketServerConnection>();
this.maxClientQLength = maxClientQLength;
this.clientQThreshold = (maxClientQLength/2 >= 0) ? maxClientQLength/2 : 0;
if (maxClientQLength <= 1) {
Logging.logMessage(Logging.LEVEL_WARN, this, "max client queue length is 1, pipelining is disabled.");
}
}
/**
* Stop the server and close all connections.
*/
@Override
public void shutdown() {
this.quit = true;
this.interrupt();
}
/**
* sends a response.
*
* @param request
* the request
*/
@Override
public void sendResponse(RPCServerRequest request, RPCServerResponse response) {
assert (response != null);
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "response sent");
final RPCNIOSocketServerConnection connection = (RPCNIOSocketServerConnection)request.getConnection();
try {
request.freeBuffers();
} catch (AssertionError ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this, "Caught an AssertionError while trying to free buffers:");
Logging.logError(Logging.LEVEL_INFO, this, ex);
}
}
assert (connection.getServer() == this);
if (!connection.isConnectionClosed()) {
synchronized (connection) {
boolean isEmpty = connection.getPendingResponses().isEmpty();
connection.addPendingResponse(response);
if (isEmpty) {
final SelectionKey key = connection.getChannel().keyFor(selector);
if (key != null) {
try {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
} catch (CancelledKeyException e) {
// Ignore it since the timeout mechanism will deal with it.
}
}
selector.wakeup();
}
}
} else {
// ignore and free bufers
response.freeBuffers();
}
}
@Override
public void run() {
notifyStarted();
if (Logging.isInfo()) {
String sslMode = "";
if (sslOptions != null) {
if (sslOptions.isFakeSSLMode()) {
sslMode = "GRID SSL mode enabled (SSL handshake only)";
} else {
sslMode = "SSL enabled (" + sslOptions.getSSLProtocol() + ")";
}
}
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this, "PBRPC Srv %d ready %s", bindPort,sslMode);
}
try {
while (!quit) {
// try to select events...
int numKeys = 0;
try {
numKeys = selector.select();
} catch (CancelledKeyException ex) {
// who cares
} catch (IOException ex) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"Exception while selecting: %s", ex.toString());
continue;
}
if (numKeys > 0) {
// fetch events
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
// process all events
while (iter.hasNext()) {
SelectionKey key = iter.next();
// remove key from the list
iter.remove();
try {
if (key.isAcceptable()) {
acceptConnection(key);
}
if (key.isReadable()) {
readConnection(key);
}
if (key.isWritable()) {
writeConnection(key);
}
} catch (CancelledKeyException ex) {
// nobody cares...
continue;
}
}
}
}
for (RPCNIOSocketServerConnection con : connections) {
try {
con.getChannel().close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
// close socket
selector.close();
socket.close();
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"PBRPC Server %d shutdown complete", bindPort);
notifyStopped();
} catch (Throwable thr) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.net, this, "PBRPC Server %d CRASHED!", bindPort);
notifyCrashed(thr);
}
}
/**
* read data from a readable connection
*
* @param key
* a readable key
*/
private void readConnection(SelectionKey key) {
final RPCNIOSocketServerConnection con = (RPCNIOSocketServerConnection) key.attachment();
final ChannelIO channel = con.getChannel();
try {
if (!channel.isShutdownInProgress()) {
if (channel.doHandshake(key)) {
while (true) {
if (con.getOpenRequests().get() > maxClientQLength) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"client sent too many requests... not accepting new requests from %s, q=%d", con
.getChannel().socket().getRemoteSocketAddress().toString(), con.getOpenRequests().get());
return;
}
ByteBuffer buf = null;
switch (con.getReceiveState()) {
case RECORD_MARKER: {
buf = con.getReceiveRecordMarker(); break;
}
case RPC_MESSAGE: {
buf = con.getReceiveBuffers()[1].getBuffer(); break;
}
case RPC_HEADER: {
buf = con.getReceiveBuffers()[0].getBuffer(); break;
}
case DATA: {
buf = con.getReceiveBuffers()[2].getBuffer(); break;
}
}
// read fragment header
final int numBytesRead = readData(key, channel, buf);
if (numBytesRead == -1) {
// connection closed
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"client closed connection (EOF): %s", channel.socket()
.getRemoteSocketAddress().toString());
}
closeConnection(key);
return;
}
if (buf.hasRemaining()) {
// not enough data...
break;
}
switch (con.getReceiveState()) {
case RECORD_MARKER: {
buf.position(0);
final int hdrLen = buf.getInt();
final int msgLen = buf.getInt();
final int dataLen = buf.getInt();
if ((hdrLen <= 0) || (hdrLen >= MAX_FRAGMENT_SIZE)
|| (msgLen < 0) || (msgLen >= MAX_FRAGMENT_SIZE)
|| (dataLen < 0) || (dataLen >= MAX_FRAGMENT_SIZE)) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.net, this,
"invalid record marker size (%d/%d/%d) received, closing connection to client %s",
hdrLen,msgLen,dataLen,channel.socket()
.getRemoteSocketAddress().toString());
closeConnection(key);
return;
}
final ReusableBuffer[] buffers = new ReusableBuffer[]{BufferPool.allocate(hdrLen),
((msgLen > 0) ? BufferPool.allocate(msgLen) : null),
((dataLen > 0) ? BufferPool.allocate(dataLen) : null) };
con.setReceiveBuffers(buffers);
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RPC_HEADER);
continue;
}
case RPC_HEADER: {
if (con.getReceiveBuffers()[1] != null) {
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RPC_MESSAGE);
continue;
} else {
if (con.getReceiveBuffers()[2] != null) {
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.DATA);
continue;
} else {
break;
}
}
}
case RPC_MESSAGE: {
if (con.getReceiveBuffers()[2] != null) {
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.DATA);
continue;
} else {
break;
}
}
}
//assemble ServerRequest
con.setReceiveState(RPCNIOSocketServerConnection.ReceiveState.RECORD_MARKER);
con.getReceiveRecordMarker().clear();
ReusableBuffer[] receiveBuffers = con.getReceiveBuffers();
receiveBuffers[0].flip();
if (receiveBuffers[1] != null)
receiveBuffers[1].flip();
if (receiveBuffers[2] != null)
receiveBuffers[2].flip();
con.setReceiveBuffers(null);
RPCServerRequest rq = null;
try {
rq = new RPCServerRequest(con, receiveBuffers[0], receiveBuffers[1], receiveBuffers[2]);
} catch (IOException ex) {
// close connection if the header cannot be parsed
Logging.logMessage(Logging.LEVEL_ERROR, Category.net,this,"invalid PBRPC header received: "+ex);
if (Logging.isDebug()) {
Logging.logError(Logging.LEVEL_DEBUG, this,ex);
}
closeConnection(key);
BufferPool.free(receiveBuffers[1]);
BufferPool.free(receiveBuffers[2]);
return;
}
// request is
// complete... send to receiver
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, rq
.toString());
}
con.getOpenRequests().incrementAndGet();
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"request received");
pendingRequests++;
if (!receiveRequest(key, rq, con)) {
closeConnection(key);
return;
}
}
}
}
} catch (CancelledKeyException ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (CancelledKeyException): %s", channel.socket().getRemoteSocketAddress()
.toString());
}
closeConnection(key);
} catch (ClosedByInterruptException ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (EOF): %s", channel.socket().getRemoteSocketAddress()
.toString());
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"connection to %s closed by remote peer", con.getChannel().socket()
.getRemoteSocketAddress().toString());
}
closeConnection(key);
} catch (IOException ex) {
// simply close the connection
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(ex));
}
closeConnection(key);
}
}
/**
* write data to a writeable connection
*
* @param key
* the writable key
*/
private void writeConnection(SelectionKey key) {
final RPCNIOSocketServerConnection con = (RPCNIOSocketServerConnection) key.attachment();
final ChannelIO channel = con.getChannel();
try {
if (!channel.isShutdownInProgress()) {
if (channel.doHandshake(key)) {
while (true) {
// final ByteBuffer fragmentHeader =
// con.getSendFragHdr();
ByteBuffer[] response = con.getSendBuffers();
if (response == null) {
synchronized (con) {
RPCServerResponse rq = con.getPendingResponses().peek();
if (rq == null) {
// no more responses, stop writing...
con.setSendBuffers(null);
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
break;
}
response = rq.packBuffers(con.getSendFragHdr());
con.setSendBuffers(response);
con.setExpectedRecordSize(rq.getRpcMessageSize());
}
}
/*
* if (fragmentHeader.hasRemaining()) { final int
* numBytesWritten = writeData(key, channel,
* fragmentHeader); if (numBytesWritten == -1) {
* //connection closed closeConnection(key); return; }
* if (fragmentHeader.hasRemaining()) { //not enough
* data... break; } //finished sending... send fragment
* data now... } else {
*/
// send fragment data
assert(response != null);
final long numBytesWritten = channel.write(response);
if (numBytesWritten == -1) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (EOF): %s", channel.socket()
.getRemoteSocketAddress().toString());
}
// connection closed
closeConnection(key);
return;
}
con.recordBytesSent(numBytesWritten);
if (response[response.length-1].hasRemaining()) {
// not enough data...
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
con.checkEnoughBytesSent();
// finished sending fragment
// clean up :-) request finished
pendingRequests--;
RPCServerResponse rq = con.getPendingResponses().poll();
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"sent response for %s", rq.toString());
}
rq.freeBuffers();
con.setSendBuffers(null);
con.getSendFragHdr().clear();
int numRq = con.getOpenRequests().decrementAndGet();
if ((key.interestOps() & SelectionKey.OP_READ) == 0) {
if (numRq < clientQThreshold) {
// read from client again
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"client allowed to send data again: %s, q=%d", con.getChannel().socket()
.getRemoteSocketAddress().toString(), numRq);
}
}
continue;
}
}
}
} catch (CancelledKeyException ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (CancelledKeyException): %s", channel.socket().getRemoteSocketAddress()
.toString());
}
closeConnection(key);
} catch (ClosedByInterruptException ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection (EOF): %s", channel.socket().getRemoteSocketAddress()
.toString());
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"connection to %s closed by remote peer", con.getChannel().socket()
.getRemoteSocketAddress().toString());
}
closeConnection(key);
} catch (IOException ex) {
// simply close the connection
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, OutputUtils
.stackTraceToString(ex));
}
closeConnection(key);
}
}
/**
* Reads data from the socket, ensures that SSL connection is ready
*
* @param key
* the SelectionKey
* @param channel
* the channel to read from
* @param buf
* the buffer to read to
* @return number of bytes read, -1 on EOF
* @throws java.io.IOException
*/
public static int readData(SelectionKey key, ChannelIO channel, ByteBuffer buf) throws IOException {
return channel.read(buf);
/*
* if (!channel.isShutdownInProgress()) { if (channel.doHandshake(key))
* { return channel.read(buf); } else { return 0; } } else { return 0; }
*/
}
public static int writeData(SelectionKey key, ChannelIO channel, ByteBuffer buf) throws IOException {
return channel.write(buf);
/*
* if (!channel.isShutdownInProgress()) { if (channel.doHandshake(key))
* { return channel.write(buf); } else { return 0; } } else { return 0;
* }
*/
}
/**
* close a connection
*
* @param key
* matching key
*/
private void closeConnection(SelectionKey key) {
final RPCNIOSocketServerConnection con = (RPCNIOSocketServerConnection) key.attachment();
final ChannelIO channel = con.getChannel();
// remove the connection from the selector and close socket
try {
connections.remove(con);
con.setConnectionClosed(true);
key.cancel();
channel.close();
} catch (Exception ex) {
} finally {
// adjust connection count and make sure buffers are freed
numConnections.decrementAndGet();
con.freeBuffers();
}
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "closing connection to %s", channel
.socket().getRemoteSocketAddress().toString());
}
}
/**
* accept a new incomming connection
*
* @param key
* the acceptable key
*/
private void acceptConnection(SelectionKey key) {
SocketChannel client = null;
RPCNIOSocketServerConnection con = null;
ChannelIO channelIO = null;
// FIXME: Better exception handling!
try {
// accept that connection
client = socket.accept();
if (sslOptions == null) {
channelIO = new ChannelIO(client);
} else {
if (sslOptions.isFakeSSLMode()) {
channelIO = new SSLHandshakeOnlyChannelIO(client, sslOptions, false);
} else {
channelIO = new SSLChannelIO(client, sslOptions, false);
}
}
con = new RPCNIOSocketServerConnection(this,channelIO);
// and configure it to be non blocking
// IMPORTANT!
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ, con);
client.socket().setTcpNoDelay(true);
numConnections.incrementAndGet();
this.connections.add(con);
if (Logging.isDebug()) {
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "connect from client at %s",
client.socket().getRemoteSocketAddress().toString());
}
} catch (ClosedChannelException ex) {
if (Logging.isInfo()) {
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this,
"client closed connection during accept");
}
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"cannot establish connection: %s", ex.toString());
if (channelIO != null) {
try {
channelIO.close();
} catch (IOException ex2) {
}
}
} catch (IOException ex) {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"cannot establish connection: %s", ex.toString());
if (channelIO != null) {
try {
channelIO.close();
} catch (IOException ex2) {
}
}
}
}
/**
*
* @param key
* @param request
* @param con
* @return true on success, false on error
*/
private boolean receiveRequest(SelectionKey key, RPCServerRequest request, RPCNIOSocketServerConnection con) {
try {
request.getHeader();
receiver.receiveRecord(request);
return true;
} catch (IllegalArgumentException ex) {
Logging.logMessage(Logging.LEVEL_ERROR, Category.net,this,"invalid PBRPC header received: "+ex);
if (Logging.isDebug()) {
Logging.logError(Logging.LEVEL_DEBUG, this,ex);
}
return false;
//closeConnection(key);
}
}
public int getNumConnections() {
return this.numConnections.get();
}
public long getPendingRequests() {
return this.pendingRequests;
}
/**
* Updates the listener. Handle with care.
*
* @param rl
*/
public void updateRequestDispatcher(RPCServerRequestListener rl) {
this.receiver = rl;
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
/**
*
* @author bjko
*/
public class RPCNIOSocketServerConnection implements RPCServerConnectionInterface {
public enum ReceiveState {
RECORD_MARKER,
RPC_HEADER,
RPC_MESSAGE,
DATA
};
private final AtomicInteger openRequests;
private Queue<RPCServerResponse> pendingResponses;
private final ChannelIO channel;
private final ByteBuffer receiveRecordMarker;
private final ByteBuffer sendFragHdr;
private ReusableBuffer[] receiveBuffers;
private ReceiveState receiveState;
private ByteBuffer[] sendBuffers;
private volatile boolean connectionClosed;
private SocketAddress clientAddress;
private RPCServerInterface server;
private long bytesSent;
private int expectedRecordSize;
public RPCNIOSocketServerConnection(RPCServerInterface server, ChannelIO channel) {
assert(server != null);
assert(channel != null);
this.channel = channel;
this.openRequests = new AtomicInteger(0);
this.pendingResponses = new ConcurrentLinkedQueue<RPCServerResponse>();
this.connectionClosed = false;
this.receiveRecordMarker = ByteBuffer.allocate(RecordMarker.HDR_SIZE);
this.sendFragHdr = ByteBuffer.allocate(RecordMarker.HDR_SIZE);
this.receiveState = ReceiveState.RECORD_MARKER;
this.server = server;
try {
this.clientAddress = channel.socket().getRemoteSocketAddress();
} catch (Exception ex) {
}
}
/**
* @return the receiveState
*/
public ReceiveState getReceiveState() {
return receiveState;
}
/**
* @param receiveState the receiveState to set
*/
public void setReceiveState(ReceiveState receiveState) {
this.receiveState = receiveState;
}
@Override
public RPCServerInterface getServer() {
return server;
}
@Override
public SocketAddress getSender() {
return clientAddress;
}
public void freeBuffers() {
if (receiveBuffers != null) {
for (ReusableBuffer buffer : receiveBuffers)
BufferPool.free(buffer);
}
for (RPCServerResponse r : pendingResponses) {
r.freeBuffers();
}
}
/**
* @return the openRequests
*/
public AtomicInteger getOpenRequests() {
return openRequests;
}
/**
* @return the channel
*/
@Override
public ChannelIO getChannel() {
return channel;
}
/**
* @return the connectionClosed
*/
public boolean isConnectionClosed() {
return connectionClosed;
}
/**
* @param connectionClosed the connectionClosed to set
*/
public void setConnectionClosed(boolean connectionClosed) {
this.connectionClosed = connectionClosed;
}
/**
* @return the pendingResponses
*/
public Queue<RPCServerResponse> getPendingResponses() {
return pendingResponses;
}
public void addPendingResponse(RPCServerResponse rq) {
this.pendingResponses.add(rq);
}
/**
* @return the fragmentHeader
*/
ByteBuffer getReceiveRecordMarker() {
return receiveRecordMarker;
}
/**
* @return the fragmentHeader
*/
ByteBuffer getSendFragHdr() {
return sendFragHdr;
}
/**
* @return the receive
*/
ReusableBuffer[] getReceiveBuffers() {
return receiveBuffers;
}
/**
* @param receive the receive to set
*/
void setReceiveBuffers(ReusableBuffer[] receive) {
this.receiveBuffers = receive;
}
/**
* @return the send
*/
ByteBuffer[] getSendBuffers() {
return sendBuffers;
}
/**
* @param send the send to set
*/
void setSendBuffers(ByteBuffer[] send) {
this.sendBuffers = send;
}
/**
* @return the clientAddress
*/
public SocketAddress getClientAddress() {
return clientAddress;
}
public void setExpectedRecordSize(int expectedRecordSize) {
this.expectedRecordSize = expectedRecordSize;
bytesSent = 0;
}
public void recordBytesSent(long bytesSent) {
this.bytesSent += bytesSent;
if (this.bytesSent > expectedRecordSize) {
String errorMessage = "Too many bytes written (expected: "
+ expectedRecordSize
+ ", actual: "
+ this.bytesSent
+ ") in connection to "
+ clientAddress;
Logging.logMessage(Logging.LEVEL_ERROR, this, errorMessage);
throw new IllegalStateException(errorMessage);
}
}
public void checkEnoughBytesSent() {
if (bytesSent != expectedRecordSize) {
String errorMessage = "Incorrect record length sent (expected: "
+ expectedRecordSize
+ ", actual: "
+ bytesSent
+ ") in connection to "
+ clientAddress;
Logging.logMessage(Logging.LEVEL_ERROR, this, errorMessage);
throw new IllegalStateException(errorMessage);
}
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import java.net.SocketAddress;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
/**
*
* @author bjko
*/
public interface RPCServerConnectionInterface {
public RPCServerInterface getServer();
public SocketAddress getSender();
public ChannelIO getChannel();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
/**
*
* @author bjko
*/
public interface RPCServerInterface {
public void sendResponse(RPCServerRequest request, RPCServerResponse response);
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import com.google.protobuf.Message;
import java.io.IOException;
import java.net.SocketAddress;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
/**
*
* @author bjko
*/
public class RPCServerRequest {
private RPC.RPCHeader header;
private ReusableBuffer message;
private ReusableBuffer data;
private final RPCServerConnectionInterface connection;
public RPCServerRequest(RPCServerConnectionInterface connection, ReusableBuffer headerBuffer, ReusableBuffer message, ReusableBuffer data) throws IOException {
try {
ReusableBufferInputStream rbis = new ReusableBufferInputStream(headerBuffer);
header = RPC.RPCHeader.parseFrom(rbis);
this.message = message;
this.data = data;
this.connection = connection;
} finally {
BufferPool.free(headerBuffer);
}
}
public RPCServerRequest(RPCServerConnectionInterface connection, RPC.RPCHeader header, ReusableBuffer message) {
this.header = header;
this.message = message;
this.data = null;
this.connection = connection;
}
public RPC.RPCHeader getHeader() {
return header;
}
/**
* @return the message
*/
public ReusableBuffer getMessage() {
return message;
}
/**
* @return the data
*/
public ReusableBuffer getData() {
return data;
}
public void freeBuffers() {
BufferPool.free(message);
BufferPool.free(data);
}
public void sendError(RPC.ErrorType type, RPC.POSIXErrno errno, String message, String debugInfo) {
RPC.RPCHeader.ErrorResponse resp = RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(type).setPosixErrno(errno).setErrorMessage(message).setDebugInfo(debugInfo).build();
sendError(resp);
}
public void sendError(RPC.ErrorType type, RPC.POSIXErrno errno, String message) {
RPC.RPCHeader.ErrorResponse resp = RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(type).setPosixErrno(errno).setErrorMessage(message).build();
sendError(resp);
}
public void sendRedirect(String target_uuid) {
RPC.RPCHeader.ErrorResponse resp = RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.REDIRECT).setPosixErrno(RPC.POSIXErrno.POSIX_ERROR_NONE).setRedirectToServerUuid(target_uuid).build();
sendError(resp);
}
public void sendError(RPC.RPCHeader.ErrorResponse error) {
try {
RPC.RPCHeader rqHdr = getHeader();
RPC.RPCHeader respHdr = RPC.RPCHeader.newBuilder().setCallId(rqHdr.getCallId()).setMessageType(RPC.MessageType.RPC_RESPONSE_ERROR).setErrorResponse(error).build();
RPCServerResponse response = new RPCServerResponse(respHdr, null, null);
getConnection().getServer().sendResponse(this, response);
} catch (IOException ex) {
Logging.logError(Logging.LEVEL_ERROR, this, ex);
}
}
public void sendResponse(Message message, ReusableBuffer data) throws IOException {
RPC.RPCHeader rqHdr = getHeader();
RPC.RPCHeader respHdr = RPC.RPCHeader.newBuilder().setCallId(rqHdr.getCallId()).setMessageType(RPC.MessageType.RPC_RESPONSE_SUCCESS).build();
RPCServerResponse response = new RPCServerResponse(respHdr, message, data);
getConnection().getServer().sendResponse(this, response);
}
public SocketAddress getSenderAddress() {
return connection.getSender();
}
/**
* @return the connection
*/
public RPCServerConnectionInterface getConnection() {
return connection;
}
public String toString() {
try {
RPC.RPCHeader hdr = getHeader();
String headerContent = "";
if (hdr.getMessageType() == RPC.MessageType.RPC_REQUEST) {
headerContent = ",proc="+hdr.getRequestHeader().getProcId()+",interf="+hdr.getRequestHeader().getInterfaceId();
}
return this.getClass().getCanonicalName()+": callid="+hdr.getCallId()+", type="+hdr.getMessageType()+headerContent;
} catch (Exception ex) {
return this.getClass().getCanonicalName()+": unparseable data: "+ex;
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
/**
*
* @author bjko
*/
public interface RPCServerRequestListener {
public void receiveRecord(RPCServerRequest rq);
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import com.google.protobuf.Message;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferOutputStream;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
/**
*
* @author bjko
*/
public class RPCServerResponse {
final int callId;
final ReusableBuffer[] buffers;
final int hdrLen;
final int msgLen;
final int dataLen;
public RPCServerResponse(RPC.RPCHeader header, Message message, ReusableBuffer data) throws IOException {
ReusableBufferOutputStream os = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
callId = header.getCallId();
hdrLen = header.getSerializedSize();
msgLen = (message != null) ? message.getSerializedSize() : 0;
dataLen = (data != null) ? data.capacity() : 0;
assert(hdrLen > 0);
assert(msgLen >= 0);
assert(dataLen >= 0);
RecordMarker rm = new RecordMarker(hdrLen, msgLen, dataLen);
rm.writeFragmentHeader(os);
header.writeTo(os);
if (message != null) {
message.writeTo(os);
}
if (data != null) {
data.position(data.limit());
os.appendBuffer(data);
}
os.flip();
buffers = os.getBuffers();
}
public ReusableBuffer[] getBuffers() {
return buffers;
}
public ByteBuffer[] packBuffers(ByteBuffer recordMarker) {
ByteBuffer[] arr = new ByteBuffer[buffers.length];
for (int i = 0; i < buffers.length; i++)
arr[i] = buffers[i].getBuffer();
return arr;
}
public void freeBuffers() {
for (int i = 0; i < buffers.length; i++) {
BufferPool.free(buffers[i]);
buffers[i] = null;
}
}
public String toString() {
return this.getClass().getCanonicalName()+": callid="+callId;
}
public int getRpcMessageSize() {
return RecordMarker.HDR_SIZE + hdrLen + dataLen + msgLen;
}
}

View File

@@ -0,0 +1,255 @@
/*
* Copyright (c) 2008-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.xtreemfs.foundation.LifeCycleThread;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader;
import org.xtreemfs.foundation.pbrpc.utils.PBRPCDatagramPacket;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import com.google.protobuf.Message;
/**
*
* @author bjko
*/
public class RPCUDPSocketServer extends LifeCycleThread implements RPCServerInterface {
public final int port;
private final DatagramChannel channel;
private final Selector selector;
private volatile boolean quit;
private final LinkedBlockingQueue<UDPMessage> q;
private final RPCServerRequestListener receiver;
public static final int MAX_UDP_SIZE = 2048;
private final AtomicInteger callIdCounter;
public RPCUDPSocketServer(int port, RPCServerRequestListener receiver) throws IOException {
super("UDPComStage");
this.port = port;
q = new LinkedBlockingQueue<UDPMessage>();
this.receiver = receiver;
callIdCounter = new AtomicInteger(1);
selector = Selector.open();
channel = DatagramChannel.open();
channel.socket().setReuseAddress(true);
channel.socket().bind(new InetSocketAddress(port));
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.net, this, "UDP socket on port %d ready", port);
}
@Override
public void sendResponse(RPCServerRequest request, RPCServerResponse response) {
UDPMessage msg = (UDPMessage)request.getConnection();
UDPMessage responseMsg = new UDPMessage(response.getBuffers()[0], msg.getAddress(), this);
request.freeBuffers();
send(responseMsg);
}
public void sendRequest(RPCHeader header, Message message, InetSocketAddress receiver) throws IOException {
PBRPCDatagramPacket dpack = new PBRPCDatagramPacket(header, message);
header = header.toBuilder().setCallId(callIdCounter.getAndIncrement()).build();
UDPMessage msg = new UDPMessage(dpack.assembleDatagramPacket(), receiver, this);
//msg.getBuffer().flip();
send(msg);
}
private void send(UDPMessage rq) {
q.add(rq);
if (q.size() == 1) {
// System.out.println("wakeup!");
selector.wakeup();
}
}
@Override
public void shutdown() {
quit = true;
interrupt();
}
@Override
public void run() {
try {
notifyStarted();
boolean isRdOnly = true;
while (!quit) {
if (q.size() == 0) {
if (!isRdOnly) {
channel.keyFor(selector).interestOps(SelectionKey.OP_READ);
// System.out.println("read only");
isRdOnly = true;
}
} else {
if (isRdOnly) {
channel.keyFor(selector).interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
// System.out.println("read write");
isRdOnly = false;
}
}
int numKeys = selector.select();
if (q.size() == 0) {
if (!isRdOnly) {
channel.keyFor(selector).interestOps(SelectionKey.OP_READ);
// System.out.println("read only");
isRdOnly = true;
}
} else {
if (isRdOnly) {
channel.keyFor(selector).interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
// System.out.println("read write");
isRdOnly = false;
}
}
if (numKeys == 0)
continue;
if (q.size() > 10000) {
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this, "QS!!!!! %d", q.size());
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this, "is readOnly: " + isRdOnly);
}
// fetch events
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
// process all events
while (iter.hasNext()) {
SelectionKey key = iter.next();
// remove key from the list
iter.remove();
if (key.isReadable()) {
InetSocketAddress sender = null;
// do {
ReusableBuffer data = BufferPool.allocate(MAX_UDP_SIZE);
sender = (InetSocketAddress) channel.receive(data.getBuffer());
if (sender == null || !data.hasRemaining()) {
BufferPool.free(data);
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"read key for empty read/empty packet");
} else {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"read data from %s", sender.toString());
try {
data.flip();
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "data: %s",
data.toString());
RecordMarker rm = new RecordMarker(data.getBuffer());
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "rm: %d/%d data: %d",
rm.getRpcHeaderLength(), rm.getMessageLength(), data.limit());
ReusableBufferInputStream rbis = new ReusableBufferInputStream(data);
final int origLimit = data.limit();
assert (origLimit == RecordMarker.HDR_SIZE + rm.getRpcHeaderLength()
+ rm.getMessageLength());
data.limit(RecordMarker.HDR_SIZE + rm.getRpcHeaderLength());
RPCHeader header = RPCHeader.newBuilder().mergeFrom(rbis).build();
data.range(RecordMarker.HDR_SIZE + rm.getRpcHeaderLength(), rm.getMessageLength());
UDPMessage msg = new UDPMessage(null, sender, this);
RPCServerRequest rq = new RPCServerRequest(msg, header, data);
receiver.receiveRecord(rq);
} catch (Throwable ex) {
ex.printStackTrace();
Logging.logMessage(Logging.LEVEL_WARN, Category.net, this,
"received invalid UPD message: "+ex);
BufferPool.free(data);
}
}
// } while (sender != null);
} else if (key.isWritable()) {
UDPMessage r = q.poll();
while (r != null) {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this,
"sent packet to %s", r.getAddress().toString());
int sent = channel.send(r.getBuffer().getBuffer(), r.getAddress());
BufferPool.free(r.getBuffer());
if (sent == 0) {
if (Logging.isDebug())
Logging.logMessage(Logging.LEVEL_DEBUG, Category.net, this, "cannot send anymore");
q.put(r);
break;
}
r = q.poll();
}
} else {
throw new RuntimeException("strange key state: " + key);
}
}
}
selector.close();
channel.close();
} catch (CancelledKeyException ex) {
// ignore
} catch (ClosedByInterruptException ex) {
// ignore
} catch (IOException ex) {
Logging.logError(Logging.LEVEL_ERROR, this, ex);
} catch (Throwable th) {
notifyCrashed(th);
return;
}
notifyStopped();
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.server;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.pbrpc.channels.ChannelIO;
/**
*
* @author bjko
*/
public class UDPMessage implements RPCServerConnectionInterface {
private final ReusableBuffer buffer;
private final InetSocketAddress address;
final RPCUDPSocketServer server;
public UDPMessage(ReusableBuffer buffer, InetSocketAddress address, RPCUDPSocketServer server) {
this.buffer = buffer;
this.address = address;
this.server = server;
}
@Override
public RPCServerInterface getServer() {
return server;
}
/**
* @return the buffer
*/
public ReusableBuffer getBuffer() {
return buffer;
}
/**
* @return the address
*/
public InetSocketAddress getAddress() {
return address;
}
@Override
public SocketAddress getSender() {
return address;
}
@Override
public ChannelIO getChannel() {
return null;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.utils;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.ErrorType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.POSIXErrno;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader.ErrorResponse;
import org.xtreemfs.foundation.util.OutputUtils;
/**
*
* @author bjko
*/
public class ErrorUtils {
public static ErrorResponse getErrorResponse(ErrorType type, POSIXErrno errno, String message, String debug) {
return ErrorResponse.newBuilder().setErrorType(type).setPosixErrno(errno).setErrorMessage(message).setDebugInfo(debug).build();
}
public static ErrorResponse getErrorResponse(ErrorType type, POSIXErrno errno, String message, Throwable cause) {
return ErrorResponse.newBuilder().setErrorType(type).setPosixErrno(errno).setErrorMessage(message).setDebugInfo(OutputUtils.stackTraceToString(cause)).build();
}
public static ErrorResponse getErrorResponse(ErrorType type, POSIXErrno errno, String message) {
return ErrorResponse.newBuilder().setErrorType(type).setPosixErrno(errno).setErrorMessage(message).build();
}
public static ErrorResponse getInternalServerError(Throwable cause) {
return ErrorResponse.newBuilder().setErrorType(ErrorType.INTERNAL_SERVER_ERROR).setPosixErrno(POSIXErrno.POSIX_ERROR_EIO).
setErrorMessage(cause.toString()).setDebugInfo(OutputUtils.stackTraceToString(cause)).build();
}
public static ErrorResponse getInternalServerError(Throwable cause, String additionalErrorMessage) {
return ErrorResponse.newBuilder().setErrorType(ErrorType.INTERNAL_SERVER_ERROR).setPosixErrno(POSIXErrno.POSIX_ERROR_EIO).
setErrorMessage(additionalErrorMessage + "; " + cause.toString()).setDebugInfo(OutputUtils.stackTraceToString(cause)).build();
}
public static String formatError(ErrorResponse error) {
if (error == null)
return "no error";
return error.getErrorType()+"/"+error.getPosixErrno()+": "+error.getErrorMessage() +(error.hasDebugInfo() ? ";\n"+error.getDebugInfo() : "");
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.utils;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.Message;
import java.io.IOException;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader;
/**
*
* @author bjko
*/
public class PBRPCDatagramPacket {
private final RPCHeader header;
private final Message message;
public PBRPCDatagramPacket(ReusableBuffer datagramToParse, Message msgPrototype) throws IOException {
RecordMarker rm = new RecordMarker(datagramToParse.getBuffer());
ReusableBufferInputStream rbis = new ReusableBufferInputStream(datagramToParse);
final int origLimit = datagramToParse.limit();
assert(origLimit == rm.HDR_SIZE+rm.getRpcHeaderLength()+rm.getMessageLength());
datagramToParse.limit(rm.HDR_SIZE+rm.getRpcHeaderLength());
header = RPCHeader.newBuilder().mergeFrom(rbis).build();
datagramToParse.limit(origLimit);
message = msgPrototype.newBuilderForType().mergeFrom(rbis).build();
}
public PBRPCDatagramPacket(RPCHeader header, Message message) {
this.header = header;
this.message = message;
}
public ReusableBuffer assembleDatagramPacket() throws IOException {
ReusableBufferOutputStream out = new ReusableBufferOutputStream(RecordMarker.HDR_SIZE+getHeader().getSerializedSize()+getMessage().getSerializedSize());
RecordMarker rm = new RecordMarker(getHeader().getSerializedSize(), getMessage().getSerializedSize(), 0);
rm.writeFragmentHeader(out);
getHeader().writeTo(out);
getMessage().writeTo(out);
out.flip();
ReusableBuffer[] bufs = out.getBuffers();
assert(bufs.length == 1);
return bufs[0];
}
/**
* @return the header
*/
public RPCHeader getHeader() {
return header;
}
/**
* @return the message
*/
public Message getMessage() {
return message;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.utils;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
*
* @author bjko
*/
public class RecordMarker {
public static final int HDR_SIZE = Integer.SIZE/8*3;
private final int rpcHeaderLength;
private final int messageLength;
private final int dataLength;
public RecordMarker(ByteBuffer buf) throws IOException {
rpcHeaderLength = buf.getInt();
messageLength = buf.getInt();
dataLength = buf.getInt();
}
public RecordMarker(int rpcHeaderLength, int messageLength, int dataLength) {
this.rpcHeaderLength = rpcHeaderLength;
this.messageLength = messageLength;
this.dataLength = dataLength;
}
public void writeFragmentHeader(ByteBuffer buf) {
buf.putInt(getRpcHeaderLength());
buf.putInt(getMessageLength());
buf.putInt(getDataLength());
}
public void writeFragmentHeader(ReusableBufferOutputStream out) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(HDR_SIZE);
buf.putInt(getRpcHeaderLength());
buf.putInt(getMessageLength());
buf.putInt(getDataLength());
out.write(buf.array());
}
/**
* @return the rpcHeaderLength
*/
public int getRpcHeaderLength() {
return rpcHeaderLength;
}
/**
* @return the messageLength
*/
public int getMessageLength() {
return messageLength;
}
/**
* @return the dataLength
*/
public int getDataLength() {
return dataLength;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.utils;
import java.io.IOException;
import java.io.InputStream;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
/**
*
* @author bjko
*/
public class ReusableBufferInputStream extends InputStream {
private final ReusableBuffer data;
public ReusableBufferInputStream(ReusableBuffer data) {
assert(data != null);
this.data = data;
}
@Override
public int read() throws IOException {
if (data.hasRemaining())
return data.get();
else
return -1;
}
@Override
public int read(byte[] buf, int offset, int length) throws IOException {
final int bytesRemaining = data.remaining();
if (bytesRemaining == 0)
return -1;
final int bytesToRead = (bytesRemaining >= length) ? length : bytesRemaining;
data.get(buf, offset, bytesToRead);
return bytesToRead;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.pbrpc.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
/**
*
* @author bjko
*/
public class ReusableBufferOutputStream extends OutputStream {
public static final int BUFF_SIZE = 1024*8;
private final int bufSize;
private final ReusableBuffer firstBuffer;
private List<ReusableBuffer> buffers;
private ReusableBuffer currentBuffer;
private int length;
public ReusableBufferOutputStream(int bufSize) {
this.bufSize = bufSize;
firstBuffer = BufferPool.allocate(bufSize);
currentBuffer = firstBuffer;
length = 0;
}
private ReusableBuffer checkAndGetBuffer(int requiredSpace) {
if (currentBuffer.remaining() < requiredSpace) {
if (buffers == null)
buffers = new ArrayList<ReusableBuffer>(15);
final int newBufSize = (bufSize >= requiredSpace) ? bufSize : requiredSpace;
final ReusableBuffer buf = BufferPool.allocate(newBufSize);
buffers.add(buf);
currentBuffer = buf;
}
return currentBuffer;
}
public void appendBuffer(ReusableBuffer buffer) {
currentBuffer = buffer;
if (buffers == null)
buffers = new ArrayList<ReusableBuffer>(15);
buffer.position(buffer.limit());
buffers.add(buffer);
length += buffer.remaining();
}
public void flip() {
firstBuffer.flip();
if (buffers != null) {
for (ReusableBuffer buffer : buffers) {
buffer.flip();
}
}
currentBuffer = firstBuffer;
}
public void freeBuffers() {
BufferPool.free(firstBuffer);
if (buffers != null) {
for (ReusableBuffer buffer : buffers) {
BufferPool.free(buffer);
}
}
}
@Override
public void write(int b) throws IOException {
checkAndGetBuffer(1).put((byte)b);
length++;
}
public void write(byte b[], int off, int len) throws IOException {
checkAndGetBuffer(len).put(b, off, len);
length += len;
}
public ReusableBuffer[] getBuffers() {
if (buffers == null) {
return new ReusableBuffer[]{firstBuffer};
} else {
ReusableBuffer[] arr = new ReusableBuffer[buffers.size()+1];
arr[0] = firstBuffer;
for (int i = 1; i <= buffers.size(); i++)
arr[i] = buffers.get(i-1);
return arr;
}
}
public int length() {
return length;
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.trace;
import java.io.FileOutputStream;
import java.io.IOException;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
/**
*
* @author bjko
*/
public class Tracer {
/**
* Set this to true to enable trace log file for all requests.
*
* @attention: MUST BE SET TO FALSE FOR NORMAL OPERATIONS.
*/
public static final boolean COLLECT_TRACES = false;
public enum TraceEvent {
RECEIVED('>'), RESPONSE_SENT('<'), ERROR_SENT('E');
private final char eventType;
TraceEvent(char eventType) {
this.eventType = eventType;
}
public char getEventType() {
return this.eventType;
}
};
private static Tracer theInstance;
private final FileOutputStream fos;
private Tracer(String traceFileName) throws IOException {
theInstance = this;
fos = new FileOutputStream(traceFileName, true);
if (Logging.isInfo())
Logging.logMessage(Logging.LEVEL_INFO, Category.misc, this,
"TRACING IS ENABLED, THIS WILL CAUSE PERFORMANCE TO BE REDUCED!");
fos.write("#requestId;internal rq sequence no;event;component;message\n".getBytes());
}
/**
* Initialize the tracer.
*
* @param traceFileName
* file name to write trace data to (append mode).
* @throws java.io.IOException
* if the file cannot be opened
*/
public static void initialize(String traceFileName) throws IOException {
new Tracer(traceFileName);
}
private void writeTraceRecord(String requestId, long intRqSeqNo, TraceEvent event, String component,
String message) {
StringBuffer sb = new StringBuffer();
if (requestId != null)
sb.append(requestId);
sb.append(';');
sb.append(intRqSeqNo);
sb.append(';');
sb.append(event.getEventType());
sb.append(';');
if (component != null)
sb.append(component);
sb.append(';');
if (message != null)
sb.append(message);
sb.append("\n");
try {
fos.write(sb.toString().getBytes());
} catch (IOException ex) {
Logging.logError(Logging.LEVEL_ERROR, this, ex);
}
}
public static void trace(String requestId, long intRqSeqNo, TraceEvent event, String component,
String message) {
assert (theInstance != null) : "Tracer not initialized";
theInstance.writeTraceRecord(requestId, intRqSeqNo, event, component, message);
}
@Override
public void finalize() {
try {
fos.close();
} catch (IOException ex) {
}
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class CLIParser {
public static final class CliOption {
public enum OPTIONTYPE {
NUMBER, STRING, SWITCH, URL, FILE
};
public final OPTIONTYPE optType;
public Boolean switchValue;
public String stringValue;
public Long numValue;
public PBRPCServiceURL urlValue;
public File fileValue;
public String urlDefaultProtocol;
public int urlDefaultPort;
public String usageParams;
public String usageText;
public CliOption(OPTIONTYPE oType) {
this.optType = oType;
if (optType == OPTIONTYPE.SWITCH)
switchValue = new Boolean(false);
}
public CliOption(OPTIONTYPE oType, String usageText, String usageParams) {
this(oType);
this.usageText = usageText;
this.usageParams = usageParams == null? "": usageParams;
}
}
public static void parseCLI(String[] args, Map<String, CliOption> options, List<String> arguments)
throws IllegalArgumentException {
List<String> argList = Arrays.asList(args);
Iterator<String> iter = argList.iterator();
while (iter.hasNext()) {
final String arg = iter.next().trim();
if (arg.startsWith("-")) {
// option
final String optName = arg.substring(1);
final CliOption option = options.get(optName);
if (option == null) {
throw new IllegalArgumentException(arg + " is not a valid option");
}
switch (option.optType) {
case SWITCH: {
option.switchValue = true;
break;
}
case STRING: {
if (iter.hasNext()) {
final String value = iter.next();
option.stringValue = value.trim();
} else {
throw new IllegalArgumentException(arg + " requires a string argument");
}
break;
}
case NUMBER: {
if (iter.hasNext()) {
final String value = iter.next();
try {
option.numValue = Long.valueOf(value.trim());
} catch (NumberFormatException ex) {
throw new IllegalArgumentException(arg + " requires a integer argument and "
+ value + " is not an integer");
}
} else {
throw new IllegalArgumentException(arg + " requires a string argument");
}
break;
}
case URL: {
if (iter.hasNext()) {
final String value = iter.next();
try {
final PBRPCServiceURL tmp = new PBRPCServiceURL(value,
option.urlDefaultProtocol, option.urlDefaultPort);
option.urlValue = tmp;
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
} else {
throw new IllegalArgumentException(arg + " requires a string argument");
}
break;
}
case FILE: {
if (iter.hasNext()) {
final String value = iter.next();
try {
final File tmp = new File(value);
option.fileValue = tmp;
} catch (Exception ex) {
throw new IllegalArgumentException(arg + " requires <protocol>://<host>:<port>");
}
} else {
throw new IllegalArgumentException(arg + " requires a string argument");
}
break;
}
}
} else {
arguments.add(arg);
}
}
}
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.net.MalformedURLException;
/**
*
* @author bjko
*/
public abstract class CLOption {
protected String shortName;
protected String longName;
protected String helpText;
protected boolean set;
public CLOption(String shortName, String longName, String helpText) {
this.shortName = shortName;
this.longName = longName;
this.helpText = helpText;
if ((shortName == null )&& (longName == null))
throw new IllegalArgumentException("must specify either a shortName or a longName or both");
}
public String getName() {
StringBuilder sb = new StringBuilder();
if (shortName != null) {
sb.append("-");
sb.append(shortName);
if (longName != null)
sb.append("/");
else
sb.append(" ");
}
if (longName != null) {
sb.append("--");
sb.append(longName);
sb.append("=");
}
return sb.toString();
}
public String getName(boolean useShortName) {
if (useShortName)
return this.shortName;
else
return this.longName;
}
public abstract String getHelp();
/**
* called only when the option is present
* @param value
* @throws IllegalArgumentException
*/
public void parse(String value) throws IllegalArgumentException {
set = true;
}
public boolean isSet() {
return set;
}
public abstract boolean requiresArgument();
@Override
public String toString() {
return getHelp();
}
public static class Switch extends CLOption {
protected boolean value;
public Switch(String shortName, String longName, String helpText) {
super(shortName,longName,helpText);
}
@Override
public String getHelp() {
return getName()+helpText;
}
@Override
public void parse(String value) throws IllegalArgumentException {
super.parse(value);
this.value = true;
}
@Override
public boolean requiresArgument() {
return false;
}
public boolean getValue() {
return value;
}
}
public static class StringValue extends CLOption {
protected String value;
public StringValue(String shortName, String longName, String helpText) {
super(shortName,longName,helpText);
}
@Override
public String getHelp() {
return getName()+"<string> "+helpText;
}
@Override
public void parse(String value) throws IllegalArgumentException {
super.parse(value);
this.value = value;
}
@Override
public boolean requiresArgument() {
return true;
}
public String getValue() {
return value;
}
}
public static class IntegerValue extends CLOption {
protected int value;
public IntegerValue(String shortName, String longName, String helpText) {
super(shortName,longName,helpText);
}
@Override
public String getHelp() {
return getName()+"<number> "+helpText;
}
@Override
public void parse(String value) throws IllegalArgumentException {
super.parse(value);
try {
this.value = Integer.valueOf(value);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("'"+value+"' is not a valid number");
}
}
@Override
public boolean requiresArgument() {
return true;
}
public int getValue() {
return value;
}
}
public static class URLValue extends CLOption {
protected PBRPCServiceURL value;
protected final String defaultSchema;
protected final int defaultPort;
public URLValue(String shortName, String longName, String helpText,
String defaultSchema, int defaultPort) {
super(shortName,longName,helpText);
this.defaultSchema = defaultSchema;
this.defaultPort = defaultPort;
}
@Override
public String getHelp() {
return getName()+"[<schema>://]<hostname>[:<port>] "+helpText+
" (default schema is "+defaultSchema+", default port is "+defaultPort+")";
}
@Override
public void parse(String value) throws IllegalArgumentException {
super.parse(value);
try {
this.value = new PBRPCServiceURL(value, defaultSchema, defaultPort);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException("'"+value+"' is not a valid URL ("+ex.getMessage()+")");
}
}
@Override
public boolean requiresArgument() {
return true;
}
public PBRPCServiceURL getValue() {
return value;
}
}
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author bjko
*/
public class CLOptionParser {
private final String programName;
private final List<CLOption> options;
private final List<String> arguments;
public CLOptionParser(String programName) {
this.programName = programName;
options = new LinkedList<CLOption>();
arguments = new LinkedList<String>();
}
public CLOption addOption(CLOption option) {
CLOption rv = option;
for (CLOption tmp : options) {
if (( (tmp.getName(true) == null) || tmp.getName(true).equals(option.getName(true)) ) &&
( (tmp.getName(false) == null) || tmp.getName(false).equals(option.getName(false))) ) {
rv = tmp;
break;
}
}
if (rv == option)
options.add(option);
return rv;
}
public void printUsage(String arguments) {
System.out.println(programName+" [options] "+arguments);
printOptionHelp();
System.out.println("");
}
public void printOptionHelp() {
for (CLOption option : options) {
System.out.println("\t"+option.getHelp());
}
}
public void parse(String[] args) throws IllegalArgumentException {
int position = 0;
boolean nextIsValue = false;
CLOption currentOption = null;
while (position < args.length) {
if (nextIsValue) {
assert(currentOption != null);
currentOption.parse(args[position]);
currentOption = null;
nextIsValue = false;
} else {
if (args[position].charAt(0) == '-') {
boolean useShortName;
String name;
String value = null;
if (args[position].charAt(1) == '-') {
useShortName = false;
name = args[position].substring(2);
if (name.length() == 0) {
throw new IllegalArgumentException("-- is not a valid option");
}
int posEq = name.indexOf("=");
if (posEq >= 0) {
value = name.substring(posEq+1);
name = name.substring(0, posEq);
}
} else {
useShortName = true;
name = args[position].substring(1);
if (name.length() == 0) {
throw new IllegalArgumentException("- is not a valid option");
}
}
boolean optFound = false;
for (CLOption option : options) {
final String optName = option.getName(useShortName);
if ((optName != null) && optName.equals(name)) {
if (option.requiresArgument()) {
if (value == null) {
currentOption = option;
nextIsValue = true;
} else {
option.parse(value);
}
} else {
option.parse(null);
}
optFound = true;
break;
}
}
if (!optFound)
throw new IllegalArgumentException("'"+args[position]+"' is not a valid option");
} else {
arguments.add(args[position]);
}
}
position++;
}
if (nextIsValue) {
throw new IllegalArgumentException("expected value for option '"+currentOption.getName()+"'");
}
}
public List<String> getArguments() {
return this.arguments;
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2008-2011 by Bjoern Kolbeck, Jan Stender,
* Felix Langner, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
/**
* A class containing helper functions for working with the local file system.
*
* @author stender
*/
public class FSUtils {
/**
* Recursively deletes all contents of the given directory.
*
* @param file
* the directory to delete
*/
public static void delTree(File file) {
if (!file.exists())
return;
File[] fileList;
if ((fileList = file.listFiles())!=null){
for (File f : fileList) {
if (f.isDirectory())
delTree(f);
else
f.delete();
}
}
file.delete();
}
/**
* Copies a whole directory tree to another directory.
*
* @param srcFile
* the source tree
* @param trgFile
* the target point where to copy the source tree
* @throws IOException
* if an I/O error occurs
*/
public static void copyTree(File srcFile, File trgFile) throws IOException {
if (srcFile.isDirectory()) {
trgFile.mkdir();
for (File file : srcFile.listFiles()) {
copyTree(file, new File(trgFile, file.getName()));
}
} else {
FileChannel in = null, out = null;
try {
in = new FileInputStream(srcFile).getChannel();
out = new FileOutputStream(trgFile).getChannel();
in.transferTo(0, in.size(), out);
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}
}
/**
* Returns the free disk space on the partition storing the given directory.
*
* @param dir
* the directory stored in the partition
* @return the free disk space
*/
public static long getFreeSpace(String dir) {
return new File(dir).getFreeSpace();
}
/**
* Returns the available disk space on the partition storing the given directory.
*
* @param dir
* the directory stored in the partition
* @return the available disk space (for non-privileged users)
*/
public static long getUsableSpace(String dir) {
return new File(dir).getUsableSpace();
}
public static File[] listRecursively(File rootDir, FileFilter filter) {
List<File> list = new ArrayList<File>();
listRecursively(rootDir, filter, list);
return list.toArray(new File[list.size()]);
}
private static void listRecursively(File rootDir, FileFilter filter, List<File> list) {
if (!rootDir.exists())
return;
// first, all files in subdirectories
File[] nestedDirs = rootDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File dir : nestedDirs)
listRecursively(dir, filter, list);
for (File f : rootDir.listFiles(filter))
list.add(f);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2010, Konrad-Zuse-Zentrum fuer Informationstechnik Berlin
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of the Konrad-Zuse-Zentrum fuer Informationstechnik Berlin
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* AUTHORS: Bjoern Kolbeck (ZIB)
*/
package org.xtreemfs.foundation.util;
/**
*
* @author bjko
*/
public class InvalidUsageException extends Exception {
private static final long serialVersionUID = -5461559345851901506L;
public InvalidUsageException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,264 @@
/*
* Copyright (c) 2008-2011 by Jan Stender, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
/**
*
* @author bjko
*/
public final class OutputUtils {
public static final char[] trHex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static final byte[] fromHex;
static {
fromHex = new byte[128];
fromHex['0'] = 0;
fromHex['1'] = 1;
fromHex['2'] = 2;
fromHex['3'] = 3;
fromHex['4'] = 4;
fromHex['5'] = 5;
fromHex['6'] = 6;
fromHex['7'] = 7;
fromHex['8'] = 8;
fromHex['9'] = 9;
fromHex['A'] = 10;
fromHex['a'] = 10;
fromHex['B'] = 11;
fromHex['b'] = 11;
fromHex['C'] = 12;
fromHex['c'] = 12;
fromHex['D'] = 13;
fromHex['d'] = 13;
fromHex['E'] = 14;
fromHex['e'] = 14;
fromHex['F'] = 15;
fromHex['f'] = 15;
}
public static final String byteToHexString(byte b) {
StringBuilder sb = new StringBuilder(2);
sb.append(trHex[((b >> 4) & 0x0F)]);
sb.append(trHex[(b & 0x0F)]);
return sb.toString();
}
public static final String byteArrayToHexString(byte[] array) {
StringBuilder sb = new StringBuilder(2 * array.length);
for (byte b : array) {
sb.append(trHex[((b >> 4) & 0x0F)]);
sb.append(trHex[(b & 0x0F)]);
}
return sb.toString();
}
public static final String byteArrayToFormattedHexString(byte[] array) {
return byteArrayToFormattedHexString(array, 0, array.length);
}
public static final String byteArrayToFormattedHexString(byte[] array, int offset, int len) {
StringBuilder sb = new StringBuilder(2 * len);
for (int i = offset; i < offset + len; i++) {
sb.append(trHex[((array[i] >> 4) & 0x0F)]);
sb.append(trHex[(array[i] & 0x0F)]);
if ((i - offset) % 4 == 3) {
if ((i - offset) % 16 == 15)
sb.append("\n");
else
sb.append(" ");
}
}
return sb.toString();
}
public static final String stackTraceToString(Throwable th) {
PrintStream ps = null;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ps = new PrintStream(out);
if (th != null)
th.printStackTrace(ps);
return new String(out.toByteArray());
} finally {
if (ps != null)
ps.close();
}
}
public static String formatBytes(long bytes) {
double kb = bytes / 1024.0;
double mb = bytes / (1024.0 * 1024.0);
double gb = bytes / (1024.0 * 1024.0 * 1024.0);
double tb = bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0);
if (tb >= 1.0) {
return String.format("%.2f TB", tb);
} else if (gb >= 1.0) {
return String.format("%.2f GB", gb);
} else if (mb >= 1.0) {
return String.format("%.2f MB", mb);
} else if (kb >= 1.0) {
return String.format("%.2f kB", kb);
} else {
return bytes + " bytes";
}
}
public static String escapeToXML(String st) {
st = st.replace("&", "&amp;");
st = st.replace("'", "&apos;");
st = st.replace("<", "&lt;");
st = st.replace(">", "&gt;");
st = st.replace("\"", "&quot;");
return st;
}
public static String unescapeFromXML(String st) {
st = st.replace("&amp;", "&");
st = st.replace("&apos;", "'");
st = st.replace("&lt;", "<");
st = st.replace("&gt;", ">");
st = st.replace("&quot;", "\"");
return st;
}
public static String encodeBase64(byte[] bytes) {
return new String(Base64.encodeBase64(bytes));
}
public static byte[] decodeBase64(String s) throws IOException {
return Base64.decodeBase64(s.getBytes());
}
public static byte[] hexStringToByteArray(String hexString) {
assert (hexString.length() % 2 == 0);
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
int b = Integer.parseInt(hexString.substring(i, i + 2), 16);
bytes[i / 2] = b >= 128 ? (byte) (b - 256) : (byte) b;
}
return bytes;
}
/**
* Writes an integer as a hex string to sb starting with the LSB.
*
* @param sb
* @param value
*/
public static void writeHexInt(final StringBuffer sb, final int value) {
sb.append(OutputUtils.trHex[(value & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 4) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 8) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 12) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 16) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 20) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 24) & 0x0F)]);
sb.append(OutputUtils.trHex[((value >> 28) & 0x0F)]);
}
public static void writeHexLong(final StringBuffer sb, final long value) {
OutputUtils.writeHexInt(sb, (int) (value & 0xFFFFFFFF));
OutputUtils.writeHexInt(sb, (int) (value >> 32));
}
/**
* Reads an integer from a hex string (starting with the LSB).
*
* @param str
* @param position
* @return
*/
public static int readHexInt(final String str, int position) {
int value = OutputUtils.fromHex[str.charAt(position)];
value += ((int) OutputUtils.fromHex[str.charAt(position + 1)]) << 4;
value += ((int) OutputUtils.fromHex[str.charAt(position + 2)]) << 8;
value += ((int) OutputUtils.fromHex[str.charAt(position + 3)]) << 12;
value += ((int) OutputUtils.fromHex[str.charAt(position + 4)]) << 16;
value += ((int) OutputUtils.fromHex[str.charAt(position + 5)]) << 20;
value += ((int) OutputUtils.fromHex[str.charAt(position + 6)]) << 24;
value += ((int) OutputUtils.fromHex[str.charAt(position + 7)]) << 28;
return value;
}
public static long readHexLong(final String str, int position) {
int low = OutputUtils.readHexInt(str, position);
int high = OutputUtils.readHexInt(str, position + 8);
// calculate the value: left-shift the upper 4 bytes by 32 bit and
// append the lower 32 bit
long value = ((long) high) << 32 | (((long) low) & 4294967295L);
return value;
}
public static String getThreadDump() {
StringBuilder sb = new StringBuilder();
sb.append("<HTML><BODY><H1>THREAD STATES</H1><PRE>");
final Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
for (Thread t : traces.keySet()) {
sb.append("<B>thread: ");
sb.append(t.getName());
sb.append("</B>\n");
final StackTraceElement[] elems = traces.get(t);
for (int i = elems.length - 1; i >= 0; i--) {
sb.append(elems[i].toString());
sb.append("\n");
}
sb.append("\n");
}
sb.append("</PRE></BODY></HTML>");
return sb.toString();
}
/**
* Formats number of seconds to a string consists of number of seconds, minutes, hours or days and the
* corresponding entity (e.g. "3 minutes" if seconds is between 180 and 239).
*
* @param seconds
* @return
*/
public static String SecondsToString(long seconds) {
String timeString = null;
if (seconds < 60) {
// seconds less than one minute
timeString = seconds + " seconds";
} else if (seconds < 3600) {
// seconds less than one hour
timeString = (seconds / 60) + " minutes";
} else if (seconds < 86400) {
// seconds less than one day
timeString = (seconds / 3600) + " hours";
} else {
// seconds equals or longer than one day
timeString = (seconds / 86400) + " days";
}
return timeString;
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.net.MalformedURLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author bjko
*/
public class PBRPCServiceURL {
static {
urlPattern = Pattern.compile("((pbrpc[gs]?):\\/\\/)?([^:]+)(:([0-9]+))?/?");
}
private static final Pattern urlPattern;
private final String protocol;
private final String host;
private final int port;
public PBRPCServiceURL(String url, String defaultProtocol, int defaultPort) throws MalformedURLException {
//parse URL
Matcher m = urlPattern.matcher(url);
if (m.matches()) {
if (m.group(2) != null)
protocol = m.group(2);
else
protocol = defaultProtocol;
host = m.group(3);
if (m.group(4) != null)
port = Integer.valueOf(m.group(4).substring(1));
else
port = defaultPort;
} else
throw new MalformedURLException("'"+url+"' is not a valid XtreemFS service URL");
}
/**
* @return the protocol
*/
public String getProtocol() {
return protocol;
}
/**
* @return the host
*/
public String getHost() {
return host;
}
/**
* @return the port
*/
public int getPort() {
return port;
}
public String toString() {
return protocol+"://"+host+":"+port;
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.util;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.logging.Logging.Category;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServer;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequest;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequestListener;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
/**
*
* @author bjko
*/
public class PingServer {
public static final String CERT_DIR = "../../tests/certs/";
public static void main(String[] args) {
try {
Logging.start(Logging.LEVEL_DEBUG, Category.all);
SSLOptions ssl = null;
if (true) {
ssl = new SSLOptions(new FileInputStream(PingServer.CERT_DIR + "Client.p12"),
"passphrase", SSLOptions.PKCS12_CONTAINER, new FileInputStream(PingServer.CERT_DIR + "trusted.jks"),
"passphrase", SSLOptions.JKS_CONTAINER, false, true, null, null);
}
RPCNIOSocketServer server = new RPCNIOSocketServer(12345, null, new RPCServerRequestListener() {
int cnt = 0;
@Override
public void receiveRecord(RPCServerRequest rq) {
try {
ReusableBufferInputStream is = new ReusableBufferInputStream(rq.getMessage());
Ping.PingRequest pingRq = Ping.PingRequest.parseFrom(is);
Ping.PingResponse resp = null;
if (pingRq.getSendError()) {
resp = Ping.PingResponse.newBuilder().setError(Ping.PingResponse.PingError.newBuilder().setErrorMessage("error message")).build();
} else {
Ping.PingResponse.PingResult result = Ping.PingResponse.PingResult.newBuilder().setText(pingRq.getText()).build();
resp = Ping.PingResponse.newBuilder().setResult(result).build();
}
ReusableBuffer data = null;
if (rq.getData() != null) {
data = rq.getData().createViewBuffer();
data.limit(data.capacity());
data.position(data.capacity());
}
rq.sendResponse(resp,data);
cnt++;
if (cnt%1000 == 0) {
System.out.println(BufferPool.getStatus());
}
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
} finally {
rq.freeBuffers();
}
}
}, ssl);
server.start();
server.waitForStartup();
System.out.println("PING server running");
} catch (Exception ex) {
Logger.getLogger(PingServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 2014 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.buffer;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* Tests different sequences of {@link BufferPool#allocate(int)} and {@link BufferPool#free(ReusableBuffer)}
* operations, some also regarding view buffers.
*
* Please note that {@link BufferPool} is a singleton and therefore the pool size increases as the number of
* run tests does. Therefore, each test has to evaluate changes in the pool size relative to the pool size at
* the start of test.
*
*/
public class BufferPoolTest {
public static final int TEST_BUFFER_SIZE = 8192;
@Test
public final void testSimpleAllocateAndFree() {
ReusableBuffer buf = null;
// There may be already a buffer pooled. If not, the pool size will stay 0 after an allocate().
int currentPoolSize = Math.max(0, BufferPool.getPoolSize(TEST_BUFFER_SIZE) - 1);
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals("BufferPool must be empty because a buffer was only allocated but not returned so far.",
currentPoolSize,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals("One buffer must have been returned and pooled.", currentPoolSize + 1,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals("Pooled buffer must have been re-allocated.", currentPoolSize,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals("One buffer must have been returned and pooled again.", currentPoolSize + 1,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
}
@Test
public final void testReusableViewBuffers() {
ReusableBuffer buf = null;
// There may be already a buffer pooled. If not, the pool size will stay 0 after an allocate().
int currentPoolSize = Math.max(0, BufferPool.getPoolSize(TEST_BUFFER_SIZE) - 1);
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals(currentPoolSize + 1, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
ReusableBuffer viewBuffer = buf.createViewBuffer();
BufferPool.free(viewBuffer);
assertEquals("Buffer not returned to pool yet since one reference is left.", currentPoolSize,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals("Buffer must have been returned to pool since no reference is left.", currentPoolSize + 1,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
}
@Test
public final void testReusableViewBuffersOfReusableViewBuffers() {
ReusableBuffer buf = null;
// There may be already a buffer pooled. If not, the pool size will stay 0 after an allocate().
int currentPoolSize = Math.max(0, BufferPool.getPoolSize(TEST_BUFFER_SIZE) - 1);
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals(currentPoolSize + 1, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
ReusableBuffer viewBuffer = buf.createViewBuffer();
// Create a view buffer of a view buffer.
ReusableBuffer viewBuffer2 = viewBuffer.createViewBuffer();
BufferPool.free(viewBuffer2);
assertEquals("Buffer not returned to pool yet since two references are left.", currentPoolSize,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(viewBuffer);
assertEquals("Buffer not returned to pool yet since one reference is left.", currentPoolSize,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals("Buffer must have been returned to pool since no reference is left.", currentPoolSize + 1,
BufferPool.getPoolSize(TEST_BUFFER_SIZE));
}
private void assertThatAssertionsAreEnabled() {
boolean assertOn = false;
// *assigns* true if assertions are on.
assert assertOn = true;
assertTrue("Enable assertions or this test won't work correctly.", assertOn);
}
@Test(expected = AssertionError.class)
public final void testDoubleFreeThrows() {
assertThatAssertionsAreEnabled();
ReusableBuffer buf = null;
// There may be already a buffer pooled. If not, the pool size will stay 0 after an allocate().
int currentPoolSize = Math.max(0, BufferPool.getPoolSize(TEST_BUFFER_SIZE) - 1);
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals(currentPoolSize + 1, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
// Double free will trigger assertion.
BufferPool.free(buf);
}
@Test(expected = AssertionError.class)
public final void testDoubleFreeOfRecursiveViewBuffersThrows() {
assertThatAssertionsAreEnabled();
ReusableBuffer buf = null;
// There may be already a buffer pooled. If not, the pool size will stay 0 after an allocate().
int currentPoolSize = Math.max(0, BufferPool.getPoolSize(TEST_BUFFER_SIZE) - 1);
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
BufferPool.free(buf);
assertEquals(currentPoolSize + 1, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
buf = BufferPool.allocate(TEST_BUFFER_SIZE);
assertEquals(currentPoolSize, BufferPool.getPoolSize(TEST_BUFFER_SIZE));
ReusableBuffer viewBuffer = buf.createViewBuffer();
// Create a view buffer of a view buffer.
ReusableBuffer viewBuffer2 = viewBuffer.createViewBuffer();
BufferPool.free(viewBuffer2);
BufferPool.free(viewBuffer);
BufferPool.free(buf);
// Double free will trigger assertion.
BufferPool.free(viewBuffer2);
}
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2010 by Bjoern Kolbeck, Zuse Institute Berlin
* 2014 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.foundation.buffer;
import static org.junit.Assert.*;
import org.junit.Test;
public class ReusableBufferTest {
@Test
public final void testArray() {
ReusableBuffer rb = ReusableBuffer.wrap("Yagga Yagga".getBytes());
ReusableBuffer vb = rb.createViewBuffer();
vb.position(0);
vb.limit(5);
String result = new String(vb.array());
assertEquals("Yagga", result);
}
@Test
public final void testRecursiveNonResuableViewBuffer() {
ReusableBuffer rb = ReusableBuffer.wrap("Yagga Yagga".getBytes());
assertFalse(rb.isReusable());
ReusableBuffer viewBuffer = rb.createViewBuffer();
assertFalse(viewBuffer.isReusable());
ReusableBuffer viewBuffer2 = viewBuffer.createViewBuffer();
assertFalse(viewBuffer2.isReusable());
}
@Test
public final void testNonResuableViewBufferHasIndependentPositions() {
ReusableBuffer rb = ReusableBuffer.wrap("Yagga Yagga".getBytes());
assertFalse(rb.isReusable());
rb.position(0);
rb.limit(5);
ReusableBuffer viewBuffer = rb.createViewBuffer();
assertFalse(viewBuffer.isReusable());
viewBuffer.position(1);
viewBuffer.limit(4);
assertEquals(0, rb.position());
assertEquals(5, rb.limit());
assertEquals(1, viewBuffer.position());
assertEquals(4, viewBuffer.limit());
ReusableBuffer viewBufferOfViewBuffer = viewBuffer.createViewBuffer();
assertFalse(viewBufferOfViewBuffer.isReusable());
viewBufferOfViewBuffer.position(2);
viewBufferOfViewBuffer.limit(3);
assertEquals(0, rb.position());
assertEquals(5, rb.limit());
assertEquals(1, viewBuffer.position());
assertEquals(4, viewBuffer.limit());
assertEquals(2, viewBufferOfViewBuffer.position());
assertEquals(3, viewBufferOfViewBuffer.limit());
}
@Test
public final void testRange() {
// Test with a view buffer and with a reusable buffer.
ReusableBuffer[] buffers = new ReusableBuffer[] { ReusableBuffer.wrap("Yagga Yagga".getBytes()),
BufferPool.allocate(12) };
for (ReusableBuffer buf : buffers) {
buf.range(1, 4);
assertEquals(0, buf.position());
assertEquals(4, buf.limit());
assertEquals(4, buf.capacity());
assertEquals(4, buf.remaining());
// Now create a view buffer which will have a different range.
ReusableBuffer viewBuf = buf.createViewBuffer();
viewBuf.range(2, 2);
assertEquals(0, viewBuf.position());
assertEquals(2, viewBuf.limit());
assertEquals(2, viewBuf.capacity());
assertEquals(2, viewBuf.remaining());
// The range of the original buffer was not affected.
assertEquals(0, buf.position());
assertEquals(4, buf.limit());
assertEquals(4, buf.capacity());
assertEquals(4, buf.remaining());
if (buf.isReusable()) {
BufferPool.free(buf);
}
}
}
@Test
public final void testShrink() {
// Test with a view buffer and with a reusable buffer.
ReusableBuffer[] buffers = new ReusableBuffer[] { ReusableBuffer.wrap("Yagga Yagga".getBytes()),
BufferPool.allocate(12) };
for (ReusableBuffer buf : buffers) {
buf.shrink(4);
assertEquals(0, buf.position());
assertEquals(4, buf.limit());
assertEquals(4, buf.capacity());
assertEquals(4, buf.remaining());
// Now create a view buffer which will have a different range.
ReusableBuffer viewBuf = buf.createViewBuffer();
viewBuf.shrink(2);
assertEquals(0, viewBuf.position());
assertEquals(2, viewBuf.limit());
assertEquals(2, viewBuf.capacity());
assertEquals(2, viewBuf.remaining());
// The range of the original buffer was not affected.
assertEquals(0, buf.position());
assertEquals(4, buf.limit());
assertEquals(4, buf.capacity());
assertEquals(4, buf.remaining());
if (buf.isReusable()) {
BufferPool.free(buf);
}
}
}
@Test
public final void testEnlarge() {
// Test with a view buffer and with a reusable buffer.
ReusableBuffer[] buffers = new ReusableBuffer[] { ReusableBuffer.wrap("Yagga Yagga".getBytes()),
BufferPool.allocate(11) };
for (ReusableBuffer buf : buffers) {
int originalBufSize = buf.capacity();
// When there is no underlying, larger buffer, enlarge won't have an effect (the capacity of the
// underlying buffer can be higher than the current buffer size.)
assertFalse(buf.enlarge(buf.capacityUnderlying() + 1));
// Enlarging to the current size should always work.
assertTrue(buf.enlarge(originalBufSize));
assertEquals(originalBufSize, buf.capacity());
// Create a view buffer first which is smaller than the original one.
buf.limit(originalBufSize / 2);
ReusableBuffer smallerBuf = buf.createViewBuffer();
// Enlarge it, but not larger than the underlying buffer.
int newBufSize = smallerBuf.capacity() * 2;
assertTrue(smallerBuf.enlarge(newBufSize));
assertEquals(0, buf.position());
assertEquals(newBufSize, smallerBuf.limit());
assertEquals(newBufSize, smallerBuf.capacity());
assertEquals(newBufSize, smallerBuf.remaining());
// You cannot enlarge it over the capacity of the original buffer.
assertFalse(smallerBuf.enlarge(buf.capacityUnderlying() + 1));
// The range of the original buffer was not affected.
assertEquals(0, buf.position());
assertEquals(originalBufSize / 2, buf.limit());
assertEquals(originalBufSize, buf.capacity());
assertEquals(originalBufSize / 2, buf.remaining());
if (buf.isReusable()) {
BufferPool.free(buf);
}
}
}
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.checksums;
import static org.junit.Assert.assertEquals;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.zip.Adler32;
import java.util.zip.Checksum;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xtreemfs.foundation.checksums.ChecksumAlgorithm;
import org.xtreemfs.foundation.checksums.ChecksumFactory;
import org.xtreemfs.foundation.checksums.ChecksumProvider;
import org.xtreemfs.foundation.checksums.provider.JavaChecksumProvider;
import org.xtreemfs.foundation.logging.Logging;
/**
* tests the checksum factory and some checksums
*
* 19.08.2008
*
* @author clorenz
*/
public class ChecksumFactoryTest {
private ChecksumFactory factory;
private ByteBuffer data;
@Before
public void setUp() throws Exception {
Logging.start(Logging.LEVEL_ERROR);
this.factory = ChecksumFactory.getInstance();
ChecksumProvider provider = new JavaChecksumProvider();
this.factory.addProvider(provider);
this.data = ByteBuffer.wrap(generateRandomBytes(1024 * 128));
}
@After
public void tearDown() throws Exception {
}
/**
* generates randomly filled byte-array
*
* @param length
* of the byte-array
*/
public static byte[] generateRandomBytes(int length) {
Random r = new Random();
byte[] bytes = new byte[length];
r.nextBytes(bytes);
return bytes;
}
/**
* tests the internal java checksum algorithms
*
* @throws Exception
*/
@Test
public void testJavaChecksumAlgorithm() throws Exception {
// compute checksum with xtreemfs ChecksumFactory
long xtreemfsValue = computeXtreemfsChecksum("Adler32", true);
// compute checksum with java API
Checksum javaAlgorithm = new Adler32();
javaAlgorithm.update(data.array(), 0, data.array().length);
long javaValue = javaAlgorithm.getValue();
// System.out.println(javaValue);
// System.out.println(xtreemfsValue);
assertEquals(javaValue, xtreemfsValue);
}
// /**
// * tests the internal java message digest algorithms
// * @throws Exception
// */
// public void testJavaMessageDigestAlgorithm() throws Exception {
// // compute checksum with xtreemfs ChecksumFactory
// String xtreemfsValue = computeXtreemfsChecksum("MD5", true);
//
// // compute checksum with java API
// String javaValue = computeJavaMessageDigest("MD5");
//
// // System.out.println("java: "+xtreemfsValue);
// // System.out.println("xtreemfs: "+javaValue.toString());
//
// assertEquals(javaValue.toString(), xtreemfsValue);
// }
/**
* @param algorithm
* @param returnAlgorithm
* @return
* @throws NoSuchAlgorithmException
*/
private long computeXtreemfsChecksum(String algorithm, boolean returnAlgorithm) throws NoSuchAlgorithmException {
// compute checksum with xtreemfs ChecksumFactory
ChecksumAlgorithm xtreemfsAlgorithm = factory.getAlgorithm(algorithm);
xtreemfsAlgorithm.update(data);
long xtreemfsValue = xtreemfsAlgorithm.getValue();
if (returnAlgorithm)
this.factory.returnAlgorithm(xtreemfsAlgorithm);
return xtreemfsValue;
}
private long computeJavaCheckSum(String algorithm) throws NoSuchAlgorithmException {
// compute checksum with java API
Adler32 adler = new Adler32();
adler.update(data.array());
return adler.getValue();
}
/**
* tests, if the internal buffer of the checksums is working correctly, if the checksum is used more than once
*
* @throws Exception
*/
@Test
public void testIfChecksumIsAlwaysTheSame() throws Exception {
ChecksumAlgorithm algorithm = factory.getAlgorithm("Adler32");
algorithm.update(data);
long oldValue = algorithm.getValue();
for (int i = 0; i < 32; i++) {
algorithm.update(data);
long newValue = algorithm.getValue();
assertEquals(oldValue, newValue);
oldValue = newValue;
}
}
/**
* tests, if the ChecksumFactory delivers only "thread-safe" instances (cache-pool)
*
* @throws Exception
*/
@Test
public void testThreadSafety() throws Exception {
final int THREADS = 8;
this.data = ByteBuffer.wrap(generateRandomBytes(1024 * 1024 * 32));
// compute correct checksum with java API
Long javaValue = computeJavaCheckSum("Adler32");
Callable<Long> computation = new Callable<Long>() {
@Override
public Long call() {
try {
// compute checksum with xtreemfs ChecksumFactory
long xtreemfsValue = computeXtreemfsChecksum("Adler32", true);
return xtreemfsValue;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return 0l;
} catch (Exception e) {
e.printStackTrace();
return 0l;
}
}
};
LinkedList<Future<Long>> results = useMultipleThreads(THREADS, computation);
// compare correct java checksum with xtreemfs checksums
for (Future<Long> result : results) {
assertEquals(javaValue, result.get());
}
}
/**
* tests, if the ChecksumFactory cache-pool works correctly
*
* @throws Exception
*/
@Test
public void testChecksumFactoryCache() throws Exception {
// FIXME: use bigger values for more comprehensive testing, but this will slow down the test
final int THREADS = 8;
final int ROUNDS = 50;
this.data = ByteBuffer.wrap(generateRandomBytes(1024 * 1024));
// compute correct checksum with java API
Long javaValue = computeJavaCheckSum("Adler32");
Callable<LinkedList<Long>> computation = new Callable<LinkedList<Long>>() {
@Override
public LinkedList<Long> call() {
try {
LinkedList<Long> values = new LinkedList<Long>();
boolean returning = false;
for (int i = 0; i < ROUNDS; i++) {
// compute checksum with xtreemfs ChecksumFactory
long xtreemfsValue = computeXtreemfsChecksum("Adler32", returning);
values.add(xtreemfsValue);
returning = !returning;
}
return values;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
};
LinkedList<Future<LinkedList<Long>>> results = useMultipleThreads(THREADS, computation);
// compare correct java checksum with xtreemfs checksums
for (Future<LinkedList<Long>> result : results) {
for (Long value : result.get()) {
assertEquals(javaValue, value);
}
}
}
/**
* executes a given computation in a couple of threads and returns the results of the computations
*
* @param THREADS
* @param computation
* @return a list of futures, which contain the results of the computations
* @throws InterruptedException
*/
private <E> LinkedList<Future<E>> useMultipleThreads(final int THREADS, Callable<E> computation)
throws InterruptedException {
LinkedList<Future<E>> results = new LinkedList<Future<E>>();
// compute xtreemfs checksums with multiple threads
ExecutorService executor = Executors.newFixedThreadPool(THREADS);
for (int i = 0; i < THREADS; i++) {
Future<E> tmp = executor.submit(computation);
results.add(tmp);
}
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);
return results;
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2008-2010 by Christian Lorenz,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.checksums;
import static org.junit.Assert.assertEquals;
import java.nio.ByteBuffer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xtreemfs.foundation.checksums.StringChecksumAlgorithm;
import org.xtreemfs.foundation.checksums.algorithms.SDBM;
import org.xtreemfs.foundation.logging.Logging;
/**
* some tests for the checksum algorithms, which are based on strings
*
* 02.09.2008
*
* @author clorenz
*/
public class StringChecksumAlgorithmTest {
private ByteBuffer bufferData;
private String stringData;
@Before
public void setUp() throws Exception {
Logging.start(Logging.LEVEL_ERROR);
this.stringData = "";
for (int i = 0; i < 1024; i++) {
this.stringData += "Test, ";
}
this.bufferData = ByteBuffer.wrap(stringData.getBytes());
}
@After
public void tearDown() throws Exception {
}
/**
* tests, if the SDBM algorithm generates the same checksum with a String-input and ByteBuffer-input
*
* @throws Exception
*/
@Test
public void testSDBMStringBufferEquality() throws Exception {
// compute checksum with xtreemfs ChecksumFactory
StringChecksumAlgorithm algorithm = new SDBM();
// string
algorithm.digest(stringData);
long stringValue = algorithm.getValue();
// buffer
algorithm.update(bufferData);
long bufferValue = algorithm.getValue();
// System.out.println(stringValue);
// System.out.println(bufferValue);
assertEquals(stringValue, bufferValue);
}
}

View File

@@ -0,0 +1,363 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.pbrpc;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.junit.Test;
import org.xtreemfs.foundation.pbrpc.Schemes;
import java.net.InetSocketAddress;
import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication;
import org.xtreemfs.foundation.pbrpc.client.RPCNIOSocketClient;
import org.xtreemfs.foundation.pbrpc.client.RPCResponse;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping.PingResponse;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.PingServiceClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.xtreemfs.foundation.SSLOptions;
import org.xtreemfs.foundation.TimeSync;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.client.PBRPCException;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping.PingRequest;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServer;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequest;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequestListener;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.util.OutputUtils;
import static org.junit.Assert.*;
/**
*
* @author bjko
*/
public class PBRPCClientServerTest {
private final int TEST_PORT = 12999;
private static final String[] schemes = new String[]{Schemes.SCHEME_PBRPC, Schemes.SCHEME_PBRPCS, Schemes.SCHEME_PBRPCG};
private static TimeSync ts = null;
public PBRPCClientServerTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
Logging.start(Logging.LEVEL_WARN, Logging.Category.all);
ts = TimeSync.initializeLocal(50);
}
@AfterClass
public static void tearDownClass() throws Exception {
ts.close();
}
// TODO add test methods here.
// The methods must be annotated with annotation @Test. For example:
//
// @Test
// public void hello() {}\
@Test
public void testRegularRPC() throws Exception {
ResponseCreator creator = new ResponseCreator() {
@Override
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception {
Ping.PingResponse.PingResult result = Ping.PingResponse.PingResult.newBuilder().setText(pRq.getText()).build();
Ping.PingResponse resp = Ping.PingResponse.newBuilder().setResult(result).build();
rq.sendResponse(resp, null);
}
};
TestExecutor exec = new TestExecutor() {
@Override
public void execTest(RPCNIOSocketClient client) throws Exception {
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, null);
assertEquals(response.get().getResult().getText(),"Hello World!");
response.freeBuffers();
response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Murpel", false, null);
assertEquals(response.get().getResult().getText(),"Murpel");
response.freeBuffers();
}
};
for (String scheme: schemes)
runTest(scheme, creator, exec);
}
@Test
public void testErrorResponse() throws Exception {
ResponseCreator creator = new ResponseCreator() {
@Override
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception {
rq.sendError(RPC.ErrorType.ERRNO, RPC.POSIXErrno.POSIX_ERROR_EIO, "YaggYagga");
}
};
TestExecutor exec = new TestExecutor() {
@Override
public void execTest(RPCNIOSocketClient client) throws Exception {
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, null);
try {
response.get();
fail("expected error response");
} catch (PBRPCException ex) {
assertEquals(ex.getErrorType(),RPC.ErrorType.ERRNO);
assertEquals(ex.getPOSIXErrno(),RPC.POSIXErrno.POSIX_ERROR_EIO);
}
response.freeBuffers();
}
};
for (String scheme: schemes)
runTest(scheme, creator, exec);
}
@Test
public void testInternalServerError() throws Exception {
ResponseCreator creator = new ResponseCreator() {
@Override
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception {
rq.sendRedirect("redirtome");
}
};
TestExecutor exec = new TestExecutor() {
@Override
public void execTest(RPCNIOSocketClient client) throws Exception {
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, null);
try {
response.get();
fail("expected error response");
} catch (PBRPCException ex) {
assertEquals(ex.getErrorType(),RPC.ErrorType.REDIRECT);
assertEquals(ex.getRedirectToServerUUID(),"redirtome");
}
response.freeBuffers();
}
};
for (String scheme: schemes)
runTest(scheme, creator, exec);
}
@Test
public void testDataPing() throws Exception {
ResponseCreator creator = new ResponseCreator() {
@Override
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception {
Ping.PingResponse.PingResult result = Ping.PingResponse.PingResult.newBuilder().setText(pRq.getText()).build();
Ping.PingResponse resp = Ping.PingResponse.newBuilder().setResult(result).build();
ReusableBuffer data = null;
if (rq.getData() != null) {
data = rq.getData().createViewBuffer();
data.limit(data.capacity());
data.position(data.capacity());
}
rq.sendResponse(resp, data);
}
};
TestExecutor exec = new TestExecutor() {
@Override
public void execTest(RPCNIOSocketClient client) throws Exception {
PingServiceClient psClient = new PingServiceClient(client,null);
byte[] arr = new byte[2065];
for (int i= 0; i < arr.length; i++)
arr[i] = 'x';
ReusableBuffer sendData = ReusableBuffer.wrap(arr);
// System.out.println("data: "+sendData);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, sendData);
assertEquals(response.get().getResult().getText(),"Hello World!");
ReusableBuffer recdata = response.getData();
assertTrue(recdata.hasRemaining());
while (recdata.hasRemaining()) {
assertEquals(recdata.get(),(byte)'x');
}
response.freeBuffers();
}
};
for (String scheme: schemes)
runTest(scheme, creator, exec);
}
@Test
public void testTimeout() throws Exception {
ResponseCreator creator = new ResponseCreator() {
@Override
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception {
//don't do anything
}
};
TestExecutor exec = new TestExecutor() {
@Override
public void execTest(RPCNIOSocketClient client) throws Exception {
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, null);
try {
response.get();
fail("expected error response");
} catch (IOException ex) {
}
response.freeBuffers();
}
};
for (String scheme: schemes)
runTest(scheme, creator, exec);
}
public void runTest(String pbrpcScheme, ResponseCreator creator, TestExecutor exec) throws Exception {
RPCNIOSocketClient client = null;
RPCNIOSocketServer server = null;
// System.out.println("loading ssl context");
SSLOptions srvSSL = null;
SSLOptions clientSSL = null;
if (pbrpcScheme.equals(Schemes.SCHEME_PBRPCS) || pbrpcScheme.equals(Schemes.SCHEME_PBRPCG)) {
srvSSL = createSSLOptions("DIR.p12", "passphrase", SSLOptions.PKCS12_CONTAINER,
"trusted.jks", "passphrase", SSLOptions.JKS_CONTAINER, pbrpcScheme.equals(Schemes.SCHEME_PBRPCG), null);
clientSSL= createSSLOptions("Client.p12", "passphrase",
SSLOptions.PKCS12_CONTAINER, "trusted.jks", "passphrase", SSLOptions.JKS_CONTAINER, pbrpcScheme.equals(Schemes.SCHEME_PBRPCG), null);
}
// System.out.println("setup done");
try {
server = getServer(creator,srvSSL);
server.start();
server.waitForStartup();
client = new RPCNIOSocketClient(clientSSL, 5000, 5*60*1000, "runTest");
client.start();
client.waitForStartup();
exec.execTest(client);
} finally {
//clean up
if (client != null) {
client.shutdown();
client.waitForShutdown();
}
if (server != null) {
server.shutdown();
server.waitForShutdown();
}
}
}
private RPCNIOSocketServer getServer(final ResponseCreator creator, SSLOptions sslOpt) throws IOException {
return new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
ReusableBufferInputStream is = new ReusableBufferInputStream(rq.getMessage());
Ping.PingRequest pingRq = Ping.PingRequest.parseFrom(is);
creator.answer(rq, pingRq);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, sslOpt);
}
private SSLOptions createSSLOptions(String keyStoreName, String ksPassphrase,
String ksContainerType, String trustStoreName, String tsPassphrase, String tsContainerType, boolean gridSSL, String sslProtocolString)
throws IOException {
ClassLoader cl = this.getClass().getClassLoader();
InputStream ks = cl.getResourceAsStream(keyStoreName);
if (ks == null) {
// Assume the working directory is "java/servers".
String testCert = "../../tests/certs/" + keyStoreName;
if (new File(testCert).isFile()) {
ks = new FileInputStream(testCert);
} else {
// Assume the working directory is the root of the project.
ks = new FileInputStream("tests/certs/" + keyStoreName);
}
}
InputStream ts = cl.getResourceAsStream(trustStoreName);
if (ts == null) {
// Assume the working directory is "java/servers".
String testCert = "../../tests/certs/" + trustStoreName;
if (new File(testCert).isFile()) {
ts = new FileInputStream(testCert);
} else {
// Assume the working directory is the root of the project.
ts = new FileInputStream("tests/certs/" + trustStoreName);
}
}
return new SSLOptions(ks, ksPassphrase, ksContainerType, ts, tsPassphrase, tsContainerType, false, gridSSL, sslProtocolString, null);
}
private static interface ResponseCreator {
public void answer(RPCServerRequest rq, PingRequest pRq) throws Exception;
}
private static interface TestExecutor {
public void execTest(RPCNIOSocketClient client) throws Exception;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.pbrpc;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.pbrpc.utils.PBRPCDatagramPacket;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping.PingRequest;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.MessageType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.UserCredentials;
import static org.junit.Assert.*;
/**
*
* @author bjko
*/
public class PBRPCDatagramPacketTest {
public PBRPCDatagramPacketTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
// TODO add test methods here.
// The methods must be annotated with annotation @Test. For example:
//
// @Test
// public void hello() {}
@Test
public void testPacket() throws Exception {
RPCHeader.RequestHeader rqHdr = RPCHeader.RequestHeader.newBuilder().setAuthData(RPCAuthentication.authNone).setUserCreds(RPCAuthentication.userService).setInterfaceId(1).setProcId(2).build();
RPCHeader hdr = RPCHeader.newBuilder().setCallId(12345).setMessageType(MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
PingRequest pRq = PingRequest.newBuilder().setText("YAGGA!").setSendError(false).build();
PBRPCDatagramPacket dp = new PBRPCDatagramPacket(hdr, pRq);
ReusableBuffer data = dp.assembleDatagramPacket();
dp = new PBRPCDatagramPacket(data, PingRequest.getDefaultInstance());
PingRequest response = (PingRequest)dp.getMessage();
assertEquals(dp.getHeader().getCallId(),12345);
assertEquals(dp.getHeader().getMessageType(),MessageType.RPC_REQUEST);
assertEquals(response.getText(),pRq.getText());
}
}

View File

@@ -0,0 +1,255 @@
/*
* Copyright (c) 2009-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.pbrpc;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.TimeSync;
import java.io.IOException;
import java.net.InetSocketAddress;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequest;
import org.xtreemfs.foundation.util.OutputUtils;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping.PingResponse;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequestListener;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication;
import org.xtreemfs.foundation.pbrpc.client.RPCNIOSocketClient;
import org.xtreemfs.foundation.pbrpc.client.RPCResponse;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.PingServiceClient;
import static org.junit.Assert.*;
/**
*
* @author bjko
*/
public class PBRPCTest {
private final int TEST_PORT = 12999;
private static TimeSync ts = null;
public PBRPCTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
Logging.start(Logging.LEVEL_WARN, Logging.Category.all);
ts = TimeSync.initializeLocal(50);
}
@AfterClass
public static void tearDownClass() throws Exception {
ts.close();
}
@Test
public void testRPCClient() throws Exception {
RPCNIOSocketClient client = null;
RPCNIOSocketServer server = null;
try {
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
ReusableBufferInputStream is = new ReusableBufferInputStream(rq.getMessage());
Ping.PingRequest pingRq = Ping.PingRequest.parseFrom(is);
Ping.PingResponse.PingResult result = Ping.PingResponse.PingResult.newBuilder().setText(pingRq.getText()).build();
Ping.PingResponse resp = Ping.PingResponse.newBuilder().setResult(result).build();
rq.sendResponse(resp, null);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
client = new RPCNIOSocketClient(null, 15000, 5*60*1000, "testRPCClient");
client.start();
client.waitForStartup();
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, null);
assertEquals(response.get().getResult().getText(),"Hello World!");
response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Murpel", false, null);
assertEquals(response.get().getResult().getText(),"Murpel");
} finally {
//clean up
if (client != null) {
client.shutdown();
client.waitForShutdown();
}
if (server != null) {
server.shutdown();
server.waitForShutdown();
}
}
}
@Test
public void testRPCWithData() throws Exception {
RPCNIOSocketClient client = null;
RPCNIOSocketServer server = null;
try {
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
ReusableBufferInputStream is = new ReusableBufferInputStream(rq.getMessage());
Ping.PingRequest pingRq = Ping.PingRequest.parseFrom(is);
Ping.PingResponse.PingResult result = Ping.PingResponse.PingResult.newBuilder().setText(pingRq.getText()).build();
Ping.PingResponse resp = Ping.PingResponse.newBuilder().setResult(result).build();
ReusableBuffer data = null;
if (rq.getData() != null) {
data = rq.getData().createViewBuffer();
data.limit(data.capacity());
data.position(data.capacity());
}
rq.sendResponse(resp, data);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
client = new RPCNIOSocketClient(null, 15000, 5*60*1000, "testRPCWithData");
client.start();
client.waitForStartup();
PingServiceClient psClient = new PingServiceClient(client,null);
byte[] arr = new byte[2065];
for (int i= 0; i < arr.length; i++)
arr[i] = 'x';
ReusableBuffer sendData = ReusableBuffer.wrap(arr);
// System.out.println("data: "+sendData);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse<PingResponse> response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Hello World!", false, sendData);
assertEquals(response.get().getResult().getText(),"Hello World!");
ReusableBuffer recdata = response.getData();
assertTrue(recdata.hasRemaining());
while (recdata.hasRemaining()) {
assertEquals(recdata.get(),(byte)'x');
}
response = psClient.doPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred, "Murpel", false, null);
assertEquals(response.get().getResult().getText(),"Murpel");
} finally {
//clean up
if (client != null) {
client.shutdown();
client.waitForShutdown();
}
if (server != null) {
server.shutdown();
server.waitForShutdown();
}
}
}
@Test
public void testEmptyMessages() throws Exception {
RPCNIOSocketClient client = null;
RPCNIOSocketServer server = null;
try {
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
assertNull(rq.getMessage());
rq.sendResponse(null, null);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
client = new RPCNIOSocketClient(null, 15000, 5*60*1000, "PBRPCTest::testEmptyMessages()");
client.start();
client.waitForStartup();
PingServiceClient psClient = new PingServiceClient(client,null);
RPC.UserCredentials userCred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("tester").build();
RPCResponse response = psClient.emptyPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred);
assertNull(response.get());
response = psClient.emptyPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred);
assertNull(response.get());
response = psClient.emptyPing(new InetSocketAddress("localhost", TEST_PORT), RPCAuthentication.authNone, userCred);
assertNull(response.get());
} finally {
//clean up
if (client != null) {
client.shutdown();
client.waitForShutdown();
}
if (server != null) {
server.shutdown();
server.waitForShutdown();
}
}
}
}

View File

@@ -0,0 +1,377 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.pbrpc;
import java.io.IOException;
import org.xtreemfs.foundation.util.OutputUtils;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC;
import org.junit.After;
import org.junit.Before;
import org.xtreemfs.foundation.pbrpc.server.RPCNIOSocketServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequest;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequestListener;
import org.xtreemfs.foundation.pbrpc.utils.RecordMarker;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferInputStream;
import org.xtreemfs.foundation.pbrpc.utils.ReusableBufferOutputStream;
import static org.junit.Assert.*;
/**
*
* @author bjko
*/
public class RPCNIOSocketServerTest {
private RPCNIOSocketServer server;
public RPCNIOSocketServerTest() {
Logging.start(Logging.LEVEL_WARN, Logging.Category.all);
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
// TODO add test methods here.
// The methods must be annotated with annotation @Test. For example:
//
// @Test
// public void hello() {}
@Test
public void testSerialization() throws Exception {
final int CALLID = 5464566;
RPC.Auth auth = RPC.Auth.newBuilder().setAuthType(RPC.AuthType.AUTH_NONE).build();
RPC.UserCredentials ucred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("user").build();
RPC.RPCHeader.RequestHeader rqHdr = RPC.RPCHeader.RequestHeader.newBuilder().setAuthData(auth).setUserCreds(ucred).setProcId(2).setInterfaceId(2).build();
RPC.RPCHeader header = RPC.RPCHeader.newBuilder().setCallId(CALLID).setMessageType(RPC.MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
ReusableBufferOutputStream ois = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
header.writeTo(ois);
ois.flip();
byte[] data = new byte[ois.getBuffers()[0].remaining()];
ois.getBuffers()[0].get(data);
ReusableBufferInputStream is = new ReusableBufferInputStream(ReusableBuffer.wrap(data));
RPC.RPCHeader deser = RPC.RPCHeader.parseFrom(is);
}
@Test
public void testSimpleRPC() throws Exception {
final int CALLID = 5464566;
final int TEST_PORT = 9991;
final String USERID = "yaggaYagga";
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
assertEquals(CALLID,rq.getHeader().getCallId());
assertEquals(RPC.MessageType.RPC_REQUEST, rq.getHeader().getMessageType());
//send a dummy message
RPC.UserCredentials msg = RPC.UserCredentials.newBuilder().setUsername(USERID).build();
ReusableBuffer data = BufferPool.allocate(2);
data.put((byte)15);
data.put((byte)20);
rq.sendResponse(msg, data);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
Socket sock = new Socket("localhost", TEST_PORT);
OutputStream out = sock.getOutputStream();
InputStream in = sock.getInputStream();
RPC.Auth auth = RPC.Auth.newBuilder().setAuthType(RPC.AuthType.AUTH_NONE).build();
RPC.UserCredentials ucred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("user").build();
RPC.RPCHeader.RequestHeader rqHdr = RPC.RPCHeader.RequestHeader.newBuilder().setAuthData(auth).setUserCreds(ucred).setProcId(2).setInterfaceId(2).build();
RPC.RPCHeader header = RPC.RPCHeader.newBuilder().setCallId(CALLID).setMessageType(RPC.MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
ReusableBufferOutputStream ois = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
header.writeTo(ois);
int hdrLen = ois.length();
ByteBuffer recordMarker = ByteBuffer.allocate(RecordMarker.HDR_SIZE);
recordMarker.putInt(hdrLen);
recordMarker.putInt(0);
recordMarker.putInt(0);
recordMarker.flip();
ois.flip();
out.write(recordMarker.array());
byte[] data = new byte[ois.getBuffers()[0].remaining()];
ois.getBuffers()[0].get(data);
out.write(data);
byte[] markerIn = new byte[RecordMarker.HDR_SIZE];
in.read(markerIn);
ReusableBuffer marker = ReusableBuffer.wrap(markerIn);
hdrLen = marker.getInt();
int msgLen = marker.getInt();
int dataLen = marker.getInt();
// System.out.println("header: "+hdrLen+"/"+msgLen+"/"+dataLen);
byte[] hdrIn = new byte[hdrLen];
byte[] msgIn = new byte[msgLen];
byte[] dataIn = new byte[dataLen];
in.read(hdrIn);
in.read(msgIn);
in.read(dataIn);
// System.out.println("read data");
RPC.RPCHeader respHdr = RPC.RPCHeader.parseFrom(hdrIn);
RPC.UserCredentials uc = RPC.UserCredentials.parseFrom(msgIn);
assertEquals(RPC.MessageType.RPC_RESPONSE_SUCCESS,respHdr.getMessageType());
assertEquals(header.getCallId(),respHdr.getCallId());
assertEquals(USERID,uc.getUsername());
assertEquals(15,dataIn[0]);
assertEquals(20,dataIn[1]);
sock.close();
server.shutdown();
server.waitForShutdown();
}
@Test
public void testRPCWithoutMessage() throws Exception {
final int CALLID = 5464566;
final int TEST_PORT = 9991;
final String USERID = "yaggaYagga";
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
assertNotNull(rq.getData());
assertNull(rq.getMessage());
assertEquals(CALLID,rq.getHeader().getCallId());
assertEquals(RPC.MessageType.RPC_REQUEST, rq.getHeader().getMessageType());
//send a dummy message
RPC.UserCredentials msg = RPC.UserCredentials.newBuilder().setUsername(USERID).build();
ReusableBuffer data = BufferPool.allocate(2);
data.put((byte)15);
data.put((byte)20);
rq.sendResponse(msg, data);
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
Socket sock = new Socket("localhost", TEST_PORT);
OutputStream out = sock.getOutputStream();
InputStream in = sock.getInputStream();
RPC.Auth auth = RPC.Auth.newBuilder().setAuthType(RPC.AuthType.AUTH_NONE).build();
RPC.UserCredentials ucred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("user").build();
RPC.RPCHeader.RequestHeader rqHdr = RPC.RPCHeader.RequestHeader.newBuilder().setAuthData(auth).setUserCreds(ucred).setProcId(2).setInterfaceId(2).build();
RPC.RPCHeader header = RPC.RPCHeader.newBuilder().setCallId(CALLID).setMessageType(RPC.MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
ReusableBufferOutputStream ois = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
header.writeTo(ois);
int hdrLen = ois.length();
ByteBuffer recordMarker = ByteBuffer.allocate(RecordMarker.HDR_SIZE);
recordMarker.putInt(hdrLen);
recordMarker.putInt(0);
recordMarker.putInt(16);
recordMarker.flip();
ois.flip();
out.write(recordMarker.array());
byte[] data = new byte[ois.getBuffers()[0].remaining()];
ois.getBuffers()[0].get(data);
out.write(data);
for (int i = 0; i < 16; i++) {
out.write('a');
}
byte[] markerIn = new byte[RecordMarker.HDR_SIZE];
in.read(markerIn);
ReusableBuffer marker = ReusableBuffer.wrap(markerIn);
hdrLen = marker.getInt();
int msgLen = marker.getInt();
int dataLen = marker.getInt();
// System.out.println("header: "+hdrLen+"/"+msgLen+"/"+dataLen);
byte[] hdrIn = new byte[hdrLen];
byte[] msgIn = new byte[msgLen];
byte[] dataIn = new byte[dataLen];
in.read(hdrIn);
in.read(msgIn);
in.read(dataIn);
// System.out.println("read data");
RPC.RPCHeader respHdr = RPC.RPCHeader.parseFrom(hdrIn);
RPC.UserCredentials uc = RPC.UserCredentials.parseFrom(msgIn);
assertEquals(RPC.MessageType.RPC_RESPONSE_SUCCESS,respHdr.getMessageType());
assertEquals(header.getCallId(),respHdr.getCallId());
assertEquals(USERID,uc.getUsername());
assertEquals(15,dataIn[0]);
assertEquals(20,dataIn[1]);
sock.close();
server.shutdown();
server.waitForShutdown();
}
@Test
public void testErrorResponse() throws Exception {
final int CALLID = 5464566;
final int TEST_PORT = 9991;
final String USERID = "yaggaYagga";
server = new RPCNIOSocketServer(TEST_PORT, null, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("received request");
try {
assertEquals(CALLID,rq.getHeader().getCallId());
assertEquals(RPC.MessageType.RPC_REQUEST, rq.getHeader().getMessageType());
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.AUTH_FAILED).setErrorMessage("dummy error").setDebugInfo("no info here").build());
} catch (Exception ex) {
ex.printStackTrace();
rq.sendError(RPC.RPCHeader.ErrorResponse.newBuilder().setErrorType(RPC.ErrorType.GARBAGE_ARGS).setErrorMessage(ex.getMessage()).setDebugInfo(OutputUtils.stackTraceToString(ex)).build());
rq.freeBuffers();
fail(ex.toString());
}
}
}, null);
server.start();
server.waitForStartup();
Socket sock = new Socket("localhost", TEST_PORT);
OutputStream out = sock.getOutputStream();
InputStream in = sock.getInputStream();
RPC.Auth auth = RPC.Auth.newBuilder().setAuthType(RPC.AuthType.AUTH_NONE).build();
RPC.UserCredentials ucred = RPC.UserCredentials.newBuilder().setUsername("test").addGroups("user").build();
RPC.RPCHeader.RequestHeader rqHdr = RPC.RPCHeader.RequestHeader.newBuilder().setAuthData(auth).setUserCreds(ucred).setProcId(2).setInterfaceId(2).build();
RPC.RPCHeader header = RPC.RPCHeader.newBuilder().setCallId(CALLID).setMessageType(RPC.MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
ReusableBufferOutputStream ois = new ReusableBufferOutputStream(ReusableBufferOutputStream.BUFF_SIZE);
header.writeTo(ois);
int hdrLen = ois.length();
ByteBuffer recordMarker = ByteBuffer.allocate(RecordMarker.HDR_SIZE);
recordMarker.putInt(hdrLen);
recordMarker.putInt(0);
recordMarker.putInt(0);
recordMarker.flip();
ois.flip();
out.write(recordMarker.array());
byte[] data = new byte[ois.getBuffers()[0].remaining()];
ois.getBuffers()[0].get(data);
out.write(data);
byte[] markerIn = new byte[RecordMarker.HDR_SIZE];
in.read(markerIn);
ReusableBuffer marker = ReusableBuffer.wrap(markerIn);
hdrLen = marker.getInt();
int msgLen = marker.getInt();
int dataLen = marker.getInt();
assertEquals(0,msgLen);
assertEquals(0,dataLen);
// System.out.println("header: "+hdrLen+"/"+msgLen+"/"+dataLen);
byte[] hdrIn = new byte[hdrLen];
in.read(hdrIn);
RPC.RPCHeader respHdr = RPC.RPCHeader.parseFrom(hdrIn);
assertEquals(RPC.MessageType.RPC_RESPONSE_ERROR,respHdr.getMessageType());
assertEquals(header.getCallId(),respHdr.getCallId());
assertEquals(RPC.ErrorType.AUTH_FAILED,respHdr.getErrorResponse().getErrorType());
sock.close();
server.shutdown();
server.waitForShutdown();
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.pbrpc;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader;
import java.net.InetSocketAddress;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequest;
import org.xtreemfs.foundation.pbrpc.server.RPCUDPSocketServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.Ping.PingRequest;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.ErrorType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.MessageType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.POSIXErrno;
import org.xtreemfs.foundation.pbrpc.server.RPCServerRequestListener;
import static org.junit.Assert.*;
/**
*
* @author bjko
*/
public class RPCUDPSocketServerTest {
RPCUDPSocketServer server1, server2;
final static int PORT_1 = 33333;
final static int PORT_2 = 33334;
public RPCUDPSocketServerTest() {
Logging.start(Logging.LEVEL_WARN, Logging.Category.all);
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
// TODO add test methods here.
// The methods must be annotated with annotation @Test. For example:
//
// @Test
// public void hello() {}
@Test
public void testUDP() throws Exception {
server1 = new RPCUDPSocketServer(PORT_1, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("srv1: "+rq);
}
});
server2 = new RPCUDPSocketServer(PORT_2, new RPCServerRequestListener() {
@Override
public void receiveRecord(RPCServerRequest rq) {
// System.out.println("srv2: "+rq);
rq.sendError(ErrorType.ERRNO, POSIXErrno.POSIX_ERROR_EIO, "yagga");
}
});
server1.start();
server2.start();
server1.waitForStartup();
server2.waitForStartup();
RPCHeader.RequestHeader rqHdr = RPCHeader.RequestHeader.newBuilder().setAuthData(RPCAuthentication.authNone).setUserCreds(RPCAuthentication.userService).setInterfaceId(1).setProcId(5).build();
RPCHeader hdr = RPCHeader.newBuilder().setCallId(555).setMessageType(MessageType.RPC_REQUEST).setRequestHeader(rqHdr).build();
PingRequest pRq = PingRequest.newBuilder().setSendError(false).setText("yagga").build();
server1.sendRequest(hdr, pRq, new InetSocketAddress("localhost",PORT_2));
Thread.sleep(100);
server1.shutdown();
server2.shutdown();
server1.waitForShutdown();
server2.waitForShutdown();
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2008-2011 by Jan Stender, Bjoern Kolbeck,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.util;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.xtreemfs.foundation.util.OutputUtils;
public class OutputUtilsTest {
@Test
public void testLongHexEncoding() throws Exception {
final long[] values = { 805306368000L, Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE,
Long.MAX_VALUE, 1, 0, -1 };
for (long value : values) {
StringBuffer sb = new StringBuffer();
OutputUtils.writeHexLong(sb, value);
assertEquals(value, OutputUtils.readHexLong(sb.toString(), 0));
}
}
@Test
public void testReadWriteHex() {
final int objno = 129;
final int objver = 459435;
final int trepo = 1;
final long checksum = 843349439598l;
final StringBuffer sb = new StringBuffer(Integer.SIZE/8*3+2*Long.SIZE/8);
OutputUtils.writeHexInt(sb,objno);
OutputUtils.writeHexInt(sb,objver);
OutputUtils.writeHexInt(sb,trepo);
OutputUtils.writeHexInt(sb,(int) (checksum >> 32));
OutputUtils.writeHexInt(sb,(int) (checksum & 0xFFFFFFFF));
OutputUtils.writeHexLong(sb, checksum);
final String result = sb.toString();
// System.out.println("result: "+result);
int tmp = OutputUtils.readHexInt(result, 0);
assertEquals(objno,tmp);
tmp = OutputUtils.readHexInt(result, 8);
assertEquals(objver,tmp);
tmp = OutputUtils.readHexInt(result, 16);
assertEquals(trepo,tmp);
tmp = OutputUtils.readHexInt(result, 24);
long tmp2 = ((long)tmp)<< 32;
tmp = OutputUtils.readHexInt(result, 32);
tmp2 += tmp;
assertEquals(checksum,tmp2);
tmp2 = OutputUtils.readHexLong(result, 40);
assertEquals(checksum,tmp2);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2011 by Bjoern Kolbeck, Felix Langner,
* Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.test.foundation.util;
import org.junit.*;
import org.xtreemfs.foundation.pbrpc.Schemes;
import org.xtreemfs.foundation.util.PBRPCServiceURL;
import static org.junit.Assert.assertEquals;
/**
*
* @author bjko
*/
public class PBRPCServiceURLTest {
public PBRPCServiceURLTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of getProtocol method, of class ONCRPCServiceURL.
*/
@Test
public void testURLParse() throws Exception {
String host = "yagga";
int port = 1254;
PBRPCServiceURL u = new PBRPCServiceURL("pbrpcg://"+host+":"+port+"/",
Schemes.SCHEME_PBRPC,12345);
assertEquals(host, u.getHost());
assertEquals(port, u.getPort());
}
}