[med-svn] [libsis-base-java] 01/05: Imported Upstream version 14.12.0
Olivier Sallou
osallou at debian.org
Fri Aug 21 14:26:32 UTC 2015
This is an automated email from the git hooks/post-receive script.
osallou pushed a commit to branch master
in repository libsis-base-java.
commit b9ca42fce35e1577723f0ff50dcd49159424655f
Author: Olivier Sallou <osallou at debian.org>
Date: Fri Aug 21 14:06:37 2015 +0000
Imported Upstream version 14.12.0
---
.classpath | 13 +
branch.sh | 35 +
build.gradle | 98 ++
dist/COPYING | 15 +
dist/COPYING_HDF | 88 ++
dist/LICENSE | 203 ++++
doc/tagged_array_def.txt | 43 +
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 50514 bytes
gradle/wrapper/gradle-wrapper.properties | 6 +
gradlew | 164 +++
gradlew.bat | 90 ++
resource/dependency-structure.ddf | 6 +
settings.gradle | 1 +
source/c/COPYING | 88 ++
source/c/compile_linux_amd64.sh | 6 +
source/c/compile_linux_arm.sh | 6 +
source/c/compile_linux_i386.sh | 6 +
source/c/compile_macosx_i386.sh | 6 +
source/c/compile_macosx_x86_64.sh | 6 +
source/c/compile_solaris_amd64.sh | 6 +
source/c/compile_solaris_sparc.sh | 6 +
source/c/compile_solaris_sparcv9.sh | 6 +
source/c/compile_solaris_x86.sh | 6 +
source/c/compile_windows_i386.mak | 181 ++++
source/c/compile_windows_x64.mak | 182 ++++
source/c/copyByteChar.c | 42 +
source/c/copyByteDouble.c | 42 +
source/c/copyByteFloat.c | 42 +
source/c/copyByteInt.c | 42 +
source/c/copyByteLong.c | 42 +
source/c/copyByteShort.c | 42 +
source/c/copyByteTarget.ctempl | 241 +++++
source/c/copyCommon.c | 268 +++++
source/c/unix.c | 446 ++++++++
.../cisd/base/BuildAndEnvironmentInfo.java | 46 +
.../systemsx/cisd/base/annotation/JsonObject.java | 43 +
.../cisd/base/convert/NativeArrayEncoding.java | 184 ++++
.../ch/systemsx/cisd/base/convert/NativeData.java | 1086 ++++++++++++++++++++
.../cisd/base/convert/NativeTaggedArray.java | 672 ++++++++++++
.../base/exceptions/CheckedExceptionTunnel.java | 285 +++++
.../cisd/base/exceptions/IErrorStrategy.java | 56 +
.../cisd/base/exceptions/IOExceptionUnchecked.java | 81 ++
.../exceptions/InterruptedExceptionUnchecked.java | 61 ++
.../cisd/base/exceptions/StopException.java | 29 +
.../base/exceptions/TimeoutExceptionUnchecked.java | 52 +
.../ch/systemsx/cisd/base/exceptions/package.html | 13 +
.../cisd/base/image/IImageTransformer.java | 35 +
.../cisd/base/image/IImageTransformerFactory.java | 36 +
.../base/image/IStreamingImageTransformer.java | 53 +
.../image/IStreamingImageTransformerFactory.java | 36 +
.../base/io/AdapterIInputStreamToInputStream.java | 157 +++
.../io/AdapterIOutputStreamToOutputStream.java | 121 +++
.../base/io/AdapterInputStreamToIInputStream.java | 157 +++
.../io/AdapterOutputStreamToIOutputStream.java | 130 +++
.../cisd/base/io/ByteBufferRandomAccessFile.java | 455 ++++++++
.../java/ch/systemsx/cisd/base/io/ICloseable.java | 37 +
.../ch/systemsx/cisd/base/io/IInputStream.java | 74 ++
.../ch/systemsx/cisd/base/io/IOutputStream.java | 60 ++
.../systemsx/cisd/base/io/IRandomAccessFile.java | 278 +++++
.../ch/systemsx/cisd/base/io/ISynchronizable.java | 34 +
.../cisd/base/io/RandomAccessFileImpl.java | 648 ++++++++++++
.../cisd/base/mdarray/MDAbstractArray.java | 480 +++++++++
.../ch/systemsx/cisd/base/mdarray/MDArray.java | 352 +++++++
.../ch/systemsx/cisd/base/mdarray/MDByteArray.java | 376 +++++++
.../systemsx/cisd/base/mdarray/MDDoubleArray.java | 376 +++++++
.../systemsx/cisd/base/mdarray/MDFloatArray.java | 376 +++++++
.../ch/systemsx/cisd/base/mdarray/MDIntArray.java | 376 +++++++
.../ch/systemsx/cisd/base/mdarray/MDLongArray.java | 376 +++++++
.../systemsx/cisd/base/mdarray/MDShortArray.java | 376 +++++++
.../ch/systemsx/cisd/base/mdarray/package.html | 19 +
.../base/namedthread/ICallableNameProvider.java | 29 +
.../base/namedthread/IRunnableNameProvider.java | 28 +
.../cisd/base/namedthread/NamedCallable.java | 28 +
.../cisd/base/namedthread/NamedFutureTask.java | 72 ++
.../cisd/base/namedthread/NamedRunnable.java | 26 +
.../cisd/base/namedthread/NamingThreadFactory.java | 88 ++
.../base/namedthread/NamingThreadPoolExecutor.java | 329 ++++++
.../cisd/base/namedthread/PoolNameThread.java | 57 +
.../ch/systemsx/cisd/base/namedthread/package.html | 14 +
.../base/tests/AbstractFileSystemTestCase.java | 145 +++
.../java/ch/systemsx/cisd/base/tests/Retry10.java | 50 +
.../java/ch/systemsx/cisd/base/tests/Retry50.java | 50 +
.../ch/systemsx/cisd/base/unix/FileLinkType.java | 37 +
source/java/ch/systemsx/cisd/base/unix/Unix.java | 901 ++++++++++++++++
.../java/ch/systemsx/cisd/base/unix/package.html | 12 +
.../utilities/AbstractBuildAndEnvironmentInfo.java | 231 +++++
.../base/utilities/NativeLibraryUtilities.java | 154 +++
.../systemsx/cisd/base/utilities/OSUtilities.java | 257 +++++
.../cisd/base/utilities/ResourceUtilities.java | 101 ++
.../ch/systemsx/cisd/base/utilities/package.html | 12 +
.../java/ch/systemsx/cisd/base/AllTests.java | 59 ++
.../cisd/base/convert/NativeDataTests.java | 504 +++++++++
.../cisd/base/convert/NativeTaggedArrayTests.java | 470 +++++++++
.../exceptions/CheckedExceptionTunnelTest.java | 88 ++
.../base/exceptions/IOExceptionUncheckedTests.java | 144 +++
.../base/io/ByteBufferRandomAccessFileTests.java | 94 ++
.../cisd/base/io/IRandomAccessFileTests.java | 196 ++++
.../cisd/base/io/RandomAccessFileImplTests.java | 97 ++
.../systemsx/cisd/base/mdarray/MDArrayTests.java | 332 ++++++
.../namedthread/NamingThreadPoolExecutorTest.java | 481 +++++++++
.../java/ch/systemsx/cisd/base/unix/UnixTests.java | 351 +++++++
sourceTest/java/tests.xml | 12 +
tag.sh | 24 +
103 files changed, 15973 insertions(+)
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..dbaf269
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="source/java"/>
+ <classpathentry kind="src" path="sourceTest/java"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/>
+ <classpathentry kind="lib" path="/libraries/restrictionchecker/restrictions.jar"/>
+ <classpathentry kind="lib" path="/libraries/commons-io/commons-io.jar" sourcepath="/libraries/commons-io/src.zip"/>
+ <classpathentry kind="lib" path="/libraries/commons-lang/commons-lang.jar" sourcepath="/libraries/commons-lang/src.zip"/>
+ <classpathentry kind="lib" path="/libraries/unix"/>
+ <classpathentry kind="lib" path="/libraries/nativedata"/>
+ <classpathentry kind="output" path="targets/classes"/>
+</classpath>
diff --git a/branch.sh b/branch.sh
new file mode 100755
index 0000000..57cf7ca
--- /dev/null
+++ b/branch.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+if [ `dirname $0` != "." ]
+then
+ echo "Please run from the same directory than the script source file is in"
+ exit 1
+fi
+
+if [ $# -ne 1 ]
+then
+ echo "Usage: ./branch.sh [branch]"
+ echo ""
+ echo "Example: ./branch.sh release/13.04.x"
+ exit 1
+fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 2>/dev/null
+if [ $? -eq 0 ]; then echo "Branch already exists!"; exit 1; fi
+
+CURRENT=`svn info|grep URL|cut -d" " -f2`
+
+svn copy $CURRENT svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 -m "create branch $1"
+mkdir -p out
+rm -r out/temp_checkout
+svn checkout --depth=empty svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 out/temp_checkout
+if [ $? -ne 0 ]; then echo "Checkout of new branch $1 failed!"; exit 1; fi
+
+cd out/temp_checkout
+svn update gradlew gradle build.gradle
+./gradlew dependencyReport
+cat out/reports/project/dependencies.txt|egrep ^.---|grep \>|sort|uniq|awk '{print $2 ":" $4}'|awk -F: '{print "s/" $1 ":" $2 ":" $3 "/" $1 ":" $2 ":" $4 "/g"}' > sed_commands
+sed -f sed_commands build.gradle > build.gradle.tmp
+mv build.gradle.tmp build.gradle
+svn commit build.gradle -m "fixed dependencies for branch $1"
+cd ../..
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..70bb26a
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,98 @@
+apply from: '../gradle/javaproject.gradle'
+
+group='sis'
+
+dependencies {
+ compile 'apache:commons-io:+',
+ 'apache:commons-lang:+',
+ 'testng:testng:+',
+ 'rinn:restrictions:+'
+}
+
+tasks.withType(Test) {
+ systemProperty "java.library.path", "libs/native/unix/amd64-Linux:libs/native/nativedata/amd64-Linux:libs/native/unix/x86_64-Mac OS X:libs/native/nativedata/x86_64-Mac OS X"
+}
+
+
+sourceSets {
+ test {
+ resources {
+ srcDir "libs"
+ include "**"
+ }
+ }
+}
+
+jar {
+ from fileTree("libs/")
+}
+
+task standaloneTestJar(type: Jar, dependsOn: [classes, testClasses]) {
+ archiveName "${project.group}-base-test.jar"
+ from files(sourceSets.main.output.classesDir)
+ from files(sourceSets.main.output.resourcesDir)
+ from files(sourceSets.test.output.classesDir)
+ from files("libs")
+
+ from {configurations.testRuntime.collect {zipTree(it)}}
+
+ manifest {
+ attributes 'Main-Class': 'ch.systemsx.cisd.base.AllTests'
+ }
+}
+
+task javadocZip(type: Zip, dependsOn: javadoc) {
+ archiveName "${project.group}-base-javadoc.zip"
+ from javadoc.destinationDir
+}
+
+task distributionZip(type: Zip, dependsOn: [jar, sourcesJar, javadocZip, standaloneTestJar]) {
+ baseName = "${project.group}-base"
+ from ('dist') {
+ into "${project.group}-base"
+ }
+
+ from ('doc') {
+ into "${project.group}-base/doc"
+ }
+
+ from (jar.archivePath) {
+ into "${project.group}-base/lib"
+ rename '(.*)', "${project.group}-base.jar"
+ }
+
+ from (sourcesJar.archivePath) {
+ into "${project.group}-base/src"
+ rename '(.*)', "${project.group}-base-src.jar"
+ }
+
+ from (standaloneTestJar.archivePath) {
+ into "${project.group}-base/lib"
+ }
+
+ from (javadocZip.archivePath) {
+ into "${project.group}-base/doc"
+ }
+}
+
+build.dependsOn distributionZip
+
+publishing {
+ publications {
+ ivy(IvyPublication) {
+ module "${project.group}-base"
+ revision project.revisionForPublication
+ from components.java
+ artifact(sourcesJar) {
+ type = 'source'
+ }
+ descriptor {
+ withXml {
+ for (org in ['testng', 'rinn']) {
+ asNode().dependencies.dependency.find { it. at org == org }.replaceNode {}
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dist/COPYING b/dist/COPYING
new file mode 100644
index 0000000..0bae472
--- /dev/null
+++ b/dist/COPYING
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/dist/COPYING_HDF b/dist/COPYING_HDF
new file mode 100644
index 0000000..7ca6009
--- /dev/null
+++ b/dist/COPYING_HDF
@@ -0,0 +1,88 @@
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF)
+Java Software Library and Utilities
+
+NCSA Hierarchical Data Format (HDF) Software Library and Utilities
+Copyright 1988-2004, the Board of Trustees of the University of Illinois.
+Copyright 2007-2009, Center for Information Sciences and Databases, ETH Zurich, Switzerland.
+All rights reserved.
+
+Contributors to the library: National Center for Supercomputing
+Applications (NCSA) at the University of Illinois, Lawrence
+Livermore Nationall Laboratory (LLNL), Sandia National Laboratories (SNL),
+Los Alamos National Laboratory (LANL). Fortner Software, Unidata
+Program Center (netCDF), The Independent JPEG Group (JPEG),
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment
+Corporation (DEC). Macintosh support contributed by Gregory L. Guerin.
+Center for Information Sciences and Databases, ETH Zurich, Switzerland
+
+The package 'glguerin':
+Copyright 1998, 1999 by Gregory L. Guerin.
+Redistribute or reuse only as described below.
+These files are from the MacBinary Toolkit for Java:
+ <http://www.amug.org/~glguerin/sw/#macbinary>
+and are redistributed by NCSA with permission of the author.
+
+This work was supported in part by a Cooperative Agreement with
+NASA under NASA grant NAG 5-2040 and NAG NCC5-599.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or materials provided with the distribution.
+
+3. In addition, redistributions of modified forms of the source or binary
+ code must carry prominent notices stating that the original code was
+ changed and the date of the change.
+
+4. All publications or advertising materials mentioning features or use of
+ this software must acknowledge that it was developed by the National
+ Center for Supercomputing Applications at the University of Illinois, and
+ credit the Contributors.
+
+5. Neither the name of the University nor the names of the Contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission from the University or the Contributors.
+
+6. THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS"
+ WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. In no event
+ shall the University or the Contributors be liable for any damages
+ suffered by the users arising out of the use of this software, even if
+ advised of the possibility of such damage.
+
+--------------------------------------------------------------------------
+Portions of HDF5 were developed with support from the University of
+California, Lawrence Livermore National Laboratory (UC LLNL).
+The following statement applies to those portions of the product
+and must be retained in any redistribution of source code, binaries,
+documentation, and/or accompanying materials:
+
+ This work was partially produced at the University of California,
+ Lawrence Livermore National Laboratory (UC LLNL) under contract no.
+ W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy
+ (DOE) and The Regents of the University of California (University)
+ for the operation of UC LLNL.
+
+ DISCLAIMER:
+ This work was prepared as an account of work sponsored by an agency
+ of the United States Government. Neither the United States
+ Government nor the University of California nor any of their
+ employees, makes any warranty, express or implied, or assumes any
+ liability or responsibility for the accuracy, completeness, or
+ usefulness of any information, apparatus, product, or process
+ disclosed, or represents that its use would not infringe privately-
+ owned rights. Reference herein to any specific commercial products,
+ process, or service by trade name, trademark, manufacturer, or
+ otherwise, does not necessarily constitute or imply its endorsement,
+ recommendation, or favoring by the United States Government or the
+ University of California. The views and opinions of authors
+ expressed herein do not necessarily state or reflect those of the
+ United States Government or the University of California, and shall
+ not be used for advertising or product endorsement purposes.
+--------------------------------------------------------------------------
+
diff --git a/dist/LICENSE b/dist/LICENSE
new file mode 100644
index 0000000..f820d4b
--- /dev/null
+++ b/dist/LICENSE
@@ -0,0 +1,203 @@
+/*
+ * Apache License
+ * Version 2.0, January 2004
+ * http://www.apache.org/licenses/
+ *
+ * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ * 1. Definitions.
+ *
+ * "License" shall mean the terms and conditions for use, reproduction,
+ * and distribution as defined by Sections 1 through 9 of this document.
+ *
+ * "Licensor" shall mean the copyright owner or entity authorized by
+ * the copyright owner that is granting the License.
+ *
+ * "Legal Entity" shall mean the union of the acting entity and all
+ * other entities that control, are controlled by, or are under common
+ * control with that entity. For the purposes of this definition,
+ * "control" means (i) the power, direct or indirect, to cause the
+ * direction or management of such entity, whether by contract or
+ * otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ * outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ * "You" (or "Your") shall mean an individual or Legal Entity
+ * exercising permissions granted by this License.
+ *
+ * "Source" form shall mean the preferred form for making modifications,
+ * including but not limited to software source code, documentation
+ * source, and configuration files.
+ *
+ * "Object" form shall mean any form resulting from mechanical
+ * transformation or translation of a Source form, including but
+ * not limited to compiled object code, generated documentation,
+ * and conversions to other media types.
+ *
+ * "Work" shall mean the work of authorship, whether in Source or
+ * Object form, made available under the License, as indicated by a
+ * copyright notice that is included in or attached to the work
+ * (an example is provided in the Appendix below).
+ *
+ * "Derivative Works" shall mean any work, whether in Source or Object
+ * form, that is based on (or derived from) the Work and for which the
+ * editorial revisions, annotations, elaborations, or other modifications
+ * represent, as a whole, an original work of authorship. For the purposes
+ * of this License, Derivative Works shall not include works that remain
+ * separable from, or merely link (or bind by name) to the interfaces of,
+ * the Work and Derivative Works thereof.
+ *
+ * "Contribution" shall mean any work of authorship, including
+ * the original version of the Work and any modifications or additions
+ * to that Work or Derivative Works thereof, that is intentionally
+ * submitted to Licensor for inclusion in the Work by the copyright owner
+ * or by an individual or Legal Entity authorized to submit on behalf of
+ * the copyright owner. For the purposes of this definition, "submitted"
+ * means any form of electronic, verbal, or written communication sent
+ * to the Licensor or its representatives, including but not limited to
+ * communication on electronic mailing lists, source code control systems,
+ * and issue tracking systems that are managed by, or on behalf of, the
+ * Licensor for the purpose of discussing and improving the Work, but
+ * excluding communication that is conspicuously marked or otherwise
+ * designated in writing by the copyright owner as "Not a Contribution."
+ *
+ * "Contributor" shall mean Licensor and any individual or Legal Entity
+ * on behalf of whom a Contribution has been received by Licensor and
+ * subsequently incorporated within the Work.
+ *
+ * 2. Grant of Copyright License. Subject to the terms and conditions of
+ * this License, each Contributor hereby grants to You a perpetual,
+ * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ * copyright license to reproduce, prepare Derivative Works of,
+ * publicly display, publicly perform, sublicense, and distribute the
+ * Work and such Derivative Works in Source or Object form.
+ *
+ * 3. Grant of Patent License. Subject to the terms and conditions of
+ * this License, each Contributor hereby grants to You a perpetual,
+ * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ * (except as stated in this section) patent license to make, have made,
+ * use, offer to sell, sell, import, and otherwise transfer the Work,
+ * where such license applies only to those patent claims licensable
+ * by such Contributor that are necessarily infringed by their
+ * Contribution(s) alone or by combination of their Contribution(s)
+ * with the Work to which such Contribution(s) was submitted. If You
+ * institute patent litigation against any entity (including a
+ * cross-claim or counterclaim in a lawsuit) alleging that the Work
+ * or a Contribution incorporated within the Work constitutes direct
+ * or contributory patent infringement, then any patent licenses
+ * granted to You under this License for that Work shall terminate
+ * as of the date such litigation is filed.
+ *
+ * 4. Redistribution. You may reproduce and distribute copies of the
+ * Work or Derivative Works thereof in any medium, with or without
+ * modifications, and in Source or Object form, provided that You
+ * meet the following conditions:
+ *
+ * (a) You must give any other recipients of the Work or
+ * Derivative Works a copy of this License; and
+ *
+ * (b) You must cause any modified files to carry prominent notices
+ * stating that You changed the files; and
+ *
+ * (c) You must retain, in the Source form of any Derivative Works
+ * that You distribute, all copyright, patent, trademark, and
+ * attribution notices from the Source form of the Work,
+ * excluding those notices that do not pertain to any part of
+ * the Derivative Works; and
+ *
+ * (d) If the Work includes a "NOTICE" text file as part of its
+ * distribution, then any Derivative Works that You distribute must
+ * include a readable copy of the attribution notices contained
+ * within such NOTICE file, excluding those notices that do not
+ * pertain to any part of the Derivative Works, in at least one
+ * of the following places: within a NOTICE text file distributed
+ * as part of the Derivative Works; within the Source form or
+ * documentation, if provided along with the Derivative Works; or,
+ * within a display generated by the Derivative Works, if and
+ * wherever such third-party notices normally appear. The contents
+ * of the NOTICE file are for informational purposes only and
+ * do not modify the License. You may add Your own attribution
+ * notices within Derivative Works that You distribute, alongside
+ * or as an addendum to the NOTICE text from the Work, provided
+ * that such additional attribution notices cannot be construed
+ * as modifying the License.
+ *
+ * You may add Your own copyright statement to Your modifications and
+ * may provide additional or different license terms and conditions
+ * for use, reproduction, or distribution of Your modifications, or
+ * for any such Derivative Works as a whole, provided Your use,
+ * reproduction, and distribution of the Work otherwise complies with
+ * the conditions stated in this License.
+ *
+ * 5. Submission of Contributions. Unless You explicitly state otherwise,
+ * any Contribution intentionally submitted for inclusion in the Work
+ * by You to the Licensor shall be under the terms and conditions of
+ * this License, without any additional terms or conditions.
+ * Notwithstanding the above, nothing herein shall supersede or modify
+ * the terms of any separate license agreement you may have executed
+ * with Licensor regarding such Contributions.
+ *
+ * 6. Trademarks. This License does not grant permission to use the trade
+ * names, trademarks, service marks, or product names of the Licensor,
+ * except as required for reasonable and customary use in describing the
+ * origin of the Work and reproducing the content of the NOTICE file.
+ *
+ * 7. Disclaimer of Warranty. Unless required by applicable law or
+ * agreed to in writing, Licensor provides the Work (and each
+ * Contributor provides its Contributions) on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied, including, without limitation, any warranties or conditions
+ * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ * PARTICULAR PURPOSE. You are solely responsible for determining the
+ * appropriateness of using or redistributing the Work and assume any
+ * risks associated with Your exercise of permissions under this License.
+ *
+ * 8. Limitation of Liability. In no event and under no legal theory,
+ * whether in tort (including negligence), contract, or otherwise,
+ * unless required by applicable law (such as deliberate and grossly
+ * negligent acts) or agreed to in writing, shall any Contributor be
+ * liable to You for damages, including any direct, indirect, special,
+ * incidental, or consequential damages of any character arising as a
+ * result of this License or out of the use or inability to use the
+ * Work (including but not limited to damages for loss of goodwill,
+ * work stoppage, computer failure or malfunction, or any and all
+ * other commercial damages or losses), even if such Contributor
+ * has been advised of the possibility of such damages.
+ *
+ * 9. Accepting Warranty or Additional Liability. While redistributing
+ * the Work or Derivative Works thereof, You may choose to offer,
+ * and charge a fee for, acceptance of support, warranty, indemnity,
+ * or other liability obligations and/or rights consistent with this
+ * License. However, in accepting such obligations, You may act only
+ * on Your own behalf and on Your sole responsibility, not on behalf
+ * of any other Contributor, and only if You agree to indemnify,
+ * defend, and hold each Contributor harmless for any liability
+ * incurred by, or claims asserted against, such Contributor by reason
+ * of your accepting any such warranty or additional liability.
+ *
+ * END OF TERMS AND CONDITIONS
+ *
+ * APPENDIX: How to apply the Apache License to your work.
+ *
+ * To apply the Apache License to your work, attach the following
+ * boilerplate notice, with the fields enclosed by brackets "[]"
+ * replaced with your own identifying information. (Don't include
+ * the brackets!) The text should be enclosed in the appropriate
+ * comment syntax for the file format. We also recommend that a
+ * file or class name and description of purpose be included on the
+ * same "printed page" as the copyright notice for easier
+ * identification within third-party archives.
+ *
+ * Copyright [yyyy] [name of copyright owner]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/doc/tagged_array_def.txt b/doc/tagged_array_def.txt
new file mode 100644
index 0000000..4fe98e2
--- /dev/null
+++ b/doc/tagged_array_def.txt
@@ -0,0 +1,43 @@
+Tagged Array Definition:
+
+All indices and lengths are given in bytes.
+
+ID: number_type
+START INDEX: 0
+LENGTH: 1
+DESCRIPTION:
+ 'F' : IEEE floating point numbers
+ 'I' : Integer numbers
+
+ID: endiness
+START INDEX: 1
+LENGTH: 1
+DESCRIPTION:
+ 'L' : Little Endian
+ 'B' : Big Endian
+
+ID: element_size
+START INDEX: 2
+LENGTH: 1
+DESCRIPTION:
+ Size in Bytes (e.g. 4 for a 32bit number, or 8 for a 64bit number)
+
+ID: rank
+START INDEX: 3
+LENGTH: 1
+DESCRIPTION:
+ Rank of the array (e.g. 2 for a matrix or 3 for a cube)
+
+ID: dimensions
+START INDEX: 4
+LENGTH: 4 * rank
+DESCRIPTION:
+ Dimensions of the array along each axis; each entry is a 32bit (4 byte) integer number in the specified endiness
+
+ID: data
+START INDEX: 4 + 4 * rank
+LENGTH: prod(dimensions)
+DESCRIPTION:
+ Number array with prod(dimensions) elements in C row-major order;
+ each element is a number of the specified number_type, endiness and element_size
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..667288a
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e4d08ce
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 23 11:31:33 CEST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://svncisd.ethz.ch/repos/cisd/ivy-repository/trunk/gradle/distribution/1.8/gradle-1.8-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+ at if "%DEBUG%" == "" @echo off
+ at rem ##########################################################################
+ at rem
+ at rem Gradle startup script for Windows
+ at rem
+ at rem ##########################################################################
+
+ at rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+ at rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+ at rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+ at rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+ at rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+ at rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+ at rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+ at rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+ at rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/resource/dependency-structure.ddf b/resource/dependency-structure.ddf
new file mode 100644
index 0000000..b463616
--- /dev/null
+++ b/resource/dependency-structure.ddf
@@ -0,0 +1,6 @@
+{package} = ch.systemsx.cisd.base
+
+layer exceptions = ${package}.exceptions
+layer rest = ${package}.mdarray ${package}.namedthread ${package}.unix ${package}.utilities
+
+check layeringOf exceptions rest
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..8062ac2
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+// Don't delete it eventough it is empty!
diff --git a/source/c/COPYING b/source/c/COPYING
new file mode 100644
index 0000000..7ca6009
--- /dev/null
+++ b/source/c/COPYING
@@ -0,0 +1,88 @@
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF)
+Java Software Library and Utilities
+
+NCSA Hierarchical Data Format (HDF) Software Library and Utilities
+Copyright 1988-2004, the Board of Trustees of the University of Illinois.
+Copyright 2007-2009, Center for Information Sciences and Databases, ETH Zurich, Switzerland.
+All rights reserved.
+
+Contributors to the library: National Center for Supercomputing
+Applications (NCSA) at the University of Illinois, Lawrence
+Livermore Nationall Laboratory (LLNL), Sandia National Laboratories (SNL),
+Los Alamos National Laboratory (LANL). Fortner Software, Unidata
+Program Center (netCDF), The Independent JPEG Group (JPEG),
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment
+Corporation (DEC). Macintosh support contributed by Gregory L. Guerin.
+Center for Information Sciences and Databases, ETH Zurich, Switzerland
+
+The package 'glguerin':
+Copyright 1998, 1999 by Gregory L. Guerin.
+Redistribute or reuse only as described below.
+These files are from the MacBinary Toolkit for Java:
+ <http://www.amug.org/~glguerin/sw/#macbinary>
+and are redistributed by NCSA with permission of the author.
+
+This work was supported in part by a Cooperative Agreement with
+NASA under NASA grant NAG 5-2040 and NAG NCC5-599.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or materials provided with the distribution.
+
+3. In addition, redistributions of modified forms of the source or binary
+ code must carry prominent notices stating that the original code was
+ changed and the date of the change.
+
+4. All publications or advertising materials mentioning features or use of
+ this software must acknowledge that it was developed by the National
+ Center for Supercomputing Applications at the University of Illinois, and
+ credit the Contributors.
+
+5. Neither the name of the University nor the names of the Contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission from the University or the Contributors.
+
+6. THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS"
+ WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. In no event
+ shall the University or the Contributors be liable for any damages
+ suffered by the users arising out of the use of this software, even if
+ advised of the possibility of such damage.
+
+--------------------------------------------------------------------------
+Portions of HDF5 were developed with support from the University of
+California, Lawrence Livermore National Laboratory (UC LLNL).
+The following statement applies to those portions of the product
+and must be retained in any redistribution of source code, binaries,
+documentation, and/or accompanying materials:
+
+ This work was partially produced at the University of California,
+ Lawrence Livermore National Laboratory (UC LLNL) under contract no.
+ W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy
+ (DOE) and The Regents of the University of California (University)
+ for the operation of UC LLNL.
+
+ DISCLAIMER:
+ This work was prepared as an account of work sponsored by an agency
+ of the United States Government. Neither the United States
+ Government nor the University of California nor any of their
+ employees, makes any warranty, express or implied, or assumes any
+ liability or responsibility for the accuracy, completeness, or
+ usefulness of any information, apparatus, product, or process
+ disclosed, or represents that its use would not infringe privately-
+ owned rights. Reference herein to any specific commercial products,
+ process, or service by trade name, trademark, manufacturer, or
+ otherwise, does not necessarily constitute or imply its endorsement,
+ recommendation, or favoring by the United States Government or the
+ University of California. The views and opinions of authors
+ expressed herein do not necessarily state or reflect those of the
+ United States Government or the University of California, and shall
+ not be used for advertising or product endorsement purposes.
+--------------------------------------------------------------------------
+
diff --git a/source/c/compile_linux_amd64.sh b/source/c/compile_linux_amd64.sh
new file mode 100755
index 0000000..038f83a
--- /dev/null
+++ b/source/c/compile_linux_amd64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -shared -O3 -fPIC unix.c -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_linux_arm.sh b/source/c/compile_linux_arm.sh
new file mode 100755
index 0000000..2b57024
--- /dev/null
+++ b/source/c/compile_linux_arm.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_linux_i386.sh b/source/c/compile_linux_i386.sh
new file mode 100755
index 0000000..e9cb840
--- /dev/null
+++ b/source/c/compile_linux_i386.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m32 -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m32 -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_macosx_i386.sh b/source/c/compile_macosx_i386.sh
new file mode 100755
index 0000000..e8f5345
--- /dev/null
+++ b/source/c/compile_macosx_i386.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib
diff --git a/source/c/compile_macosx_x86_64.sh b/source/c/compile_macosx_x86_64.sh
new file mode 100755
index 0000000..ec2d736
--- /dev/null
+++ b/source/c/compile_macosx_x86_64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -D_DARWIN_USE_64_BIT_INODE -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib
diff --git a/source/c/compile_solaris_amd64.sh b/source/c/compile_solaris_amd64.sh
new file mode 100755
index 0000000..16c3ac9
--- /dev/null
+++ b/source/c/compile_solaris_amd64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_sparc.sh b/source/c/compile_solaris_sparc.sh
new file mode 100755
index 0000000..99e2dd2
--- /dev/null
+++ b/source/c/compile_solaris_sparc.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
+cc -G -KPIC -DMACHINE_BYTE_ORDER=2 copy*.c -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_sparcv9.sh b/source/c/compile_solaris_sparcv9.sh
new file mode 100755
index 0000000..37852b4
--- /dev/null
+++ b/source/c/compile_solaris_sparcv9.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
+cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=2 copy*.c -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_x86.sh b/source/c/compile_solaris_x86.sh
new file mode 100755
index 0000000..588e192
--- /dev/null
+++ b/source/c/compile_solaris_x86.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+cc -G -KPIC -fast -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_windows_i386.mak b/source/c/compile_windows_i386.mak
new file mode 100644
index 0000000..8ebb900
--- /dev/null
+++ b/source/c/compile_windows_i386.mak
@@ -0,0 +1,181 @@
+#============================================================================
+#
+# Makefile to compile the 'nativedata' native library
+# Usage: nmake /f compile_windows_i386.mak
+#
+#============================================================================
+
+# Visual C++ directory, for example
+VCPPDIR=C:\Program Files\Microsoft Visual Studio 9.0\VC
+
+# Directory where JDK is installed (We require JDK 1.6)
+JAVADIR=C:\Program Files\Java\jdk1.6.0_37
+
+# Common parent directory
+PARENTDIR=C:\nativeData
+
+# Directory of the HDF Java Products, for example
+SRCDIR=$(PARENTDIR)\c\
+
+#===========================================================================
+# Do not make any change below this line unless you know what you do
+#===========================================================================
+PATH=$(PATH);$(VCPPDIR)\BIN
+SRCDIR=$(SRCDIR)
+
+VALID_PATH_SET=YES
+#-------------------------------------------------------
+# Test if all path is valid
+
+!IF EXISTS("$(VCPPDIR)")
+!ELSE
+!MESSAGE ERROR: Visual C++ directory $(VCPPDIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+!IF EXISTS("$(JAVADIR)")
+!ELSE
+!MESSAGE ERROR: JDK directory $(JAVADIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+!IF EXISTS("$(SRCDIR)")
+!ELSE
+!MESSAGE ERROR: C source directory $(SRCDIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+#-------------------------------------------------------
+
+
+!IF "$(VALID_PATH_SET)" == "YES"
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+INTDIR=.\nativedata\Release
+OUTDIR=$(SRCDIR)\lib\win
+
+INCLUDES = \
+ "$(JAVADIR)\include\jni.h" \
+ "$(JAVADIR)\include\win32\jni_md.h"
+
+
+ALL : "$(OUTDIR)\nativedata.dll"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /W3 /EHsc /O2 /I "$(JAVADIR)\include" /I "$(JAVADIR)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "MACHINE_BYTE_ORDER=1" /Fp"$(INTDIR)\nativedata.pch" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(INTDIR)\nativedata.bsc"
+BSC32_SBRS= \
+
+LINK=link.exe
+LINK_FLAGS=/nologo /dll /nodefaultlib:msvcrt /incremental:no /pdb:"$(INTDIR)\nativedata.pdb" /machine:I386 /out:"$(OUTDIR)\nativedata.dll" /implib:"$(INTDIR)\nativedata.lib"
+LINK_OBJS= \
+ "$(INTDIR)\copyCommon.obj" \
+ "$(INTDIR)\copyByteDouble.obj" \
+ "$(INTDIR)\copyByteFloat.obj" \
+ "$(INTDIR)\copyByteInt.obj" \
+ "$(INTDIR)\copyByteLong.obj" \
+ "$(INTDIR)\copyByteShort.obj" \
+ "$(INTDIR)\copyByteChar.obj"
+
+"$(OUTDIR)\nativedata.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
+ $(LINK) @<<
+ $(LINK_FLAGS) $(LINK_OBJS)
+<<
+
+
+SOURCE=$(SRCDIR)\copyCommon.c
+
+"$(INTDIR)\copyCommon.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=$(SRCDIR)\copyByteDouble.c
+
+"$(INTDIR)\copyByteDouble.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteFloat.c
+
+"$(INTDIR)\copyByteFloat.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteInt.c
+
+"$(INTDIR)\copyByteInt.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteLong.c
+
+"$(INTDIR)\copyByteLong.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteShort.c
+
+"$(INTDIR)\copyByteShort.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteChar.c
+
+"$(INTDIR)\copyByteChar.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+CLEAN :
+ - at erase "$(INTDIR)\copyCommon.obj"
+ - at erase "$(INTDIR)\copyByteDouble.obj"
+ - at erase "$(INTDIR)\copyByteFloat.obj"
+ - at erase "$(INTDIR)\copyByteInt.obj"
+ - at erase "$(INTDIR)\copyByteLong.obj"
+ - at erase "$(INTDIR)\copyByteShort.obj"
+ - at erase "$(INTDIR)\copyByteChar.obj"
+ - at erase "$(INTDIR)\vc90.idb"
+ - at erase "$(INTDIR)\nativedata.exp"
+ - at erase "$(INTDIR)\nativedata.lib"
+ - at erase "$(OUTDIR)\nativedata.dll"
+
+!ENDIF
diff --git a/source/c/compile_windows_x64.mak b/source/c/compile_windows_x64.mak
new file mode 100644
index 0000000..52f71d7
--- /dev/null
+++ b/source/c/compile_windows_x64.mak
@@ -0,0 +1,182 @@
+#============================================================================
+#
+# Makefile to compile the 'nativedata' native library
+# Usage: nmake /f compile_windows_i386.mak
+#
+#============================================================================
+
+# Visual C++ directory, for example
+VCPPDIR=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC
+
+# Directory where JDK is installed (We require JDK 1.6)
+JAVADIR=C:\Program Files\Java\jdk1.6.0_37
+
+# Common parent directory
+PARENTDIR=C:\nativeData
+
+# Directory of the HDF Java Products, for example
+SRCDIR=$(PARENTDIR)\c\
+
+#===========================================================================
+# Do not make any change below this line unless you know what you do
+#===========================================================================
+PATH=$(PATH);$(VCPPDIR)\BIN
+SRCDIR=$(SRCDIR)
+
+VALID_PATH_SET=YES
+#-------------------------------------------------------
+# Test if all path is valid
+
+!IF EXISTS("$(VCPPDIR)")
+!ELSE
+!MESSAGE ERROR: Visual C++ directory $(VCPPDIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+!IF EXISTS("$(JAVADIR)")
+!ELSE
+!MESSAGE ERROR: JDK directory $(JAVADIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+!IF EXISTS("$(SRCDIR)")
+!ELSE
+!MESSAGE ERROR: C source directory $(SRCDIR) does not exist
+VALID_PATH_SET=NO
+!ENDIF
+
+#-------------------------------------------------------
+
+
+!IF "$(VALID_PATH_SET)" == "YES"
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+INTDIR=.\nativedata\Release
+OUTDIR=$(SRCDIR)\lib\win
+
+INCLUDES = \
+ "$(JAVADIR)\include\jni.h" \
+ "$(JAVADIR)\include\win32\jni_md.h"
+
+
+ALL : "$(OUTDIR)\nativedata.dll"
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /W3 /EHsc /O2 /I "$(JAVADIR)\include" /I "$(JAVADIR)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "MACHINE_BYTE_ORDER=1" /Fp"$(INTDIR)\nativedata.pch" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(INTDIR)\nativedata.bsc"
+BSC32_SBRS= \
+
+LINK=link.exe
+LINK_FLAGS=/nologo /dll /nodefaultlib:msvcrt /incremental:no /pdb:"$(INTDIR)\nativedata.pdb" /machine:x64 /out:"$(OUTDIR)\nativedata.dll" /implib:"$(INTDIR)\nativedata.lib"
+LINK_OBJS= \
+ "$(INTDIR)\copyCommon.obj" \
+ "$(INTDIR)\copyByteDouble.obj" \
+ "$(INTDIR)\copyByteFloat.obj" \
+ "$(INTDIR)\copyByteInt.obj" \
+ "$(INTDIR)\copyByteLong.obj" \
+ "$(INTDIR)\copyByteShort.obj" \
+ "$(INTDIR)\copyByteChar.obj"
+
+
+"$(OUTDIR)\nativedata.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
+ $(LINK) @<<
+ $(LINK_FLAGS) $(LINK_OBJS)
+<<
+
+
+SOURCE=$(SRCDIR)\copyCommon.c
+
+"$(INTDIR)\copyCommon.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=$(SRCDIR)\copyByteDouble.c
+
+"$(INTDIR)\copyByteDouble.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteFloat.c
+
+"$(INTDIR)\copyByteFloat.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteInt.c
+
+"$(INTDIR)\copyByteInt.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteLong.c
+
+"$(INTDIR)\copyByteLong.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteShort.c
+
+"$(INTDIR)\copyByteShort.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteChar.c
+
+"$(INTDIR)\copyByteChar.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+CLEAN :
+ - at erase "$(INTDIR)\copyCommon.obj"
+ - at erase "$(INTDIR)\copyByteDouble.obj"
+ - at erase "$(INTDIR)\copyByteFloat.obj"
+ - at erase "$(INTDIR)\copyByteInt.obj"
+ - at erase "$(INTDIR)\copyByteLong.obj"
+ - at erase "$(INTDIR)\copyByteShort.obj"
+ - at erase "$(INTDIR)\copyByteChar.obj"
+ - at erase "$(INTDIR)\vc90.idb"
+ - at erase "$(INTDIR)\nativedata.exp"
+ - at erase "$(INTDIR)\nativedata.lib"
+ - at erase "$(OUTDIR)\nativedata.dll"
+
+!ENDIF
diff --git a/source/c/copyByteChar.c b/source/c/copyByteChar.c
new file mode 100644
index 0000000..02b8a17
--- /dev/null
+++ b/source/c/copyByteChar.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jchar
+#define TARGET_ARRAY jcharArray
+#define METHODNAMETB "copyCharToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyCharToByte___3CI_3BIII
+#define METHODNAMEBT "copyByteToChar"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToChar___3BI_3CIII
+#define COPY_FUNC GetCharArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_2
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteDouble.c b/source/c/copyByteDouble.c
new file mode 100644
index 0000000..734d739
--- /dev/null
+++ b/source/c/copyByteDouble.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, double, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jdouble
+#define TARGET_ARRAY jdoubleArray
+#define METHODNAMETB "copyDoubleToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyDoubleToByte___3DI_3BIII
+#define METHODNAMEBT "copyByteToDouble"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToDouble___3BI_3DIII
+#define COPY_FUNC GetDoubleArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_8
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteFloat.c b/source/c/copyByteFloat.c
new file mode 100644
index 0000000..797a818
--- /dev/null
+++ b/source/c/copyByteFloat.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jfloat
+#define TARGET_ARRAY jfloatArray
+#define METHODNAMETB "copyFloatToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyFloatToByte___3FI_3BIII
+#define METHODNAMEBT "copyByteToFloat"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToFloat___3BI_3FIII
+#define COPY_FUNC GetFloatArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_4
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteInt.c b/source/c/copyByteInt.c
new file mode 100644
index 0000000..4227546
--- /dev/null
+++ b/source/c/copyByteInt.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jint
+#define TARGET_ARRAY jintArray
+#define METHODNAMETB "copyIntToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyIntToByte___3II_3BIII
+#define METHODNAMEBT "copyByteToInt"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToInt___3BI_3IIII
+#define COPY_FUNC GetIntArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_4
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteLong.c b/source/c/copyByteLong.c
new file mode 100644
index 0000000..c28352f
--- /dev/null
+++ b/source/c/copyByteLong.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jlong
+#define TARGET_ARRAY jlongArray
+#define METHODNAMETB "copyLongToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyLongToByte___3JI_3BIII
+#define METHODNAMEBT "copyByteToLong"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToLong___3BI_3JIII
+#define COPY_FUNC GetLongArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_8
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteShort.c b/source/c/copyByteShort.c
new file mode 100644
index 0000000..5081ab7
--- /dev/null
+++ b/source/c/copyByteShort.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#define TARGET jshort
+#define TARGET_ARRAY jshortArray
+#define METHODNAMETB "copyShortToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyShortToByte___3SI_3BIII
+#define METHODNAMEBT "copyByteToShort"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToShort___3BI_3SIII
+#define COPY_FUNC GetShortArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_2
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteTarget.ctempl b/source/c/copyByteTarget.ctempl
new file mode 100644
index 0000000..7d9b8d2
--- /dev/null
+++ b/source/c/copyByteTarget.ctempl
@@ -0,0 +1,241 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This module contains the implementation of all the native methods
+ * used for number conversion. This is represented by the Java
+ * class HDFNativeData.
+ *
+ * These routines convert one dimensional arrays of bytes into
+ * one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ * These routines are called from the Java parts of the Java-C
+ * interface.
+ *
+ * ***Important notes:
+ *
+ * 1. These routines are designed to be portable--they use the
+ * C compiler to do the required native data manipulation.
+ * 2. These routines copy the data at least once -- a serious
+ * but unavoidable performance hit.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <jni.h>
+
+extern jboolean h5JNIFatalError( JNIEnv *env, char *functName);
+extern jboolean h5nullArgument( JNIEnv *env, char *functName);
+extern jboolean h5badArgument( JNIEnv *env, char *functName);
+extern jboolean h5indexOutOfBounds( JNIEnv *env, char *functName);
+
+/* Change byte order for data type of length 2. */
+#define CHANGE_BYTE_ORDER_2(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[1]; ARRAY[1]=_tmp;}
+/* Change byte order for data type of length 4. */
+#define CHANGE_BYTE_ORDER_4(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[3]; ARRAY[3]=_tmp; _tmp=ARRAY[1]; ARRAY[1]=ARRAY[2]; ARRAY[2]=_tmp;}
+/* Change byte order for data type of length 8. */
+#define CHANGE_BYTE_ORDER_8(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[7]; ARRAY[7]=_tmp; _tmp=ARRAY[1]; ARRAY[1]=ARRAY[6]; ARRAY[6]=_tmp; _tmp=ARRAY[2]; ARRAY[2]=ARRAY[5]; ARRAY[5]=_tmp; _tmp=ARRAY[3]; ARRAY[3]=ARRAY[4]; ARRAY[4]=_tmp;}
+
+#define INDATA_IS_NULL_ERR_TB METHODNAMETB ": inData is NULL"
+#define OUTDATA_IS_NULL_ERR_TB METHODNAMETB ": outData is NULL"
+#define OOB_IN_ERR_TB METHODNAMETB ": inStart or len is out of bounds"
+#define OOB_OUT_ERR_TB METHODNAMETB ": outStart or len is out of bounds"
+#define PINNING_OUT_ERR_TB METHODNAMETB ": pinning outArray failed"
+
+#define INDATA_IS_NULL_ERR_BT METHODNAMEBT ": inData is NULL"
+#define OUTDATA_IS_NULL_ERR_BT METHODNAMEBT ": outData is NULL"
+#define OOB_IN_ERR_BT METHODNAMEBT ": inStart or len is out of bounds"
+#define OOB_OUT_ERR_BT METHODNAMEBT ": outStart or len is out of bounds"
+#define PINNING_OUT_ERR_BT METHODNAMEBT ": pinning outArray failed"
+
+/*
+ * public static native void copy<TARGET_CAPT>oByte(<TARGET>[] inData, int inStart,
+ * byte[] outData, int outStart, int len, int byteOrder);
+ */
+JNIEXPORT void JNICALL FUNCTIONNAMETB
+(JNIEnv *env,
+ jclass clss,
+ TARGET_ARRAY inData, /* IN: array of TARGET */
+ jint inStart,
+ jbyteArray outData, /* OUT: array of byte */
+ jint outStart,
+ jint len,
+ jint byteOrder
+)
+{
+ jsize inSize, outSize;
+ jint lenInBytes;
+ jbyte *outArray;
+ jboolean isCopy;
+
+ if (inData == NULL) {
+ h5nullArgument(env, INDATA_IS_NULL_ERR_BT);
+ return;
+ }
+
+ if (outData == NULL) {
+ h5nullArgument(env, OUTDATA_IS_NULL_ERR_TB);
+ return;
+ }
+
+ lenInBytes = len * sizeof(TARGET);
+
+#ifdef __cplusplus
+ inSize = env->GetArrayLength(inData);
+#else
+ inSize = (*env)->GetArrayLength(env, inData);
+#endif
+ if ((inStart < 0) || (inStart + len > inSize)) {
+ h5indexOutOfBounds(env, OOB_IN_ERR_TB);
+ return;
+ }
+
+#ifdef __cplusplus
+ outSize = env->GetArrayLength(outData);
+#else
+ outSize = (*env)->GetArrayLength(env, outData);
+#endif
+ if ((outStart < 0) || (outStart + lenInBytes > outSize)) {
+ h5indexOutOfBounds(env, OOB_OUT_ERR_TB);
+ return;
+ }
+
+#ifdef __cplusplus
+ outArray = env->GetPrimitiveArrayCritical(outData, &isCopy);
+#else
+ outArray = (*env)->GetPrimitiveArrayCritical(env, outData, &isCopy);
+#endif
+ if (outArray == NULL) {
+ h5JNIFatalError(env, PINNING_OUT_ERR_TB);
+ return;
+ }
+
+#ifdef __cplusplus
+ env->COPY_FUNC(inData, inStart, len, (TARGET*) (outArray + outStart));
+#else
+ (*env)->COPY_FUNC(env, inData, inStart, len, (TARGET*) (outArray + outStart));
+#endif
+
+ if (byteOrder > 0 && byteOrder != MACHINE_BYTE_ORDER)
+ {
+ jbyte *buf = outArray + outStart;
+ int nelmts;
+ for(nelmts = 0; nelmts < len; ++nelmts)
+ {
+ CHANGE_BYTE_ORDER(buf);
+ buf += sizeof(TARGET);
+ }
+ }
+
+#ifdef __cplusplus
+ env->ReleasePrimitiveArrayCritical(outData, outArray, 0);
+#else
+ (*env)->ReleasePrimitiveArrayCritical(env, outData,outArray, 0);
+#endif
+
+ return;
+}
+
+/*
+ * public static native void copyByteTo<TARGET_CAP>(byte[] inData, int inStart,
+ * TARGET[] outData, int outStart, int len, int byteOrder);
+ */
+JNIEXPORT void JNICALL FUNCTIONNAMEBT
+(JNIEnv *env,
+ jclass clss,
+ jbyteArray inData, /* IN: array of byte */
+ jint inStart,
+ TARGET_ARRAY outData, /* OUT: array of TAGET */
+ jint outStart,
+ jint len,
+ jint byteOrder
+ )
+{
+ jsize inSize, outSize;
+ jint lenInBytes;
+ TARGET *outArray;
+ jboolean isCopy;
+
+ if (inData == NULL) {
+ h5nullArgument(env, INDATA_IS_NULL_ERR_BT);
+ return;
+ }
+
+ if (outData == NULL) {
+ h5nullArgument(env, OUTDATA_IS_NULL_ERR_BT);
+ return;
+ }
+
+ lenInBytes = len * sizeof(TARGET);
+
+#ifdef __cplusplus
+ inSize = env->GetArrayLength(inData);
+#else
+ inSize = (*env)->GetArrayLength(env, inData);
+#endif
+ if ((inStart < 0) || (inStart + lenInBytes > inSize)) {
+ h5indexOutOfBounds(env, OOB_IN_ERR_BT);
+ return;
+ }
+
+#ifdef __cplusplus
+ outSize = env->GetArrayLength(outData);
+#else
+ outSize = (*env)->GetArrayLength(env, outData);
+#endif
+ if ((outStart < 0) || (outStart + len > outSize)) {
+ h5indexOutOfBounds(env, OOB_OUT_ERR_BT);
+ return;
+ }
+
+#ifdef __cplusplus
+ outArray = env->GetPrimitiveArrayCritical(outData, &isCopy);
+#else
+ outArray = (*env)->GetPrimitiveArrayCritical(env, outData, &isCopy);
+#endif
+ if (outArray == NULL) {
+ h5JNIFatalError(env, PINNING_OUT_ERR_BT);
+ return;
+ }
+
+#ifdef __cplusplus
+ env->GetByteArrayRegion(inData, inStart, lenInBytes, outArray + outStart);
+#else
+ (*env)->GetByteArrayRegion(env, inData, inStart, lenInBytes, (jbyte*) (outArray + outStart));
+#endif
+
+ if (byteOrder > 0 && byteOrder != MACHINE_BYTE_ORDER)
+ {
+ jbyte *buf = (jbyte*) outArray + outStart;
+ int nelmts;
+ for(nelmts = 0; nelmts < len; ++nelmts)
+ {
+ CHANGE_BYTE_ORDER(buf);
+ buf += sizeof(TARGET);
+ }
+ }
+
+#ifdef __cplusplus
+ env->ReleasePrimitiveArrayCritical(outData, outArray, 0);
+#else
+ (*env)->ReleasePrimitiveArrayCritical(env, outData, outArray, 0);
+#endif
+
+ return;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/c/copyCommon.c b/source/c/copyCommon.c
new file mode 100755
index 0000000..40a0278
--- /dev/null
+++ b/source/c/copyCommon.c
@@ -0,0 +1,268 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Comptational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+/*
+ * This is a utility program used by native code to generate Java exceptions.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "jni.h"
+
+/*
+ * public static native boolean isLittleEndian();
+ */
+JNIEXPORT jboolean JNICALL Java_ch_systemsx_cisd_base_convert_NativeData_isLittleEndian
+(JNIEnv *env,
+ jclass clss
+ )
+{
+ return MACHINE_BYTE_ORDER == 1;
+}
+
+/*
+ * A fatal error in a JNI call
+ * Create and throw an 'InternalError'
+ *
+ * Note: This routine never returns from the 'throw',
+ * and the Java native method immediately raises the
+ * exception.
+ */
+jboolean h5JNIFatalError( JNIEnv *env, char *functName)
+{
+ jmethodID jm;
+ jclass jc;
+ char * args[2];
+ jobject ex;
+ jstring str;
+ int rval;
+
+#ifdef __cplusplus
+ jc = env->FindClass("java/lang/InternalError");
+#else
+ jc = (*env)->FindClass(env, "java/lang/InternalError");
+#endif
+ if (jc == NULL) {
+ return JNI_FALSE;
+ }
+#ifdef __cplusplus
+ jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+ jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+ if (jm == NULL) {
+ return JNI_FALSE;
+ }
+
+#ifdef __cplusplus
+ str = env->NewStringUTF(functName);
+#else
+ str = (*env)->NewStringUTF(env,functName);
+#endif
+ args[0] = (char *)str;
+ args[1] = 0;
+#ifdef __cplusplus
+ ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+ rval = env->Throw( (jthrowable) ex );
+#else
+ ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+ rval = (*env)->Throw(env, ex );
+#endif
+ if (rval < 0) {
+ fprintf(stderr, "FATAL ERROR: JNIFatal: Throw failed\n");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+/*
+ * A NULL argument in an HDF5 call
+ * Create and throw an 'NullPointerException'
+ *
+ * Note: This routine never returns from the 'throw',
+ * and the Java native method immediately raises the
+ * exception.
+ */
+jboolean h5nullArgument( JNIEnv *env, char *functName)
+{
+ jmethodID jm;
+ jclass jc;
+ char * args[2];
+ jobject ex;
+ jstring str;
+ int rval;
+
+#ifdef __cplusplus
+ jc = env->FindClass("java/lang/NullPointerException");
+#else
+ jc = (*env)->FindClass(env, "java/lang/NullPointerException");
+#endif
+ if (jc == NULL) {
+ return JNI_FALSE;
+ }
+#ifdef __cplusplus
+ jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+ jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+ if (jm == NULL) {
+ return JNI_FALSE;
+ }
+
+#ifdef __cplusplus
+ str = env->NewStringUTF(functName);
+#else
+ str = (*env)->NewStringUTF(env,functName);
+#endif
+ args[0] = (char *)str;
+ args[1] = 0;
+#ifdef __cplusplus
+ ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+ rval = env->Throw((jthrowable) ex );
+#else
+ ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+ rval = (*env)->Throw(env, ex );
+#endif
+
+ if (rval < 0) {
+ fprintf(stderr, "FATAL ERROR: NullPointer: Throw failed\n");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+/*
+ * A bad argument in an HDF5 call
+ * Create and throw an 'IllegalArgumentException'
+ *
+ * Note: This routine never returns from the 'throw',
+ * and the Java native method immediately raises the
+ * exception.
+ */
+jboolean h5badArgument( JNIEnv *env, char *functName)
+{
+ jmethodID jm;
+ jclass jc;
+ char * args[2];
+ jobject ex;
+ jstring str;
+ int rval;
+
+#ifdef __cplusplus
+ jc = env->FindClass("java/lang/IllegalArgumentException");
+#else
+ jc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
+#endif
+ if (jc == NULL) {
+ return JNI_FALSE;
+ }
+#ifdef __cplusplus
+ jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+ jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+ if (jm == NULL) {
+ return JNI_FALSE;
+ }
+
+#ifdef __cplusplus
+ str = env->NewStringUTF(functName);
+#else
+ str = (*env)->NewStringUTF(env,functName);
+#endif
+ args[0] = (char *)str;
+ args[1] = 0;
+#ifdef __cplusplus
+ ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+ rval = env->Throw((jthrowable) ex );
+#else
+ ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+ rval = (*env)->Throw(env, ex );
+#endif
+ if (rval < 0) {
+ fprintf(stderr, "FATAL ERROR: BadArgument: Throw failed\n");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+/*
+ * An Index-out-of-bounds error argument in an HDF5 call
+ * Create and throw an 'IllegalArgumentException'
+ *
+ * Note: This routine never returns from the 'throw',
+ * and the Java native method immediately raises the
+ * exception.
+ */
+jboolean h5indexOutOfBounds( JNIEnv *env, char *functName)
+{
+ jmethodID jm;
+ jclass jc;
+ char * args[2];
+ jobject ex;
+ jstring str;
+ int rval;
+
+#ifdef __cplusplus
+ jc = env->FindClass("java/lang/IndexOutOfBoundsException");
+#else
+ jc = (*env)->FindClass(env, "java/lang/IndexOutOfBoundsException");
+#endif
+ if (jc == NULL) {
+ return JNI_FALSE;
+ }
+#ifdef __cplusplus
+ jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+ jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+ if (jm == NULL) {
+ return JNI_FALSE;
+ }
+
+#ifdef __cplusplus
+ str = env->NewStringUTF(functName);
+#else
+ str = (*env)->NewStringUTF(env,functName);
+#endif
+ args[0] = (char *)str;
+ args[1] = 0;
+#ifdef __cplusplus
+ ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+ rval = env->Throw((jthrowable) ex );
+#else
+ ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+ rval = (*env)->Throw(env, ex );
+#endif
+ if (rval < 0) {
+ fprintf(stderr, "FATAL ERROR: BadArgument: Throw failed\n");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/c/unix.c b/source/c/unix.c
new file mode 100644
index 0000000..1cfeef9
--- /dev/null
+++ b/source/c/unix.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <jni.h>
+
+/* Types of links. Keep in sync with Java enum. */
+#define REGULAR_FILE 0
+#define DIRECTORY 1
+#define SYMLINK 2
+#define OTHER 3
+
+#ifndef __STAT
+#define __STAT stat
+#endif
+
+#ifndef __LSTAT
+#define __LSTAT lstat
+#endif
+
+/* Global references. */
+jclass stringClass;
+jclass passwordClass;
+jmethodID passwordConstructorID;
+jclass groupClass;
+jmethodID groupConstructorID;
+jclass statClass;
+jmethodID statConstructorID;
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_init
+ (JNIEnv *env, jclass clss)
+{
+ stringClass = (*env)->FindClass(env, "java/lang/String");
+ if (stringClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+ {
+ return -1;
+ }
+ stringClass = (*env)->NewGlobalRef(env, stringClass);
+ passwordClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Password");
+ if (passwordClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+ {
+ return -1;
+ }
+ passwordClass = (*env)->NewGlobalRef(env, passwordClass);
+ passwordConstructorID = (*env)->GetMethodID(env, passwordClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ if (passwordConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+ {
+ return -1;
+ }
+ groupClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Group");
+ if (groupClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+ {
+ return -1;
+ }
+ groupClass = (*env)->NewGlobalRef(env, groupClass);
+ groupConstructorID = (*env)->GetMethodID(env, groupClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;)V");
+ if (groupConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+ {
+ return -1;
+ }
+ statClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Stat");
+ if (statClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+ {
+ return -1;
+ }
+ statClass = (*env)->NewGlobalRef(env, statClass);
+ statConstructorID = (*env)->GetMethodID(env, statClass, "<init>", "(JJSBIIIJJJJJI)V");
+ if (groupConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+ {
+ return -1;
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_link
+ (JNIEnv *env, jclass clss, jstring filename, jstring linktarget)
+{
+ const char* pfilename;
+ const char* plinktarget;
+ int retval;
+
+ pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+ plinktarget = (char *)(*env)->GetStringUTFChars(env, linktarget, NULL);
+
+ retval = link(pfilename, plinktarget);
+ if (retval < 0)
+ {
+ retval = -errno;
+ }
+
+ (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+ (*env)->ReleaseStringUTFChars(env, linktarget, plinktarget);
+
+ return retval;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_symlink
+ (JNIEnv *env, jclass clss, jstring filename, jstring linktarget)
+{
+ const char* pfilename;
+ const char* plinktarget;
+ int retval;
+
+ pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+ plinktarget = (char *)(*env)->GetStringUTFChars(env, linktarget, NULL);
+
+ retval = symlink(pfilename, plinktarget);
+ if (retval < 0) {
+ retval = -errno;
+ }
+
+ (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+ (*env)->ReleaseStringUTFChars(env, linktarget, plinktarget);
+
+ return retval;
+}
+
+/* Function pointer for stat function calls. */
+typedef int (*stat_func_ptr)(const char *path, struct __STAT *buf);
+
+jobject call_stat(JNIEnv *env, jclass clss, jstring filename, stat_func_ptr statf)
+{
+ const char* pfilename;
+ struct __STAT s;
+ jobject result;
+ int retval;
+ jbyte type;
+
+ pfilename = (char *) (*env)->GetStringUTFChars(env, filename, NULL);
+ retval = statf(pfilename, &s);
+ (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+ if (retval < 0)
+ {
+ return NULL;
+ } else
+ {
+ if (S_ISLNK(s.st_mode))
+ {
+ type = SYMLINK;
+ } else if (S_ISDIR(s.st_mode))
+ {
+ type = DIRECTORY;
+ } else if (S_ISREG(s.st_mode))
+ {
+ type = REGULAR_FILE;
+ } else
+ {
+ type = OTHER;
+ }
+ result = (*env)->NewObject(env, statClass, statConstructorID, (jlong) s.st_dev, (jlong) s.st_ino,
+ (jshort) (s.st_mode & 07777), (jbyte) type, (jint) s.st_nlink,
+ (jint) s.st_uid, (jint) s.st_gid, (jlong) s.st_atime, (jlong) s.st_mtime,
+ (jlong) s.st_ctime, (jlong) s.st_size, (jlong) s.st_blocks, (jint) s.st_blksize);
+ return result;
+ }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_stat(JNIEnv *env, jclass clss, jstring filename)
+{
+ return call_stat(env, clss, filename, &__STAT);
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_lstat(JNIEnv *env, jclass clss, jstring filename)
+{
+ return call_stat(env, clss, filename, &__LSTAT);
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_readlink(JNIEnv *env, jclass clss, jstring linkname, jint linkvallen)
+{
+ const char* plinkname;
+ char plinkvalue[linkvallen + 1];
+ int retval;
+
+ plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+ retval = readlink(plinkname, plinkvalue, linkvallen);
+ (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+ if (retval < 0)
+ {
+ return NULL;
+ } else
+ {
+ plinkvalue[linkvallen] = '\0';
+ return (*env)->NewStringUTF(env, plinkvalue);
+ }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_chmod(JNIEnv *env, jclass clss, jstring linkname, jshort mode)
+{
+ const char* plinkname;
+ int retval;
+
+ plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+ retval = chmod(plinkname, mode);
+ (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+ if (retval < 0)
+ {
+ return -errno;
+ } else
+ {
+ return 0;
+ }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_chown(JNIEnv *env, jclass clss, jstring linkname, jint uid, jint gid)
+{
+ const char* plinkname;
+ int retval;
+
+ plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+ retval = chown(plinkname, uid, gid);
+ (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+ if (retval < 0)
+ {
+ return -errno;
+ } else
+ {
+ return 0;
+ }
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuser(JNIEnv *env, jclass clss, jint uid)
+{
+ struct passwd *pw;
+
+ pw = getpwuid(uid);
+ if (pw == NULL)
+ {
+ return NULL;
+ } else
+ {
+ return (*env)->NewStringUTF(env, pw->pw_name);
+ }
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgroup(JNIEnv *env, jclass clss, jint gid)
+{
+ struct group *gp;
+
+ gp = getgrgid(gid);
+ if (gp == NULL)
+ {
+ return NULL;
+ } else
+ {
+ return (*env)->NewStringUTF(env, gp->gr_name);
+ }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuid__(JNIEnv *env, jclass clss)
+{
+ return getuid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_geteuid(JNIEnv *env, jclass clss)
+{
+ return geteuid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuid__Ljava_lang_String_2(JNIEnv *env, jclass clss, jstring user)
+{
+ const char* puser;
+ struct passwd *pw;
+
+ puser = (char *)(*env)->GetStringUTFChars(env, user, NULL);
+ pw = getpwnam(puser);
+ (*env)->ReleaseStringUTFChars(env, user, puser);
+ if (pw == NULL)
+ {
+ return -errno;
+ } else
+ {
+ return pw->pw_uid;
+ }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpwnam(JNIEnv *env, jclass clss, jstring user)
+{
+ const char* puser;
+ struct passwd *pw;
+ jstring passwd;
+ jstring fullname;
+ jstring homedir;
+ jstring shell;
+ jobject result;
+
+ puser = (char *)(*env)->GetStringUTFChars(env, user, NULL);
+ pw = getpwnam(puser);
+ (*env)->ReleaseStringUTFChars(env, user, puser);
+ if (pw == NULL)
+ {
+ return NULL;
+ } else
+ {
+ passwd = (*env)->NewStringUTF(env, pw->pw_passwd);
+ fullname = (*env)->NewStringUTF(env, pw->pw_gecos);
+ homedir = (*env)->NewStringUTF(env, pw->pw_dir);
+ shell = (*env)->NewStringUTF(env, pw->pw_shell);
+ result = (*env)->NewObject(env, passwordClass, passwordConstructorID, user, passwd, pw->pw_uid, pw->pw_gid, fullname, homedir, shell);
+ return result;
+ }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpwuid(JNIEnv *env, jclass clss, jint uid)
+{
+ struct passwd *pw;
+ jstring user;
+ jstring passwd;
+ jstring fullname;
+ jstring homedir;
+ jstring shell;
+ jobject result;
+
+ pw = getpwuid(uid);
+ if (pw == NULL)
+ {
+ return NULL;
+ } else
+ {
+ user = (*env)->NewStringUTF(env, pw->pw_name);
+ passwd = (*env)->NewStringUTF(env, pw->pw_passwd);
+ fullname = (*env)->NewStringUTF(env, pw->pw_gecos);
+ homedir = (*env)->NewStringUTF(env, pw->pw_dir);
+ shell = (*env)->NewStringUTF(env, pw->pw_shell);
+ result = (*env)->NewObject(env, passwordClass, passwordConstructorID, user, passwd, pw->pw_uid, pw->pw_gid, fullname, homedir, shell);
+ return result;
+ }
+}
+
+JNIEXPORT jobjectArray JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgrnam(JNIEnv *env, jclass clss, jstring group)
+{
+ const char* pgroup;
+ struct group *gr;
+ jstring grouppwd;
+ jobject result;
+ jobjectArray members;
+ int i;
+
+ pgroup = (char *)(*env)->GetStringUTFChars(env, group, NULL);
+ gr = getgrnam(pgroup);
+ (*env)->ReleaseStringUTFChars(env, group, pgroup);
+ if (gr == NULL)
+ {
+ return NULL;
+ } else
+ {
+ grouppwd = (*env)->NewStringUTF(env, gr->gr_passwd);
+ /* Count group members. */
+ for (i = 0; (gr->gr_mem)[i] != NULL; ++i);
+ members = (*env)->NewObjectArray(env, i, stringClass, NULL);
+ for (i = 0; (gr->gr_mem)[i] != NULL; ++i)
+ {
+ (*env)->SetObjectArrayElement(env, members, i, (*env)->NewStringUTF(env, (gr->gr_mem)[i]));
+ }
+ result = (*env)->NewObject(env, groupClass, groupConstructorID, group, grouppwd, gr->gr_gid, members);
+ return result;
+ }
+}
+
+JNIEXPORT jobjectArray JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgrgid(JNIEnv *env, jclass clss, jint gid)
+{
+ struct group *gr;
+ jstring group;
+ jstring grouppwd;
+ jobject result;
+ jobjectArray members;
+ int i;
+
+ gr = getgrgid(gid);
+ if (gr == NULL)
+ {
+ return NULL;
+ } else
+ {
+ group = (*env)->NewStringUTF(env, gr->gr_name);
+ grouppwd = (*env)->NewStringUTF(env, gr->gr_passwd);
+ /* Count group members. */
+ for (i = 0; (gr->gr_mem)[i] != NULL; ++i);
+ members = (*env)->NewObjectArray(env, i, stringClass, NULL);
+ for (i = 0; (gr->gr_mem)[i] != NULL; ++i)
+ {
+ (*env)->SetObjectArrayElement(env, members, i, (*env)->NewStringUTF(env, (gr->gr_mem)[i]));
+ }
+ result = (*env)->NewObject(env, groupClass, groupConstructorID, group, grouppwd, gr->gr_gid, members);
+ return result;
+ }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgid__(JNIEnv *env, jclass clss)
+{
+ return getgid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getegid(JNIEnv *env, jclass clss)
+{
+ return getegid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgid__Ljava_lang_String_2(JNIEnv *env, jclass clss, jstring group)
+{
+ const char* pgroup;
+ struct group *gr;
+
+ pgroup = (char *)(*env)->GetStringUTFChars(env, group, NULL);
+ gr = getgrnam(pgroup);
+ (*env)->ReleaseStringUTFChars(env, group, pgroup);
+ if (gr == NULL)
+ {
+ return -errno;
+ } else
+ {
+ return gr->gr_gid;
+ }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpid(JNIEnv *env, jclass clss)
+{
+ return getpid();
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_strerror__I(JNIEnv *env, jclass clss, jint errnum)
+{
+ return (*env)->NewStringUTF(env, strerror(errnum < 0 ? -errnum : errnum));
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_strerror__(JNIEnv *env, jclass clss)
+{
+ return (*env)->NewStringUTF(env, strerror(errno));
+}
diff --git a/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java b/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java
new file mode 100644
index 0000000..91a10b5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base;
+
+import ch.systemsx.cisd.base.utilities.AbstractBuildAndEnvironmentInfo;
+
+
+/**
+ * The build and environment information for cisd-base.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BuildAndEnvironmentInfo extends AbstractBuildAndEnvironmentInfo
+{
+ private final static String BASE = "base";
+
+ public final static BuildAndEnvironmentInfo INSTANCE = new BuildAndEnvironmentInfo();
+
+ private BuildAndEnvironmentInfo()
+ {
+ super(BASE);
+ }
+
+ /**
+ * Shows build and environment information on the console.
+ */
+ public static void main(String[] args)
+ {
+ System.out.println(INSTANCE);
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java b/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java
new file mode 100644
index 0000000..abf69e3
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation all JSON transfered classes should be marked with. It was originally created to
+ * replace @JsonTypeName annotation which was not visible in the documentation. With @JsonTypeName
+ * annotation it would be impossible for our users to find a logical type name of a class to be sent
+ * to JSON-RPC services.
+ *
+ * @author pkupczyk
+ */
+ at Target(
+ { ElementType.TYPE })
+ at Retention(RetentionPolicy.RUNTIME)
+ at Documented
+public @interface JsonObject
+{
+ /**
+ * Logical type name for annotated type.
+ */
+ public String value();
+}
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java b/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
new file mode 100644
index 0000000..e2bfa3d
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * An enum for encoding array of numbers (integer or float) in native (host) format.
+ *
+ * @author Bernd Rinn
+ */
+public enum NativeArrayEncoding
+{
+ INT8_NATIVE(false, (byte) 1, NativeData.ByteOrder.NATIVE),
+
+ INT16_LITTLE_ENDIAN(false, (byte) 2, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+ INT32_LITTLE_ENDIAN(false, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+ INT64_LITTLE_ENDIAN(false, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+ INT16_BIG_ENDIAN(false, (byte) 2, NativeData.ByteOrder.BIG_ENDIAN),
+
+ INT32_BIG_ENDIAN(false, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+ INT64_BIG_ENDIAN(false, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+ FLOAT32_LITTLE_ENDIAN(true, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+ FLOAT64_LITTLE_ENDIAN(true, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+ FLOAT32_BIG_ENDIAN(true, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+ FLOAT64_BIG_ENDIAN(true, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+ ;
+
+ private static final int MIN_ENCODING_HEADER_SIZE = 8;
+
+ private static final int CHAR_N = 78;
+
+ private static final int CHAR_B = 66;
+
+ private static final int CHAR_L = 76;
+
+ private static final int CHAR_I = 73;
+
+ private static final int CHAR_F = 70;
+
+ private boolean floatingPoint;
+
+ private ByteOrder byteOrder;
+
+ private byte sizeInBytes;
+
+ private byte[] magic;
+
+ NativeArrayEncoding(boolean floatingPoint, byte sizeInBytes, NativeData.ByteOrder byteOrder)
+ {
+ this.floatingPoint = floatingPoint;
+ this.byteOrder = byteOrder;
+ this.sizeInBytes = sizeInBytes;
+ this.magic =
+ new byte[]
+ {
+ (byte) (floatingPoint ? CHAR_F : CHAR_I),
+ (byte) ((byteOrder == ByteOrder.LITTLE_ENDIAN) ? CHAR_L
+ : (byteOrder == ByteOrder.BIG_ENDIAN) ? CHAR_B : CHAR_N),
+ sizeInBytes };
+ }
+
+ /**
+ * Returns <code>true</code>, if the encoded array is a float array.
+ */
+ public boolean isFloatingPoint()
+ {
+ return floatingPoint;
+ }
+
+ /**
+ * Returns <code>true</code>, if the encoded array is an int array.
+ */
+ public boolean isInteger()
+ {
+ return floatingPoint == false;
+ }
+
+ /**
+ * Returns the byte order of the array.
+ */
+ public NativeData.ByteOrder getByteOrder()
+ {
+ return byteOrder;
+ }
+
+ /**
+ * Returns the size of one element in bytes.
+ */
+ public byte getSizeInBytes()
+ {
+ return sizeInBytes;
+ }
+
+ byte[] getMagic()
+ {
+ return magic;
+ }
+
+ static NativeArrayEncoding tryGetIntEncoding(ByteOrder byteOrder, byte sizeInBytes)
+ {
+ assert byteOrder != null;
+ if (sizeInBytes == 1 && byteOrder == ByteOrder.NATIVE)
+ {
+ return INT8_NATIVE;
+ } else if (sizeInBytes == 2)
+ {
+ return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT16_LITTLE_ENDIAN : INT16_BIG_ENDIAN;
+ } else if (sizeInBytes == 4)
+ {
+ return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT32_LITTLE_ENDIAN : INT32_BIG_ENDIAN;
+
+ } else if (sizeInBytes == 8)
+ {
+ return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT64_LITTLE_ENDIAN : INT64_BIG_ENDIAN;
+ }
+ return null;
+ }
+
+ static NativeArrayEncoding tryGetFloatEncoding(ByteOrder byteOrder, byte sizeInBytes)
+ {
+ assert byteOrder != null;
+ if (sizeInBytes == 4)
+ {
+ return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT32_LITTLE_ENDIAN
+ : FLOAT32_BIG_ENDIAN;
+ } else if (sizeInBytes == 8)
+ {
+ return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT64_LITTLE_ENDIAN
+ : FLOAT64_BIG_ENDIAN;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoding for the given <var>byteArr</var>, or <code>null</code>, if
+ * <var>byteArr</var> is not an encoded array.
+ */
+ public static NativeArrayEncoding tryGetEncoding(byte[] byteArr)
+ {
+ if (byteArr.length < MIN_ENCODING_HEADER_SIZE)
+ {
+ return null;
+ }
+ final ByteOrder byteOrder =
+ (byteArr[1] == CHAR_L) ? ByteOrder.LITTLE_ENDIAN
+ : (byteArr[1] == CHAR_B) ? ByteOrder.BIG_ENDIAN : null;
+ if (byteOrder == null)
+ {
+ return null;
+ }
+ if (byteArr[0] == CHAR_F)
+ {
+ return tryGetFloatEncoding(byteOrder, byteArr[2]);
+ } else if (byteArr[0] == CHAR_I)
+ {
+ return tryGetIntEncoding(byteOrder, byteArr[2]);
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeData.java b/source/java/ch/systemsx/cisd/base/convert/NativeData.java
new file mode 100644
index 0000000..f962af5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeData.java
@@ -0,0 +1,1086 @@
+/****************************************************************************
+ * NCSA HDF *
+ * National Computational Science Alliance *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * COPYING file. *
+ * *
+ ****************************************************************************/
+
+package ch.systemsx.cisd.base.convert;
+
+import java.nio.ByteBuffer;
+
+import ch.systemsx.cisd.base.utilities.NativeLibraryUtilities;
+
+/**
+ * This class encapsulates native methods to deal with arrays of numbers, converting from numbers to
+ * bytes and bytes to numbers.
+ * <p>
+ * These routines are used by class <b>HDFArray</b> to pass data to and from the HDF5 library.
+ * <p>
+ * Methods copyXxxToByte() convert a Java array of primitive numbers (int, short, ...) to a Java
+ * array of bytes. Methods copyByteToXxx() convert from a Java array of bytes into a Java array of
+ * primitive numbers (int, short, ...)
+ * <p>
+ * Variant interfaces convert only a sub-array.
+ * <p>
+ * The class has optimized methods using jni-libraries for some common platforms and a pure-java
+ * implementation (called <i>javamode</i> if the jni-libraries are not available). If you want to
+ * enforce <i>javamode</i>, you need to pass the property <code>nativedata.javamode=true</code> to
+ * the JRE.
+ */
+public class NativeData
+{
+ private static final boolean useNativeLib;
+
+ static
+ {
+ if (Boolean.getBoolean("nativedata.javamode"))
+ {
+ useNativeLib = false;
+ } else
+ {
+ useNativeLib = NativeLibraryUtilities.loadNativeLibrary("nativedata");
+ }
+ }
+
+ /** Size of a <code>short</code> value in <code>byte</code>s. */
+ public final static int SHORT_SIZE = 2;
+
+ /** Size of a <code>char</code> value in <code>byte</code>s. */
+ public final static int CHAR_SIZE = 2;
+
+ /** Size of an <code>int</code> value in <code>byte</code>s. */
+ public final static int INT_SIZE = 4;
+
+ /** Size of a <code>long</code> value in <code>byte</code>s. */
+ public final static int LONG_SIZE = 8;
+
+ /** Size of a <code>float</code> value in <code>byte</code>s. */
+ public final static int FLOAT_SIZE = 4;
+
+ /** Size of a <code>double</code> value in <code>byte</code>s. */
+ public final static int DOUBLE_SIZE = 8;
+
+ /** Byte Order enumeration. */
+ // Implementation note: the ordinal of the entries needs to be understood by the native methods
+ public enum ByteOrder
+ {
+ /** <code>byte[]</code> is in native byte order (that is: don't change byte order) */
+ NATIVE(java.nio.ByteOrder.nativeOrder()),
+ /** <code>byte[]</code> is in little endian byte order */
+ LITTLE_ENDIAN(java.nio.ByteOrder.LITTLE_ENDIAN),
+ /** <code>byte[]</code> is in big endian byte order */
+ BIG_ENDIAN(java.nio.ByteOrder.BIG_ENDIAN);
+
+ private final java.nio.ByteOrder nioByteOrder;
+
+ ByteOrder(java.nio.ByteOrder nioByteOrder)
+ {
+ this.nioByteOrder = nioByteOrder;
+ }
+
+ java.nio.ByteOrder getNioByteOrder()
+ {
+ return nioByteOrder;
+ }
+
+ static ByteOrder getNativeByteOrder()
+ {
+ return NATIVE.nioByteOrder.equals(LITTLE_ENDIAN.nioByteOrder) ? LITTLE_ENDIAN
+ : BIG_ENDIAN;
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if this platform is a little-endian platform and <code>false</code>
+ * , if it is a big-endian platform.
+ */
+ private static native boolean isLittleEndian();
+
+ /**
+ * Copies a range from an array of <code>int</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>int</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>int</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>int</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyIntToByte(int[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>int</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>int</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>int</code> to
+ * start
+ * @param len The number of <code>int</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToInt(byte[] inData, int inStart, int[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>long</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>long</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>long</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>long</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyLongToByte(long[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>long</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>long</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>long</code> to
+ * start
+ * @param len The number of <code>long</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToLong(byte[] inData, int inStart, long[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>short</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>short</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>short</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>short</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyShortToByte(short[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>short</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>short</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+ * start
+ * @param len The number of <code>short</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToShort(byte[] inData, int inStart, short[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>char</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>char</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>char</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>char</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyCharToByte(char[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>char</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>char</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>char</code> to
+ * start
+ * @param len The number of <code>char</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToChar(byte[] inData, int inStart, char[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>float</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>float</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>float</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>float</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyFloatToByte(float[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>float</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>float</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>float</code> to
+ * start
+ * @param len The number of <code>float</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToFloat(byte[] inData, int inStart, float[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>double</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>double</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>double</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>double</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyDoubleToByte(double[] inData, int inStart, byte[] outData,
+ int outStart, int len, int byteOrder);
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>double</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>double</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>double</code> to
+ * start
+ * @param len The number of <code>double</code> to copy
+ * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+ * <var>outData</var> should be in.
+ */
+ private static native void copyByteToDouble(byte[] inData, int inStart, double[] outData,
+ int outStart, int len, int byteOrder);
+
+ //
+ // Public
+ //
+
+ /** Call to ensure that the native library is loaded. */
+ public static void ensureNativeLibIsLoaded()
+ {
+ }
+
+ /**
+ * Returns <code>true</code>, if this class uses the native library and <code>false</code>
+ * otherwise.
+ */
+ public static boolean isUseNativeLib()
+ {
+ return useNativeLib;
+ }
+
+ /**
+ * Returns the native byte order of the host running this JRE.
+ */
+ public static ByteOrder getNativeByteOrder()
+ {
+ return ByteOrder.getNativeByteOrder();
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>s</var>.
+ */
+ public static short changeByteOrder(short s)
+ {
+ return (short) ((s << 8) | ((s >> 8) & 0xff));
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>c</var>.
+ */
+ public static char changeByteOrder(char c)
+ {
+ return (char) ((c << 8) | ((c >> 8) & 0xff));
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>i</var>.
+ */
+ public static int changeByteOrder(int i)
+ {
+ return ((changeByteOrder((short) i) << 16) | (changeByteOrder((short) (i >> 16)) & 0xffff));
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>f</var>.
+ */
+ public static float changeByteOrder(float f)
+ {
+ return Float.intBitsToFloat(changeByteOrder(Float.floatToRawIntBits(f)));
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>l</var>.
+ */
+ public static long changeByteOrder(long l)
+ {
+ return (((long) changeByteOrder((int) (l)) << 32) | (changeByteOrder((int) (l >> 32)) & 0xffffffffL));
+ }
+
+ /**
+ * Changes the byte order of the bytes constituting <var>d</var>.
+ */
+ public static double changeByteOrder(double d)
+ {
+ return Double.longBitsToDouble(changeByteOrder(Double.doubleToRawLongBits(d)));
+ }
+
+ /**
+ * Copies a range from an array of <code>int</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>int</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>int</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>int</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyIntToByte(int[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyIntToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * INT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asIntBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>int</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>int</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>int</code> to
+ * start
+ * @param len The number of <code>int</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToInt(byte[] inData, int inStart, int[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToInt(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * INT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asIntBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>long</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>long</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>long</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>long</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyLongToByte(long[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyLongToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * LONG_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asLongBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>long</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>long</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>long</code> to
+ * start
+ * @param len The number of <code>long</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToLong(byte[] inData, int inStart, long[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToLong(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * LONG_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asLongBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>short</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>short</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>short</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>short</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyShortToByte(short[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyShortToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * SHORT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asShortBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>char</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>char</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>char</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>char</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyCharToByte(char[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyCharToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * SHORT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asCharBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>short</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>short</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+ * start
+ * @param len The number of <code>short</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToShort(byte[] inData, int inStart, short[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToShort(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * SHORT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asShortBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>char</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>short</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+ * start
+ * @param len The number of <code>short</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToChar(byte[] inData, int inStart, char[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToChar(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * CHAR_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asCharBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>float</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>float</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>float</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>float</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyFloatToByte(float[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyFloatToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * FLOAT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asFloatBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>float</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>float</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>float</code> to
+ * start
+ * @param len The number of <code>float</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToFloat(byte[] inData, int inStart, float[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToFloat(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * FLOAT_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asFloatBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>double</code> into an array of <code>byte</code>.
+ *
+ * @param inData The input array of <code>double</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>double</code> to
+ * start
+ * @param outData The output array of <code>byte</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+ * start
+ * @param len The number of <code>double</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyDoubleToByte(double[] inData, int inStart, byte[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyDoubleToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * DOUBLE_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asDoubleBuffer().put(inData, inStart, len);
+ }
+ }
+
+ /**
+ * Copies a range from an array of <code>byte</code> into an array of <code>double</code>.
+ *
+ * @param inData The input array of <code>byte</code> values.
+ * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+ * start
+ * @param outData The output array of <code>double</code> values.
+ * @param outStart The start in the output array <code>byteData</code> of <code>double</code> to
+ * start
+ * @param len The number of <code>double</code> to copy
+ * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+ * should be in.
+ */
+ public static void copyByteToDouble(byte[] inData, int inStart, double[] outData, int outStart,
+ int len, ByteOrder byteOrder)
+ {
+ if (useNativeLib)
+ {
+ copyByteToDouble(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+ } else
+ {
+ final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * DOUBLE_SIZE);
+ bb.order(byteOrder.getNioByteOrder());
+ bb.asDoubleBuffer().get(outData, outStart, len);
+ }
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>char[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>short</code> values to convert.
+ * @return The <code>char[]</code> array.
+ */
+ public static char[] byteToChar(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final char[] array = new char[len];
+ copyByteToChar(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>char[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>char[]</code> array.
+ */
+ public static char[] byteToChar(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % CHAR_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / SHORT_SIZE;
+ final char[] array = new char[len];
+ copyByteToChar(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>short[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>short</code> values to convert.
+ * @return The <code>short[]</code> array.
+ */
+ public static short[] byteToShort(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final short[] array = new short[len];
+ copyByteToShort(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>short[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>short[]</code> array.
+ */
+ public static short[] byteToShort(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % SHORT_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / SHORT_SIZE;
+ final short[] array = new short[len];
+ copyByteToShort(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>short[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>short</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] shortToByte(short[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[SHORT_SIZE * len];
+ copyShortToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>short[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] shortToByte(short[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[SHORT_SIZE * data.length];
+ copyShortToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>char[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>char</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] charToByte(char[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[CHAR_SIZE * len];
+ copyCharToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>char[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] charToByte(char[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[CHAR_SIZE * data.length];
+ copyCharToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into an <code>int[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>int</code> values to convert.
+ * @return The <code>int[]</code> array.
+ */
+ public static int[] byteToInt(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final int[] array = new int[len];
+ copyByteToInt(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into an <code>int[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>int[]</code> array.
+ */
+ public static int[] byteToInt(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % INT_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / INT_SIZE;
+ final int[] array = new int[len];
+ copyByteToInt(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>int[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>int</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] intToByte(int[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[INT_SIZE * len];
+ copyIntToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>int[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] intToByte(int[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[INT_SIZE * data.length];
+ copyIntToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>long[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>long</code> values to convert.
+ * @return The <code>long[]</code> array.
+ */
+ public static long[] byteToLong(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final long[] array = new long[len];
+ copyByteToLong(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>long[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>long[]</code> array.
+ */
+ public static long[] byteToLong(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % LONG_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / LONG_SIZE;
+ final long[] array = new long[len];
+ copyByteToLong(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>long[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>long</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] longToByte(long[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[LONG_SIZE * len];
+ copyLongToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>long[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] longToByte(long[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[LONG_SIZE * data.length];
+ copyLongToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>float[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>float</code> values to convert.
+ * @return The <code>float[]</code> array.
+ */
+ public static float[] byteToFloat(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final float[] array = new float[len];
+ copyByteToFloat(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>float[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>float[]</code> array.
+ */
+ public static float[] byteToFloat(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % FLOAT_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / FLOAT_SIZE;
+ final float[] array = new float[len];
+ copyByteToFloat(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>float[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>float</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] floatToByte(float[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[FLOAT_SIZE * len];
+ copyFloatToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>float[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] floatToByte(float[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[FLOAT_SIZE * data.length];
+ copyFloatToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>double[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @param start The position in the <var>byteArr</var> to start the conversion.
+ * @param len The number of <code>double</code> values to convert.
+ * @return The <code>double[]</code> array.
+ */
+ public static double[] byteToDouble(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+ {
+ final double[] array = new double[len];
+ copyByteToDouble(byteArr, start, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>byte[]</code> array into a <code>double[]</code> array.
+ *
+ * @param byteArr The <code>byte[]</code> to convert.
+ * @param byteOrder The byte order of <var>byteArr</var>.
+ * @return The <code>double[]</code> array.
+ */
+ public static double[] byteToDouble(byte[] byteArr, ByteOrder byteOrder)
+ {
+ if (byteArr.length % DOUBLE_SIZE != 0)
+ {
+ throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+ }
+ final int len = byteArr.length / DOUBLE_SIZE;
+ final double[] array = new double[len];
+ copyByteToDouble(byteArr, 0, array, 0, len, byteOrder);
+ return array;
+ }
+
+ /**
+ * Converts a <code>double[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @param start The position in <var>data</var> to start the conversion.
+ * @param len The number of <code>double</code> values to convert.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] doubleToByte(double[] data, ByteOrder byteOrder, int start, int len)
+ {
+ final byte[] byteArr = new byte[DOUBLE_SIZE * len];
+ copyDoubleToByte(data, start, byteArr, 0, len, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts a <code>double[]</code> array to a <code>byte[]</code> array.
+ *
+ * @param data The array to convert.
+ * @param byteOrder The byte order of the returned <code>byte[]</code>.
+ * @return The converted <code>byte[]</code> array.
+ */
+ public static byte[] doubleToByte(double[] data, ByteOrder byteOrder)
+ {
+ final byte[] byteArr = new byte[DOUBLE_SIZE * data.length];
+ copyDoubleToByte(data, 0, byteArr, 0, data.length, byteOrder);
+ return byteArr;
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java b/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
new file mode 100644
index 0000000..da8c6b8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import static ch.systemsx.cisd.base.convert.NativeData.DOUBLE_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.FLOAT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.INT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.LONG_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.SHORT_SIZE;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+import ch.systemsx.cisd.base.mdarray.MDAbstractArray;
+import ch.systemsx.cisd.base.mdarray.MDDoubleArray;
+import ch.systemsx.cisd.base.mdarray.MDFloatArray;
+import ch.systemsx.cisd.base.mdarray.MDIntArray;
+import ch.systemsx.cisd.base.mdarray.MDLongArray;
+import ch.systemsx.cisd.base.mdarray.MDShortArray;
+
+/**
+ * A utility class that supports encoding and decoding of arrays of primitive number types to byte
+ * arrays such that the characteristics of the number type (float or integer, byte order, element
+ * size) and the dimensions are known and can be checked for correctness when converted back to the
+ * number type.
+ *
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArray
+{
+
+ private final static NativeData.ByteOrder NATIVE_BYTE_ORDER = NativeData.getNativeByteOrder();
+
+ private static final int MAGIC_SIZE = 3;
+
+ private static final int RANK_SIZE = 1;
+
+ private static final int RANK_INDEX = 3;
+
+ private static final int LENGTH_SIZE = 4;
+
+ private static final int LENGTH_INDEX = 4;
+
+ private static final int RANK_1 = 1;
+
+ /**
+ * A class to return the array encoding and dimensions of a native tagged array.
+ */
+ public static class NativeArrayTag
+ {
+ private final NativeArrayEncoding encoding;
+
+ private final int[] dimensions;
+
+ NativeArrayTag(NativeArrayEncoding encoding, int[] dimensions)
+ {
+ this.encoding = encoding;
+ this.dimensions = dimensions;
+ }
+
+ /**
+ * Returns the {@link NativeArrayEncoding} of the array.
+ */
+ public NativeArrayEncoding getEncoding()
+ {
+ return encoding;
+ }
+
+ /**
+ * Resurns the dimensions of the array.
+ */
+ public int[] getDimensions()
+ {
+ return dimensions;
+ }
+ }
+
+ /**
+ * Returns the array tag of the native tagged array encoded in <var>data</var>, or
+ * <code>null</code>, if <var>data</var> does not encode a native tagged array.
+ */
+ public static NativeArrayTag tryGetArrayTag(byte[] data)
+ {
+ final NativeArrayEncoding encodingOrNull = NativeArrayEncoding.tryGetEncoding(data);
+ if (encodingOrNull == null)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank,
+ encodingOrNull.getByteOrder());
+ return new NativeArrayTag(encodingOrNull, dimensions);
+ }
+
+ //
+ // Float
+ //
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(float[] data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(float[] data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) FLOAT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+ final byte[] byteArr = new byte[headerSize + FLOAT_SIZE * data.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = RANK_1;
+ NativeData.copyIntToByte(new int[]
+ { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+ NativeData.copyFloatToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(MDFloatArray data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(MDFloatArray data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) FLOAT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final byte rank = (byte) data.rank();
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+ final float[] flatDataArray = data.getAsFlatArray();
+ final byte[] byteArr = new byte[headerSize + FLOAT_SIZE * flatDataArray.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = rank;
+ NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+ NativeData.copyFloatToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+ byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a float array or <code>null</code>, if
+ * <var>data</var> is not a tagged 1D float array.
+ */
+ public static float[] tryToFloatArray1D(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != FLOAT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ if (rank != 1)
+ {
+ return null;
+ }
+ final int[] dimensions = new int[1];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+ if (dimensions[0] * FLOAT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+ {
+ return null;
+ }
+ final float[] floatData = new float[dimensions[0]];
+ NativeData.copyByteToFloat(data, LENGTH_INDEX + LENGTH_SIZE, floatData, 0,
+ floatData.length, encoding.getByteOrder());
+ return floatData;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a {@link MDFloatArray} or <code>null</code>, if
+ * <var>data</var> is not a tagged (multi-dimensional) float array.
+ */
+ public static MDFloatArray tryToFloatArray(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != FLOAT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+ final int length = MDAbstractArray.getLength(dimensions);
+ final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+ if (length * FLOAT_SIZE + headerSize != data.length)
+ {
+ return null;
+ }
+ final float[] intData = new float[length];
+ NativeData.copyByteToFloat(data, headerSize, intData, 0, intData.length,
+ encoding.getByteOrder());
+ return new MDFloatArray(intData, dimensions);
+ }
+
+ //
+ // Double
+ //
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(double[] data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(double[] data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) DOUBLE_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+ final byte[] byteArr = new byte[headerSize + DOUBLE_SIZE * data.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = RANK_1;
+ NativeData.copyIntToByte(new int[]
+ { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+ NativeData.copyDoubleToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(MDDoubleArray data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(MDDoubleArray data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) DOUBLE_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final byte rank = (byte) data.rank();
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+ final double[] flatDataArray = data.getAsFlatArray();
+ final byte[] byteArr = new byte[headerSize + DOUBLE_SIZE * flatDataArray.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = rank;
+ NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+ NativeData.copyDoubleToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+ byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a double array or <code>null</code>, if
+ * <var>data</var> is not a tagged 1D double array.
+ */
+ public static double[] tryToDoubleArray1D(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != DOUBLE_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ if (rank != 1)
+ {
+ return null;
+ }
+ final int[] dimensions = new int[1];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+ if (dimensions[0] * DOUBLE_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+ {
+ return null;
+ }
+ final double[] doubleData = new double[dimensions[0]];
+ NativeData.copyByteToDouble(data, LENGTH_INDEX + LENGTH_SIZE, doubleData, 0,
+ doubleData.length, encoding.getByteOrder());
+ return doubleData;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a {@link MDDoubleArray} or <code>null</code>, if
+ * <var>data</var> is not a tagged (multi-dimensional) double array.
+ */
+ public static MDDoubleArray tryToDoubleArray(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != DOUBLE_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+ final int length = MDAbstractArray.getLength(dimensions);
+ final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+ if (length * DOUBLE_SIZE + headerSize != data.length)
+ {
+ return null;
+ }
+ final double[] intData = new double[length];
+ NativeData.copyByteToDouble(data, headerSize, intData, 0, intData.length,
+ encoding.getByteOrder());
+ return new MDDoubleArray(intData, dimensions);
+ }
+
+ //
+ // Short
+ //
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(short[] data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(short[] data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) SHORT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+ final byte[] byteArr = new byte[headerSize + SHORT_SIZE * data.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = RANK_1;
+ NativeData.copyIntToByte(new int[]
+ { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+ NativeData.copyShortToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(MDShortArray data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(MDShortArray data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) SHORT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final byte rank = (byte) data.rank();
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+ final short[] flatDataArray = data.getAsFlatArray();
+ final byte[] byteArr = new byte[headerSize + SHORT_SIZE * flatDataArray.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = rank;
+ NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+ NativeData.copyShortToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+ byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a short array or <code>null</code>, if
+ * <var>data</var> is not a tagged 1D short array.
+ */
+ public static short[] tryToShortArray1D(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint()
+ || encoding.getSizeInBytes() != SHORT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ if (rank != 1)
+ {
+ return null;
+ }
+ final int[] dimensions = new int[1];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+ if (dimensions[0] * SHORT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+ {
+ return null;
+ }
+ final short[] shortData = new short[dimensions[0]];
+ NativeData.copyByteToShort(data, LENGTH_INDEX + LENGTH_SIZE, shortData, 0,
+ shortData.length, encoding.getByteOrder());
+ return shortData;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a {@link MDShortArray} or <code>null</code>, if
+ * <var>data</var> is not a tagged (multi-dimensional) short array.
+ */
+ public static MDShortArray tryToShortArray(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint()
+ || encoding.getSizeInBytes() != SHORT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+ final int length = MDAbstractArray.getLength(dimensions);
+ final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+ if (length * SHORT_SIZE + headerSize != data.length)
+ {
+ return null;
+ }
+ final short[] intData = new short[length];
+ NativeData.copyByteToShort(data, headerSize, intData, 0, intData.length,
+ encoding.getByteOrder());
+ return new MDShortArray(intData, dimensions);
+ }
+
+ //
+ // Int
+ //
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(int[] data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(int[] data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) INT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+ final byte[] byteArr = new byte[headerSize + INT_SIZE * data.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = RANK_1;
+ NativeData.copyIntToByte(new int[]
+ { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+ NativeData.copyIntToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(MDIntArray data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(MDIntArray data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) INT_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final byte rank = (byte) data.rank();
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+ final int[] flatDataArray = data.getAsFlatArray();
+ final byte[] byteArr = new byte[headerSize + INT_SIZE * flatDataArray.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = rank;
+ NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+ NativeData.copyIntToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+ byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as an int array or <code>null</code>, if
+ * <var>data</var> is not a tagged 1D int array.
+ */
+ public static int[] tryToIntArray1D(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint() || encoding.getSizeInBytes() != INT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ if (rank != 1)
+ {
+ return null;
+ }
+ final int[] dimensions = new int[1];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+ if (dimensions[0] * INT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+ {
+ return null;
+ }
+ final int[] intData = new int[dimensions[0]];
+ NativeData.copyByteToInt(data, LENGTH_INDEX + LENGTH_SIZE, intData, 0, intData.length,
+ encoding.getByteOrder());
+ return intData;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a {@link MDIntArray} or <code>null</code>, if
+ * <var>data</var> is not a tagged (multi-dimensional) int array.
+ */
+ public static MDIntArray tryToIntArray(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint() || encoding.getSizeInBytes() != INT_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+ final int length = MDAbstractArray.getLength(dimensions);
+ final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+ if (length * INT_SIZE + headerSize != data.length)
+ {
+ return null;
+ }
+ final int[] intData = new int[length];
+ NativeData.copyByteToInt(data, headerSize, intData, 0, intData.length,
+ encoding.getByteOrder());
+ return new MDIntArray(intData, dimensions);
+ }
+
+ //
+ // Long
+ //
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(long[] data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(long[] data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) LONG_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+ final byte[] byteArr = new byte[headerSize + LONG_SIZE * data.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = RANK_1;
+ NativeData.copyIntToByte(new int[]
+ { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+ NativeData.copyLongToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in native byte order.
+ */
+ public static byte[] toByteArray(MDLongArray data)
+ {
+ return toByteArray(data, NATIVE_BYTE_ORDER);
+ }
+
+ /**
+ * Converts <var>data</var> into a tagged array in given byte order.
+ */
+ public static byte[] toByteArray(MDLongArray data, ByteOrder byteOrder)
+ {
+ final byte[] magic =
+ NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) LONG_SIZE).getMagic();
+ assert magic.length == MAGIC_SIZE;
+ final byte rank = (byte) data.rank();
+ final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+ final long[] flatDataArray = data.getAsFlatArray();
+ final byte[] byteArr = new byte[headerSize + LONG_SIZE * flatDataArray.length];
+ System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+ byteArr[RANK_INDEX] = rank;
+ NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+ NativeData.copyLongToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+ byteOrder);
+ return byteArr;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a long array or <code>null</code>, if
+ * <var>data</var> is not a tagged 1D long array.
+ */
+ public static long[] tryToLongArray1D(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint()
+ || encoding.getSizeInBytes() != LONG_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ if (rank != 1)
+ {
+ return null;
+ }
+ final int[] dimensions = new int[1];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+ if (dimensions[0] * LONG_SIZE + LENGTH_INDEX + 1 * LENGTH_SIZE != data.length)
+ {
+ return null;
+ }
+ final long[] longData = new long[dimensions[0]];
+ NativeData.copyByteToLong(data, LENGTH_INDEX + LENGTH_SIZE, longData, 0, longData.length,
+ encoding.getByteOrder());
+ return longData;
+ }
+
+ /**
+ * Returns the tagged array <var>data</var> as a {@link MDLongArray} or <code>null</code>, if
+ * <var>data</var> is not a tagged (multi-dimensional) long array.
+ */
+ public static MDLongArray tryToLongArray(byte[] data)
+ {
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+ if (encoding == null || encoding.isFloatingPoint()
+ || encoding.getSizeInBytes() != LONG_SIZE)
+ {
+ return null;
+ }
+ final int rank = data[RANK_INDEX];
+ final int[] dimensions = new int[rank];
+ NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+ final int length = MDAbstractArray.getLength(dimensions);
+ final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+ if (length * LONG_SIZE + headerSize != data.length)
+ {
+ return null;
+ }
+ final long[] longData = new long[length];
+ NativeData.copyByteToLong(data, headerSize, longData, 0, longData.length,
+ encoding.getByteOrder());
+ return new MDLongArray(longData, dimensions);
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java b/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java
new file mode 100644
index 0000000..c874c44
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * An exception for tunneling checked exception through code that doesn't expect it.
+ *
+ * @author Bernd Rinn
+ */
+public class CheckedExceptionTunnel extends RuntimeException
+{
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Returns an unchecked exception from a <var>checkedException</var>.
+ *
+ * @param checkedExceptionOrNull The checked exception to tunnel.
+ */
+ public CheckedExceptionTunnel(final Exception checkedExceptionOrNull)
+ {
+ super(checkedExceptionOrNull);
+
+ assert (checkedExceptionOrNull instanceof RuntimeException) == false;
+ }
+
+ protected CheckedExceptionTunnel(final String msg)
+ {
+ super(msg);
+ }
+
+ protected CheckedExceptionTunnel()
+ {
+ }
+
+ @Override
+ public String getMessage()
+ {
+ if (getCause() != null && getCause().getMessage() != null)
+ {
+ return getCause().getMessage();
+ }
+ return super.getMessage();
+ }
+
+ @Override
+ public String toString()
+ {
+ if (getCause() != null)
+ {
+ return getCause().toString();
+ }
+ return super.toString();
+ }
+
+ @Override
+ public void printStackTrace(PrintStream s)
+ {
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(s);
+ } else
+ {
+ super.printStackTrace(s);
+ }
+ }
+
+ @Override
+ public void printStackTrace(PrintWriter s)
+ {
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(s);
+ } else
+ {
+ super.printStackTrace(s);
+ }
+ }
+
+ /**
+ * Like {@link #printStackTrace()}, but includes the tunnel's stacktrace as well.
+ */
+ public void printFullStackTrace()
+ {
+ printFullStackTrace(System.err);
+ }
+
+ /**
+ * Like {@link #printStackTrace(PrintStream)}, but includes the tunnel's stacktrace as well.
+ */
+ public void printFullStackTrace(PrintStream s)
+ {
+ synchronized (s) {
+ s.println(super.toString());
+ StackTraceElement[] trace = getStackTrace();
+ for (int i=0; i < trace.length; i++)
+ s.println("\tat " + trace[i]);
+
+ Throwable ourCause = getCause();
+ if (ourCause != null)
+ {
+ printStackTraceAsCause(ourCause, s, trace);
+ }
+ }
+ }
+
+ /**
+ * Print our stack trace as a cause for the specified stack trace.
+ */
+ private static void printStackTraceAsCause(Throwable cause, PrintStream s,
+ StackTraceElement[] causedTrace)
+ {
+ final StackTraceElement[] trace = cause.getStackTrace();
+ int m = trace.length-1, n = causedTrace.length-1;
+ while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
+ m--; n--;
+ }
+ final int framesInCommon = trace.length - 1 - m;
+
+ s.println("Caused by: " + cause);
+ for (int i=0; i <= m; i++)
+ s.println("\tat " + trace[i]);
+ if (framesInCommon != 0)
+ s.println("\t... " + framesInCommon + " more");
+
+ final Throwable ourCauseesCause = cause.getCause();
+ if (ourCauseesCause != null)
+ {
+ printStackTraceAsCause(ourCauseesCause, s, trace);
+ }
+ }
+
+ /**
+ * Like {@link #printStackTrace(PrintWriter)}, but includes the tunnel's stacktrace as well.
+ */
+ public void printFullStackTrace(PrintWriter s)
+ {
+ synchronized (s) {
+ s.println(super.toString());
+ StackTraceElement[] trace = getStackTrace();
+ for (int i=0; i < trace.length; i++)
+ s.println("\tat " + trace[i]);
+
+ Throwable ourCause = getCause();
+ if (ourCause != null)
+ {
+ printStackTraceAsCause(ourCause, s, trace);
+ }
+ }
+ }
+
+ /**
+ * Print our stack trace as a cause for the specified stack trace.
+ */
+ private static void printStackTraceAsCause(Throwable cause, PrintWriter s,
+ StackTraceElement[] causedTrace)
+ {
+ final StackTraceElement[] trace = cause.getStackTrace();
+ int m = trace.length-1, n = causedTrace.length-1;
+ while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
+ m--; n--;
+ }
+ final int framesInCommon = trace.length - 1 - m;
+
+ s.println("Caused by: " + cause);
+ for (int i=0; i <= m; i++)
+ s.println("\tat " + trace[i]);
+ if (framesInCommon != 0)
+ s.println("\t... " + framesInCommon + " more");
+
+ final Throwable ourCauseesCause = cause.getCause();
+ if (ourCauseesCause != null)
+ {
+ printStackTraceAsCause(ourCauseesCause, s, trace);
+ }
+ }
+
+ /**
+ * Convenience wrapper for {@link #wrapIfNecessary(Exception)}. If <var>throwable</var> is an
+ * {@link Error}, this method will not return but the error will be thrown.
+ *
+ * @param throwable The exception to represent by the return value.
+ * @return A {@link RuntimeException} representing the <var>throwable</var>.
+ * @throws Error If <var>throwable</var> is an {@link Error} (except when it is a
+ * {@link ThreadDeath}, which returns a {@link InterruptedExceptionUnchecked}).
+ */
+ public final static RuntimeException wrapIfNecessary(final Throwable throwable) throws Error
+ {
+ if (throwable instanceof Error)
+ {
+ if (throwable instanceof ThreadDeath)
+ {
+ return new InterruptedExceptionUnchecked();
+ } else
+ {
+ throw (Error) throwable;
+ }
+ }
+ return wrapIfNecessary((Exception) throwable);
+ }
+
+ /**
+ * Returns a {@link RuntimeException} from an <var>exception</var>. If <var>exception</var> is
+ * already a {@link RuntimeException}, itself is returned, otherwise an appropriate unchecked
+ * equivalent. If no unchecked equivalent exists, a {@link CheckedExceptionTunnel} is returned
+ * with <var>exception</var> as checked exception argument.
+ *
+ * @param exception The exception to represent by the return value.
+ * @return A {@link RuntimeException} representing the <var>exception</var>.
+ */
+ public final static RuntimeException wrapIfNecessary(final Exception exception)
+ {
+ if (exception instanceof RuntimeException)
+ {
+ return (RuntimeException) exception;
+ }
+ if (exception instanceof IOException)
+ {
+ return new IOExceptionUnchecked((IOException) exception);
+ }
+ if (exception instanceof InterruptedException)
+ {
+ return new InterruptedExceptionUnchecked((InterruptedException) exception);
+ }
+ if (exception instanceof java.util.concurrent.TimeoutException)
+ {
+ return new TimeoutExceptionUnchecked((java.util.concurrent.TimeoutException) exception);
+ }
+ return new CheckedExceptionTunnel(exception);
+ }
+
+ /**
+ * Returns the original exception before being wrapped, if the exception has been wrapped, or
+ * <var>exception</var> otherwise.
+ */
+ public final static Exception unwrapIfNecessary(final Exception exception)
+ {
+ assert exception != null : "Exception not specified.";
+ if (exception instanceof CheckedExceptionTunnel)
+ {
+ // We are sure that the wrapped exception is an 'Exception'.
+ final Exception causeOrNull = (Exception) exception.getCause();
+ if (causeOrNull != null)
+ {
+ return causeOrNull;
+ }
+ }
+ return exception;
+ }
+
+ /**
+ * Returns the original throwable before being wrapped, if the throwable has been wrapped, or
+ * <var>exception</var> otherwise.
+ */
+ public final static Throwable unwrapIfNecessary(final Throwable throwable)
+ {
+ assert throwable != null : "Exception not specified.";
+ if (throwable instanceof Error)
+ {
+ return throwable;
+ } else
+ {
+ return unwrapIfNecessary((Exception) throwable);
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java b/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java
new file mode 100644
index 0000000..cfd17ee
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+/**
+ * A strategy role for dealing with errors.
+ *
+ * @author Bernd Rinn
+ */
+public interface IErrorStrategy
+{
+ /**
+ * The default error strategy, just re-throws the exception.
+ */
+ public static final IErrorStrategy DEFAULT_ERROR_STRATEGY = new IErrorStrategy()
+ {
+ @Override
+ public void dealWithError(Throwable th) throws RuntimeException, Error
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(th);
+ }
+
+ @Override
+ public void warning(String message)
+ {
+ System.err.println(message);
+ }
+ };
+
+ /**
+ * Called when an exception <var>ex</var> has occurred. Can, but doesn't have to, abort the
+ * operation by re-throwing the exception.
+ *
+ * @throws RuntimeException if the operation should be aborted.
+ */
+ public void dealWithError(final Throwable th) throws RuntimeException, Error;
+
+ /**
+ * Called to issue a warning message.
+ */
+ public void warning(String message);
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java
new file mode 100644
index 0000000..caa7b39
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+
+/**
+ * A {@link CheckedExceptionTunnel} for an {@link IOException}.
+ *
+ * @author Bernd Rinn
+ */
+public class IOExceptionUnchecked extends CheckedExceptionTunnel
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Returns an <code>IOExceptionUnchecked</code> from a <code>IOException</code>.
+ *
+ * @param checkedException The checked exception to tunnel.
+ */
+ public IOExceptionUnchecked(final IOException checkedException)
+ {
+ super(checkedException);
+
+ assert checkedException != null;
+ }
+
+ /**
+ * Returns an <code>IOExceptionUnchecked</code> from a newly created <code>IOException</code>
+ * with given <var>msg</var>.
+ *
+ * @param msg The checked exception to tunnel.
+ */
+ public IOExceptionUnchecked(final String msg)
+ {
+ this(new IOException(msg));
+ }
+
+ private static IOException createIOException(final Throwable throwable)
+ {
+ final IOException ioe =
+ new IOException(throwable.getClass().getSimpleName() + ": "
+ + throwable.getMessage());
+ ioe.initCause(throwable);
+ return ioe;
+ }
+
+ /**
+ * Returns an <code>IOExceptionUnchecked</code> from newly created <code>IOException</code> with
+ * given <var>throwable</var> as its cause.
+ *
+ * @param throwable The throwable to use the cause of the created <code>IOException</code>.
+ */
+ public IOExceptionUnchecked(final Throwable throwable)
+ {
+ super(createIOException(throwable));
+
+ assert throwable != null;
+ }
+
+ @Override
+ public IOException getCause()
+ {
+ return (IOException) super.getCause();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java
new file mode 100644
index 0000000..d420052
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+/**
+ * Exception that signals that whoever gets it should stop its current work. This is an unchecked
+ * equivalent to an {@link InterruptedException}.
+ * <p>
+ * This is usually triggered by interrupting the thread that the work package is processed in and
+ * regularly checking with {@link #check()}.
+ * </p>
+ *
+ * @author Bernd Rinn
+ */
+public class InterruptedExceptionUnchecked extends CheckedExceptionTunnel
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public InterruptedExceptionUnchecked()
+ {
+ super();
+ }
+
+ public InterruptedExceptionUnchecked(final InterruptedException cause)
+ {
+ super(cause);
+ }
+
+ /**
+ * Checks whether the current thread has been interrupted and, if it has, throw a
+ * {@link InterruptedExceptionUnchecked}.
+ */
+ public final static void check() throws InterruptedExceptionUnchecked
+ {
+ if (Thread.interrupted())
+ {
+ throw new InterruptedExceptionUnchecked();
+ }
+ }
+
+ @Override
+ public InterruptedException getCause()
+ {
+ return (InterruptedException) super.getCause();
+ }
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/StopException.java b/source/java/ch/systemsx/cisd/base/exceptions/StopException.java
new file mode 100644
index 0000000..47c4b5b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/StopException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+/**
+ * An exception that signals that <code>Thread.stop()</code> has been called on the current thread.
+ *
+ * @author Bernd Rinn
+ */
+public class StopException extends InterruptedExceptionUnchecked
+{
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java
new file mode 100644
index 0000000..2768a8b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Exception thrown when a blocking operation times out. This is an unchecked equivalent of
+ * {@link TimeoutException}, that is it is derived from {@link CheckedExceptionTunnel}.
+ *
+ * @author Bernd Rinn
+ */
+public class TimeoutExceptionUnchecked extends CheckedExceptionTunnel
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public TimeoutExceptionUnchecked()
+ {
+ }
+
+ public TimeoutExceptionUnchecked(String msg)
+ {
+ super(msg);
+ }
+
+ public TimeoutExceptionUnchecked(java.util.concurrent.TimeoutException cause)
+ {
+ super(cause);
+ }
+
+ @Override
+ public TimeoutException getCause()
+ {
+ return (TimeoutException) super.getCause();
+ }
+
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/package.html b/source/java/ch/systemsx/cisd/base/exceptions/package.html
new file mode 100644
index 0000000..b5b2cd1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/package.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Exceptions.</title>
+</head>
+<body>
+<p>
+This package provides basic exceptions thrown by CISD software. Note that all exceptions are
+unchecked.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java b/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java
new file mode 100644
index 0000000..bcc9599
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.image;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Interface for classes which can transform images. The transformation depends only on some
+ * parameters and an image as input.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IImageTransformer
+{
+ /**
+ * Transforms the specified image. The transformation must <i>not</i> change the input image.
+ *
+ * @return The transformed image.
+ */
+ public BufferedImage transform(BufferedImage image);
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java b/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java
new file mode 100644
index 0000000..c0c76a2
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.image;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+
+/**
+ * Factory creating an {@link IImageTransformer}. The parameters of the transformer should be
+ * stored as serializable attributes of concrete implementations of this interface.
+ *
+ * @author Franz-Josef Elmer
+ */
+ at JsonObject(value="IImageTransformerFactory")
+public interface IImageTransformerFactory extends Serializable
+{
+ /**
+ * Creates a transformer object based on the attributes of the factory.
+ */
+ public IImageTransformer createTransformer();
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java
new file mode 100644
index 0000000..5520617
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.image;
+
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+
+/**
+ * Interface for classes which can transform images in a streaming mode. The transformation depends
+ * only on some parameters and an image as stream of bytes.
+ *
+ * @author Bernd Rinn
+ */
+public interface IStreamingImageTransformer extends IImageTransformer
+{
+
+ /**
+ * Transforms the image provided as the <var>input</var> stream.
+ *
+ * @return The transformed image.
+ */
+ public BufferedImage transform(InputStream input);
+
+ /**
+ * Transforms the image provided as the <var>input</var> stream.
+ *
+ * @return The transformed image as a byte array that constitutes a PNG file.
+ */
+ public byte[] transformToPNG(InputStream input);
+
+ /**
+ * Transforms the image provided as the <var>input</var> stream. Writes the transformed PNG file
+ * to the <var>output</var> stream.
+ */
+ public void transformToPNGStream(InputStream input, OutputStream output);
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java
new file mode 100644
index 0000000..6b4e06f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.image;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+
+/**
+ * Factory creating an {@link IStreamingImageTransformer}. The parameters of the transformer should
+ * be stored as serializable attributes of concrete implementations of this interface.
+ *
+ * @author Bernd Rinn
+ */
+ at JsonObject(value="IStreamingImageTransformerFactory")
+public interface IStreamingImageTransformerFactory extends IImageTransformerFactory
+{
+ /**
+ * Creates a transformer object based on the attributes of the factory.
+ */
+ @Override
+ public IStreamingImageTransformer createTransformer();
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java
new file mode 100644
index 0000000..0876766
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link IInputStream} that extends {@link java.io.InputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterIInputStreamToInputStream extends InputStream
+{
+
+ private final IInputStream delegate;
+
+ public AdapterIInputStreamToInputStream(IInputStream delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int available() throws IOException
+ {
+ try
+ {
+ return delegate.available();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ try
+ {
+ delegate.close();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public synchronized void mark(int readlimit)
+ {
+ delegate.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return delegate.markSupported();
+ }
+
+ @Override
+ public int read() throws IOException
+ {
+ try
+ {
+ return delegate.read();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ try
+ {
+ return delegate.read(b, off, len);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException
+ {
+ try
+ {
+ return delegate.read(b);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public synchronized void reset() throws IOException
+ {
+ try
+ {
+ delegate.reset();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException
+ {
+ try
+ {
+ return delegate.skip(n);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return delegate.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java
new file mode 100644
index 0000000..55b6e5f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link IOutputStream} that extends {@link java.io.OutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterIOutputStreamToOutputStream extends OutputStream
+{
+
+ private final IOutputStream delegate;
+
+ public AdapterIOutputStreamToOutputStream(IOutputStream delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void write(int b) throws IOException
+ {
+ try
+ {
+ delegate.write(b);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ try
+ {
+ delegate.close();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public void flush() throws IOException
+ {
+ try
+ {
+ delegate.flush();
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ try
+ {
+ delegate.write(b, off, len);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException
+ {
+ try
+ {
+ delegate.write(b);
+ } catch (IOExceptionUnchecked ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return delegate.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java
new file mode 100644
index 0000000..c9e46a5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link java.io.InputStream} that implements {@link IInputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterInputStreamToIInputStream implements IInputStream
+{
+
+ private final java.io.InputStream delegate;
+
+ public AdapterInputStreamToIInputStream(java.io.InputStream delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int available() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return delegate.available();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void close() throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.close();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void mark(int readlimit)
+ {
+ delegate.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return delegate.markSupported();
+ }
+
+ @Override
+ public int read() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return delegate.read();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return delegate.read(b, off, len);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return delegate.read(b);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void reset() throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.reset();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return delegate.skip(n);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public String toString()
+ {
+ return delegate.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java
new file mode 100644
index 0000000..0720195
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link java.io.OutputStream} that implements {@link IOutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterOutputStreamToIOutputStream implements IOutputStream
+{
+
+ private final java.io.OutputStream delegate;
+
+ public AdapterOutputStreamToIOutputStream(java.io.OutputStream delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ //
+ // IOutputStream
+ //
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.write(b, off, len);
+ } catch (IOException ex)
+ {
+ throw new IOExceptionUnchecked(ex);
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.write(b);
+ } catch (IOException ex)
+ {
+ throw new IOExceptionUnchecked(ex);
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.write(b);
+ } catch (IOException ex)
+ {
+ throw new IOExceptionUnchecked(ex);
+ }
+ }
+
+ @Override
+ public void close() throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.close();
+ } catch (IOException ex)
+ {
+ throw new IOExceptionUnchecked(ex);
+ }
+ }
+
+ @Override
+ public void flush() throws IOExceptionUnchecked
+ {
+ try
+ {
+ delegate.flush();
+ } catch (IOException ex)
+ {
+ throw new IOExceptionUnchecked(ex);
+ }
+ }
+
+ @Override
+ public void synchronize() throws IOExceptionUnchecked
+ {
+ flush();
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return delegate.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java b/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java
new file mode 100644
index 0000000..1055b8b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.EOFException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import ch.systemsx.cisd.base.convert.NativeData;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An implementation of {@link IRandomAccessFile} based on a {@link ByteBuffer}.
+ * <p>
+ * Does <i>not</i> implement {@link IRandomAccessFile#readLine()}.
+ *
+ * @author Bernd Rinn
+ */
+public class ByteBufferRandomAccessFile implements IRandomAccessFile
+{
+
+ private final ByteBuffer buf;
+
+ private void addToLength(int newItemLen)
+ {
+ final int rem = buf.remaining();
+ if (newItemLen > rem)
+ {
+ buf.limit(buf.limit() + (newItemLen - rem));
+ }
+ }
+
+ /**
+ * Creates a {@link IRandomAccessFile} wrapper for the given <var>buf</var>.
+ *
+ * @param buf The buffer to wrap.
+ * @param initialLength The initially set length (corresponds to the {@link ByteBuffer#limit()}
+ * ).
+ */
+ public ByteBufferRandomAccessFile(ByteBuffer buf, int initialLength)
+ {
+ this(buf);
+ setLength(initialLength);
+ }
+
+ /**
+ * Creates a {@link IRandomAccessFile} wrapper for the given <var>buf</var>. Does not change the
+ * {@link ByteBuffer#limit()} of <var>buf</var>.
+ *
+ * @param buf The buffer to wrap.
+ */
+ public ByteBufferRandomAccessFile(ByteBuffer buf)
+ {
+ this.buf = buf;
+ }
+
+ /**
+ * Creates a {@link IRandomAccessFile} wrapper for the given <var>array</var>.
+ *
+ * @param array The byte array to wrap.
+ * @param initialLength The initially set length.
+ */
+ public ByteBufferRandomAccessFile(byte[] array, int initialLength)
+ {
+ this(array);
+ setLength(initialLength);
+ }
+
+ /**
+ * Creates a {@link IRandomAccessFile} wrapper for the given <var>array</var>. The initial
+ * {@link ByteBuffer#limit()} will be <code>array.length</code>.
+ *
+ * @param array The byte array to wrap.
+ */
+ public ByteBufferRandomAccessFile(byte[] array)
+ {
+ this(ByteBuffer.wrap(array));
+ }
+
+ /**
+ * Creates a {@link IRandomAccessFile} wrapper for a {@link ByteBuffer} with
+ * <var>capacity</var>. The initial {@link ByteBuffer#limit()} will be <code>0</code>.
+ *
+ * @param capacity The maximal size of the {@link ByteBuffer}.
+ */
+ public ByteBufferRandomAccessFile(int capacity)
+ {
+ this(ByteBuffer.allocate(capacity));
+ setLength(0);
+ }
+
+ @Override
+ public ByteOrder getByteOrder()
+ {
+ return buf.order();
+ }
+
+ @Override
+ public void setByteOrder(ByteOrder byteOrder)
+ {
+ buf.order(byteOrder);
+ }
+
+ @Override
+ public void readFully(byte[] b) throws IOExceptionUnchecked
+ {
+ readFully(b, 0, b.length);
+ }
+
+ @Override
+ public void readFully(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ if (available0() == -1)
+ {
+ throw new IOExceptionUnchecked(new EOFException());
+ } else
+ {
+ buf.get(b, off, len);
+ }
+ }
+
+ @Override
+ public int skipBytes(int n) throws IOExceptionUnchecked
+ {
+ if (n <= 0)
+ {
+ return 0;
+ }
+ final int pos = buf.position();
+ final int len = buf.limit();
+ final int newpos = Math.min(len, pos + n);
+ buf.position(newpos);
+ return (newpos - pos);
+ }
+
+ @Override
+ public void close() throws IOExceptionUnchecked
+ {
+ // NOOP
+ }
+
+ @Override
+ public int read() throws IOExceptionUnchecked
+ {
+ return buf.get() & 0xff;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOExceptionUnchecked
+ {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ final int bytesRead = Math.min(available0(), len);
+ if (bytesRead < 0)
+ {
+ return bytesRead;
+ }
+ buf.get(b, off, bytesRead);
+ return bytesRead;
+ }
+
+ @Override
+ public long skip(long n) throws IOExceptionUnchecked
+ {
+ if (n > Integer.MAX_VALUE)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ return skipBytes((int) n);
+ }
+
+ private int available0() throws IOExceptionUnchecked
+ {
+ return (buf.remaining() == 0) ? -1 : buf.remaining();
+ }
+
+ @Override
+ public int available() throws IOExceptionUnchecked
+ {
+ return buf.remaining();
+ }
+
+ @Override
+ public void mark(int readlimit)
+ {
+ buf.mark();
+ }
+
+ @Override
+ public void reset() throws IOExceptionUnchecked
+ {
+ buf.reset();
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ @Override
+ public void flush() throws IOExceptionUnchecked
+ {
+ // NOOP
+ }
+
+ @Override
+ public void synchronize() throws IOExceptionUnchecked
+ {
+ // NOOP
+ }
+
+ @Override
+ public long getFilePointer() throws IOExceptionUnchecked
+ {
+ return buf.position();
+ }
+
+ @Override
+ public void seek(long pos) throws IOExceptionUnchecked
+ {
+ buf.position((int) pos);
+ }
+
+ @Override
+ public long length() throws IOExceptionUnchecked
+ {
+ return buf.limit();
+ }
+
+ @Override
+ public void setLength(long newLength) throws IOExceptionUnchecked
+ {
+ buf.limit((int) newLength);
+ }
+
+ @Override
+ public boolean readBoolean() throws IOExceptionUnchecked
+ {
+ return buf.get() != 0;
+ }
+
+ @Override
+ public byte readByte() throws IOExceptionUnchecked
+ {
+ return buf.get();
+ }
+
+ @Override
+ public int readUnsignedByte() throws IOExceptionUnchecked
+ {
+ return buf.get() & 0xff;
+ }
+
+ @Override
+ public short readShort() throws IOExceptionUnchecked
+ {
+ return buf.getShort();
+ }
+
+ @Override
+ public int readUnsignedShort() throws IOExceptionUnchecked
+ {
+ return buf.getShort() & 0xffff;
+ }
+
+ @Override
+ public char readChar() throws IOExceptionUnchecked
+ {
+ return buf.getChar();
+ }
+
+ @Override
+ public int readInt() throws IOExceptionUnchecked
+ {
+ return buf.getInt();
+ }
+
+ @Override
+ public long readLong() throws IOExceptionUnchecked
+ {
+ return buf.getLong();
+ }
+
+ @Override
+ public float readFloat() throws IOExceptionUnchecked
+ {
+ return buf.getFloat();
+ }
+
+ @Override
+ public double readDouble() throws IOExceptionUnchecked
+ {
+ return buf.getDouble();
+ }
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public String readLine() throws UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String readUTF()
+ {
+ try
+ {
+ final byte[] strBuf = new byte[readUnsignedShort()];
+ buf.get(strBuf);
+ return new String(strBuf, "UTF-8");
+ } catch (UnsupportedEncodingException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOExceptionUnchecked
+ {
+ addToLength(1);
+ buf.put((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOExceptionUnchecked
+ {
+ addToLength(b.length);
+ buf.put(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ addToLength(len);
+ buf.put(b, off, len);
+ }
+
+ @Override
+ public void writeBoolean(boolean v) throws IOExceptionUnchecked
+ {
+ addToLength(1);
+ buf.put((byte) (v ? 1 : 0));
+ }
+
+ @Override
+ public void writeByte(int v) throws IOExceptionUnchecked
+ {
+ write((byte) v);
+ }
+
+ @Override
+ public void writeShort(int v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.SHORT_SIZE);
+ buf.putShort((short) v);
+ }
+
+ @Override
+ public void writeChar(int v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.CHAR_SIZE);
+ buf.putChar((char) v);
+ }
+
+ @Override
+ public void writeInt(int v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.INT_SIZE);
+ buf.putInt(v);
+ }
+
+ @Override
+ public void writeLong(long v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.LONG_SIZE);
+ buf.putLong(v);
+ }
+
+ @Override
+ public void writeFloat(float v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.FLOAT_SIZE);
+ buf.putFloat(v);
+ }
+
+ @Override
+ public void writeDouble(double v) throws IOExceptionUnchecked
+ {
+ addToLength(NativeData.DOUBLE_SIZE);
+ buf.putDouble(v);
+ }
+
+ @Override
+ public void writeBytes(String s) throws IOExceptionUnchecked
+ {
+ final int len = s.length();
+ addToLength(len);
+ for (int i = 0; i < len; i++)
+ {
+ buf.put((byte) s.charAt(i));
+ }
+ }
+
+ @Override
+ public void writeChars(String s) throws IOExceptionUnchecked
+ {
+ final int len = s.length();
+ addToLength(NativeData.CHAR_SIZE * len);
+ for (int i = 0; i < len; i++)
+ {
+ final int v = s.charAt(i);
+ buf.put((byte) ((v >>> 8) & 0xFF));
+ buf.put((byte) ((v >>> 0) & 0xFF));
+ }
+ }
+
+ @Override
+ public void writeUTF(String str) throws UnsupportedOperationException
+ {
+ try
+ {
+ final byte[] strBuf = str.getBytes("UTF-8");
+ addToLength(NativeData.SHORT_SIZE + strBuf.length);
+ writeShort(strBuf.length);
+ write(strBuf);
+ } catch (UnsupportedEncodingException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ICloseable.java b/source/java/ch/systemsx/cisd/base/io/ICloseable.java
new file mode 100644
index 0000000..1f3073e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ICloseable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * A role that allows to close resource. Like {@link java.io.Closeable} but doesn't throw an
+ * {@link IOException} but a {@link IOExceptionUnchecked} instead.
+ *
+ * @author Bernd Rinn
+ */
+public interface ICloseable
+{
+
+ /**
+ * Closes the resource.
+ */
+ public void close() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IInputStream.java b/source/java/ch/systemsx/cisd/base/io/IInputStream.java
new file mode 100644
index 0000000..c43e112
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IInputStream.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An interface for {@link java.io.InputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IInputStream
+{
+
+ /**
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#read(byte[])
+ */
+ public int read(byte b[]) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public int read(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#skip(long)
+ */
+ public long skip(long n) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#available()
+ */
+ public int available() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#close()
+ */
+ public void close() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#mark(int)
+ */
+ public void mark(int readlimit);
+
+ /**
+ * @see java.io.InputStream#reset()
+ */
+ public void reset() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.InputStream#markSupported()
+ */
+ public boolean markSupported();
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IOutputStream.java b/source/java/ch/systemsx/cisd/base/io/IOutputStream.java
new file mode 100644
index 0000000..7445d49
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IOutputStream.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An interface for {@link java.io.OutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IOutputStream extends ICloseable, ISynchronizable
+{
+ /**
+ * @see java.io.OutputStream#write(int)
+ */
+ public void write(int b) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.OutputStream#write(byte[])
+ */
+ public void write(byte b[]) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.OutputStream#flush()
+ */
+ public void flush() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.OutputStream#flush()
+ */
+ @Override
+ public void synchronize() throws IOExceptionUnchecked;
+
+ /**
+ * @see java.io.OutputStream#close()
+ */
+ @Override
+ public void close() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java b/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java
new file mode 100644
index 0000000..8cd83ec
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.nio.ByteOrder;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * The interface of {@link java.io.RandomAccessFile}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IRandomAccessFile extends DataInput, DataOutput, Closeable, IInputStream,
+ IOutputStream
+{
+ /**
+ * Gets the byte-order (endiness) of the random access file. Default is network-byte order
+ * (big-endian).
+ */
+ public ByteOrder getByteOrder();
+
+ /**
+ * Sets the byte-order (endiness) of the random access file.
+ */
+ public void setByteOrder(ByteOrder byteOrder);
+
+ //
+ // RandomAccessFile
+ //
+
+ /**
+ * Returns the current offset in this file.
+ *
+ * @return the offset from the beginning of the file, in bytes, at which the next read or write
+ * occurs.
+ * @exception IOExceptionUnchecked if an I/O error occurs.
+ */
+ public long getFilePointer() throws IOExceptionUnchecked;
+
+ /**
+ * Sets the file-pointer offset, measured from the beginning of this file, at which the next
+ * read or write occurs. The offset may be set beyond the end of the file. Setting the offset
+ * beyond the end of the file does not change the file length. The file length will change only
+ * by writing after the offset has been set beyond the end of the file.
+ *
+ * @param pos the offset position, measured in bytes from the beginning of the file, at which to
+ * set the file pointer.
+ * @exception IOExceptionUnchecked if <code>pos</code> is less than <code>0</code> or if an I/O
+ * error occurs.
+ */
+ public void seek(long pos) throws IOExceptionUnchecked;
+
+ /**
+ * Returns the length of this file.
+ *
+ * @return the length of this file, measured in bytes.
+ * @exception IOExceptionUnchecked if an I/O error occurs.
+ */
+ public long length() throws IOExceptionUnchecked;
+
+ /**
+ * Sets the length of this file.
+ * <p>
+ * If the present length of the file as returned by the <code>length</code> method is greater
+ * than the <code>newLength</code> argument then the file will be truncated. In this case, if
+ * the file offset as returned by the <code>getFilePointer</code> method is greater than
+ * <code>newLength</code> then after this method returns the offset will be equal to
+ * <code>newLength</code>.
+ * <p>
+ * If the present length of the file as returned by the <code>length</code> method is smaller
+ * than the <code>newLength</code> argument then the file will be extended. In this case, the
+ * contents of the extended portion of the file are not defined.
+ *
+ * @param newLength The desired length of the file
+ * @exception IOExceptionUnchecked If an I/O error occurs
+ */
+ public void setLength(long newLength) throws IOExceptionUnchecked;
+
+ //
+ // DataInput
+ //
+
+ /**
+ * @see DataInput#readFully(byte[])
+ */
+ @Override
+ public void readFully(byte b[]) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readFully(byte[], int, int)
+ */
+ @Override
+ public void readFully(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#skipBytes(int)
+ */
+ @Override
+ public int skipBytes(int n) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readBoolean()
+ */
+ @Override
+ public boolean readBoolean() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readByte()
+ */
+ @Override
+ public byte readByte() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readUnsignedByte()
+ */
+ @Override
+ public int readUnsignedByte() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readShort()
+ */
+ @Override
+ public short readShort() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readUnsignedShort()
+ */
+ @Override
+ public int readUnsignedShort() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readChar()
+ */
+ @Override
+ public char readChar() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readInt()
+ */
+ @Override
+ public int readInt() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readLong()
+ */
+ @Override
+ public long readLong() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readFloat()
+ */
+ @Override
+ public float readFloat() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readDouble()
+ */
+ @Override
+ public double readDouble() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readLine()
+ */
+ @Override
+ public String readLine() throws IOExceptionUnchecked;
+
+ /**
+ * @see DataInput#readUTF()
+ */
+ @Override
+ public String readUTF() throws IOExceptionUnchecked;
+
+ //
+ // DataOutput
+ //
+
+ /**
+ * @see DataOutput#write(int)
+ */
+ @Override
+ public void write(int b) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#write(byte[])
+ */
+ @Override
+ public void write(byte b[]) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#write(byte[], int, int)
+ */
+ @Override
+ public void write(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeBoolean(boolean)
+ */
+ @Override
+ public void writeBoolean(boolean v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeByte(int)
+ */
+ @Override
+ public void writeByte(int v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeShort(int)
+ */
+ @Override
+ public void writeShort(int v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeChar(int)
+ */
+ @Override
+ public void writeChar(int v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeInt(int)
+ */
+ @Override
+ public void writeInt(int v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeLong(long)
+ */
+ @Override
+ public void writeLong(long v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeFloat(float)
+ */
+ @Override
+ public void writeFloat(float v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeDouble(double)
+ */
+ @Override
+ public void writeDouble(double v) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeBytes(String)
+ */
+ @Override
+ public void writeBytes(String s) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeChars(String)
+ */
+ @Override
+ public void writeChars(String s) throws IOExceptionUnchecked;
+
+ /**
+ * @see DataOutput#writeUTF(String)
+ */
+ @Override
+ public void writeUTF(String str) throws IOExceptionUnchecked;
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java b/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java
new file mode 100644
index 0000000..67c1591
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * A roles that allows to synchronize a resource with an underlying resource.
+ *
+ * @author Bernd Rinn
+ */
+public interface ISynchronizable
+{
+
+ /**
+ * Performs a synchronization of the resource.
+ */
+ public void synchronize() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java b/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java
new file mode 100644
index 0000000..e5f1ce7
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import static ch.systemsx.cisd.base.convert.NativeData.changeByteOrder;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * The file implementation of {@link IRandomAccessFile}.
+ *
+ * @author Bernd Rinn
+ */
+public class RandomAccessFileImpl implements IRandomAccessFile
+{
+
+ private final RandomAccessFile randomAccessFile;
+
+ private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+ private boolean changeByteOrder = ByteOrder.LITTLE_ENDIAN.equals(byteOrder);
+
+ private long markedPosition = -1;
+
+ public RandomAccessFileImpl(RandomAccessFile randomAccessFile)
+ {
+ this.randomAccessFile = randomAccessFile;
+ }
+
+ public RandomAccessFileImpl(String name, String mode) throws IOExceptionUnchecked
+ {
+ try
+ {
+ this.randomAccessFile = new RandomAccessFile(name, mode);
+ } catch (FileNotFoundException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ public RandomAccessFileImpl(File file, String mode) throws IOExceptionUnchecked
+ {
+ try
+ {
+ this.randomAccessFile = new RandomAccessFile(file, mode);
+ } catch (FileNotFoundException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ public final FileDescriptor getFD() throws IOException
+ {
+ return randomAccessFile.getFD();
+ }
+
+ public final FileChannel getChannel()
+ {
+ return randomAccessFile.getChannel();
+ }
+
+ @Override
+ public ByteOrder getByteOrder()
+ {
+ return byteOrder;
+ }
+
+ @Override
+ public void setByteOrder(ByteOrder byteOrder)
+ {
+ this.byteOrder = byteOrder;
+ this.changeByteOrder = ByteOrder.LITTLE_ENDIAN.equals(byteOrder);
+ }
+
+ @Override
+ public int read() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.read();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.read(b, off, len);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.read(b);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void readFully(byte[] b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.readFully(b);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void readFully(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.readFully(b, off, len);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int skipBytes(int n) throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.skipBytes(n);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.write(b);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.write(b);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.write(b, off, len);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public long getFilePointer() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.getFilePointer();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.seek(pos);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public long length() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.length();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void setLength(long newLength) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.setLength(newLength);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void close() throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.close();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final boolean readBoolean() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.readBoolean();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final byte readByte() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.readByte();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final int readUnsignedByte() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.readUnsignedByte();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final short readShort() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final short s = randomAccessFile.readShort();
+ return changeByteOrder ? changeByteOrder(s) : s;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final int readUnsignedShort() throws IOExceptionUnchecked
+ {
+ return readShort() & 0xffff;
+ }
+
+ @Override
+ public final char readChar() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final char c = randomAccessFile.readChar();
+ return changeByteOrder ? changeByteOrder(c) : c;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final int readInt() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final int i = randomAccessFile.readInt();
+ return changeByteOrder ? changeByteOrder(i) : i;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final long readLong() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final long l = randomAccessFile.readLong();
+ return changeByteOrder ? changeByteOrder(l) : l;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final float readFloat() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final float f = randomAccessFile.readFloat();
+ return changeByteOrder ? changeByteOrder(f) : f;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final double readDouble() throws IOExceptionUnchecked
+ {
+ try
+ {
+ final double d = randomAccessFile.readDouble();
+ return changeByteOrder ? changeByteOrder(d) : d;
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final String readLine() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.readLine();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final String readUTF() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return randomAccessFile.readUTF();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeBoolean(boolean v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeBoolean(v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeByte(int v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeByte(v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeShort(int v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeShort(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeChar(int v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeChar(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeInt(int v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeInt(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeLong(long v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeLong(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeFloat(float v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeFloat(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeDouble(double v) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeDouble(changeByteOrder ? changeByteOrder(v) : v);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeBytes(String s) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeBytes(s);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeChars(String s) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeChars(s);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public final void writeUTF(String str) throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.writeUTF(str);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOExceptionUnchecked
+ {
+ if (n <= 0)
+ {
+ return 0;
+ }
+ try
+ {
+ final long pos = randomAccessFile.getFilePointer();
+ final long len = randomAccessFile.length();
+ final long newpos = Math.min(len, pos + n);
+ randomAccessFile.seek(newpos);
+ return (int) (newpos - pos);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public int available() throws IOExceptionUnchecked
+ {
+ try
+ {
+ return (int) Math.min(randomAccessFile.length() - randomAccessFile.getFilePointer(), Integer.MAX_VALUE);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void mark(int readlimit)
+ {
+ try
+ {
+ markedPosition = randomAccessFile.getFilePointer();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public void reset() throws IOExceptionUnchecked
+ {
+ if (markedPosition == -1)
+ {
+ throw new IOExceptionUnchecked(new IOException("mark() not called"));
+ }
+ try
+ {
+ randomAccessFile.seek(markedPosition);
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Override
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ @Override
+ public void flush() throws IOExceptionUnchecked
+ {
+ // NOOP
+ }
+
+ @Override
+ public void synchronize() throws IOExceptionUnchecked
+ {
+ try
+ {
+ randomAccessFile.getFD().sync();
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ return randomAccessFile.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return randomAccessFile.equals(obj);
+ }
+
+ @Override
+ public String toString()
+ {
+ return randomAccessFile.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java
new file mode 100644
index 0000000..d2dd838
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.ClassUtils;
+
+/**
+ * Base class of a multi-dimensional array. The <var>dimensions</var> of an array are provided
+ * separately from the data as a <code>int[]</code>.
+ * <p>
+ * The array can grow or shrink in the first dimension (<var>dimensions[0]</var>). Dimensions
+ * <code>1...n</code> are static. They are said to form a <i>hyper-row</i>.
+ *
+ * @author Bernd Rinn
+ */
+public abstract class MDAbstractArray<T> implements Serializable,
+ Iterable<MDAbstractArray<T>.ArrayEntry>
+{
+ private static final long serialVersionUID = 1L;
+
+ protected final int[] dimensions;
+
+ protected int hyperRowLength;
+
+ protected int capacityHyperRows;
+
+ protected int size;
+
+ /**
+ * A class to represent an entry (index and value) of a {@link MDArray}, used for iteration.
+ */
+ public class ArrayEntry
+ {
+ private final int linearIndex;
+
+ ArrayEntry(int linearIndex)
+ {
+ this.linearIndex = linearIndex;
+ }
+
+ /**
+ * The multi-dimensional index of this entry.
+ */
+ public int[] getIndex()
+ {
+ return computeReverseIndex(linearIndex);
+ }
+
+ /**
+ * The linear index of this entry.
+ */
+ public int getLinearIndex()
+ {
+ return linearIndex;
+ }
+
+ /**
+ * The value of this entry.
+ */
+ public T getValue()
+ {
+ return getAsObject(linearIndex);
+ }
+ }
+
+ protected MDAbstractArray(int[] dimensions, int arrayLength, int capacityHyperRows)
+ {
+ assert dimensions != null;
+
+ this.dimensions = dimensions;
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ if (hyperRowLength == 0)
+ {
+ this.capacityHyperRows = 0;
+ this.size = 0;
+ } else
+ {
+ if (arrayLength % hyperRowLength != 0)
+ {
+ throw new IllegalArgumentException("Actual array length " + arrayLength
+ + " does not match hyper-row length " + hyperRowLength + ".");
+ }
+ this.capacityHyperRows =
+ (capacityHyperRows > 0) ? capacityHyperRows : Math.max(dimensions[0],
+ arrayLength / hyperRowLength);
+ this.size = dimensions[0] * hyperRowLength;
+ }
+ }
+
+ protected int computeHyperRowLength(@SuppressWarnings("hiding")
+ int[] dimensions)
+ {
+ int hyperRowLen = 1;
+ for (int i = 1; i < dimensions.length; ++i)
+ {
+ hyperRowLen *= dimensions[i];
+ }
+ return hyperRowLen;
+ }
+
+ /**
+ * Returns the rank of the array.
+ */
+ public int rank()
+ {
+ return dimensions.length;
+ }
+
+ /**
+ * Returns the extent of the array along its <var>dim</var>-th axis.
+ */
+ public int size(int dim)
+ {
+ assert dim < dimensions.length;
+
+ return dimensions[dim];
+ }
+
+ /**
+ * Returns a copy of the dimensions of the multi-dimensional array.
+ */
+ public int[] dimensions()
+ {
+ return dimensions.clone();
+ }
+
+ /**
+ * Returns a copy of the dimensions of the multi-dimensional array as <code>long[]</code>.
+ */
+ public long[] longDimensions()
+ {
+ final long[] dimensionsCopy = new long[dimensions.length];
+ for (int i = 0; i < dimensionsCopy.length; ++i)
+ {
+ dimensionsCopy[i] = dimensions[i];
+ }
+ return dimensionsCopy;
+ }
+
+ /**
+ * Returns the number of elements in the array.
+ */
+ public int size()
+ {
+ return size;
+ }
+
+ /**
+ * Returns the current number of hyper rows of of this array.
+ */
+ public int numberOfHyperRows()
+ {
+ return numberOfHyperRows();
+ }
+
+ /**
+ * Return an object which has the same value as the element of the array specified by
+ * <var>linearIndex</var>.
+ *
+ * @param linearIndex The index in the linear array returned by {@link #getAsFlatArray()}.
+ * @return The value at the specified index.
+ */
+ public abstract T getAsObject(int linearIndex);
+
+ /**
+ * Return an object which has the same value as the element of the array specified by
+ * <var>indices</var>.
+ */
+ public abstract T getAsObject(int... indices);
+
+ /**
+ * Sets the element of the array specified by <var>indices</var> to the particular
+ * <var>value</var>.
+ */
+ public abstract void setToObject(T value, int... indices);
+
+ /**
+ * Sets the element of the array specified by <var>linearIndex</var> to the particular
+ * <var>value</var>.
+ *
+ * @param value The new value to set.
+ * @param linearIndex The index in the linear array returned by {@link #getAsFlatArray()}.
+ */
+ public abstract void setToObject(T value, int linearIndex);
+
+ /**
+ * Returns the array in flattened form. Changes to the returned object will change the
+ * multi-dimensional array directly.
+ */
+ public abstract Object getAsFlatArray();
+
+ /**
+ * Returns a copy of the array in flattened form. Changes to the returned object will <i>not</i>
+ * change the multi-dimensional array directly.
+ */
+ public abstract Object getCopyAsFlatArray();
+
+ protected abstract void adaptCapacityHyperRows();
+
+ /**
+ * Returns the capacity of elements in the array.
+ */
+ public abstract int capacity();
+
+ /**
+ * Increase the number of hyper-rows by <var>count</var>. Doubles the capacity if needed.
+ *
+ * @return The new number of rows.
+ */
+ public int incNumberOfHyperRows(int count)
+ {
+ dimensions[0] += count;
+ if (dimensions[0] > capacityHyperRows)
+ {
+ capacityHyperRows = Math.max(capacityHyperRows * 2, dimensions[0]);
+ adaptCapacityHyperRows();
+ }
+ size += count * hyperRowLength;
+ return dimensions[0];
+ }
+
+ /**
+ * Decrease the number of hyper-rows by <var>count</var>.
+ *
+ * @return The new number of rows.
+ */
+ public int decNumberOfHyperRows(int count)
+ {
+ dimensions[0] -= count;
+ size -= count * hyperRowLength;
+ return dimensions[0];
+ }
+
+ /**
+ * Computes the linear index for the multi-dimensional <var>indices</var> provided.
+ */
+ public int computeIndex(int... indices)
+ {
+ assert indices != null;
+ assert indices.length == dimensions.length;
+
+ int index = indices[0];
+ for (int i = 1; i < indices.length; ++i)
+ {
+ index = index * dimensions[i] + indices[i];
+ }
+ return index;
+ }
+
+ /**
+ * Computes the multi-dimensional index from the <var>linearIndex</var>.
+ */
+ public int[] computeReverseIndex(int linearIndex)
+ {
+ final int[] index = new int[dimensions.length];
+ int workIndex = linearIndex;
+ int blockSize = size;
+ for (int i = 0; i < dimensions.length; ++i)
+ {
+ blockSize /= dimensions[i];
+ index[i] = workIndex / blockSize;
+ workIndex = workIndex - index[i] * blockSize;
+ }
+ return index;
+ }
+
+ /**
+ * Computes the linear index for the two-dimensional (<var>indexX, indexY</var>) provided.
+ */
+ public int computeIndex(int indexX, int indexY)
+ {
+ assert 2 == dimensions.length;
+
+ return dimensions[1] * indexX + indexY;
+ }
+
+ /**
+ * Computes the linear index for the three-dimensional (<var>indexX, indexY, indexZ</var>)
+ * provided.
+ */
+ public int computeIndex(int indexX, int indexY, int indexZ)
+ {
+ assert 3 == dimensions.length;
+
+ return dimensions[2] * (dimensions[1] * indexX + indexY) + indexZ;
+ }
+
+ /**
+ * Converts the <var>dimensions</var> from <code>long[]</code> to <code>int[]</code>.
+ */
+ public static int[] toInt(final long[] dimensions)
+ {
+ assert dimensions != null;
+
+ final int[] result = new int[dimensions.length];
+ for (int i = 0; i < result.length; ++i)
+ {
+ result[i] = (int) dimensions[i];
+ if (result[i] != dimensions[i])
+ {
+ throw new IllegalArgumentException("Dimension " + i + " is too large ("
+ + dimensions[i] + ")");
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts the <var>dimensions</var> from <code>int[]</code> to <code>long[]</code>.
+ */
+ public static long[] toLong(final int[] dimensions)
+ {
+ assert dimensions != null;
+
+ final long[] result = new long[dimensions.length];
+ for (int i = 0; i < result.length; ++i)
+ {
+ result[i] = dimensions[i];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the one-dimensional length of the multi-dimensional array defined by
+ * <var>dimensions</var>.
+ *
+ * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+ */
+ public static int getLength(final int[] dimensions)
+ {
+ return getLength(dimensions, 0);
+ }
+
+ /**
+ * Returns the one-dimensional length of the multi-dimensional array defined by
+ * <var>dimensions</var>. If <code>capacityHyperRows > dimensions[0]</code>, then it will
+ * replace <var>dimensions[0]</var> by <var>capacityHyperRows</var>
+ *
+ * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+ */
+ public static int getLength(final int[] dimensions, int capacityHyperRows)
+ {
+ assert dimensions != null;
+
+ if (dimensions.length == 0)
+ {
+ return 0;
+ }
+ long length = Math.max(capacityHyperRows, dimensions[0]);
+ for (int i = 1; i < dimensions.length; ++i)
+ {
+ length *= dimensions[i];
+ }
+ int intLength = (int) length;
+ if (length != intLength)
+ {
+ throw new IllegalArgumentException("Length is too large (" + length + ")");
+ }
+ return intLength;
+ }
+
+ /**
+ * Returns the one-dimensional length of the multi-dimensional array defined by
+ * <var>dimensions</var>.
+ *
+ * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+ */
+ public static int getLength(final long[] dimensions)
+ {
+ return getLength(dimensions, 0);
+ }
+
+ /**
+ * Returns the one-dimensional length of the multi-dimensional array defined by
+ * <var>dimensions</var>. If <code>capacityHyperRows > dimensions[0]</code>, then it will
+ * replace <var>dimensions[0]</var> by <var>capacityHyperRows</var>
+ *
+ * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+ */
+ public static int getLength(final long[] dimensions, long capacityHyperRows)
+ {
+ assert dimensions != null;
+
+ if (dimensions.length == 0) // NULL data space needs to be treated differently
+ {
+ return 0;
+ }
+ long length = Math.max(capacityHyperRows, dimensions[0]);
+ for (int i = 1; i < dimensions.length; ++i)
+ {
+ length *= dimensions[i];
+ }
+ int intLength = (int) length;
+ if (length != intLength)
+ {
+ throw new IllegalArgumentException("Length is too large (" + length + ")");
+ }
+ return intLength;
+ }
+
+ //
+ // Iterable
+ //
+
+ @Override
+ public Iterator<ArrayEntry> iterator()
+ {
+ return new Iterator<ArrayEntry>()
+ {
+ int linearIndex = 0;
+
+ @Override
+ public boolean hasNext()
+ {
+ return linearIndex < size;
+ }
+
+ @Override
+ public ArrayEntry next()
+ {
+ final ArrayEntry next = new ArrayEntry(linearIndex);
+ ++linearIndex;
+ return next;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public String toString()
+ {
+ final int length = getLength(dimensions, 0);
+ final StringBuilder b = new StringBuilder();
+ b.append(ClassUtils.getShortCanonicalName(this.getClass()));
+ b.append('(');
+ b.append(ArrayUtils.toString(dimensions));
+ b.append(')');
+ if (length <= 100)
+ {
+ b.append(": ");
+ if (dimensions[0] < capacityHyperRows)
+ {
+ b.append(ArrayUtils.toString(getCopyAsFlatArray()));
+ } else
+ {
+ b.append(ArrayUtils.toString(getAsFlatArray()));
+ }
+ }
+ return b.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java
new file mode 100644
index 0000000..1a4a236
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional array of generic type <code>T</code>.
+ *
+ * @author Bernd Rinn
+ */
+public class MDArray<T> extends MDAbstractArray<T>
+{
+ private static final long serialVersionUID = 1L;
+
+ private T[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDArray(Class<T> componentClass, long[] dimensions)
+ {
+ this(createArray(componentClass, getLength(dimensions, 0)), toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDArray(Class<T> componentClass, long[] dimensions, long capacityHyperRows)
+ {
+ this(createArray(componentClass, getLength(dimensions, capacityHyperRows)),
+ toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDArray} from the given {@code flattenedArray} and {@code dimensions}. It is
+ * checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDArray(T[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDArray} from the given <var>flattenedArray</var> and <var>dimensions</var>.
+ * If <var>checkDimensions</var> is {@code true}, it is checked that the arguments are
+ * compatible. Convenience method if <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDArray(T[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDArray} with the <var>dimensions</var>.
+ */
+ public MDArray(Class<T> componentClass, int[] dimensions)
+ {
+ this(createArray(componentClass, getLength(dimensions, 0)), dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDArray(Class<T> componentClass, int[] dimensions, int capacityHyperRows)
+ {
+ this(createArray(componentClass, getLength(dimensions, capacityHyperRows)), dimensions,
+ false);
+ }
+
+ /**
+ * Creates a {@link MDArray} from the given {@code flattenedArray} and {@code dimensions}. It is
+ * checked that the arguments are compatible.
+ */
+ public MDArray(T[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDArray} from the given <var>flattenedArray</var> and <var>dimensions</var>.
+ * If <var>checkDimensions</var> is {@code true}, it is checked that the arguments are
+ * compatible.
+ */
+ public MDArray(T[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <V> V[] createArray(Class<V> componentClass, final int vectorLength)
+ {
+ final V[] value = (V[]) java.lang.reflect.Array.newInstance(componentClass, vectorLength);
+ return value;
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public T getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(T value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public T getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(T value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public T[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public T[] getCopyAsFlatArray()
+ {
+ return toTArray(ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength));
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final T[] oldArray = this.flattenedArray;
+ this.flattenedArray =
+ toTArray(createArray(oldArray.getClass().getComponentType(), capacityHyperRows
+ * hyperRowLength));
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ @SuppressWarnings("unchecked")
+ private T[] toTArray(Object obj)
+ {
+ return (T[]) obj;
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public T get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public T get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public T get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public T get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(T value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(T value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(T value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(T value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Returns the component type of this array.
+ */
+ @SuppressWarnings("unchecked")
+ public Class<T> getComponentClass()
+ {
+ return (Class<T>) flattenedArray.getClass().getComponentType();
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ final MDArray<T> other = toMDArray(obj);
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private T[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ private MDArray<T> toMDArray(Object obj)
+ {
+ return (MDArray<T>) obj;
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java
new file mode 100644
index 0000000..4bb36ad
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>byte</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDByteArray extends MDAbstractArray<Byte>
+{
+ private static final long serialVersionUID = 1L;
+
+ private byte[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDByteArray(long[] dimensions)
+ {
+ this(new byte[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDByteArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDByteArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new byte[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDByteArray(byte[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDByteArray(byte[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDByteArray} with the <var>dimensions</var>.
+ */
+ public MDByteArray(int[] dimensions)
+ {
+ this(new byte[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDByteArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDByteArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new byte[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDByteArray(byte[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDByteArray(byte[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDByteArray(byte[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDByteArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDByteArray(byte[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new byte[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(byte[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Byte getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Byte value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Byte getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Byte value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public byte[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public byte[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final byte[] oldArray = this.flattenedArray;
+ this.flattenedArray = new byte[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public byte get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public byte get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public byte get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public byte get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(byte value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(byte value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(byte value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(byte value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public byte[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final byte[][] result = new byte[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDByteArray other = (MDByteArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private byte[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java
new file mode 100644
index 0000000..8a755f4
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>double</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDDoubleArray extends MDAbstractArray<Double>
+{
+ private static final long serialVersionUID = 1L;
+
+ private double[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDDoubleArray(long[] dimensions)
+ {
+ this(new double[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDDoubleArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new double[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDDoubleArray(double[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDDoubleArray(double[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>.
+ */
+ public MDDoubleArray(int[] dimensions)
+ {
+ this(new double[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDDoubleArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new double[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDDoubleArray(double[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDDoubleArray(double[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDDoubleArray(double[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDDoubleArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDDoubleArray(double[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new double[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(double[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Double getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Double value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Double getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Double value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public double[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public double[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final double[] oldArray = this.flattenedArray;
+ this.flattenedArray = new double[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public double get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public double get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public double get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public double get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(double value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(double value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(double value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(double value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public double[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final double[][] result = new double[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDDoubleArray other = (MDDoubleArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private double[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java
new file mode 100644
index 0000000..4b10fb8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>float</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDFloatArray extends MDAbstractArray<Float>
+{
+ private static final long serialVersionUID = 1L;
+
+ private float[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDFloatArray(long[] dimensions)
+ {
+ this(new float[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDFloatArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new float[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDFloatArray(float[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDFloatArray(float[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>.
+ */
+ public MDFloatArray(int[] dimensions)
+ {
+ this(new float[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDFloatArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new float[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDFloatArray(float[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDFloatArray(float[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDFloatArray(float[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDFloatArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDFloatArray(float[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new float[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(float[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Float getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Float value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Float getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Float value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public float[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public float[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final float[] oldArray = this.flattenedArray;
+ this.flattenedArray = new float[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public float get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public float get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public float get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public float get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(float value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(float value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(float value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(float value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public float[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final float[][] result = new float[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDFloatArray other = (MDFloatArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private float[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java
new file mode 100644
index 0000000..76cbcd1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>int</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDIntArray extends MDAbstractArray<Integer>
+{
+ private static final long serialVersionUID = 1L;
+
+ private int[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDIntArray(long[] dimensions)
+ {
+ this(new int[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDIntArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new int[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDIntArray(int[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDIntArray(int[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>.
+ */
+ public MDIntArray(int[] dimensions)
+ {
+ this(new int[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDIntArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new int[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDIntArray(int[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDIntArray(int[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDIntArray(int[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDIntArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDIntArray(int[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new int[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(int[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Integer getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Integer value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Integer getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Integer value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public int[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public int[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final int[] oldArray = this.flattenedArray;
+ this.flattenedArray = new int[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public int get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public int get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public int get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public int get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(int value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(int value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(int value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(int value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public int[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final int[][] result = new int[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDIntArray other = (MDIntArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private int[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java
new file mode 100644
index 0000000..3b927b1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>long</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDLongArray extends MDAbstractArray<Long>
+{
+ private static final long serialVersionUID = 1L;
+
+ private long[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDLongArray(long[] dimensions)
+ {
+ this(new long[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDLongArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDLongArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new long[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDLongArray(long[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDLongArray(long[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDLongArray} with the <var>dimensions</var>.
+ */
+ public MDLongArray(int[] dimensions)
+ {
+ this(new long[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDLongArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDLongArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new long[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDLongArray(long[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDLongArray(long[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDLongArray(long[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDLongArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDLongArray(long[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new long[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(long[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Long getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Long value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Long getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Long value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public long[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public long[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final long[] oldArray = this.flattenedArray;
+ this.flattenedArray = new long[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public long get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public long get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public long get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public long get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(long value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(long value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(long value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(long value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public long[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final long[][] result = new long[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDLongArray other = (MDLongArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private long[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java
new file mode 100644
index 0000000..eefb0b8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>short</code> array.
+ *
+ * @author Bernd Rinn
+ */
+public final class MDShortArray extends MDAbstractArray<Short>
+{
+ private static final long serialVersionUID = 1L;
+
+ private short[] flattenedArray;
+
+ /**
+ * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+ * <var>dimensions</var> are available as {@code long[]}.
+ */
+ public MDShortArray(long[] dimensions)
+ {
+ this(new short[getLength(dimensions, 0)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates an empty {@link MDShortArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDShortArray(long[] dimensions, long capacityHyperRows)
+ {
+ this(new short[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+ * available as {@code long[]}.
+ */
+ public MDShortArray(short[] flattenedArray, long[] dimensions)
+ {
+ this(flattenedArray, toInt(dimensions), true);
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+ * {@code long[]}.
+ */
+ public MDShortArray(short[] flattenedArray, long[] dimensions, boolean checkdimensions)
+ {
+ this(flattenedArray, toInt(dimensions), checkdimensions);
+ }
+
+ /**
+ * Creates an empty {@link MDShortArray} with the <var>dimensions</var>.
+ */
+ public MDShortArray(int[] dimensions)
+ {
+ this(new short[getLength(dimensions, 0)], dimensions, false);
+ }
+
+ /**
+ * Creates an empty {@link MDShortArray} with the <var>dimensions</var>. If
+ * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+ * of <var>capacityHyperRows</var> hyper-rows.
+ */
+ public MDShortArray(int[] dimensions, int capacityHyperRows)
+ {
+ this(new short[getLength(dimensions, capacityHyperRows)], dimensions, false);
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given {@code flattenedArray} and {@code dimensions}. It
+ * is checked that the arguments are compatible.
+ */
+ public MDShortArray(short[] flattenedArray, int[] dimensions)
+ {
+ this(flattenedArray, dimensions, true);
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given <var>flattenedArray</var> and
+ * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+ * arguments are compatible.
+ */
+ public MDShortArray(short[] flattenedArray, int[] dimensions, boolean checkdimensions)
+ {
+ super(dimensions, flattenedArray.length, 0);
+ assert flattenedArray != null;
+
+ if (checkdimensions)
+ {
+ final int expectedLength = getLength(dimensions, 0);
+ if (flattenedArray.length != expectedLength)
+ {
+ throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+ + " does not match expected length " + expectedLength + ".");
+ }
+ }
+ this.flattenedArray = flattenedArray;
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given <var>matrix</var> of rank 2. Note that the values
+ * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+ * independent from <var>matrix</var> after construction.
+ */
+ public MDShortArray(short[][] matrix)
+ {
+ this(matrix, getDimensions(matrix));
+ }
+
+ /**
+ * Creates a {@link MDShortArray} from the given <var>matrix</var> of rank 2 and the
+ * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+ * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+ * will be independent from <var>matrix</var> after construction.
+ */
+ public MDShortArray(short[][] matrix, int[] dimensions)
+ {
+ super(dimensions, 0, matrix.length);
+
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ int length = getLength(dimensions, 0);
+ this.flattenedArray = new short[length];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+ }
+ }
+
+ private static int[] getDimensions(short[][] matrix)
+ {
+ assert matrix != null;
+
+ return new int[]
+ { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+ }
+
+ @Override
+ public int capacity()
+ {
+ return flattenedArray.length;
+ }
+
+ @Override
+ public Short getAsObject(int... indices)
+ {
+ return get(indices);
+ }
+
+ @Override
+ public void setToObject(Short value, int... indices)
+ {
+ set(value, indices);
+ }
+
+ @Override
+ public Short getAsObject(int linearIndex)
+ {
+ return get(linearIndex);
+ }
+
+ @Override
+ public void setToObject(Short value, int linearIndex)
+ {
+ set(value, linearIndex);
+ }
+
+ @Override
+ public short[] getAsFlatArray()
+ {
+ return flattenedArray;
+ }
+
+ @Override
+ public short[] getCopyAsFlatArray()
+ {
+ return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+ }
+
+ @Override
+ protected void adaptCapacityHyperRows()
+ {
+ final short[] oldArray = this.flattenedArray;
+ this.flattenedArray = new short[capacityHyperRows * hyperRowLength];
+ System.arraycopy(oldArray, 0, flattenedArray, 0,
+ Math.min(oldArray.length, flattenedArray.length));
+ }
+
+ /**
+ * Returns the value of array at the position defined by <var>indices</var>.
+ */
+ public short get(int... indices)
+ {
+ return flattenedArray[computeIndex(indices)];
+ }
+
+ /**
+ * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public short get(int index)
+ {
+ return flattenedArray[index];
+ }
+
+ /**
+ * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+ * <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public short get(int indexX, int indexY)
+ {
+ return flattenedArray[computeIndex(indexX, indexY)];
+ }
+
+ /**
+ * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+ * <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public short get(int indexX, int indexY, int indexZ)
+ {
+ return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+ }
+
+ /**
+ * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+ */
+ public void set(short value, int... indices)
+ {
+ flattenedArray[computeIndex(indices)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a one-dimension array at the position defined by
+ * <var>index</var>.
+ * <p>
+ * <b>Do not call for arrays other than one-dimensional!</b>
+ */
+ public void set(short value, int index)
+ {
+ flattenedArray[index] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a two-dimensional array at the position defined by
+ * <var>indexX</var> and <var>indexY</var>.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public void set(short value, int indexX, int indexY)
+ {
+ flattenedArray[computeIndex(indexX, indexY)] = value;
+ }
+
+ /**
+ * Sets the <var>value</var> of a three-dimensional array at the position defined by
+ * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+ * <p>
+ * <b>Do not call for arrays other than three-dimensional!</b>
+ */
+ public void set(short value, int indexX, int indexY, int indexZ)
+ {
+ flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+ }
+
+ /**
+ * Creates and returns a matrix from a two-dimensional array.
+ * <p>
+ * <b>Do not call for arrays other than two-dimensional!</b>
+ */
+ public short[][] toMatrix()
+ {
+ final int sizeX = dimensions[0];
+ final int sizeY = dimensions[1];
+ final short[][] result = new short[sizeX][sizeY];
+ for (int i = 0; i < sizeX; ++i)
+ {
+ System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+ }
+ return result;
+ }
+
+ //
+ // Object
+ //
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+ result = prime * result + Arrays.hashCode(dimensions);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ MDShortArray other = (MDShortArray) obj;
+ if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+ {
+ return false;
+ }
+ if (Arrays.equals(dimensions, other.dimensions) == false)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private short[] getValuesAsFlatArray()
+ {
+ return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (hyperRowLength == 0)
+ {
+ this.hyperRowLength = computeHyperRowLength(dimensions);
+ }
+ if (capacityHyperRows == 0)
+ {
+ this.capacityHyperRows = dimensions[0];
+ }
+ if (size == 0)
+ {
+ this.size = hyperRowLength * dimensions[0];
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/package.html b/source/java/ch/systemsx/cisd/base/mdarray/package.html
new file mode 100644
index 0000000..1788c17
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/package.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Multi-dimensional arrays.</title>
+</head>
+<body>
+<p>
+This package provides an implementation of multi-dimensional numerical arrays in Java. Contrary to
+the <i>array of arrays</i> representation that is built into the Java language, the classes in this
+package use one contiguous array and appropriate index operations to access the elements of the
+array.
+</p>
+<p>
+The number of indices (or axis') of an array is called the <i>rank</i> of the array, the set of
+extends of the array along each of its axis' are called the <i>dimensions</i> of the array.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java b/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java
new file mode 100644
index 0000000..061e213
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A name provider for a {@link java.util.concurrent.Callable}.
+ *
+ * @author Bernd Rinn
+ */
+public interface ICallableNameProvider
+{
+ /** Returns the name to be used for the thread name. */
+ public String getCallableName();
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java b/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java
new file mode 100644
index 0000000..adf021b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A name provider for a {@link Runnable}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IRunnableNameProvider
+{
+ /** Returns the name to be used for the thread name. */
+ public String getRunnableName();
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java
new file mode 100644
index 0000000..7bf3022
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A {@link Callable} with a name.
+ *
+ * @author Bernd Rinn
+ */
+public interface NamedCallable<T> extends Callable<T>, ICallableNameProvider
+{
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java
new file mode 100644
index 0000000..7114e2a
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/**
+ * A {@link FutureTask} with a name.
+ *
+ * @author Bernd Rinn
+ */
+class NamedFutureTask<V> extends FutureTask<V> implements NamedRunnable
+{
+ private final String name;
+
+ private Thread thread;
+
+ private String oldThreadName;
+
+ NamedFutureTask(Callable<V> callable)
+ {
+ super(callable);
+ this.name =
+ (callable instanceof ICallableNameProvider) ? ((ICallableNameProvider) callable)
+ .getCallableName() : null;
+ }
+
+ NamedFutureTask(Runnable runnable, V result)
+ {
+ super(runnable, result);
+ this.name =
+ (runnable instanceof IRunnableNameProvider) ? ((IRunnableNameProvider) runnable)
+ .getRunnableName() : null;
+ }
+
+ void restoreThreadName()
+ {
+ if (this.thread != null)
+ {
+ this.thread.setName(oldThreadName);
+ this.thread = null;
+ }
+ }
+
+ void setThread(Thread thread)
+ {
+ this.thread = thread;
+ this.oldThreadName = thread.getName();
+ }
+
+ @Override
+ public String getRunnableName()
+ {
+ return name;
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java
new file mode 100644
index 0000000..e4ceec0
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A {@link Runnable} with a name.
+ *
+ * @author Bernd Rinn
+ */
+public interface NamedRunnable extends Runnable, IRunnableNameProvider
+{
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java
new file mode 100644
index 0000000..f74e529
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * A {@link ThreadFactory} that gives (non-standard) names to new threads. If a name is a
+ * {@link IRunnableNameProvider}, the name provided by
+ * {@link IRunnableNameProvider#getRunnableName()} will be used, otherwise the
+ * <var>defaultName</var>. The thread count (number of already created threads in this factory) will
+ * always be appended.
+ *
+ * @author Bernd Rinn
+ */
+public class NamingThreadFactory implements ThreadFactory
+{
+
+ private final String poolName;
+
+ private boolean createDaemonThreads;
+
+ private boolean addPoolName;
+
+ private int threadCount;
+
+ public NamingThreadFactory(String poolName)
+ {
+ this.poolName = poolName;
+ this.addPoolName = true;
+ this.createDaemonThreads = false;
+ this.threadCount = 0;
+ }
+
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ ++threadCount;
+ final String completePoolName = poolName + "-T" + threadCount;
+ final Thread thread = new PoolNameThread(r, completePoolName, addPoolName);
+ thread.setDaemon(createDaemonThreads);
+ return thread;
+ }
+
+ String getPoolName()
+ {
+ return poolName;
+ }
+
+ public final boolean isCreateDaemonThreads()
+ {
+ return createDaemonThreads;
+ }
+
+ public final void setCreateDaemonThreads(boolean createDaemonThreads)
+ {
+ this.createDaemonThreads = createDaemonThreads;
+ }
+
+ public final int getThreadCount()
+ {
+ return threadCount;
+ }
+
+ public final boolean isAddPoolName()
+ {
+ return addPoolName;
+ }
+
+ public final void setAddPoolName(boolean addPoolName)
+ {
+ this.addPoolName = addPoolName;
+ }
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java
new file mode 100644
index 0000000..1cd26ed
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ThreadPoolExecutor} that allows to attach names to the threads it manages. These names
+ * can come either from {@link IRunnableNameProvider}s or {@link ICallableNameProvider}s, or, if
+ * their standard counterparts are submitted, a default name is used.
+ *
+ * @author Bernd Rinn
+ */
+public class NamingThreadPoolExecutor extends ThreadPoolExecutor
+{
+
+ /**
+ * The default time (in milli-seconds) to keep threads alive that are above the core pool size.
+ */
+ public final static long DEFAULT_KEEP_ALIVE_TIME_MILLIS = 10000L;
+
+ /**
+ * Creates a new (caching) <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ * This executor will create new threads as needed.
+ *
+ * @param poolName the default name for new threads
+ */
+ public NamingThreadPoolExecutor(String poolName)
+ {
+ this(poolName, 0);
+ }
+
+ /**
+ * Creates a new (caching) <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ * This executor will create new threads as needed.
+ *
+ * @param poolName The default name for new threads.
+ * @param workQueueSize The size of the work queue (0 for no queue).
+ *
+ */
+ public NamingThreadPoolExecutor(String poolName, int workQueueSize)
+ {
+ super(1, Integer.MAX_VALUE, DEFAULT_KEEP_ALIVE_TIME_MILLIS, TimeUnit.MILLISECONDS,
+ workQueueSize == 0 ? new SynchronousQueue<Runnable>()
+ : new LinkedBlockingQueue<Runnable>(workQueueSize),
+ new NamingThreadFactory(poolName));
+ }
+
+ /**
+ * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ *
+ * @param poolName the default name for new threads
+ * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+ * @param maximumPoolSize the maximum number of threads to allow in the pool.
+ * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+ * time that excess idle threads will wait for new tasks before terminating.
+ * @param unit the time unit for the keepAliveTime argument.
+ * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+ * hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+ * @param handler the handler to use when execution is blocked because the thread bounds and
+ * queue capacities are reached.
+ * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+ * maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+ * maximumPoolSize.
+ * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> or
+ * <tt>handler</tt> are null.
+ */
+ public NamingThreadPoolExecutor(String poolName, int corePoolSize, int maximumPoolSize,
+ long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
+ RejectedExecutionHandler handler)
+ {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ new NamingThreadFactory(poolName), handler);
+ }
+
+ /**
+ * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ *
+ * @param poolName the default name for new threads
+ * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+ * @param maximumPoolSize the maximum number of threads to allow in the pool.
+ * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+ * time that excess idle threads will wait for new tasks before terminating.
+ * @param unit the time unit for the keepAliveTime argument.
+ * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+ * hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+ * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+ * maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+ * maximumPoolSize.
+ * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> are null.
+ */
+ public NamingThreadPoolExecutor(String poolName, int corePoolSize, int maximumPoolSize,
+ long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
+ {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ new NamingThreadFactory(poolName));
+ }
+
+ /**
+ * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+ * @param maximumPoolSize the maximum number of threads to allow in the pool.
+ * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+ * time that excess idle threads will wait for new tasks before terminating.
+ * @param unit the time unit for the keepAliveTime argument.
+ * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+ * hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+ * @param threadFactory the factory to use when the executor creates a new thread.
+ * @param handler the handler to use when execution is blocked because the thread bounds and
+ * queue capacities are reached.
+ * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+ * maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+ * maximumPoolSize.
+ * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> or
+ * <tt>handler</tt> are null.
+ */
+ public NamingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+ TimeUnit unit, BlockingQueue<Runnable> workQueue, NamingThreadFactory threadFactory,
+ RejectedExecutionHandler handler)
+ {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+ }
+
+ /**
+ * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+ * @param maximumPoolSize the maximum number of threads to allow in the pool.
+ * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+ * time that excess idle threads will wait for new tasks before terminating.
+ * @param unit the time unit for the keepAliveTime argument.
+ * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+ * hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+ * @param threadFactory the factory to use when the executor creates a new thread.
+ * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+ * maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+ * maximumPoolSize.
+ * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> are null.
+ */
+ public NamingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+ TimeUnit unit, BlockingQueue<Runnable> workQueue, NamingThreadFactory threadFactory)
+ {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+ }
+
+ /**
+ * Sets the thread factory of this pool executor to daemon creation mode.
+ * <p>
+ * This method is supposed to be used in chaining mode, i.e.
+ *
+ * <pre>
+ * final ExecutorService executor = new NamingThreadPoolExecutor("name").daemonize();
+ * </pre>
+ *
+ * @return This class itself.
+ */
+ public NamingThreadPoolExecutor daemonize()
+ {
+ getThreadFactory().setCreateDaemonThreads(true);
+ return this;
+ }
+
+ /**
+ * Same as {@link #setCorePoolSize(int)}, but returns the object itself for chaining.
+ */
+ public NamingThreadPoolExecutor corePoolSize(int corePoolSize)
+ {
+ setCorePoolSize(corePoolSize);
+ return this;
+ }
+
+ /**
+ * Same as {@link #setMaximumPoolSize(int)}, but returns the object itself for chaining.
+ */
+ public NamingThreadPoolExecutor maximumPoolSize(int maximumPoolSize)
+ {
+ setMaximumPoolSize(maximumPoolSize);
+ return this;
+ }
+
+ /**
+ * Same as {@link #setKeepAliveTime(long, TimeUnit)}, but uses always
+ * {@link TimeUnit#MILLISECONDS} and returns the object itself for chaining.
+ */
+ public NamingThreadPoolExecutor keepAliveTime(long keepAliveTimeMillis)
+ {
+ setKeepAliveTime(keepAliveTimeMillis, TimeUnit.MILLISECONDS);
+ return this;
+ }
+
+ /**
+ * If <var>addPoolName</var> is <code>true</code>, the threads will contain the pool name as the
+ * first part of the thread names.
+ */
+ public NamingThreadPoolExecutor addPoolName(boolean addPoolName)
+ {
+ getThreadFactory().setAddPoolName(addPoolName);
+ return this;
+ }
+
+ @Override
+ public NamingThreadFactory getThreadFactory()
+ {
+ return (NamingThreadFactory) super.getThreadFactory();
+ }
+
+ /**
+ * Sets the thread factory of this pool executor.
+ */
+ public void setThreadFactory(NamingThreadFactory threadFactory)
+ {
+ super.setThreadFactory(threadFactory);
+ }
+
+ /**
+ * @deprecated Use {@link #setThreadFactory(NamingThreadFactory)} instead!
+ */
+ @Override
+ @Deprecated
+ public void setThreadFactory(ThreadFactory threadFactory)
+ {
+ if (threadFactory instanceof NamingThreadFactory == false)
+ {
+ throw new IllegalArgumentException("thread factory is of type '"
+ + threadFactory.getClass().getCanonicalName() + ", but needs to be of type "
+ + NamingThreadFactory.class.getCanonicalName());
+ }
+ super.setThreadFactory(threadFactory);
+ }
+
+ @Override
+ protected void beforeExecute(Thread t, Runnable r)
+ {
+ if (r instanceof IRunnableNameProvider == false)
+ {
+ return;
+ }
+ final String runnableName = ((IRunnableNameProvider) r).getRunnableName();
+ if (runnableName == null)
+ {
+ return;
+ }
+ if (r instanceof NamedFutureTask<?>)
+ {
+ ((NamedFutureTask<?>) r).setThread(t);
+ }
+ if (t instanceof PoolNameThread)
+ {
+ ((PoolNameThread) t).setRunnableName(runnableName);
+ } else
+ {
+ t.setName(runnableName);
+ }
+ super.beforeExecute(t, r);
+ }
+
+ @Override
+ protected void afterExecute(Runnable r, Throwable t)
+ {
+ if (r instanceof NamedFutureTask<?>)
+ {
+ ((NamedFutureTask<?>) r).restoreThreadName();
+ }
+ super.afterExecute(r, t);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task)
+ {
+ if (task == null)
+ {
+ throw new NullPointerException();
+ }
+
+ final FutureTask<Object> ftask = new NamedFutureTask<Object>(task, null);
+ execute(ftask);
+ return ftask;
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result)
+ {
+ if (task == null)
+ {
+ throw new NullPointerException();
+ }
+
+ final FutureTask<T> ftask = new NamedFutureTask<T>(task, result);
+ execute(ftask);
+ return ftask;
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task)
+ {
+ if (task == null)
+ {
+ throw new NullPointerException();
+ }
+ final FutureTask<T> ftask = new NamedFutureTask<T>(task);
+ execute(ftask);
+ return ftask;
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java b/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java
new file mode 100644
index 0000000..550efea
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A {@link Thread} that knows its pool name.
+ *
+ * @author Bernd Rinn
+ */
+public class PoolNameThread extends Thread
+{
+ private final String poolName;
+
+ private final boolean addPoolName;
+
+ public PoolNameThread(Runnable target, String poolName, boolean addPoolName)
+ {
+ super(target, poolName);
+ this.poolName = poolName;
+ this.addPoolName = addPoolName;
+ }
+
+ /**
+ * Sets the thread's name to the <var>runnableName</var>, possibly adding the pool name if
+ * <var>addPoolName</var> has been set to <code>true</code> in the constructor.
+ */
+ public void setRunnableName(String runnableName)
+ {
+ if (addPoolName)
+ {
+ setName(poolName + "::" + runnableName);
+ } else
+ {
+ setName(runnableName);
+ }
+ }
+
+ /** Clears the name of the runnable, setting the name of the thread to the pool name. */
+ public void clearRunnableName()
+ {
+ setName(poolName);
+ }
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/package.html b/source/java/ch/systemsx/cisd/base/namedthread/package.html
new file mode 100644
index 0000000..d2a54d4
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/package.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Named pool threads.</title>
+</head>
+<body>
+<p>
+This package provides <i>named pool threads</i> when using an
+{@code java.util.concurrent.ExecutorService}. This can be helpful in debugging and monitoring
+multi-threaded Java applications. Start having a look at the {@code NamedThreadPoolExecutor}.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java b/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java
new file mode 100644
index 0000000..b91323b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.tests;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * An <code>abstract</code> test case which accesses the file system.
+ * <p>
+ * It constructs an appropriate working directory which is test class specific.
+ * </p>
+ *
+ * @author Christian Ribeaud
+ */
+public abstract class AbstractFileSystemTestCase extends AssertJUnit
+{
+ protected static final String UNIT_TEST_WORKING_DIRECTORY = "unit-test-wd";
+
+ protected static final String TARGETS_DIRECTORY = "targets";
+
+ protected static final File UNIT_TEST_ROOT_DIRECTORY = new File(TARGETS_DIRECTORY
+ + File.separator + UNIT_TEST_WORKING_DIRECTORY);
+
+ protected final File workingDirectory;
+
+ private final boolean cleanAfterMethod;
+
+ protected AbstractFileSystemTestCase()
+ {
+ this(true);
+ }
+
+ protected AbstractFileSystemTestCase(final boolean cleanAfterMethod)
+ {
+ workingDirectory = createWorkingDirectory();
+ this.cleanAfterMethod = cleanAfterMethod;
+ }
+
+ /**
+ * Creates a {@link File} with <var>name</var> in the working directory. Ensure it doesn't
+ * exist and is deleted on exit.
+ */
+ protected File create(String name)
+ {
+ final File file = new File(workingDirectory, name);
+ file.delete();
+ file.deleteOnExit();
+ return file;
+ }
+
+ /**
+ * Creates a directory in the unit test root directory "targets/unit-test-wd"
+ */
+ protected final File createDirectoryInUnitTestRoot(String dirName)
+ {
+ final File directory = new File(UNIT_TEST_ROOT_DIRECTORY, dirName);
+ directory.mkdirs();
+ directory.deleteOnExit();
+ return directory;
+ }
+
+ private final File createWorkingDirectory()
+ {
+ return createDirectoryInUnitTestRoot(getClass().getName());
+ }
+
+ @BeforeMethod
+ public void setUp() throws IOException
+ {
+ cleanUpDirectoryBeforeTheTest(workingDirectory);
+ }
+
+ /**
+ * Deletes, recreates and verifies that this is the empty directory
+ */
+ protected void cleanUpDirectoryBeforeTheTest(File directory)
+ {
+ deleteDirectory(directory);
+ directory.mkdirs();
+ assertEquals(true, directory.isDirectory());
+ File[] files = directory.listFiles();
+ if (files != null)
+ {
+ assertEquals("Unexpected files " + Arrays.asList(files), 0, files.length);
+ }
+ }
+
+ private void deleteDirectory(File dir)
+ {
+ try
+ {
+ FileUtils.deleteDirectory(dir);
+ } catch (IOException e)
+ {
+ System.err.println("Could not delete the directory " + dir.getPath() + " because: "
+ + e.getMessage());
+ try
+ {
+ FileUtils.deleteDirectory(dir);
+ } catch (IOException e2)
+ {
+ System.err.println("Could not delete the directory " + dir.getPath()
+ + " in second try because: " + e2.getMessage());
+ }
+ }
+ }
+
+ @AfterClass
+ public void afterClass() throws IOException
+ {
+ if (cleanAfterMethod == false)
+ {
+ return;
+ }
+ try
+ {
+ FileUtils.deleteDirectory(workingDirectory);
+ } catch (FileNotFoundException ex)
+ {
+ // Ignore
+ }
+ }
+}
diff --git a/source/java/ch/systemsx/cisd/base/tests/Retry10.java b/source/java/ch/systemsx/cisd/base/tests/Retry10.java
new file mode 100644
index 0000000..e3438e7
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/Retry10.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.tests;
+
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+import org.testng.util.RetryAnalyzerCount;
+
+/**
+ * An {@link RetryAnalyzerCount} extension which sets the count to <code>10</code>.
+ * <p>
+ * This {@link IRetryAnalyzer} should only be applied to methods we know they should run
+ * successfully but do not for some reason. The retry analyzer exits as soon as it made a successful
+ * call.
+ * </p>
+ *
+ * @author Christian Ribeaud
+ */
+public final class Retry10 extends RetryAnalyzerCount
+{
+ public Retry10()
+ {
+ setCount(10);
+ }
+
+ //
+ // RetryAnalyzerCount
+ //
+
+ @Override
+ public final boolean retryMethod(final ITestResult result)
+ {
+ return true;
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/tests/Retry50.java b/source/java/ch/systemsx/cisd/base/tests/Retry50.java
new file mode 100644
index 0000000..60df88e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/Retry50.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.tests;
+
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+import org.testng.util.RetryAnalyzerCount;
+
+/**
+ * An {@link RetryAnalyzerCount} extension which sets the count to <code>50</code>.
+ * <p>
+ * This {@link IRetryAnalyzer} should only be applied to methods we know they should run
+ * successfully but do not for some reason. The retry analyzer exits as soon as it made a successful
+ * call.
+ * </p>
+ *
+ * @author Bernd Rinn
+ */
+public final class Retry50 extends RetryAnalyzerCount
+{
+ public Retry50()
+ {
+ setCount(50);
+ }
+
+ //
+ // RetryAnalyzerCount
+ //
+
+ @Override
+ public final boolean retryMethod(final ITestResult result)
+ {
+ return true;
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java b/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java
new file mode 100644
index 0000000..5a0f72e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.unix;
+
+import java.io.Serializable;
+
+/**
+ * The type of a link in the file system.
+ *
+ * @author Bernd Rinn
+ */
+public enum FileLinkType implements Serializable
+{
+ REGULAR_FILE, DIRECTORY, SYMLINK, OTHER;
+
+ /**
+ * Returns <code>true</code> if the <var>linkMode</var> corresponds to a symbolic link.
+ */
+ static boolean isSymLink(long linkMode)
+ {
+ return linkMode == SYMLINK.ordinal();
+ }
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/unix/Unix.java b/source/java/ch/systemsx/cisd/base/unix/Unix.java
new file mode 100644
index 0000000..fc02834
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/Unix.java
@@ -0,0 +1,901 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.unix;
+
+import java.io.File;
+import java.io.IOException;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+import ch.systemsx.cisd.base.utilities.NativeLibraryUtilities;
+
+/**
+ * A utility class that provides access to common Unix system calls. Obviously, this will only work
+ * on Unix platforms and it requires a native library to be loaded.
+ * <p>
+ * <i>Check with {@link #isOperational()} if this class is operational and only call the other
+ * methods if <code>Unix.isOperational() == true</code>.</i>
+ *
+ * @author Bernd Rinn
+ */
+public final class Unix
+{
+
+ private enum ProcessDetection
+ {
+ PROCFS, PS, NONE
+ }
+
+ private final static boolean operational;
+
+ private final static ProcessDetection processDetection;
+
+ static
+ {
+ operational = NativeLibraryUtilities.loadNativeLibrary("unix");
+ if (operational)
+ {
+ init();
+ final int myPid = getPid();
+ if (isProcessRunningProcFS(myPid))
+ {
+ processDetection = ProcessDetection.PROCFS;
+ } else if (isProcessRunningPS(myPid))
+ {
+ processDetection = ProcessDetection.PS;
+ } else
+ {
+ processDetection = ProcessDetection.NONE;
+ }
+ } else
+ {
+ processDetection = ProcessDetection.NONE;
+ }
+ }
+
+ /** set user ID on execution */
+ public static final short S_ISUID = 04000;
+
+ /** set group ID on execution */
+ public static final short S_ISGID = 02000;
+
+ /** sticky bit */
+ public static final short S_ISVTX = 01000;
+
+ /** read by owner */
+ public static final short S_IRUSR = 00400;
+
+ /** write by owner */
+ public static final short S_IWUSR = 00200;
+
+ /** execute/search by owner */
+ public static final short S_IXUSR = 00100;
+
+ /** read by group */
+ public static final short S_IRGRP = 00040;
+
+ /** write by group */
+ public static final short S_IWGRP = 00020;
+
+ /** execute/search by group */
+ public static final short S_IXGRP = 00010;
+
+ /** read by others */
+ public static final short S_IROTH = 00004;
+
+ /** write by others */
+ public static final short S_IWOTH = 00002;
+
+ /** execute/search by others */
+ public static final short S_IXOTH = 00001;
+
+ /**
+ * A class representing the Unix <code>stat</code> structure.
+ */
+ public static final class Stat
+ {
+ private final long deviceId;
+
+ private final long inode;
+
+ private final short permissions;
+
+ private final FileLinkType linkType;
+
+ private String symbolicLinkOrNull;
+
+ private final int numberOfHardLinks;
+
+ private final int uid;
+
+ private final int gid;
+
+ private final long lastAccess;
+
+ private final long lastModified;
+
+ private final long lastStatusChange;
+
+ private final long size;
+
+ private final long numberOfBlocks;
+
+ private final int blockSize;
+
+ Stat(long deviceId, long inode, short permissions, byte linkType, int numberOfHardLinks,
+ int uid, int gid, long lastAccess, long lastModified, long lastStatusChange,
+ long size, long numberOfBlocks, int blockSize)
+ {
+ this.deviceId = deviceId;
+ this.inode = inode;
+ this.permissions = permissions;
+ this.linkType = FileLinkType.values()[linkType];
+ this.numberOfHardLinks = numberOfHardLinks;
+ this.uid = uid;
+ this.gid = gid;
+ this.lastAccess = lastAccess;
+ this.lastModified = lastModified;
+ this.lastStatusChange = lastStatusChange;
+ this.size = size;
+ this.numberOfBlocks = numberOfBlocks;
+ this.blockSize = blockSize;
+ }
+
+ void setSymbolicLinkOrNull(String symbolicLinkOrNull)
+ {
+ this.symbolicLinkOrNull = symbolicLinkOrNull;
+ }
+
+ public String tryGetSymbolicLink()
+ {
+ return symbolicLinkOrNull;
+ }
+
+ public long getDeviceId()
+ {
+ return deviceId;
+ }
+
+ public long getInode()
+ {
+ return inode;
+ }
+
+ public short getPermissions()
+ {
+ return permissions;
+ }
+
+ public FileLinkType getLinkType()
+ {
+ return linkType;
+ }
+
+ /**
+ * Returns <code>true</code>, if this link is a symbolic link.
+ */
+ public final boolean isSymbolicLink()
+ {
+ return FileLinkType.SYMLINK == linkType;
+ }
+
+ public int getNumberOfHardLinks()
+ {
+ return numberOfHardLinks;
+ }
+
+ public int getUid()
+ {
+ return uid;
+ }
+
+ public int getGid()
+ {
+ return gid;
+ }
+
+ public long getLastAccess()
+ {
+ return lastAccess;
+ }
+
+ public long getLastModified()
+ {
+ return lastModified;
+ }
+
+ public long getLastStatusChange()
+ {
+ return lastStatusChange;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public long getNumberOfBlocks()
+ {
+ return numberOfBlocks;
+ }
+
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ }
+
+ /**
+ * A class representing the Unix <code>group</code> struct.
+ */
+ public static final class Group
+ {
+ private final String groupName;
+
+ private final String groupPasswordHash;
+
+ private final int gid;
+
+ private final String[] groupMembers;
+
+ Group(String groupName, String groupPasswordHash, int gid, String[] groupMembers)
+ {
+ this.groupName = groupName;
+ this.groupPasswordHash = groupPasswordHash;
+ this.gid = gid;
+ this.groupMembers = groupMembers;
+ }
+
+ public String getGroupName()
+ {
+ return groupName;
+ }
+
+ public String getGroupPasswordHash()
+ {
+ return groupPasswordHash;
+ }
+
+ public int getGid()
+ {
+ return gid;
+ }
+
+ public String[] getGroupMembers()
+ {
+ return groupMembers;
+ }
+ }
+
+ /**
+ * A class representing the Unix <code>passwd</code> struct.
+ */
+ public static final class Password
+ {
+ private final String userName;
+
+ private final String passwordHash;
+
+ private final int uid;
+
+ private final int gid;
+
+ private final String userFullName;
+
+ private final String homeDirectory;
+
+ private final String shell;
+
+ Password(String userName, String passwordHash, int uid, int gid, String userFullName,
+ String homeDirectory, String shell)
+ {
+ this.userName = userName;
+ this.passwordHash = passwordHash;
+ this.uid = uid;
+ this.gid = gid;
+ this.userFullName = userFullName;
+ this.homeDirectory = homeDirectory;
+ this.shell = shell;
+ }
+
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ public String getPasswordHash()
+ {
+ return passwordHash;
+ }
+
+ public int getUid()
+ {
+ return uid;
+ }
+
+ public int getGid()
+ {
+ return gid;
+ }
+
+ public String getUserFullName()
+ {
+ return userFullName;
+ }
+
+ public String getHomeDirectory()
+ {
+ return homeDirectory;
+ }
+
+ public String getShell()
+ {
+ return shell;
+ }
+ }
+
+ private static void throwLinkCreationException(String type, String source, String target,
+ String errorMessage)
+ {
+ throw new IOExceptionUnchecked(new IOException(String.format(
+ "Creating %s link '%s' -> '%s': %s", type, target, source, errorMessage)));
+ }
+
+ private static void throwStatException(String filename, String errorMessage)
+ {
+ throw new IOExceptionUnchecked(new IOException(String.format(
+ "Cannot obtain inode info for file '%s': %s", filename, errorMessage)));
+ }
+
+ private static void throwFileException(String operation, String filename, String errorMessage)
+ {
+ throw new IOExceptionUnchecked(new IOException(String.format("Cannot %s of file '%s': %s",
+ operation, filename, errorMessage)));
+ }
+
+ private static native int init();
+
+ private static native int getpid();
+
+ private static native int getuid();
+
+ private static native int geteuid();
+
+ private static native int getgid();
+
+ private static native int getegid();
+
+ private static native int link(String filename, String linktarget);
+
+ private static native int symlink(String filename, String linktarget);
+
+ private static native Stat stat(String filename);
+
+ private static native Stat lstat(String filename);
+
+ private static native String readlink(String filename, int linkvallen);
+
+ private static native int chmod(String filename, short mode);
+
+ private static native int chown(String filename, int uid, int gid);
+
+ private static native String getuser(int uid);
+
+ private static native String getgroup(int gid);
+
+ private static native int getuid(String user);
+
+ private static native Password getpwnam(String user);
+
+ private static native Password getpwuid(int uid);
+
+ private static native int getgid(String group);
+
+ private static native Group getgrnam(String group);
+
+ private static native Group getgrgid(int gid);
+
+ private static native String strerror(int errnum);
+
+ private static native String strerror();
+
+ @Private
+ static boolean isProcessRunningProcFS(int pid)
+ {
+ return new File("/proc/" + pid).isDirectory();
+ }
+
+ @Private
+ static boolean isProcessRunningPS(int pid)
+ {
+ try
+ {
+ return Runtime.getRuntime().exec(new String[]
+ { "ps", "-p", Integer.toString(pid) }).waitFor() == 0;
+ } catch (IOException ex)
+ {
+ return false;
+ } catch (InterruptedException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ //
+ // Public
+ //
+
+ /**
+ * Returns <code>true</code>, if the native library has been loaded successfully and the link
+ * utilities are operational, <code>false</code> otherwise.
+ */
+ public static final boolean isOperational()
+ {
+ return operational;
+ }
+
+ /**
+ * Returns <code>true</code>, if process detection is available on this system.
+ */
+ public static boolean canDetectProcesses()
+ {
+ return processDetection != ProcessDetection.NONE;
+ }
+
+ /**
+ * Returns the last error that occurred in this class. Use this to find out what went wrong
+ * after {@link #tryGetLinkInfo(String)} or {@link #tryGetFileInfo(String)} returned
+ * <code>null</code>.
+ */
+ public static String getLastError()
+ {
+ return strerror();
+ }
+
+ //
+ // Process functions
+ //
+
+ /**
+ * Returns the process identifier of the current process.
+ */
+ public static int getPid()
+ {
+ return getpid();
+ }
+
+ /**
+ * Returns <code>true</code>, if the process with <var>pid</var> is currently running and
+ * <code>false</code>, if it is not running or if process detection is not available (
+ * {@link #canDetectProcesses()} <code>== false</code>).
+ */
+ public static boolean isProcessRunning(int pid)
+ {
+ switch (processDetection)
+ {
+ case PROCFS:
+ return isProcessRunningProcFS(pid);
+ case PS:
+ return isProcessRunningPS(pid);
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns the uid of the user that started this process.
+ */
+ public static final int getUid()
+ {
+ return getuid();
+ }
+
+ /**
+ * Returns the effective uid that determines the permissions of this process.
+ */
+ public static final int getEuid()
+ {
+ return geteuid();
+ }
+
+ /**
+ * Returns the gid of the user that started this process.
+ */
+ public static final int getGid()
+ {
+ return getgid();
+ }
+
+ /**
+ * Returns the effective gid that determines the permissions of this process.
+ */
+ public static final int getEgid()
+ {
+ return getegid();
+ }
+
+ //
+ // File functions
+ //
+
+ /**
+ * Creates a hard link <var>linkName</var> that points to <var>fileName</var>.
+ *
+ * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
+ * <var>linkName</var> already exists or <var>fileName</var> does not exist.
+ */
+ public static final void createHardLink(String fileName, String linkName)
+ throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ if (linkName == null)
+ {
+ throw new NullPointerException("linkName");
+ }
+ final int result = link(fileName, linkName);
+ if (result < 0)
+ {
+ throwLinkCreationException("hard", fileName, linkName, strerror(result));
+ }
+ }
+
+ /**
+ * Creates a symbolic link <var>linkName</var> that points to <var>fileName</var>.
+ *
+ * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
+ * <var>linkName</var> already exists.
+ */
+ public static final void createSymbolicLink(String fileName, String linkName)
+ throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ if (linkName == null)
+ {
+ throw new NullPointerException("linkName");
+ }
+ final int result = symlink(fileName, linkName);
+ if (result < 0)
+ {
+ throwLinkCreationException("symbolic", fileName, linkName, strerror(result));
+ }
+ }
+
+ private static Stat tryGetStat(String fileName) throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ return stat(fileName);
+ }
+
+ private static Stat getStat(String fileName) throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ final Stat result = stat(fileName);
+ if (result == null)
+ {
+ throwStatException(fileName, strerror());
+ }
+ return result;
+ }
+
+ private static Stat tryGetLStat(String linkName) throws IOExceptionUnchecked
+ {
+ if (linkName == null)
+ {
+ throw new NullPointerException("linkName");
+ }
+ return lstat(linkName);
+ }
+
+ private static Stat getLStat(String linkName) throws IOExceptionUnchecked
+ {
+ if (linkName == null)
+ {
+ throw new NullPointerException("linkName");
+ }
+ final Stat result = lstat(linkName);
+ if (result == null)
+ {
+ throwStatException(linkName, strerror());
+ }
+ return result;
+ }
+
+ /**
+ * Returns the inode for the <var>fileName</var>.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final long getInode(String fileName) throws IOExceptionUnchecked
+ {
+ return getLStat(fileName).getInode();
+ }
+
+ /**
+ * Returns the number of hard links for the <var>fileName</var>.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final int getNumberOfHardLinks(String fileName) throws IOExceptionUnchecked
+ {
+ return getLStat(fileName).getNumberOfHardLinks();
+ }
+
+ /**
+ * Returns <code>true</code> if <var>fileName</var> is a symbolic link and <code>false</code>
+ * otherwise.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final boolean isSymbolicLink(String fileName) throws IOExceptionUnchecked
+ {
+ return getLStat(fileName).isSymbolicLink();
+ }
+
+ /**
+ * Returns the value of the symbolik link <var>linkName</var>, or <code>null</code>, if
+ * <var>linkName</var> is not a symbolic link.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final String tryReadSymbolicLink(String linkName) throws IOExceptionUnchecked
+ {
+ final Stat stat = getLStat(linkName);
+ return stat.isSymbolicLink() ? readlink(linkName, (int) stat.getSize()) : null;
+ }
+
+ /**
+ * Returns the information about <var>fileName</var>.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the file
+ * does not exist.
+ */
+ public static final Stat getFileInfo(String fileName) throws IOExceptionUnchecked
+ {
+ return getStat(fileName);
+ }
+
+ /**
+ * Returns the information about <var>fileName</var>, or {@link NullPointerException}, if the
+ * information could not be obtained, e.g. because the file does not exist (call
+ * {@link #getLastError()} to find out what went wrong).
+ */
+ public static final Stat tryGetFileInfo(String fileName) throws IOExceptionUnchecked
+ {
+ return tryGetStat(fileName);
+ }
+
+ /**
+ * Returns the information about <var>linkName</var>.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final Stat getLinkInfo(String linkName) throws IOExceptionUnchecked
+ {
+ return getLinkInfo(linkName, true);
+ }
+
+ /**
+ * Returns the information about <var>linkName</var>. If
+ * <code>readSymbolicLinkTarget == true</code>, then the symbolic link target is read when
+ * <var>linkName</var> is a symbolic link.
+ *
+ * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+ * does not exist.
+ */
+ public static final Stat getLinkInfo(String linkName, boolean readSymbolicLinkTarget)
+ throws IOExceptionUnchecked
+ {
+ final Stat stat = getLStat(linkName);
+ final String symbolicLinkOrNull =
+ (readSymbolicLinkTarget && stat.isSymbolicLink()) ? readlink(linkName,
+ (int) stat.getSize()) : null;
+ stat.setSymbolicLinkOrNull(symbolicLinkOrNull);
+ return stat;
+ }
+
+ /**
+ * Returns the information about <var>linkName</var>, or {@link NullPointerException}, if the
+ * information could not be obtained, e.g. because the link does not exist (call
+ * {@link #getLastError()} to find out what went wrong).
+ */
+ public static final Stat tryGetLinkInfo(String linkName) throws IOExceptionUnchecked
+ {
+ return tryGetLinkInfo(linkName, true);
+ }
+
+ /**
+ * Returns the information about <var>linkName</var>, or <code>null</code> if the information
+ * can not be obtained, e.g. because the link does not exist (call {@link #getLastError()} to
+ * find out what went wrong). If <code>readSymbolicLinkTarget == true</code>, then the symbolic
+ * link target is read when <var>linkName</var> is a symbolic link.
+ */
+ public static final Stat tryGetLinkInfo(String linkName, boolean readSymbolicLinkTarget)
+ throws IOExceptionUnchecked
+ {
+ final Stat stat = tryGetLStat(linkName);
+ if (stat == null)
+ {
+ return null;
+ }
+ final String symbolicLinkOrNull =
+ (readSymbolicLinkTarget && stat.isSymbolicLink()) ? readlink(linkName,
+ (int) stat.getSize()) : null;
+ stat.setSymbolicLinkOrNull(symbolicLinkOrNull);
+ return stat;
+ }
+
+ /**
+ * Sets the access mode of <var>filename</var> to the specified <var>mode</var> value.
+ */
+ public static final void setAccessMode(String fileName, short mode) throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ final int result = chmod(fileName, mode);
+ if (result < 0)
+ {
+ throwFileException("set mode", fileName, strerror(result));
+ }
+ }
+
+ /**
+ * Sets the owner of <var>filename</var> to the specified <var>uid</var> and <var>gid</var>
+ * values.
+ */
+ public static final void setOwner(String fileName, int uid, int gid)
+ throws IOExceptionUnchecked
+ {
+ if (fileName == null)
+ {
+ throw new NullPointerException("fileName");
+ }
+ final int result = chown(fileName, uid, gid);
+ if (result < 0)
+ {
+ throwFileException("set owner", fileName, strerror(result));
+ }
+ }
+
+ //
+ // User functions
+ //
+
+ /**
+ * Returns the name of the user identified by <var>uid</var>.
+ */
+ public static final String tryGetUserNameForUid(int uid)
+ {
+ return getuser(uid);
+ }
+
+ /**
+ * Returns the uid of the <var>userName</var>, or <code>-1</code>, if no user with this name
+ * exists.
+ */
+ public static final int getUidForUserName(String userName)
+ {
+ if (userName == null)
+ {
+ throw new NullPointerException("userName");
+ }
+ return getuid(userName);
+ }
+
+ /**
+ * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
+ * user with that name exists.
+ */
+ public static final Password tryGetUserByName(String userName)
+ {
+ if (userName == null)
+ {
+ throw new NullPointerException("userName");
+ }
+ return getpwnam(userName);
+ }
+
+ /**
+ * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
+ * user with that name exists.
+ */
+ public static final Password tryGetUserByUid(int uid)
+ {
+ return getpwuid(uid);
+ }
+
+ //
+ // Group functions
+ //
+
+ /**
+ * Returns the name of the group identified by <var>gid</var>, or <code>null</code>, if no group
+ * with that <var>gid</var> exists.
+ */
+ public static final String tryGetGroupNameForGid(int gid)
+ {
+ return getgroup(gid);
+ }
+
+ /**
+ * Returns the gid of the <var>groupName</var>, or <code>-1</code>, if no group with this name
+ * exists.
+ */
+ public static final int getGidForGroupName(String groupName)
+ {
+ if (groupName == null)
+ {
+ throw new NullPointerException("groupName");
+ }
+ return getgid(groupName);
+ }
+
+ /**
+ * Returns the {@link Group} for the given <var>groupName</var>, or <code>null</code>, if no
+ * group with that name exists.
+ */
+ public static final Group tryGetGroupByName(String groupName)
+ {
+ if (groupName == null)
+ {
+ throw new NullPointerException("groupName");
+ }
+ return getgrnam(groupName);
+ }
+
+ /**
+ * Returns the {@link Group} for the given <var>gid</var>, or <code>null</code>, if no group
+ * with that gid exists.
+ */
+ public static final Group tryGetGroupByGid(int gid)
+ {
+ return getgrgid(gid);
+ }
+
+ //
+ // Error
+ //
+
+ /**
+ * Returns the error string for the given <var>errnum</var>.
+ */
+ public static final String getErrorString(int errnum)
+ {
+ return strerror(errnum);
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/unix/package.html b/source/java/ch/systemsx/cisd/base/unix/package.html
new file mode 100644
index 0000000..f8a9751
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Unix system calls.</title>
+</head>
+<body>
+<p>
+This package provides some basic (POSIX-compliant) Unix system calls.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java b/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java
new file mode 100644
index 0000000..1a9dae6
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.utilities;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Abstract of all classes providing build and environment information.
+ * <p>
+ * Does <em>not</em> depend on any library jar files.
+ * </p>
+ *
+ * @author Franz-Josef Elmer
+ */
+public abstract class AbstractBuildAndEnvironmentInfo
+{
+ private static final String UNKNOWN = "UNKNOWN";
+
+ private final String version;
+
+ private final String revision;
+
+ private final boolean cleanSources;
+
+ private final String applicationName;
+
+ protected AbstractBuildAndEnvironmentInfo(String applicationName)
+ {
+ this.applicationName = applicationName;
+ String extractedVersion = UNKNOWN;
+ String extractedRevision = UNKNOWN;
+ boolean extractedCleanFlag = false;
+ final InputStream stream =
+ AbstractBuildAndEnvironmentInfo.class.getResourceAsStream("/BUILD-" + applicationName
+ + ".INFO");
+ if (stream != null)
+ {
+ BufferedReader reader = null;
+ try
+ {
+ reader = new BufferedReader(new InputStreamReader(stream));
+ final String line = reader.readLine();
+ if (line != null)
+ {
+ final StringTokenizer tokenizer = new StringTokenizer(line, ":");
+ extractedVersion = tokenizer.nextToken();
+ extractedRevision = tokenizer.nextToken();
+ extractedCleanFlag = "clean".equals(tokenizer.nextToken());
+ }
+ } catch (IOException ex)
+ {
+ // ignored
+ } finally
+ {
+ try
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ } catch (IOException ioe)
+ {
+ // ignore
+ }
+ }
+ }
+ this.version = extractedVersion;
+ this.revision = extractedRevision;
+ this.cleanSources = extractedCleanFlag;
+ }
+
+ private final static String getProperty(final String property)
+ {
+ return System.getProperty(property, UNKNOWN);
+ }
+
+ private final static boolean isUnknown(final String property)
+ {
+ return property.equals(UNKNOWN);
+ }
+
+ /**
+ * @return Name of the CPU architecture.
+ */
+ public final String getCPUArchitecture()
+ {
+ return getProperty("os.arch");
+ }
+
+ /**
+ * @return Name and version of the operating system.
+ */
+ public final String getOS()
+ {
+ final String osName = getProperty("os.name");
+ final String osVersion = getProperty("os.version");
+ if (isUnknown(osName) || isUnknown(osVersion))
+ {
+ return osName;
+ }
+ return osName + " (v" + osVersion + ")";
+ }
+
+ /**
+ * @return Name and version of the Java Virtual Machine.
+ */
+ public final String getJavaVM()
+ {
+ final String vmName = getProperty("java.vm.name");
+ final String vmVersion = getProperty("java.vm.version");
+ if (isUnknown(vmName) || isUnknown(vmVersion))
+ {
+ return vmName;
+ }
+ return vmName + " (v" + vmVersion + ")";
+ }
+
+ /**
+ * @return The version of the software.
+ */
+ public final String getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * @return <code>true</code> if the versioned entities of the working copy have been clean when
+ * this build has been made, in other words, whether the revision given by
+ * {@link #getRevision()} does really identify the source that is build has been
+ * produced from.
+ */
+ public final boolean isCleanSources()
+ {
+ return cleanSources;
+ }
+
+ /**
+ * @return The revision number.
+ */
+ public final String getRevision()
+ {
+ return revision;
+ }
+
+ /**
+ * Returns the version accompanied by the build number of the software (if known).
+ */
+ public final String getFullVersion()
+ {
+ final StringBuilder builder = new StringBuilder();
+ final String rev = getRevision();
+ final boolean isDirty = isCleanSources() == false;
+ builder.append(getVersion());
+ if (isUnknown(rev) == false)
+ {
+ builder.append(" (r").append(rev);
+ if (isDirty)
+ {
+ builder.append("*");
+ }
+ builder.append(")");
+ } else
+ {
+ if (isDirty)
+ {
+ builder.append("*");
+ }
+ }
+ return builder.toString();
+ }
+
+ public String getApplicationName()
+ {
+ return applicationName;
+ }
+
+ /**
+ * Returns version, build number, Java VM, and OS as a {@link List} with four entries.
+ */
+ public final List<String> getEnvironmentInfo()
+ {
+ final List<String> environmentInfo = new ArrayList<String>();
+ environmentInfo.add("Application: " + getApplicationName());
+ environmentInfo.add("Version: " + getFullVersion());
+ environmentInfo.add("Java VM: " + getJavaVM());
+ environmentInfo.add("CPU Architecture: " + getCPUArchitecture());
+ environmentInfo.add("OS: " + getOS());
+ return environmentInfo;
+ }
+
+ /**
+ * Returns version, build number, Java VM, and OS in a four-liner as one {@link String}.
+ */
+ @Override
+ public final String toString()
+ {
+ final StringBuilder builder = new StringBuilder();
+ final List<String> environmentInfo = getEnvironmentInfo();
+ final int n = environmentInfo.size();
+ for (int i = 0; i < n; i++)
+ {
+ builder.append(environmentInfo.get(i));
+ if (i < n - 1)
+ {
+ builder.append(System.getProperty("line.separator"));
+ }
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java
new file mode 100644
index 0000000..785e662
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+
+/**
+ * A library for loading native libraries.
+ *
+ * @author Bernd Rinn
+ */
+public final class NativeLibraryUtilities
+{
+ private static final String JNI_LIB_PREFIX = getJNILibPrefixForSystem();
+
+ private static final String JNI_LIB_EXTENSION = getJNILibExtensionForSystem();
+
+ private static String getJNILibPrefixForSystem()
+ {
+ return OSUtilities.isWindows() ? "" : "lib";
+ }
+
+ private static String getJNILibExtensionForSystem()
+ {
+ if (OSUtilities.isMacOS())
+ {
+ return "jnilib";
+ } else if (OSUtilities.isWindows())
+ {
+ return "dll";
+ } else
+ {
+ return "so";
+ }
+ }
+
+ /**
+ * Loads the native library <var>libraryName</var>. The native library will be searched for in
+ * this way:
+ * <ol>
+ * <li>Try to use {@link System#loadLibrary(String)}. If this fails, use the next method.</li>
+ * <li>The library path can either be provided as a Java property {@code
+ * native.libpath.<libraryName>}.</li>
+ * <li>Or a prefix on the filesystem can be provided by specifying the Java property {@code
+ * native.libpath} and then the library is expected to be in {@code
+ * <native.libpath>/<libraryName>/<platform_id>/<libraryName>.so}.</li>
+ * <li>Finally, the routine will try to find the library as a resource in the class path with
+ * resource name {@code /native/<libraryName>/<platform_id>/<libraryName>.so}.</li>
+ * </ol>
+ *
+ * @return <code>true</code> if the library has been loaded successfully and <code>false</code>
+ * otherwise.
+ */
+ public static boolean loadNativeLibrary(final String libraryName)
+ {
+ // Try specific path
+ String linkLibNameOrNull = System.getProperty("native.libpath." + libraryName);
+ if (linkLibNameOrNull != null)
+ {
+ return loadLib(linkLibNameOrNull);
+ }
+
+ // Try generic path
+ final String linkLibPathOrNull = System.getProperty("native.libpath");
+ if (linkLibPathOrNull != null)
+ {
+ linkLibNameOrNull = getLibPath(linkLibPathOrNull, libraryName);
+ return loadLib(linkLibNameOrNull);
+ }
+
+ // Try resource
+ linkLibNameOrNull = tryCopyNativeLibraryToTempFile(libraryName);
+ if (linkLibNameOrNull != null)
+ {
+ return loadLib(linkLibNameOrNull);
+ }
+ // Finally, try system dependent loading
+ return loadSystemLibrary(libraryName);
+ }
+
+ private static boolean loadLib(String libPath)
+ {
+ final File linkLib = new File(libPath);
+ if (linkLib.exists() && linkLib.canRead() && linkLib.isFile())
+ {
+ final String linkLibNameAbsolute = linkLib.getAbsolutePath();
+ try
+ {
+ System.load(linkLibNameAbsolute);
+ return true;
+ } catch (final Throwable err)
+ {
+ System.err.printf("Native library '%s' failed to load:\n", linkLibNameAbsolute);
+ err.printStackTrace();
+ return false;
+ }
+ } else
+ {
+ System.err.printf("Native library '%s' does not exist or is not readable.\n", linkLib
+ .getAbsolutePath());
+ return false;
+ }
+ }
+
+ private static boolean loadSystemLibrary(String libName)
+ {
+ try
+ {
+ System.loadLibrary(libName);
+ return true;
+ } catch (Throwable th)
+ {
+ // Silence this - we return failure back as boolean value.
+ return false;
+ }
+ }
+
+ /**
+ * Tries to copy a native library which is available as a resource to a temporary file. It will
+ * use the following naming schema to locate the resource containing the native library:
+ * <p>
+ * {@code /native/<libraryName>/<platform_id>/<libraryName>.so}.
+ *
+ * @param libraryName The name of the library.
+ * @return The name of the temporary file, or <code>null</code>, if the resource could not be
+ * copied.
+ */
+ public static String tryCopyNativeLibraryToTempFile(final String libraryName)
+ {
+ return ResourceUtilities.tryCopyResourceToTempFile(getLibPath("/native", libraryName),
+ libraryName, ".so");
+ }
+
+ private static String getLibPath(final String prefix, final String libraryName)
+ {
+ return String.format("%s/%s/%s/%s%s.%s", prefix, libraryName, OSUtilities
+ .getCompatibleComputerPlatform(), JNI_LIB_PREFIX, libraryName, JNI_LIB_EXTENSION);
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java
new file mode 100644
index 0000000..11e8485
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Some useful methods related to the operating system.
+ * <p>
+ * Does <em>not</em> depend on any library jar files. But before using or extending this class and
+ * if you do not mind using <a href="http://jakarta.apache.org/commons/lang/">commons lang</a>, then
+ * have a look on <code>SystemUtils</code>.
+ * </p>
+ *
+ * @author Bernd Rinn
+ */
+public class OSUtilities
+{
+
+ /** Platform specific line separator. */
+ public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ /**
+ * @return <code>true</code> if the operating system is UNIX like.
+ */
+ public static boolean isUnix()
+ {
+ return (File.separatorChar == '/');
+ }
+
+ /**
+ * @return <code>true</code> if the operating system is a MS Windows type.
+ */
+ public static boolean isWindows()
+ {
+ return (File.separatorChar == '\\');
+ }
+
+ /**
+ * @return <code>true</code> if the the operating system is a flavor of Mac OS X.
+ */
+ public static boolean isMacOS()
+ {
+ return "Mac OS X".equals(System.getProperty("os.name"));
+ }
+
+ /**
+ * @return The name of the computer platform that is compatible with respect to executables (CPU
+ * architecture and OS name, both as precise as possible to be able to share libraries
+ * and binaries).
+ */
+ public static String getCompatibleComputerPlatform()
+ {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Windows"))
+ {
+ osName = "Windows";
+ }
+ return System.getProperty("os.arch") + "-" + osName;
+ }
+
+ /**
+ * @return The name of the CPU architecture.
+ */
+ public static String getCPUArchitecture()
+ {
+ return System.getProperty("os.arch");
+ }
+
+ /**
+ * @return The name of the operating system.
+ */
+ public static String getOSName()
+ {
+ return System.getProperty("os.name");
+ }
+
+ /**
+ * @return The name of the computer platform (CPU architecture and OS name).
+ */
+ public static String getComputerPlatform()
+ {
+ return System.getProperty("os.arch") + "-" + System.getProperty("os.name");
+ }
+
+ /**
+ * @return The name of user that runs this program.
+ */
+ public static String getUsername()
+ {
+ return System.getProperty("user.name");
+ }
+
+ /**
+ * @return <code>true</code> if the user that runs this program is known to have root privileges
+ * (based on his name).
+ */
+ public static boolean isRoot()
+ {
+ if (isUnix())
+ {
+ return "root".equals(getUsername());
+ } else
+ {
+ return "Administrator".equals(getUsername());
+ }
+ }
+
+ /**
+ * @return The <var>PATH</var> as provided by the operating system.
+ */
+ public static Set<String> getOSPath()
+ {
+ final String[] pathEntries =
+ System.getenv("PATH").split(Pattern.quote(System.getProperty("path.separator")));
+ return new LinkedHashSet<String>(Arrays.asList(pathEntries));
+ }
+
+ /**
+ * @param root Whether the path should be prepared for root or not.
+ * @return The path as provided by the operating system plus some path entries that should
+ * always be available.
+ * @see #getOSPath()
+ */
+ public static Set<String> getSafeOSPath(boolean root)
+ {
+ final Set<String> pathEntries = getOSPath();
+ if (isUnix())
+ {
+ if (isMacOS())
+ {
+ pathEntries.add("/opt/local/bin"); // MacPorts
+ pathEntries.add("/sw/bin"); // Fink
+ if (root)
+ {
+ pathEntries.add("/opt/local/sbin");
+ pathEntries.add("/sw/sbin");
+ }
+ }
+ pathEntries.add("/usr/local/bin");
+ pathEntries.add("/usr/bin");
+ pathEntries.add("/bin");
+ if (root)
+ {
+ pathEntries.add("/usr/local/sbin");
+ pathEntries.add("/usr/sbin");
+ pathEntries.add("/sbin");
+ }
+ }
+ return pathEntries;
+ }
+
+ /**
+ * Convenience method for {@link #getSafeOSPath(boolean)} with <code>root=false</code>.
+ *
+ * @return The path as provided by the operating system plus some path entries that should
+ * always be available.
+ * @see #getSafeOSPath(boolean)
+ */
+ public static Set<String> getSafeOSPath()
+ {
+ return getSafeOSPath(false);
+ }
+
+ /**
+ * Search for the binary program with name <code>binaryName</code> in the operating system
+ * path..
+ *
+ * @param executableName The name of the executable to search for. Under Windows, a name with
+ * and without <code>.exe</code> appended will work, but the executable found needs
+ * to have the .exe extension.
+ * @return The binary file that has been found in the path, or <code>null</code>, if no binary
+ * file could be found.
+ */
+ public static File findExecutable(String executableName)
+ {
+ return OSUtilities.findExecutable(executableName, getSafeOSPath());
+ }
+
+ /**
+ * Search for the binary program with name <code>binaryName</code> in the set of paths denoted
+ * by <code>pathSet</code>.
+ *
+ * @param executableName The name of the executable to search for. Under Windows, a name with
+ * and without <code>.exe</code> appended will work, but the executable found needs
+ * to have the .exe extension.
+ * @param pathSet The set of paths to search for. It is recommended to use an ordered set like
+ * the {@link LinkedHashSet} here in order to get results that are independent of the
+ * JRE implementation.
+ * @return The binary file that has been found in the path, or <code>null</code>, if no binary
+ * file could be found.
+ */
+ public static File findExecutable(String executableName, Set<String> pathSet)
+ {
+ final String executableNameWithExtension =
+ addWindowsExecutableExtensionIfNecessary(executableName);
+ for (String dir : pathSet)
+ {
+ final File fileToCheck = new File(dir, executableNameWithExtension);
+ if (fileToCheck.exists())
+ {
+ return fileToCheck;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return <code>true</code> if and only if an executable of name <var>executableName</var>
+ * exists.
+ */
+ public static boolean executableExists(String executableName)
+ {
+ return (new File(OSUtilities.addWindowsExecutableExtensionIfNecessary(executableName)))
+ .exists();
+ }
+
+ /**
+ * @return <code>true</code> if and only if an executable of name <var>executableName</var>
+ * exists.
+ */
+ public static boolean executableExists(File executable)
+ {
+ return (new File(OSUtilities.addWindowsExecutableExtensionIfNecessary(executable.getPath())))
+ .exists();
+ }
+
+ private static String addWindowsExecutableExtensionIfNecessary(String executableName)
+ {
+ if (isWindows() && executableName.indexOf('.') < 0)
+ {
+ return executableName + ".exe";
+ } else
+ {
+ return executableName;
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java
new file mode 100644
index 0000000..50b8c6e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * Utilities for handling Java resources.
+ *
+ * @author Bernd Rinn
+ */
+public class ResourceUtilities
+{
+
+ /**
+ * Tries to copy the resource with the given name to a temporary file.
+ *
+ * @param resource The name of the resource to copy.
+ * @param prefix The prefix to use for the temporary name.
+ * @param postfix The postfix to use for the temporary name.
+ * @return The name of the temporary file, or <code>null</code>, if the resource could not be
+ * copied.
+ */
+ public static String tryCopyResourceToTempFile(final String resource, final String prefix,
+ final String postfix)
+ {
+ try
+ {
+ return copyResourceToTempFile(resource, prefix, postfix);
+ } catch (final Exception ex)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Copies the resource with the given name to a temporary file. The file will be deleted on
+ * program exit.
+ *
+ * @param resource The name of the resource to copy.
+ * @param prefix The prefix to use for the temporary name.
+ * @param postfix The postfix to use for the temporary name.
+ * @return The name of the temporary file.
+ * @throws IllegalArgumentException If the resource cannot be found in the class path.
+ * @throws IOExceptionUnchecked If an {@link IOException} occurs.
+ */
+ public static String copyResourceToTempFile(final String resource, final String prefix,
+ final String postfix) throws IOExceptionUnchecked
+ {
+ final InputStream resourceStream = ResourceUtilities.class.getResourceAsStream(resource);
+ if (resourceStream == null)
+ {
+ throw new IllegalArgumentException("Resource '" + resource + "' not found.");
+ }
+ try
+ {
+ final File tempFile = File.createTempFile(prefix, postfix);
+ tempFile.deleteOnExit();
+ final OutputStream fileStream = new FileOutputStream(tempFile);
+ try
+ {
+ IOUtils.copy(resourceStream, fileStream);
+ fileStream.close();
+ } finally
+ {
+ IOUtils.closeQuietly(fileStream);
+ }
+ return tempFile.getAbsolutePath();
+ } catch (final IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ } finally
+ {
+ IOUtils.closeQuietly(resourceStream);
+ }
+ }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/package.html b/source/java/ch/systemsx/cisd/base/utilities/package.html
new file mode 100644
index 0000000..d7eda7f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Basic utilities.</title>
+</head>
+<body>
+<p>
+This package provides some basic utility classes.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/sourceTest/java/ch/systemsx/cisd/base/AllTests.java b/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
new file mode 100644
index 0000000..3d6288f
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base;
+
+import ch.systemsx.cisd.base.convert.NativeDataTests;
+import ch.systemsx.cisd.base.convert.NativeTaggedArrayTests;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUncheckedTests;
+import ch.systemsx.cisd.base.io.ByteBufferRandomAccessFileTests;
+import ch.systemsx.cisd.base.io.RandomAccessFileImplTests;
+import ch.systemsx.cisd.base.mdarray.MDArrayTests;
+import ch.systemsx.cisd.base.namedthread.NamingThreadPoolExecutorTest;
+import ch.systemsx.cisd.base.unix.Unix;
+import ch.systemsx.cisd.base.unix.UnixTests;
+
+/**
+ * Run all unit tests.
+ *
+ * @author Bernd Rinn
+ */
+public class AllTests
+{
+
+ public static void main(String[] args) throws Throwable
+ {
+ NativeDataTests.main(args);
+ System.out.println();
+ NativeTaggedArrayTests.main(args);
+ System.out.println();
+ IOExceptionUncheckedTests.main(args);
+ System.out.println();
+ ByteBufferRandomAccessFileTests.main(args);
+ System.out.println();
+ RandomAccessFileImplTests.main(args);
+ System.out.println();
+ MDArrayTests.main(args);
+ System.out.println();
+ NamingThreadPoolExecutorTest.main(args);
+ System.out.println();
+ if (Unix.isOperational())
+ {
+ UnixTests.main(args);
+ }
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java
new file mode 100644
index 0000000..d4a68e2
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * Test cases for {@link NativeData}.
+ *
+ * @author Bernd Rinn
+ */
+public class NativeDataTests
+{
+
+ @DataProvider(name = "getOfs")
+ private Object[][] getOfs()
+ {
+ return new Object[][]
+ {
+ { 0, 0 },
+ { 0, 1 },
+ { 0, 2 },
+ { 0, 3 },
+ { 1, 0 },
+ { 1, 1 },
+ { 1, 2 },
+ { 1, 3 },
+ { 2, 0 },
+ { 2, 1 },
+ { 2, 2 },
+ { 2, 3 },
+ { 3, 0 },
+ { 3, 1 },
+ { 3, 2 },
+ { 3, 3 }, };
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testIntToByteToInt(int sourceOfs, int targetOfs)
+ {
+ final int sizeOfTarget = 4;
+ final int[] orignalArr = new int[]
+ { -1, 17, 100000, -1000000 };
+ final int[] iarr = new int[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyIntToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final int[] iarr2 = new int[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToInt(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test
+ public void testIntChangeByteOrderAndBack()
+ {
+ assertEquals(0, NativeData.changeByteOrder(NativeData.changeByteOrder(0)));
+ assertEquals(1, NativeData.changeByteOrder(NativeData.changeByteOrder(1)));
+ assertEquals(-1, NativeData.changeByteOrder(NativeData.changeByteOrder(-1)));
+ assertEquals(Integer.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Integer.MAX_VALUE)));
+ assertEquals(Integer.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Integer.MIN_VALUE)));
+ }
+
+ @Test
+ public void testShortChangeByteOrderAndBack()
+ {
+ assertEquals((short) 0, NativeData.changeByteOrder(NativeData.changeByteOrder((short) 0)));
+ assertEquals((short) 1, NativeData.changeByteOrder(NativeData.changeByteOrder((short) 1)));
+ assertEquals((short) -1, NativeData.changeByteOrder(NativeData.changeByteOrder((short) -1)));
+ assertEquals(Short.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Short.MAX_VALUE)));
+ assertEquals(Short.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Short.MIN_VALUE)));
+ }
+
+ @Test
+ public void testCharChangeByteOrderAndBack()
+ {
+ assertEquals((char) 0, NativeData.changeByteOrder(NativeData.changeByteOrder((char) 0)));
+ assertEquals((char) 1, NativeData.changeByteOrder(NativeData.changeByteOrder((char) 1)));
+ assertEquals((char) -1, NativeData.changeByteOrder(NativeData.changeByteOrder((char) -1)));
+ assertEquals((char) Short.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder((char) Short.MAX_VALUE)));
+ assertEquals((char) Short.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder((char) Short.MIN_VALUE)));
+ }
+
+ @Test
+ public void testLongChangeByteOrderAndBack()
+ {
+ assertEquals(0, NativeData.changeByteOrder(NativeData.changeByteOrder(0L)));
+ assertEquals(1, NativeData.changeByteOrder(NativeData.changeByteOrder(1L)));
+ assertEquals(-1, NativeData.changeByteOrder(NativeData.changeByteOrder(-1L)));
+ assertEquals(Long.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Long.MAX_VALUE)));
+ assertEquals(Long.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Long.MIN_VALUE)));
+ }
+
+ @Test
+ public void testFloatChangeByteOrderAndBack()
+ {
+ assertEquals(0f, NativeData.changeByteOrder(NativeData.changeByteOrder(0f)));
+ assertEquals(1f, NativeData.changeByteOrder(NativeData.changeByteOrder(1f)));
+ assertEquals(-1f, NativeData.changeByteOrder(NativeData.changeByteOrder(-1f)));
+ assertEquals(Float.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Float.MAX_VALUE)));
+ assertEquals(Float.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Float.MIN_VALUE)));
+ assertEquals(-Float.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(-Float.MAX_VALUE)));
+ assertEquals(-Float.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(-Float.MIN_VALUE)));
+ }
+
+ @Test
+ public void testDoubleChangeByteOrderAndBack()
+ {
+ assertEquals(0., NativeData.changeByteOrder(NativeData.changeByteOrder(0.)));
+ assertEquals(1., NativeData.changeByteOrder(NativeData.changeByteOrder(1.)));
+ assertEquals(-1., NativeData.changeByteOrder(NativeData.changeByteOrder(-1.)));
+ assertEquals(Double.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Double.MAX_VALUE)));
+ assertEquals(Double.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(Double.MIN_VALUE)));
+ assertEquals(-Double.MAX_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(-Double.MAX_VALUE)));
+ assertEquals(-Double.MIN_VALUE,
+ NativeData.changeByteOrder(NativeData.changeByteOrder(-Double.MIN_VALUE)));
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testLongToByteToLong(int sourceOfs, int targetOfs)
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 8;
+ final long[] orignalArr = new long[]
+ { -1, 17, 100000, -1000000 };
+ final long[] iarr = new long[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyLongToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final long[] iarr2 = new long[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToLong(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testShortToByteToShort(int sourceOfs, int targetOfs)
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 2;
+ final short[] orignalArr = new short[]
+ { -1, 17, 20000, (short) -50000 };
+ final short[] iarr = new short[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyShortToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final short[] iarr2 = new short[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToShort(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testCharToByteToChar(int sourceOfs, int targetOfs)
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 2;
+ final char[] orignalArr = new char[]
+ { 'c', ';', '\u0222', '\u1000' };
+ final char[] iarr = new char[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyCharToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final char[] iarr2 = new char[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToChar(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testFloatToByteToFloat(int sourceOfs, int targetOfs)
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 4;
+ final float[] orignalArr = new float[]
+ { -1, 17, 3.14159f, -1e6f };
+ final float[] iarr = new float[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyFloatToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final float[] iarr2 = new float[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToFloat(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test(dataProvider = "getOfs")
+ public void testDoubleToByteToDouble(int sourceOfs, int targetOfs)
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 8;
+ final double[] orignalArr = new double[]
+ { -1, 17, 3.14159, -1e42 };
+ final double[] iarr = new double[sourceOfs + orignalArr.length];
+ System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+ final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+ NativeData.copyDoubleToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ final double[] iarr2 = new double[(barr.length - targetOfs) / sizeOfTarget];
+ NativeData.copyByteToDouble(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+ NativeData.ByteOrder.NATIVE);
+ assertTrue(Arrays.equals(iarr, iarr2));
+ }
+
+ @Test
+ public void testShortEndianConversion()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final short[] values = new short[]
+ { 1, 2, 4, 8, 16, 256, 512 };
+ final short[] convertedValuesExpected = new short[]
+ { 1 << 8, 1 << 9, 1 << 10, 1 << 11, 1 << 12, 1, 2 };
+ final short[] convertedValuesFound =
+ NativeData.byteToShort(NativeData.shortToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.LITTLE_ENDIAN);
+ assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+ }
+
+ @Test
+ public void testIntEndianConversion()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int[] values = new int[]
+ { 1, 2, 4, 8, 16, 256, 1 << 16 };
+ final int[] convertedValuesExpected = new int[]
+ { 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 16, 256 };
+ final int[] convertedValuesFound =
+ NativeData.byteToInt(NativeData.intToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.LITTLE_ENDIAN);
+ assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+ }
+
+ @Test
+ public void testLongEndianConversion()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final long[] values = new long[]
+ { 1, 2, 4, 8, 16, 256, 1L << 16, 1L << 24 };
+ final long[] convertedValuesExpected = new long[]
+ { 1L << 56, 1L << 57, 1L << 58, 1L << 59, 1L << 60, 1L << 48, 1L << 40, 1L << 32 };
+ final long[] convertedValuesFound =
+ NativeData.byteToLong(NativeData.longToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.LITTLE_ENDIAN);
+ assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+ }
+
+ @Test
+ public void testFloatLittleEndianRoundtrip()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final float[] values = new float[]
+ { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+ final float[] convertedValuesFound =
+ NativeData.byteToFloat(NativeData.floatToByte(values, ByteOrder.LITTLE_ENDIAN),
+ ByteOrder.LITTLE_ENDIAN);
+ assertTrue(Arrays.equals(values, convertedValuesFound));
+ }
+
+ @Test
+ public void testFloatBigEndianRoundtrip()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final float[] values = new float[]
+ { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+ final float[] convertedValuesFound =
+ NativeData.byteToFloat(NativeData.floatToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.BIG_ENDIAN);
+ assertTrue(Arrays.equals(values, convertedValuesFound));
+ }
+
+ @Test
+ public void testDoubleLittleEndianRoundtrip()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final double[] values = new double[]
+ { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+ final double[] convertedValuesFound =
+ NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.LITTLE_ENDIAN),
+ ByteOrder.LITTLE_ENDIAN);
+ assertTrue(Arrays.equals(values, convertedValuesFound));
+ }
+
+ @Test
+ public void testDoubleBigEndianRoundtrip()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final double[] values = new double[]
+ { 1.1, 2.2, 3.3, 1e-25, 1e25 };
+ final double[] convertedValuesFound =
+ NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.BIG_ENDIAN);
+ assertTrue(Arrays.equals(values, convertedValuesFound));
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testNPE()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ NativeData.copyByteToLong(null, 0, null, 0, 0, ByteOrder.NATIVE);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testIOOB()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ NativeData.copyByteToLong(new byte[] {}, -1, new long[] {}, 0, 0, ByteOrder.NATIVE);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testIOOB2()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ NativeData.copyByteToLong(new byte[] {}, 0, new long[] {}, 10, 0, ByteOrder.NATIVE);
+ }
+
+ @Test
+ public void testPlatformEndiness()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final double[] values = new double[]
+ { 1.1, 2.2, 3.3, 1e-200, 1e200 };
+ final double[] valuesLE =
+ NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.LITTLE_ENDIAN),
+ ByteOrder.NATIVE);
+ final double[] valuesBE =
+ NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.BIG_ENDIAN),
+ ByteOrder.NATIVE);
+ if (Arrays.equals(values, valuesLE))
+ {
+ assertEquals(NativeData.ByteOrder.LITTLE_ENDIAN, NativeData.getNativeByteOrder());
+ assertFalse(Arrays.equals(values, valuesBE));
+ }
+ if (Arrays.equals(values, valuesBE))
+ {
+ assertEquals(NativeData.ByteOrder.BIG_ENDIAN, NativeData.getNativeByteOrder());
+ assertFalse(Arrays.equals(values, valuesLE));
+ }
+ }
+
+ @Test
+ public void testFloatToByteNonNativeByteOrderPartialOutputArray()
+ {
+ assertTrue(NativeData.isUseNativeLib());
+ final int sizeOfTarget = 4;
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final float[] iarr = new float[]
+ { -1, 17, 3.14159f, -1e6f };
+ final byte[] headerArray = new byte[]
+ { 1, 2, 3, 4 };
+ final byte[] trailerArray = new byte[]
+ { 5, 6, 7, 8 };
+ final byte[] barr =
+ new byte[iarr.length * sizeOfTarget + headerArray.length + trailerArray.length];
+ System.arraycopy(headerArray, 0, barr, 0, headerArray.length);
+ System.arraycopy(trailerArray, 0, barr, headerArray.length + iarr.length * sizeOfTarget,
+ trailerArray.length);
+ NativeData.copyFloatToByte(iarr, 0, barr, headerArray.length, iarr.length,
+ nonNativeByteOrder);
+ final byte[] headerArray2 = ArrayUtils.subarray(barr, 0, headerArray.length);
+ final byte[] trailerArray2 =
+ ArrayUtils.subarray(barr, headerArray.length + iarr.length * sizeOfTarget,
+ barr.length);
+ assertTrue(Arrays.equals(headerArray, headerArray2));
+ assertTrue(Arrays.equals(trailerArray, trailerArray2));
+ }
+
+ private void afterClass()
+ {
+ }
+
+ private void setUp()
+ {
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + NativeDataTests.class.getSimpleName());
+ System.out.println();
+ NativeData.ensureNativeLibIsLoaded();
+ final NativeDataTests test = new NativeDataTests();
+ try
+ {
+ for (Method m : NativeDataTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ if (m.getParameterTypes().length == 2
+ && "getOfs".equals(testAnnotation.dataProvider()))
+ {
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ final Object[][] testArgs = test.getOfs();
+ for (Object[] a : testArgs)
+ {
+ System.out.println(" Arguments: " + Arrays.toString(a));
+ m.invoke(test, a);
+ }
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ } finally
+ {
+ test.afterClass();
+ }
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
new file mode 100644
index 0000000..13b0115
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.convert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+import ch.systemsx.cisd.base.mdarray.MDDoubleArray;
+import ch.systemsx.cisd.base.mdarray.MDFloatArray;
+import ch.systemsx.cisd.base.mdarray.MDIntArray;
+import ch.systemsx.cisd.base.mdarray.MDLongArray;
+import ch.systemsx.cisd.base.mdarray.MDShortArray;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link NativeTaggedArray}.
+ *
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArrayTests
+{
+
+ @Test
+ public static void testFloat1DArrayNativeByteOrder()
+ {
+ final float[] floatArr = new float[]
+ { 1.1f, -3.2f, 1001.5f };
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr);
+ assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+ final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+ final NativeTaggedArray.NativeArrayTag tag = NativeTaggedArray.tryGetArrayTag(taggedArr);
+ final NativeArrayEncoding encoding = tag.getEncoding();
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertEquals(1, tag.getDimensions().length);
+ assertEquals(3, tag.getDimensions()[0]);
+ assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+ }
+
+ @Test
+ public static void testFloat1DArrayNonNativeByteOrder()
+ {
+ final float[] floatArr = new float[]
+ { 1.1f, -3.2f, 1001.5f };
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr, nonNativeByteOrder);
+ assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+ final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+ }
+
+ @Test
+ public static void testFloat2DArrayNativeByteOrder()
+ {
+ final MDFloatArray floatArr = new MDFloatArray(new float[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr);
+ assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+ final MDFloatArray convertedFloatArr = NativeTaggedArray.tryToFloatArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(floatArr.equals(convertedFloatArr));
+ }
+
+ @Test
+ public static void testFloat2DArrayNonNativeByteOrder()
+ {
+ final MDFloatArray floatArr = new MDFloatArray(new float[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr, nonNativeByteOrder);
+ assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+ final MDFloatArray convertedFloatArr = NativeTaggedArray.tryToFloatArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(floatArr.equals(convertedFloatArr));
+ }
+
+ @Test
+ public static void testDouble1DArrayNativeByteOrder()
+ {
+ final double[] doubleArr = new double[]
+ { 1.1, -3.2, 1001.5 };
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr);
+ assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+ final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+ }
+
+ @Test
+ public static void testDouble1DArrayNonNativeByteOrder()
+ {
+ final double[] doubleArr = new double[]
+ { 1.1, -3.2, 1001.5 };
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr, nonNativeByteOrder);
+ assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+ final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+ }
+
+ @Test
+ public static void testDouble2DArrayNativeByteOrder()
+ {
+ final MDDoubleArray doubleArr = new MDDoubleArray(new double[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr);
+ assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+ final MDDoubleArray convertedDoubleArr = NativeTaggedArray.tryToDoubleArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(doubleArr.equals(convertedDoubleArr));
+ }
+
+ @Test
+ public static void testDouble2DArrayNonNativeByteOrder()
+ {
+ final MDDoubleArray doubleArr = new MDDoubleArray(new double[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr, nonNativeByteOrder);
+ assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+ final MDDoubleArray convertedDoubleArr = NativeTaggedArray.tryToDoubleArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertTrue(encoding.isFloatingPoint());
+ assertFalse(encoding.isInteger());
+ assertTrue(doubleArr.equals(convertedDoubleArr));
+ }
+
+ @Test
+ public static void testShort1DArrayNativeByteOrder()
+ {
+ final short[] shortArr = new short[]
+ { 1, -3, 1001 };
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr);
+ assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+ final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(2, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(shortArr, convertedShortArr));
+ }
+
+ @Test
+ public static void testShort1DArrayNonNativeByteOrder()
+ {
+ final short[] shortArr = new short[]
+ { 1, -3, 1001 };
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr, nonNativeByteOrder);
+ assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+ final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(2, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(shortArr, convertedShortArr));
+ }
+
+ @Test
+ public static void testShort2DArrayNativeByteOrder()
+ {
+ final MDShortArray shortArr = new MDShortArray(new short[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr);
+ assertEquals(4 * 2 + 2 * 4 + 4, taggedArr.length);
+ final MDShortArray convertedShortArr = NativeTaggedArray.tryToShortArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(2, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(shortArr.equals(convertedShortArr));
+ }
+
+ @Test
+ public static void testShort2DArrayNonNativeByteOrder()
+ {
+ final MDShortArray shortArr = new MDShortArray(new short[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr, nonNativeByteOrder);
+ assertEquals(4 * 2 + 2 * 4 + 4, taggedArr.length);
+ final MDShortArray convertedShortArr = NativeTaggedArray.tryToShortArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(2, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(shortArr.equals(convertedShortArr));
+ }
+
+ @Test
+ public static void testInt1DArrayNativeByteOrder()
+ {
+ final int[] intArr = new int[]
+ { 1, -3, 1001 };
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr);
+ assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+ final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(intArr, convertedIntArr));
+ }
+
+ @Test
+ public static void testInt1DArrayNonNativeByteOrder()
+ {
+ final int[] intArr = new int[]
+ { 1, -3, 1001 };
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr, nonNativeByteOrder);
+ assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+ final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(intArr, convertedIntArr));
+ }
+
+ @Test
+ public static void testInt2DArrayNativeByteOrder()
+ {
+ final MDIntArray intArr = new MDIntArray(new int[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr);
+ assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+ final MDIntArray convertedIntArr = NativeTaggedArray.tryToIntArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(intArr.equals(convertedIntArr));
+ }
+
+ @Test
+ public static void testInt2DArrayNonNativeByteOrder()
+ {
+ final MDIntArray intArr = new MDIntArray(new int[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr, nonNativeByteOrder);
+ assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+ final MDIntArray convertedIntArr = NativeTaggedArray.tryToIntArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(4, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(intArr.equals(convertedIntArr));
+ }
+
+ @Test
+ public static void testLong1DArrayNativeByteOrder()
+ {
+ final long[] longArr = new long[]
+ { 1, -3, 1001 };
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr);
+ assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+ final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(longArr, convertedLongArr));
+ }
+
+ @Test
+ public static void testLong1DArrayNonNativeByteOrder()
+ {
+ final long[] longArr = new long[]
+ { 1, -3, 1001 };
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr, nonNativeByteOrder);
+ assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+ final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(Arrays.equals(longArr, convertedLongArr));
+ }
+
+ @Test
+ public static void testLong2DArrayNativeByteOrder()
+ {
+ final MDLongArray longArr = new MDLongArray(new long[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr);
+ assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+ final MDLongArray convertedLongArr = NativeTaggedArray.tryToLongArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(longArr.equals(convertedLongArr));
+ }
+
+ @Test
+ public static void testLong2DArrayNonNativeByteOrder()
+ {
+ final MDLongArray longArr = new MDLongArray(new long[]
+ { 1, 2, 3, 4 }, new int[] { 2, 2 });
+ final ByteOrder nonNativeByteOrder =
+ (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+ : ByteOrder.LITTLE_ENDIAN;
+ final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr, nonNativeByteOrder);
+ assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+ final MDLongArray convertedLongArr = NativeTaggedArray.tryToLongArray(taggedArr);
+ final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+ assertNotNull(encoding);
+ assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+ assertEquals(8, encoding.getSizeInBytes());
+ assertFalse(encoding.isFloatingPoint());
+ assertTrue(encoding.isInteger());
+ assertTrue(longArr.equals(convertedLongArr));
+ }
+
+ private void afterClass()
+ {
+ }
+
+ private void setUp()
+ {
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + NativeTaggedArrayTests.class.getSimpleName());
+ System.out.println();
+ NativeData.ensureNativeLibIsLoaded();
+ final NativeTaggedArrayTests test = new NativeTaggedArrayTests();
+ try
+ {
+ for (Method m : NativeTaggedArrayTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null || m.getParameterTypes().length > 0)
+ {
+ continue;
+ }
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ } finally
+ {
+ test.afterClass();
+ }
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java b/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java
new file mode 100644
index 0000000..04e34eb
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.commons.lang.StringUtils;
+import org.testng.annotations.Test;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link CheckedExceptionTunnel}
+ *
+ * @author Bernd Rinn
+ */
+public class CheckedExceptionTunnelTest
+{
+
+ @Test
+ public void testGetMessage()
+ {
+ final IOException ioe = new IOException("This is the message");
+ final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ioe);
+ assertEquals("This is the message", re.getMessage());
+ }
+
+ @Test
+ public void testToString()
+ {
+ final InterruptedException ioe = new InterruptedException("Somehow got interrupted");
+ final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ioe);
+ assertEquals("java.lang.InterruptedException: Somehow got interrupted", re.toString());
+ }
+
+ @Test
+ public void testPrintStackTrace()
+ {
+ final InterruptedException ie = new InterruptedException("Somehow got interrupted");
+ ie.fillInStackTrace();
+ final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ie);
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ re.printStackTrace(pw);
+ final String[] lines = StringUtils.split(sw.toString(), '\n');
+ assertEquals("java.lang.InterruptedException: Somehow got interrupted", lines[0]);
+ assertTrue(
+ lines[1],
+ lines[1].startsWith("\tat ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnelTest."
+ + "testPrintStackTrace(CheckedExceptionTunnelTest.java"));
+ }
+
+ @Test
+ public void testPrintFullStackTrace()
+ {
+ final Exception e = new Exception("Some exceptional condition");
+ e.fillInStackTrace();
+ final CheckedExceptionTunnel re = new CheckedExceptionTunnel(e);
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ re.printFullStackTrace();
+ re.printFullStackTrace(pw);
+ final String[] lines = StringUtils.split(sw.toString(), '\n');
+ assertEquals(
+ "ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel: Some exceptional condition",
+ lines[0]);
+ assertTrue(
+ lines[1],
+ lines[1].startsWith("\tat ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnelTest."
+ + "testPrintFullStackTrace(CheckedExceptionTunnelTest.java:"));
+ }
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java b/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java
new file mode 100644
index 0000000..76db02d
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.exceptions;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * Test cases for {@link IOExceptionUnchecked}.
+ *
+ * @author Bernd Rinn
+ */
+public class IOExceptionUncheckedTests
+{
+ private void generateFileNotFoundException() throws IOExceptionUnchecked
+ {
+ try
+ {
+ new FileInputStream(new File("doesnt.exist"));
+ } catch (IOException ex)
+ {
+ throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+ }
+ }
+
+ @Test
+ public void testWrapUnwrapIOException()
+ {
+ try
+ {
+ generateFileNotFoundException();
+ fail("No IOException thrown");
+ } catch (IOExceptionUnchecked e)
+ {
+ final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+ assertTrue(ex instanceof FileNotFoundException);
+ assertTrue(ex.getMessage().startsWith("doesnt.exist"));
+ }
+ }
+
+ @Test
+ public void testWrapUnwrapNonIOException()
+ {
+ try
+ {
+ throw new IOExceptionUnchecked(new IllegalStateException("Don't like this state"));
+ } catch (CheckedExceptionTunnel e)
+ {
+ final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+ assertTrue(ex instanceof IOException);
+ assertEquals("IllegalStateException: Don't like this state", ex.getMessage());
+ assertNotNull(ex.getCause());
+ assertTrue(ex.getCause() instanceof IllegalStateException);
+ assertEquals("Don't like this state", ex.getCause().getMessage());
+ }
+ }
+
+ @Test
+ public void testWrapUnwrapIOExceptionGivingMsg()
+ {
+ try
+ {
+ throw new IOExceptionUnchecked("Some message");
+ } catch (CheckedExceptionTunnel e)
+ {
+ final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+ assertTrue(ex instanceof IOException);
+ assertEquals("Some message", ex.getMessage());
+ assertNull(ex.getCause());
+ }
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + IOExceptionUncheckedTests.class.getSimpleName());
+ System.out.println();
+ final IOExceptionUncheckedTests test = new IOExceptionUncheckedTests();
+ for (Method m : IOExceptionUncheckedTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java
new file mode 100644
index 0000000..0987c34
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link RandomAccessFileImpl}.
+ *
+ * @author Bernd Rinn
+ */
+public class ByteBufferRandomAccessFileTests extends IRandomAccessFileTests
+{
+
+ @Override
+ protected IRandomAccessFile createRandomAccessFile(String name)
+ {
+ return new ByteBufferRandomAccessFile(4096);
+ }
+
+ @Override
+ protected IRandomAccessFile createRandomAccessFile(String name, byte[] content)
+ {
+ return new ByteBufferRandomAccessFile(content);
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + ByteBufferRandomAccessFileTests.class.getSimpleName());
+ System.out.println();
+ final ByteBufferRandomAccessFileTests test = new ByteBufferRandomAccessFileTests();
+ try
+ {
+ for (Method m : ByteBufferRandomAccessFileTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ } finally
+ {
+ test.afterClass();
+ }
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java
new file mode 100644
index 0000000..57ddec1
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+import org.apache.commons.io.IOUtils;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.convert.NativeData;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+
+/**
+ * Test cases for {@link IRandomAccessFile} implementations.
+ *
+ * @author Bernd Rinn
+ */
+public abstract class IRandomAccessFileTests extends AbstractFileSystemTestCase
+{
+
+ abstract protected IRandomAccessFile createRandomAccessFile(String name);
+
+ abstract protected IRandomAccessFile createRandomAccessFile(String name, byte[] content);
+
+ @Test
+ public void testSkip()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testSkip");
+ final byte[] b = new byte[4096];
+ for (int i = 0; i < b.length; ++i)
+ {
+ b[i] = (byte) i;
+ }
+ raf.write(b);
+ raf.seek(0);
+ assertEquals(509, raf.skip(509));
+ assertEquals(509, raf.getFilePointer());
+ assertEquals(-3, raf.readByte());
+ assertEquals(4096 - 509 - 1, raf.skip(4096));
+ assertEquals(4096, raf.getFilePointer());
+ raf.close();
+ }
+
+ @Test
+ public void testLongByteOrder()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testLongByteOrder");
+ raf.writeLong(1);
+ final byte[] buf = new byte[8];
+ raf.seek(0);
+ raf.read(buf);
+ // Default is big endian
+ assertEquals(0, buf[0]);
+ assertEquals(1, buf[7]);
+
+ raf.seek(0);
+ raf.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ raf.writeLong(1);
+ raf.seek(0);
+ raf.read(buf);
+ assertEquals(1, buf[0]);
+ assertEquals(0, buf[7]);
+ raf.close();
+ }
+
+ @Test
+ public void testMark()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testMark");
+ final byte[] buf = new byte[128];
+ raf.write(buf);
+ raf.seek(0);
+ assertTrue(raf.markSupported());
+ raf.mark(0);
+ raf.read();
+ assertEquals(1, raf.getFilePointer());
+ raf.reset();
+ assertEquals(0, raf.getFilePointer());
+ raf.read();
+ raf.read();
+ raf.read();
+ raf.mark(0);
+ raf.read();
+ raf.read();
+ raf.read();
+ raf.reset();
+ assertEquals(3, raf.getFilePointer());
+ raf.close();
+ }
+
+ @Test
+ public void testWriteReadByte()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadByte");
+ raf.write(254);
+ raf.seek(0);
+ assertEquals(-2, raf.readByte());
+ raf.seek(0);
+ assertEquals(254, raf.read());
+ raf.seek(0);
+ assertEquals(254, raf.readUnsignedByte());
+ raf.close();
+ }
+
+ @Test
+ public void testWriteReadShort()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadShort");
+ raf.writeShort(65534);
+ raf.seek(0);
+ assertEquals(-2, raf.readShort());
+ raf.seek(0);
+ assertEquals(65534, raf.readUnsignedShort());
+ raf.close();
+ }
+
+ @Test
+ public void testAvailable()
+ {
+ final IRandomAccessFile raf = createRandomAccessFile("testAvailable");
+ assertEquals(0, raf.available());
+ raf.writeDouble(5.5);
+ raf.seek(0);
+ assertEquals(8, raf.available());
+ raf.close();
+ }
+
+ @Test
+ public void testWriteReadStringBytes()
+ {
+ final String s = "teststring";
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringBytes");
+ raf.writeBytes(s);
+ raf.seek(0);
+ assertEquals(s.length(), raf.available());
+ final byte[] buf = new byte[raf.available()];
+ raf.read(buf);
+ assertEquals(s, new String(buf));
+ raf.close();
+ }
+
+ @Test
+ public void testWriteReadStringChars()
+ {
+ final String s = "teststring";
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars");
+ raf.writeChars(s);
+ raf.seek(0);
+ assertEquals(2 * s.length(), raf.available());
+ final byte[] buf = new byte[raf.available()];
+ raf.read(buf);
+ assertEquals(
+ s,
+ new String(NativeData.byteToChar(buf,
+ ch.systemsx.cisd.base.convert.NativeData.ByteOrder.BIG_ENDIAN)));
+ raf.close();
+ }
+
+ @Test
+ public void testReadLine() throws IOException
+ {
+ final byte[] bytes = "hello world".getBytes();
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars", bytes);
+ final AdapterIInputStreamToInputStream is = new AdapterIInputStreamToInputStream(raf);
+
+ assertEquals("[hello world]", IOUtils.readLines(is).toString());
+ raf.close();
+ }
+
+ @Test
+ public void testToByteArray() throws IOException
+ {
+ final byte[] bytes = "hello world".getBytes();
+ final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars", bytes);
+ final AdapterIInputStreamToInputStream is = new AdapterIInputStreamToInputStream(raf);
+
+ assertEquals(bytes, IOUtils.toByteArray(is));
+ raf.close();
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java
new file mode 100644
index 0000000..2bc200b
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.io;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link RandomAccessFileImpl}.
+ *
+ * @author Bernd Rinn
+ */
+public class RandomAccessFileImplTests extends IRandomAccessFileTests
+{
+
+ @Override
+ protected IRandomAccessFile createRandomAccessFile(String name)
+ {
+ return new RandomAccessFileImpl(create(name), "rw");
+ }
+
+ @Override
+ protected IRandomAccessFile createRandomAccessFile(String name, byte[] content)
+ {
+ final IRandomAccessFile f = new RandomAccessFileImpl(create(name), "rw");
+ f.write(content);
+ f.seek(0L);
+ return f;
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + RandomAccessFileImplTests.class.getSimpleName());
+ System.out.println();
+ final RandomAccessFileImplTests test = new RandomAccessFileImplTests();
+ try
+ {
+ for (Method m : RandomAccessFileImplTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ } finally
+ {
+ test.afterClass();
+ }
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java b/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java
new file mode 100644
index 0000000..38a9182
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.mdarray;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link MDAbstractArray}.
+ *
+ * @author Bernd Rinn
+ */
+public class MDArrayTests
+{
+ @Test
+ public void testGetLength()
+ {
+ assertEquals(0, MDAbstractArray.getLength(new int[]
+ { 0 }, 0));
+ assertEquals(1, MDAbstractArray.getLength(new int[]
+ { 1 }, 0));
+ assertEquals(2, MDAbstractArray.getLength(new int[]
+ { 1 }, 2));
+ assertEquals(15, MDAbstractArray.getLength(new int[]
+ { 5, 3 }, 0));
+ assertEquals(21, MDAbstractArray.getLength(new int[]
+ { 5, 3 }, 7));
+ assertEquals(15, MDAbstractArray.getLength(new int[]
+ { 5, 3 }, 3));
+ assertEquals(1, MDAbstractArray.getLength(new int[]
+ { 1, 1, 1 }, 0));
+ assertEquals(3, MDAbstractArray.getLength(new int[]
+ { 1, 1, 1 }, 3));
+ assertEquals(8, MDAbstractArray.getLength(new int[]
+ { 2, 2, 2 }, 0));
+ assertEquals(20, MDAbstractArray.getLength(new int[]
+ { 2, 2, 2 }, 5));
+ assertEquals(2, MDAbstractArray.getLength(new int[]
+ { 1, 1, 2 }, 0));
+ assertEquals(2, MDAbstractArray.getLength(new int[]
+ { 1, 2, 1 }, 0));
+ assertEquals(2, MDAbstractArray.getLength(new int[]
+ { 2, 1, 1 }, 0));
+ assertEquals(50, MDAbstractArray.getLength(new int[]
+ { 10, 1, 5 }, 0));
+ assertEquals(50, MDAbstractArray.getLength(new long[]
+ { 10, 1, 5 }, 0));
+ }
+
+ @Test
+ public void testToInt()
+ {
+ assertTrue(Arrays.equals(new int[]
+ { 1, 2, 3 }, MDAbstractArray.toInt(new long[]
+ { 1, 2, 3 })));
+ assertTrue(Arrays.equals(new int[] {}, MDAbstractArray.toInt(new long[] {})));
+ }
+
+ @Test
+ public void testComputeIndex()
+ {
+ MDArray<Object> array;
+ array = new MDArray<Object>(Object.class, new int[]
+ { 33 });
+ assertEquals(17, array.computeIndex(new int[]
+ { 17 }));
+ assertTrue(Arrays.toString(array.computeReverseIndex(17)), Arrays.equals(new int[]
+ { 17 }, array.computeReverseIndex(17)));
+ array = new MDArray<Object>(Object.class, new int[]
+ { 100, 10 });
+ assertEquals(10 * 42 + 8, array.computeIndex(new int[]
+ { 42, 8 }));
+ assertTrue(Arrays.toString(array.computeReverseIndex(10 * 42 + 8)),
+ Arrays.equals(new int[]
+ { 42, 8 }, array.computeReverseIndex(10 * 42 + 8)));
+ array = new MDArray<Object>(Object.class, new int[]
+ { 2, 7, 3 });
+ assertEquals(3 * 7 * 1 + 3 * 3 + 2, array.computeIndex(new int[]
+ { 1, 3, 2 }));
+ assertTrue(Arrays.toString(array.computeReverseIndex(3 * 7 * 1 + 3 * 3 + 2)),
+ Arrays.equals(new int[]
+ { 1, 3, 2 }, array.computeReverseIndex(3 * 7 * 1 + 3 * 3 + 2)));
+ }
+
+ @Test
+ public void testComputeIndex2D()
+ {
+ MDArray<Object> array;
+ array = new MDArray<Object>(Object.class, new int[]
+ { 100, 10 });
+ assertEquals(array.computeIndex(new int[]
+ { 5, 8, }), array.computeIndex(5, 8));
+ assertEquals(array.computeIndex(new int[]
+ { 9, 1, }), array.computeIndex(9, 1));
+ array = new MDArray<Object>(Object.class, new int[]
+ { 101, 11 });
+ assertEquals(array.computeIndex(new int[]
+ { 5, 8, }), array.computeIndex(5, 8));
+ assertEquals(array.computeIndex(new int[]
+ { 9, 1, }), array.computeIndex(9, 1));
+ }
+
+ @Test
+ public void testComputeIndex3()
+ {
+ MDArray<Object> array;
+ array = new MDArray<Object>(Object.class, new int[]
+ { 100, 10, 17 });
+ assertEquals(array.computeIndex(new int[]
+ { 5, 8, 16 }), array.computeIndex(5, 8, 16));
+ assertEquals(array.computeIndex(new int[]
+ { 9, 1, 5 }), array.computeIndex(9, 1, 5));
+ array = new MDArray<Object>(Object.class, new int[]
+ { 101, 11, 3 });
+ assertEquals(array.computeIndex(new int[]
+ { 5, 8, 0 }), array.computeIndex(5, 8, 0));
+ assertEquals(array.computeIndex(new int[]
+ { 9, 1, 2 }), array.computeIndex(9, 1, 2));
+ }
+
+ @Test
+ public void testEmptyMatrix()
+ {
+ final MDFloatArray arr = new MDFloatArray(new float[0][0]);
+ assertEquals(0, arr.dimensions()[0]);
+ assertEquals(0, arr.dimensions()[1]);
+ }
+
+ @Test
+ public void testChangeHyperRowCountIntArray()
+ {
+ final MDIntArray arr = new MDIntArray(new int[]
+ { 2, 2 }, 3);
+ assertEquals(2, arr.dimensions[0]);
+ assertEquals(2, arr.dimensions[1]);
+ arr.set(1, 0, 0);
+ arr.set(2, 0, 1);
+ arr.set(3, 1, 0);
+ arr.set(4, 1, 1);
+
+ final MDIntArray arr2 = new MDIntArray(arr.getCopyAsFlatArray(), arr.dimensions());
+ assertTrue(arr2.equals(arr));
+
+ arr.incNumberOfHyperRows(1);
+ assertEquals(3, arr.dimensions[0]);
+ assertEquals(1, arr.get(0, 0));
+ assertEquals(2, arr.get(0, 1));
+ assertEquals(3, arr.get(1, 0));
+ assertEquals(4, arr.get(1, 1));
+ arr.set(5, 2, 0);
+ arr.set(6, 2, 1);
+ arr.incNumberOfHyperRows(2);
+ assertEquals(5, arr.dimensions[0]);
+ assertEquals(1, arr.get(0, 0));
+ assertEquals(2, arr.get(0, 1));
+ assertEquals(3, arr.get(1, 0));
+ assertEquals(4, arr.get(1, 1));
+ assertEquals(5, arr.get(2, 0));
+ assertEquals(6, arr.get(2, 1));
+ arr.set(7, 3, 0);
+ arr.set(8, 3, 1);
+ arr.decNumberOfHyperRows(1);
+ assertEquals(4, arr.dimensions[0]);
+ assertEquals(1, arr.get(0, 0));
+ assertEquals(2, arr.get(0, 1));
+ assertEquals(3, arr.get(1, 0));
+ assertEquals(4, arr.get(1, 1));
+ assertEquals(5, arr.get(2, 0));
+ assertEquals(6, arr.get(2, 1));
+ assertEquals(7, arr.get(3, 0));
+ assertEquals(8, arr.get(3, 1));
+ }
+
+ @Test
+ public void testChangeHyperRowCountIntArrayFromZero()
+ {
+ final MDIntArray arr = new MDIntArray(new int[]
+ { 0 });
+ assertEquals(0, arr.size(0));
+ arr.incNumberOfHyperRows(1);
+ assertEquals(1, arr.size(0));
+ arr.set(17, 0);
+ assertEquals(17, arr.get(0));
+ arr.incNumberOfHyperRows(1);
+ arr.incNumberOfHyperRows(1);
+ assertEquals(3, arr.size());
+ }
+
+ @Test
+ public void testChangeHyperRowCountTArray()
+ {
+ final MDArray<Integer> arr = new MDArray<Integer>(Integer.class, new int[]
+ { 2, 2 }, 3);
+ assertEquals(2, arr.dimensions[0]);
+ assertEquals(2, arr.dimensions[1]);
+ arr.set(1, 0, 0);
+ arr.set(2, 0, 1);
+ arr.set(3, 1, 0);
+ arr.set(4, 1, 1);
+ arr.incNumberOfHyperRows(1);
+ assertEquals(3, arr.dimensions[0]);
+ assertEquals(1, (int) arr.get(0, 0));
+ assertEquals(2, (int) arr.get(0, 1));
+ assertEquals(3, (int) arr.get(1, 0));
+ assertEquals(4, (int) arr.get(1, 1));
+ arr.set(5, 2, 0);
+ arr.set(6, 2, 1);
+ arr.incNumberOfHyperRows(2);
+ assertEquals(5, arr.dimensions[0]);
+ assertEquals(1, (int) arr.get(0, 0));
+ assertEquals(2, (int) arr.get(0, 1));
+ assertEquals(3, (int) arr.get(1, 0));
+ assertEquals(4, (int) arr.get(1, 1));
+ assertEquals(5, (int) arr.get(2, 0));
+ assertEquals(6, (int) arr.get(2, 1));
+ arr.set(7, 3, 0);
+ arr.set(8, 3, 1);
+ arr.decNumberOfHyperRows(1);
+ assertEquals(4, arr.dimensions[0]);
+ assertEquals(1, (int) arr.get(0, 0));
+ assertEquals(2, (int) arr.get(0, 1));
+ assertEquals(3, (int) arr.get(1, 0));
+ assertEquals(4, (int) arr.get(1, 1));
+ assertEquals(5, (int) arr.get(2, 0));
+ assertEquals(6, (int) arr.get(2, 1));
+ assertEquals(7, (int) arr.get(3, 0));
+ assertEquals(8, (int) arr.get(3, 1));
+ }
+
+ @Test
+ public void testMDIntArrayIterator()
+ {
+ final int[] linArray = new int[120];
+ for (int i = 0; i < linArray.length; ++i)
+ {
+ linArray[i] = i;
+ }
+ final MDIntArray array = new MDIntArray(linArray, new int[]
+ { 2, 3, 4, 5 });
+ for (MDIntArray.ArrayEntry e : array)
+ {
+ assertEquals(e.getLinearIndex(), e.getValue().intValue());
+ assertEquals(e.getLinearIndex(), array.computeIndex(e.getIndex()));
+ }
+ }
+
+ @Test
+ public void testMDFloatArrayMatrix()
+ {
+ final float[][] matrix1 = new float[][]
+ {
+ { 1f, 2f, 3f, 4f },
+ { 5f, 6f, 7f, 8f },
+ { 9f, 10f, 11f, 12f } };
+ final MDFloatArray array = new MDFloatArray(matrix1);
+ assertEquals(2, array.rank());
+ assertEquals(12, array.size());
+ assertEquals(3, array.size(0));
+ assertEquals(4, array.size(1));
+ assertEquals(7f, array.get(1, 2));
+ final float[][] matrix2 = array.toMatrix();
+ assertEquals(matrix1.length, matrix2.length);
+ for (int i = 0; i < matrix1.length; ++i)
+ {
+ assertTrue(Arrays.equals(matrix1[i], matrix2[i]));
+ }
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + MDArrayTests.class.getSimpleName());
+ System.out.println();
+ final MDArrayTests test = new MDArrayTests();
+ for (Method m : MDArrayTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java b/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java
new file mode 100644
index 0000000..582a02a
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.namedthread;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.tests.Retry10;
+
+/**
+ * Test cases for the {@link NamingThreadPoolExecutor}.
+ *
+ * @author Bernd Rinn
+ */
+public class NamingThreadPoolExecutorTest
+{
+
+ private final static String name = "This is the pool name";
+
+ @Test
+ public void testNamedPool() throws Throwable
+ {
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(2, eservice.getMaximumPoolSize());
+ final Future<?> future = eservice.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ assertEquals(name + "-T1", Thread.currentThread().getName());
+ }
+ });
+ try
+ {
+ future.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Test
+ public void testDaemonize()
+ {
+ final NamingThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2);
+ assertFalse(eservice.getThreadFactory().isCreateDaemonThreads());
+ eservice.daemonize();
+ assertTrue(eservice.getThreadFactory().isCreateDaemonThreads());
+ }
+
+ @Test
+ public void testSetNamedThreadFactory()
+ {
+ final NamingThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+ final NamingThreadFactory factory = new NamingThreadFactory("name");
+ eservice.setThreadFactory(factory);
+ assertEquals(factory, eservice.getThreadFactory());
+ }
+
+ @Test
+ public void testSetThreadFactory()
+ {
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+ final ThreadFactory factory = new NamingThreadFactory("name");
+ eservice.setThreadFactory(factory);
+ assertEquals(factory, eservice.getThreadFactory());
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testSetThreadFactoryFailed()
+ {
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+ final ThreadFactory factory = new ThreadFactory()
+ {
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ return null; // Doesn't matter, never used
+ }
+ };
+ // It needs to be NamingThreadFactory, thus it will throw an IllegalArgumentException.
+ eservice.setThreadFactory(factory);
+ }
+
+ @Test(groups = "slow")
+ public void testThreadDefaultNames() throws Throwable
+ {
+ final int max = 10;
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(max).maximumPoolSize(max).daemonize();
+ assertEquals(max, eservice.getCorePoolSize());
+ assertEquals(max, eservice.getMaximumPoolSize());
+ final Set<String> expectedThreadNameSet = new HashSet<String>();
+ for (int i = 1; i <= max; ++i)
+ {
+ expectedThreadNameSet.add(name + "-T" + i);
+ }
+ final Set<String> threadNameSet = Collections.synchronizedSet(new HashSet<String>());
+ final Set<Future<?>> futureSet = new HashSet<Future<?>>();
+ for (int i = 0; i < max; ++i)
+ {
+ futureSet.add(eservice.submit(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ threadNameSet.add(Thread.currentThread().getName());
+ try
+ {
+ Thread.sleep(20L);
+ } catch (InterruptedException ex)
+ {
+ fail("We got interrupted.");
+ }
+ }
+ }));
+ }
+ for (Future<?> future : futureSet)
+ {
+ try
+ {
+ future.get(400L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+ assertEquals(expectedThreadNameSet, threadNameSet);
+ }
+
+ @Test(groups = "slow")
+ public void testSubmitNamedRunnable() throws Throwable
+ {
+ final String runnableName = "This is the special runnable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Future<?> future = eservice.submit(new NamedRunnable()
+ {
+ @Override
+ public void run()
+ {
+ assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+ }
+
+ @Override
+ public String getRunnableName()
+ {
+ return runnableName;
+ }
+ });
+ try
+ {
+ future.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Test(groups = "slow")
+ public void testExecuteNamedRunnable() throws Throwable
+ {
+ final String runnableName = "This is the special runnable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Semaphore sem = new Semaphore(0);
+ eservice.execute(new NamedRunnable()
+ {
+ @Override
+ public void run()
+ {
+ assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+ sem.release();
+ }
+
+ @Override
+ public String getRunnableName()
+ {
+ return runnableName;
+ }
+ });
+ assertTrue(sem.tryAcquire(200L, TimeUnit.MILLISECONDS));
+ }
+
+ interface MyRunnable extends Runnable, IRunnableNameProvider
+ {
+ }
+
+ @Test(groups = "slow")
+ public void testExecuteNamedMyRunnable() throws Throwable
+ {
+ final String runnableName = "This is the special runnable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Semaphore sem = new Semaphore(0);
+ eservice.execute(new MyRunnable()
+ {
+ @Override
+ public void run()
+ {
+ assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+ sem.release();
+ }
+
+ @Override
+ public String getRunnableName()
+ {
+ return runnableName;
+ }
+ });
+ assertTrue(sem.tryAcquire(200L, TimeUnit.MILLISECONDS));
+ }
+
+ @Test(groups = "slow")
+ public void testSubmitNamedCallable() throws Throwable
+ {
+ final String callableName = "This is the special callable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Future<?> future = eservice.submit(new NamedCallable<Object>()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName, Thread.currentThread().getName());
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName;
+ }
+ });
+ try
+ {
+ future.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ interface MyCallable extends Callable<Object>, ICallableNameProvider
+ {
+ }
+
+ @Test(groups = "slow")
+ public void testSubmitMyNamedCallable() throws Throwable
+ {
+ final String callableName = "This is the special callable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Future<?> future = eservice.submit(new MyCallable()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName, Thread.currentThread().getName());
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName;
+ }
+ });
+ try
+ {
+ future.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ @Test(groups = "slow", retryAnalyzer = Retry10.class)
+ public void testSubmitNamedCallables() throws Throwable
+ {
+ final String callableName1 = "This is the first special callable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Future<?> future1 = eservice.submit(new NamedCallable<Object>()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName1;
+ }
+ });
+ try
+ {
+ future1.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ // On Linux x64, Java 1.6 we get a RejectedExecutionException if we continue immediately.
+ Thread.sleep(200L);
+ final String callableName2 = "This is the second special callable name";
+ final Future<?> future2 = eservice.submit(new NamedCallable<Object>()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName2, Thread.currentThread().getName());
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName2;
+ }
+ });
+ try
+ {
+ future2.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+
+ @Test(groups = "slow", retryAnalyzer = Retry10.class)
+ public void testSubmitQueuedNamedCallables() throws Throwable
+ {
+ final String callableName1 = "This is the first special callable name";
+ final ThreadPoolExecutor eservice =
+ new NamingThreadPoolExecutor(name, 1).corePoolSize(1).maximumPoolSize(1).daemonize();
+ assertEquals(1, eservice.getCorePoolSize());
+ assertEquals(1, eservice.getMaximumPoolSize());
+ final Future<?> future1 = eservice.submit(new NamedCallable<Object>()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+ Thread.sleep(100L);
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName1;
+ }
+ });
+ final Future<?> future2 = eservice.submit(new NamedCallable<Object>()
+ {
+ @Override
+ public Object call() throws Exception
+ {
+ assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+ Thread.sleep(100L);
+ return null;
+ }
+
+ @Override
+ public String getCallableName()
+ {
+ return callableName1;
+ }
+ });
+ try
+ {
+ future1.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ try
+ {
+ future2.get(200L, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException ex)
+ {
+ throw ex.getCause();
+ }
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + NamingThreadPoolExecutorTest.class.getSimpleName());
+ System.out.println();
+ final NamingThreadPoolExecutorTest test = new NamingThreadPoolExecutorTest();
+ for (Method m : NamingThreadPoolExecutorTest.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ if (m.getParameterTypes().length == 0)
+ {
+ System.out.println("Running " + m.getName());
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java b/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java
new file mode 100644
index 0000000..3371488
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.base.unix;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.Test;
+
+import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.base.unix.Unix.Group;
+import ch.systemsx.cisd.base.unix.Unix.Password;
+import ch.systemsx.cisd.base.unix.Unix.Stat;
+
+/**
+ * Test cases for the {@link Unix} system calls.
+ *
+ * @author Bernd Rinn
+ */
+ at Friend(toClasses = Unix.class)
+public class UnixTests extends AbstractFileSystemTestCase
+{
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoRegularFile() throws IOException
+ {
+ final short accessMode = (short) 0777;
+ final String content = "someText\n";
+ final File f = new File(workingDirectory, "someFile");
+ FileUtils.writeStringToFile(f, content);
+ Unix.setAccessMode(f.getAbsolutePath(), accessMode);
+ final Stat info = Unix.getLinkInfo(f.getAbsolutePath());
+ Unix.setOwner(f.getAbsolutePath(), info.getUid(), info.getGid());
+ assertEquals(1, info.getNumberOfHardLinks());
+ assertEquals(content.length(), info.getSize());
+ assertEquals(accessMode, info.getPermissions());
+ assertEquals("root", Unix.tryGetUserNameForUid(0));
+ assertEquals(FileLinkType.REGULAR_FILE, info.getLinkType());
+ assertFalse(info.isSymbolicLink());
+ assertEquals(f.lastModified(), 1000 * info.getLastModified());
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testGetLinkNull() throws IOException
+ {
+ Unix.getLinkInfo(null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoDirectory() throws IOException
+ {
+ final File d = new File(workingDirectory, "someDir");
+ d.mkdir();
+ final Stat info = Unix.getLinkInfo(d.getAbsolutePath());
+ assertEquals(2, info.getNumberOfHardLinks());
+ assertEquals(FileLinkType.DIRECTORY, info.getLinkType());
+ assertFalse(info.isSymbolicLink());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoSymLink() throws IOException
+ {
+ final File f = new File(workingDirectory, "someOtherFile");
+ final String content = "someMoreText\n";
+ FileUtils.writeStringToFile(f, content);
+ final File s = new File(workingDirectory, "someLink");
+ Unix.createSymbolicLink(f.getAbsolutePath(), s.getAbsolutePath());
+ final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+ assertEquals(1, info.getNumberOfHardLinks());
+ assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+ assertTrue(info.isSymbolicLink());
+ assertEquals(f.getAbsolutePath(), info.tryGetSymbolicLink());
+ assertEquals(f.getAbsolutePath(), Unix.tryReadSymbolicLink(s.getAbsolutePath()));
+ assertNull(Unix.getLinkInfo(s.getAbsolutePath(), false).tryGetSymbolicLink());
+
+ final Stat info2 = Unix.getFileInfo(s.getAbsolutePath());
+ assertEquals(1, info2.getNumberOfHardLinks());
+ assertEquals(content.length(), info2.getSize());
+ assertEquals(FileLinkType.REGULAR_FILE, info2.getLinkType());
+ assertFalse(info2.isSymbolicLink());
+ assertNull(info2.tryGetSymbolicLink());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoSymLinkDanglingLink() throws IOException
+ {
+ final File s = new File(workingDirectory, "someDanglingLink");
+ Unix.createSymbolicLink("link_to_nowhere", s.getAbsolutePath());
+ final Stat info = Unix.tryGetLinkInfo(s.getAbsolutePath());
+ assertNotNull(info);
+ assertEquals(1, info.getNumberOfHardLinks());
+ assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+ assertTrue(info.isSymbolicLink());
+ final Stat info2 = Unix.tryGetFileInfo(s.getAbsolutePath());
+ assertNull(info2);
+ assertEquals("No such file or directory", Unix.getLastError());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoNonExistent() throws IOException
+ {
+ final File s = new File(workingDirectory, "nonExistent");
+ final Stat info = Unix.tryGetLinkInfo(s.getAbsolutePath());
+ assertNull(info);
+ assertEquals("No such file or directory", Unix.getLastError());
+ final Stat info2 = Unix.tryGetFileInfo(s.getAbsolutePath());
+ assertNull(info2);
+ assertEquals("No such file or directory", Unix.getLastError());
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testCreateSymbolicLinkNull() throws IOException
+ {
+ Unix.createSymbolicLink(null, null);
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testCreateHardLinkNull() throws IOException
+ {
+ Unix.createHardLink(null, null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetLinkInfoHardLink() throws IOException
+ {
+ final File f = new File(workingDirectory, "someOtherFile");
+ f.createNewFile();
+ final File s = new File(workingDirectory, "someLink");
+ Unix.createHardLink(f.getAbsolutePath(), s.getAbsolutePath());
+ final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+ assertEquals(2, info.getNumberOfHardLinks());
+ assertEquals(FileLinkType.REGULAR_FILE, info.getLinkType());
+ assertFalse(info.isSymbolicLink());
+ assertNull(info.tryGetSymbolicLink());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetUid()
+ {
+ assertTrue(Unix.getUid() > 0);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetEuid()
+ {
+ assertTrue(Unix.getEuid() > 0);
+ assertEquals(Unix.getUid(), Unix.getEuid());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetGid()
+ {
+ assertTrue(Unix.getGid() > 0);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetEgid()
+ {
+ assertTrue(Unix.getEgid() > 0);
+ assertEquals(Unix.getGid(), Unix.getEgid());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetUidForUserName()
+ {
+ assertEquals(0, Unix.getUidForUserName("root"));
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testGetUidForUserNameNull() throws IOException
+ {
+ Unix.getUidForUserName(null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testGetGidForGroupName()
+ {
+ final String rootGroup = Unix.tryGetGroupNameForGid(0);
+ assertTrue(rootGroup, "root".equals(rootGroup) || "wheel".equals(rootGroup));
+ assertEquals(0, Unix.getGidForGroupName(rootGroup));
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testGetGidForGroupNameNull() throws IOException
+ {
+ Unix.getGidForGroupName(null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testTryGetGroupByName()
+ {
+ final String rootGroup = Unix.tryGetGroupNameForGid(0);
+ final Group group = Unix.tryGetGroupByName(rootGroup);
+ assertNotNull(group);
+ assertEquals(rootGroup, group.getGroupName());
+ assertEquals(0, group.getGid());
+ assertNotNull(group.getGroupMembers());
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testTryGetGroupByNameNull() throws IOException
+ {
+ Unix.tryGetGroupByName(null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testTryGetGroupByGid()
+ {
+ final Group group = Unix.tryGetGroupByGid(0);
+ assertNotNull(group);
+ final String rootGroup = group.getGroupName();
+ assertTrue(rootGroup, "root".equals(rootGroup) || "wheel".equals(rootGroup));
+ assertEquals(0, group.getGid());
+ assertNotNull(group.getGroupMembers());
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testTryGetUserByName()
+ {
+ final Password user = Unix.tryGetUserByName("root");
+ assertNotNull(user);
+ assertEquals("root", user.getUserName());
+ assertEquals(0, user.getUid());
+ assertEquals(0, user.getGid());
+ assertNotNull(user.getUserFullName());
+ assertNotNull(user.getHomeDirectory());
+ assertNotNull(user.getShell());
+ assertTrue(user.getShell().startsWith("/"));
+ }
+
+ @Test(groups =
+ { "requires_unix" }, expectedExceptions = NullPointerException.class)
+ public void testTryGetUserByNameNull() throws IOException
+ {
+ Unix.tryGetUserByName(null);
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testTryGetUserByUid()
+ {
+ final Password user = Unix.tryGetUserByUid(0);
+ assertNotNull(user);
+ assertEquals("root", user.getUserName());
+ assertEquals(0, user.getUid());
+ assertEquals(0, user.getGid());
+ assertNotNull(user.getUserFullName());
+ assertNotNull(user.getHomeDirectory());
+ assertNotNull(user.getShell());
+ assertTrue(user.getShell().startsWith("/"));
+ }
+
+ @Test(groups =
+ { "requires_unix" })
+ public void testDetectProcess()
+ {
+ assertTrue(Unix.canDetectProcesses());
+ assertTrue(Unix.isProcessRunningPS(Unix.getPid()));
+ }
+
+ public static void main(String[] args) throws Throwable
+ {
+ System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+ System.out.println("Test class: " + UnixTests.class.getSimpleName());
+ System.out.println();
+ if (Unix.isOperational() == false)
+ {
+ System.err.println("No unix library found.");
+ System.exit(1);
+ }
+ final UnixTests test = new UnixTests();
+ try
+ {
+ for (Method m : UnixTests.class.getMethods())
+ {
+ final Test testAnnotation = m.getAnnotation(Test.class);
+ if (testAnnotation == null)
+ {
+ continue;
+ }
+ System.out.println("Running " + m.getName());
+ test.setUp();
+ try
+ {
+ m.invoke(test);
+ } catch (InvocationTargetException wrapperThrowable)
+ {
+ final Throwable th = wrapperThrowable.getCause();
+ boolean exceptionFound = false;
+ for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+ {
+ if (expectedExClazz == th.getClass())
+ {
+ exceptionFound = true;
+ break;
+ }
+ }
+ if (exceptionFound == false)
+ {
+ throw th;
+ }
+ }
+ }
+ System.out.println("Tests OK!");
+ } finally
+ {
+ test.afterClass();
+ }
+ }
+
+}
diff --git a/sourceTest/java/tests.xml b/sourceTest/java/tests.xml
new file mode 100644
index 0000000..0a6ff5b
--- /dev/null
+++ b/sourceTest/java/tests.xml
@@ -0,0 +1,12 @@
+<suite name="All" verbose="1">
+ <test name="All">
+ <groups>
+ <run>
+ <exclude name="broken" />
+ </run>
+ </groups>
+ <packages>
+ <package name="ch.systemsx.cisd.base.*" />
+ </packages>
+ </test>
+</suite>
diff --git a/tag.sh b/tag.sh
new file mode 100755
index 0000000..a4f1cce
--- /dev/null
+++ b/tag.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ `dirname $0` != "." ]
+then
+ echo "Please run from the same directory than the script source file is in"
+ exit 1
+fi
+
+if [ $# -ne 2 ]
+then
+ echo "Usage: ./tag.sh [branch] [tag]"
+ echo ""
+ echo "Example: ./tag.sh release/13.04.x 13.04.1"
+ exit 1
+fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 2>/dev/null
+if [ $? -ne 0 ]; then echo "Branch does not exist!"; exit 1; fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1/$2 2>/dev/null
+if [ $? -eq 0 ]; then echo "Tag already exists!"; exit 1; fi
+
+svn mkdir --parents svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1 -m "create tag folders $1/$2"
+svn copy svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1/$2 -m "create tag $1/$2"
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/libsis-base-java.git
More information about the debian-med-commit
mailing list