Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit 3bdf04215af57e48e65ed35db509b630564bad57 0 parents
Yifeng Jiang authored
Showing with 5,218 additions and 0 deletions.
  1. +19 −0 .gitignore
  2. +3 −0  CHANGES.txt
  3. +202 −0 LICENSE.txt
  4. +3 −0  README
  5. +106 −0 build.xml
  6. +105 −0 framework/ruby/classes/Condition.rb
  7. +131 −0 framework/ruby/classes/Initialize.rb
  8. +356 −0 framework/ruby/classes/Query.rb
  9. +27 −0 framework/ruby/classes/TableMap.rb
  10. +203 −0 framework/ruby/classes/Util.rb
  11. +52 −0 framework/ruby/classes/commands/Command.rb
  12. +130 −0 framework/ruby/classes/commands/CommandHistory.rb
  13. +83 −0 framework/ruby/classes/common/String.rb
  14. +65 −0 framework/ruby/classes/const/CommandConst.rb
  15. +57 −0 framework/ruby/classes/const/ConstantsBase.rb
  16. +63 −0 framework/ruby/classes/const/DateFormat.rb
  17. +33 −0 framework/ruby/classes/const/EncodeConst.rb
  18. +80 −0 framework/ruby/classes/const/OSConst.rb
  19. +32 −0 framework/ruby/classes/const/OptionConst.rb
  20. +32 −0 framework/ruby/classes/const/ProcessMode.rb
  21. +32 −0 framework/ruby/classes/const/ViewMode.rb
  22. +46 −0 framework/ruby/classes/exception/HBaseClientException.rb
  23. +525 −0 framework/ruby/classes/tables/TableBase.rb
  24. +217 −0 framework/ruby/classes/viewer/Viewer.rb
  25. +29 −0 framework/ruby/doc/help.txt
  26. +38 −0 framework/ruby/modules/Out.rb
  27. +22 −0 framework/ruby/rdocgen.sh
  28. +109 −0 framework/ruby/sculptor.rb
  29. +115 −0 framework/src/sculptor/framework/FixedSplit.java
  30. +61 −0 framework/src/sculptor/framework/HClassDescriptor.java
  31. +565 −0 framework/src/sculptor/framework/HClient.java
  32. +40 −0 framework/src/sculptor/framework/HCompareOp.java
  33. +168 −0 framework/src/sculptor/framework/HEntity.java
  34. +60 −0 framework/src/sculptor/framework/HFieldDescriptor.java
  35. +109 −0 framework/src/sculptor/framework/HScanner.java
  36. +161 −0 framework/src/sculptor/framework/PutWrapper.java
  37. +34 −0 framework/src/sculptor/framework/annotation/Column.java
  38. +33 −0 framework/src/sculptor/framework/annotation/Rowkey.java
  39. +33 −0 framework/src/sculptor/framework/annotation/Table.java
  40. +310 −0 framework/src/sculptor/framework/util/ByteArray.java
  41. +75 −0 framework/src/sculptor/framework/util/ClassUtils.java
  42. +26 −0 ivy.xml
  43. +477 −0 sample/src/sculptor/sample/HItemData.java
  44. +117 −0 sample/src/sculptor/sample/ItemData.java
  45. +34 −0 sculptor
19 .gitignore
@@ -0,0 +1,19 @@
+*.swp
+*.jar
+*.class
+lib
+build
+framework/lib
+framework/.classpath
+framework/.project
+framework/.settings
+framework/javadoc
+framework/build
+framework/bin
+sample/lib
+sample/.classpath
+sample/.project
+sample/.settings
+sample/javadoc
+sample/build
+sample/bin
3  CHANGES.txt
@@ -0,0 +1,3 @@
+Release 0.0.1 - 2012-03-07
+
+ 1. The first release of Sculptor.
202 LICENSE.txt
@@ -0,0 +1,202 @@
+
+ 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.
3  README
@@ -0,0 +1,3 @@
+Sculptor is a framework and command line interface that makes using Apache HBase much easier.
+
+Please see the doc at the wiki page.
106 build.xml
@@ -0,0 +1,106 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<project name="sculptor" default="sample-jar" xmlns:ivy="antlib:org.apache.ivy.ant">
+ <!-- some variables used -->
+ <property name="lib.dir" value="lib" />
+ <property name="build.dir" value="build" />
+ <property name="version" value="0.0.1" />
+
+ <!-- =================================
+ target: resolve
+ ================================= -->
+ <target name="resolve" description="--> retreive dependencies with ivy">
+ <ivy:retrieve/>
+ </target>
+
+ <!-- =================================
+ target: clean
+ ================================= -->
+ <target name="clean" description="--> clean the project">
+ <delete quiet="true" includeemptydirs="true">
+ <fileset dir="${build.dir}">
+ </fileset>
+ </delete>
+ <mkdir dir="${build.dir}" />
+ <mkdir dir="${build.dir}/framework/classes" />
+ <mkdir dir="${build.dir}/sample/classes" />
+ </target>
+
+ <target name="framework-compile" depends="clean,resolve">
+ <javac
+ encoding="UTF-8"
+ srcdir="framework/src"
+ destdir="${build.dir}/framework/classes"
+ debug="true">
+ <classpath>
+ <fileset dir="${lib.dir}">
+ <include name="**/*.jar" />
+ </fileset>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="framework-jar" depends="framework-compile" description="Making sculptor-${version}.jar">
+ <jar jarfile="sculptor-${version}.jar"
+ basedir="${build.dir}/framework/classes">
+ </jar>
+ </target>
+
+ <target name="sample-compile" depends="framework-jar">
+ <javac
+ encoding="UTF-8"
+ srcdir="sample/src"
+ destdir="${build.dir}/sample/classes"
+ debug="true">
+ <classpath>
+ <fileset dir="${lib.dir}">
+ <include name="**/*.jar" />
+ </fileset>
+ <fileset dir="./">
+ <include name="*.jar" />
+ </fileset>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="sample-jar" depends="sample-compile" description="Making sculptor-sample-${version}.jar">
+ <jar jarfile="sculptor-sample-${version}.jar"
+ basedir="${build.dir}/sample/classes">
+ </jar>
+ </target>
+
+ <!-- javadoc target -->
+ <target name="javadoc" depends="clean">
+ <javadoc destdir="./javadoc"
+ encoding="UTF-8"
+ version="true"
+ docencoding="UTF-8"
+ charset="UTF-8"
+ access="public">
+ <classpath>
+ <fileset dir="${lib.dir}">
+ <include name="**/*.jar" />
+ </fileset>
+ </classpath>
+ <sourcepath path="framework/src" />
+ <package name="sculptor.*" />
+ </javadoc>
+ </target>
+
+</project>
105 framework/ruby/classes/Condition.rb
@@ -0,0 +1,105 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+#=検索条件を定義する
+#
+#
+class Condition
+ #対象のカラム名
+ attr_accessor :columnName;
+ #関係演算子
+ attr_accessor :sign;
+ #値
+ attr_accessor :value;
+ #
+ #===関係演算子をセットする
+ #
+ #==== args
+ #signEnum :: sculptor.framework.HCompareOp
+ def setSign(signEnum)
+ @sign = nil;
+ case signEnum
+ when "<"
+ @sign = HCompareOp::LESS;
+ when "<="
+ @sign = HCompareOp::LESS_OR_EQUAL;
+ when "="
+ @sign = HCompareOp::EQUAL;
+ when ">="
+ @sign = HCompareOp::GREATER_OR_EQUAL;
+ when ">"
+ @sign = HCompareOp::GREATER;
+ end
+ end
+
+ #
+ #===文字列から関係演算子Enumを取得
+ #
+ #==== args
+ #sign :: 関係演算子を表す文字列(<|<=|=|>=|>)
+ #==== return
+ #signEnum :: sculptor.framework.HCompareOp
+ def self.getEnum(sign)
+ sign = nil;
+ case sign
+ when "<"
+ sign = HCompareOp::LESS;
+ when "<="
+ sign = HCompareOp::LESS_OR_EQUAL;
+ when "="
+ sign = HCompareOp::EQUAL;
+ when ">="
+ sign = HCompareOp::GREATER_OR_EQUAL;
+ when ">"
+ sign = HCompareOp::GREATER;
+ end
+
+ return sign;
+ end
+
+ #
+ #===2値を比較する
+ #
+ #==== args
+ #value1 :: 値
+ #value2 :: 比較したい値
+ #signEnum :: sculptor.framework.HCompareOp
+ #==== return
+ #比較結果が正ならtrue
+ def self.compare(value1, value2, sign)
+ ret = false;
+
+ case sign
+ when HCompareOp::LESS
+ ret = value1.to_i < value2.to_i;
+ when HCompareOp::LESS_OR_EQUAL
+ ret = value1.to_i <= value2.to_i;
+ when HCompareOp::EQUAL
+ ret = value1 == value2;
+ when HCompareOp::GREATER_OR_EQUAL
+ ret = value1.to_i >= value2.to_i;
+ when HCompareOp::GREATER
+ ret = value1.to_i < value2.to_i;
+ end
+
+ return ret;
+ end
+end
131 framework/ruby/classes/Initialize.rb
@@ -0,0 +1,131 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require 'java'
+require 'pp'
+
+#libディレクトリのパス
+LIB_DIR = $basePath + "/../../lib/";
+#classesディレクトリのパス
+CLAASES_DIR = $basePath + "/classes/";
+#constディレクトリのパス
+CONST_DIR = CLAASES_DIR + "const/";
+#modulesディレクトリのパス
+MODULES_DIR = $basePath + "/modules/";
+#docディレクトリのパス
+DOC_DIR = $basePath + "/doc/";
+
+#apacheパッケージ
+APACHE_PACKAGE = "org.apache.";
+#data store package
+#TODO should read tables automatically
+DATASTORE_PACKAGE = "sculptor.sample";
+
+require CLAASES_DIR + 'common/String.rb'
+require CLAASES_DIR + 'commands/CommandHistory.rb';
+
+sculptorJar = "";
+#LIB_DIR直下のjarファイルをぜんぶrequire
+Dir::entries(LIB_DIR).each do |jarFile|
+ if (jarFile.endsWith(".jar"))
+ require LIB_DIR + jarFile;
+ end
+end
+
+# require sculptor.jar
+require $basePath + "/../../sculptor-0.0.1.jar"
+
+# TODO read from modules
+sculptorJar = $basePath + "/../../sculptor-sample-0.0.1.jar"
+require sculptorJar
+
+require CLAASES_DIR + 'Util.rb'
+require CLAASES_DIR + 'Query.rb'
+require CONST_DIR + 'ViewMode.rb'
+require CONST_DIR + 'ProcessMode.rb'
+require CONST_DIR + 'CommandConst.rb'
+require CONST_DIR + 'OptionConst.rb'
+require CONST_DIR + 'EncodeConst.rb'
+require CONST_DIR + 'DateFormat.rb'
+require CLAASES_DIR + 'exception/HBaseClientException.rb'
+require CLAASES_DIR + 'commands/Command.rb'
+require CLAASES_DIR + 'tables/TableBase.rb'
+require MODULES_DIR + 'Out.rb'
+
+include Out;
+
+eputs $title;
+
+import 'sculptor.framework.HCompareOp'
+import 'sculptor.framework.util.ClassUtils'
+
+tableClassNameList = ClassUtils.getJavaClasses(DATASTORE_PACKAGE, sculptorJar);
+eputs "テーブルを読み込んでいます...";
+
+#できるだけグローバルなんは避けたいけど、とりあえず
+# 表示モード。デフォルトはline
+$view_mode = ViewMode::LINE;
+# 処理モード。デフォルトはnomal
+$process_mode = ProcessMode::NORMAL;
+
+log_level = org.apache.log4j.Level::ERROR
+org.apache.log4j.Logger.getLogger("org.apache.zookeeper").setLevel(log_level)
+org.apache.log4j.Logger.getLogger("org.apache.hadoop").setLevel(log_level)
+org.apache.log4j.Logger.getLogger("sculptor").setLevel(log_level)
+
+$tableNameList = [];
+$fieldNameList = [];
+$fieldNameHash = Hash.new;
+tableClassNameList.each do |tableClassName|
+
+ begin
+ tClassName = tableClassName.sub(DATASTORE_PACKAGE + ".", "");
+
+ unless (tClassName.startsWith("H"))
+ import DATASTORE_PACKAGE + "." + tClassName;
+ tbObj = self.class.const_get(tClassName).new();
+ tableClassInfo = tbObj.getClassInfo();
+
+ tableName = tableClassInfo.getTable();
+ puts tableName;
+
+ $tableNameList << tableName;
+
+ tableClassFieldInfoList = tableClassInfo.gethFieldDescriptors();
+ tableClassFieldInfoList.each do |tableClassFieldInfo|
+ tableClassFieldName = tableClassFieldInfo.getQualifier();
+ $fieldNameList << tableClassFieldName;
+ end
+ $fieldNameHash[tableName] = $fieldNameList;
+ end
+ rescue NativeException => e
+ pp e;
+ rescue NoMethodError => e
+ pp e;
+ rescue ArgumentError => e
+ pp e;
+ rescue NameError => e
+ pp e.backtrace;
+ rescue TypeError => e
+ pp e;
+ rescue
+ end
+end
+$tableNameList = $tableNameList.uniq();
356 framework/ruby/classes/Query.rb
@@ -0,0 +1,356 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CLAASES_DIR + "Condition.rb";
+
+#
+#=HBaseClientのクエリを定義する
+#
+#
+class Query
+
+ ERROR_MSG_TEMPLATE = "%s: %sが不正です";
+ ERROR_NOT_EXISTS_MSG_TEMPLATE = "%s: %sは存在しません";
+
+ #コマンド
+ attr_accessor :operation;
+ #表示カラム名一覧
+ attr_accessor :showColumnArray;
+ #from句
+ attr_accessor :from;
+ #テーブル名
+ attr_accessor :tableName;
+ #検索条件(Conditionオブジェクト)の配列
+ attr_accessor :conditionArray;
+ #第二コマンド
+ attr_accessor :mOperation;
+ #オフセット
+ attr_accessor :offset;
+ #リミット
+ attr_accessor :limit;
+
+ public
+ #
+ #===クエリをパースし、自分自身にセットする
+ #
+ #==== args
+ #query :: クエリ文字列
+ def parse(query)
+
+ @showColumnArray = [];
+ @conditionArray = [];
+
+ # ぐーるぐる
+ Query.splitRecord(query).each_with_index do |value, index|
+ if (value != nil)
+ if (index == 0)
+ # 最初のトークン
+ #operation
+ @operation = value.downcase;
+ else
+ if (@operation == CommandConst::SET)
+ if (index == 1)
+ @mOperation = value.downcase;
+ else
+ if (@mOperation == "view")
+ # viewMode切り替え
+ if (ViewMode.isDefined(value.downcase))
+ $view_mode = value.downcase;
+ eputs "view mode : " + $view_mode;
+ else
+ errMsg = sprintf(ERROR_MSG_TEMPLATE, "表示モード", value.downcase);
+ raise HBaseClientException.new(errMsg);
+ end
+ elsif (@mOperation == "process")
+ # processMode切り替え
+ if (ProcessMode.isDefined(value.downcase))
+ $process_mode = value.downcase;
+ eputs "process mode : " + $process_mode;
+ else
+ errMsg = sprintf(ERROR_MSG_TEMPLATE, "処理モード", value.downcase);
+ raise HBaseClientException.new(errMsg);
+ end
+ end
+ end
+ elsif (@operation == CommandConst::PUT)
+ # putコマンドの場合は表示カラム名とfrom句がない
+ if (index == 1)
+ # 2番目のトークン
+ #tableName
+ @tableName = value.downcase;
+ else
+ # テーブル名以降は「カラム名=値」
+ #condition
+ condition = parseCondition(value);
+ unless (condition == nil)
+ @conditionArray << condition;
+ end
+ end
+ else
+ if (@from == nil)
+ if (value.downcase == "from")
+ #from
+ @from = value.downcase;
+ else
+ #showColumn
+ @showColumnArray << value.downcase;
+ end
+ else
+ # from句以降
+ if (@tableName == nil)
+ # from句の次はテーブル名
+ #tableName
+ @tableName = value.downcase;
+ else
+ # テーブル名以降は検索条件
+ #condition
+ condition = parseCondition(value);
+ unless (condition == nil)
+ @conditionArray << condition;
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ @offset = String::nvl(@offset, 0);
+ @limit = String::nvl(@limit, -1);
+
+ # カラム名チェック
+ Query.checkParam(self);
+ end
+
+ public
+
+ #
+ #===検索条件をパースし、Conditionオブジェクトにセット
+ #
+ #==== args
+ #query :: クエリ文字列
+ #==== return
+ #Conditionオブジェクト
+ def parseCondition(query)
+
+ condition = nil;
+ arr = query.scan(/(\S+?)([=|<|>|\s]+)(.+)/);# TODO ここの正規表現なおす
+
+ unless (arr == nil || arr == [])
+ columnName = arr[0][0].strip();
+ sign = arr[0][1].strip();
+ value = arr[0][2].strip();
+
+# p value;
+# if (value.startsWith("\"") && value.endsWith("\""))
+# value = value.slice(1..value.length - 2);
+## value = value.gsub("\"", "\\\\\\\"");
+# end
+# p value;
+ if (columnName == OptionConst::OFFSET)
+ @offset = value != nil ? value.to_i : nil;
+ elsif (columnName == OptionConst::LIMIT)
+ @limit = value != nil ? value.to_i : nil;
+ else
+ condition = Condition.new();
+ condition.columnName = columnName;
+ condition.setSign(sign);
+ condition.value = value;
+
+ if (condition.columnName() == nil || condition.sign() == nil || condition.value() == nil)
+ errMsg = sprintf(ERROR_MSG_TEMPLATE, "", query);
+ raise HBaseClientException.new(errMsg);
+ end
+ end
+ else
+ errMsg = sprintf(ERROR_MSG_TEMPLATE, "", query);
+ raise HBaseClientException.new(errMsg);
+ end
+
+ return condition;
+ end
+
+ private
+
+ #
+ #===クエリの各パラメータをチェックする
+ #
+ #==== args
+ #query Queryオブジェクト
+ #==== raise
+ #HBaseClientException
+ def self.checkParam(query)
+
+ # オペレーションのチェック
+ operation = query.operation();
+ self.checkCommand!(operation);
+
+ # テーブル名のチェック
+ tableName = query.tableName();
+ self.checkTableName(tableName);
+
+ # 表示カラム名のチェック
+ query.showColumnArray().each do |fieldName|
+ self.checkColumnName(tableName, fieldName);
+ end
+
+ if (CommandConst.isIndispensableConditionCommand(operation) && query.conditionArray() == [])
+ errMsg = operation + "コマンドには条件を必ず指定してください";
+ raise HBaseClientException.new(errMsg);
+ end
+
+ # 検索条件のカラム名のチェック
+ query.conditionArray().each do |condition|
+ self.checkColumnName(tableName, condition.columnName());
+ self.checkSyntax(condition.value());
+ end
+ end
+
+ private
+
+ #
+ #===コマンドが定義されたものかどうかチェックする
+ #※破壊メソッド
+ #
+ #==== args
+ #command :: コマンド文字列
+ def self.checkCommand!(command)
+ if (command != nil && !CommandConst.isDefined(command))
+ #raise HBaseClientException.new("コマンド: " + command + "が不正です");
+ command = CommandConst::HELP;;
+ end
+ end
+
+ private
+
+ #
+ #===テーブルが存在するものかどうかチェックする
+ #
+ #==== args
+ #tableName :: テーブル名
+ #==== raise
+ #HBaseClientException :: 指定されたテーブルが存在しない場合
+ def self.checkTableName(tableName)
+ if (tableName != nil && !$tableNameList.include?(tableName))
+ errMsg = sprintf(ERROR_NOT_EXISTS_MSG_TEMPLATE, "テーブル", tableName);
+ raise HBaseClientException.new(errMsg);
+ end
+ end
+
+ #
+ #===カラムが指定されたテーブルに存在するものかどうかチェックする
+ #
+ #==== args
+ #tableName :: テーブル名
+ #fieldName :: フィールド名
+ #==== raise
+ #HBaseClientException :: 指定されたカラムがテーブルに存在しない場合
+ def self.checkColumnName(tableName, fieldName)
+ unless (fieldName == OptionConst::OFFSET || fieldName == OptionConst::LIMIT)
+ if (tableName != nil && fieldName != nil && !$fieldNameHash[tableName].include?(fieldName))
+ errMsg = sprintf(ERROR_NOT_EXISTS_MSG_TEMPLATE, "カラム", tableName + "." + fieldName);
+ raise HBaseClientException.new(errMsg);
+ end
+ end
+ end
+
+ #
+ #===入力値のSyntaxをチェックする
+ #
+ #==== args
+ #value :: 文字列
+ #==== raise
+ #HBaseClientException
+ def self.checkSyntax(value)
+ test = nil;
+ begin
+ # evalに食わせてSyntaxErrorがないかチェックする
+ eval("test = \"" + value.to_s + "\";");
+ rescue SyntaxError => e
+ begin
+ eval("test = " + value.to_s + ";");
+ rescue SyntaxError => e
+ errMsg = sprintf(ERROR_MSG_TEMPLATE, "", value);
+ raise HBaseClientException.new(errMsg);
+ end
+ end
+ end
+
+ #
+ #===クエリ文字列を分解する
+ #
+ #==== args
+ #message :: クエリ文字列
+ #==== return
+ #分解されたクエリ文字列の配列
+ def self.splitRecord(message)
+
+ records = [];
+
+ quotStart = false;
+ msg = "";
+
+ words = message.split(/\s/);
+
+ words.each_with_index do |value, index|
+ isPut = false;
+
+ msg += value;
+
+ if (quotStart)# ダブルクォートの中
+ if (value.index("\"") != nil)# ダブルクォートが見つかった
+ isPut = true;
+ quotStart = false;
+ else
+ msg += " ";
+ end
+ else
+ if (value.index("\"") != nil)# ダブルクォートが見つかった
+ # ↓ダブルクォートのなか
+ if (value.index("\"", value.index("\"") + 1) != nil)# 二つ目のダブルクォートがみつかった
+ # ダブルクォートの外
+ isPut = true;
+ quotStart = false;
+ else
+ # ダブルクォートのなか
+ # splitで半角スペース一個なくなっちゃってるから足す
+ msg += " ";
+ quotStart = true;
+ end
+ else
+ if (msg != "")# ダブルクォートの外の半角スペースはひとつにまとめる
+ isPut = true;
+ else
+ msg = "";
+ end
+ end
+ end
+
+ # 最後の要素は無条件で追加
+ if (isPut || index + 1 == words.length())
+ records << msg;
+ msg = "";
+ end
+ end
+
+ return records;
+ end
+end
+
27 framework/ruby/classes/TableMap.rb
@@ -0,0 +1,27 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+#
+class TableMap
+ def TableMap.getTableClassName(tableName)
+ tableClassName = Marshal.load(Marshal.dump(tableName));
+ tableClassName[0, 2] = "H";
+ return tableClassName;
+ end
+end
203 framework/ruby/classes/Util.rb
@@ -0,0 +1,203 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+#=ユーティリティクラス
+#雑多に
+#
+#
+class Util
+ #
+ #===コンテンツアシストにに表示するワード一覧を取得
+ #
+ #====return
+ #コンテンツアシストにに表示するワード一覧
+ def self.getCompletionWords
+ words = [
+ "view",
+ "process",
+ "from",
+ "offset",
+ "limit"
+ ];
+ return words
+ end
+
+ #
+ #===Javaのフィールド名をrubyにあわせて変換
+ #キャメルでケースで定義されたフィールド名をスネークに変換
+ #その際にイレギュラーにも対応する
+ #
+ #==== args
+ #fName :: Javaのフィールド名
+ #==== return
+ #rubyのフィールド名
+ def self.getFieldName(fName)
+ fieldName = fName.toSnake();
+ fieldName = fieldName.sub("_i_d", "_id");
+
+ return fieldName;
+ end
+
+ #
+ #===文字列からjava.util.Dateオブジェクトを生成
+ #
+ #==== args
+ #yyyymmdd :: 日付文字列
+ #==== return
+ #指定された日付のjava.util.Dateオブジェクト
+ def self.createJavaUtilDate(yyyymmdd)
+ import 'java.util.Date';
+ import 'java.text.SimpleDateFormat';
+
+ date = nil;
+
+ if (yyyymmdd != nil)
+ yyyymmdd = yyyymmdd.to_s;
+
+ msg = "";
+ count = 0;
+
+ df = DateFormat.new;
+ while (dateFormat = df.next())
+
+ if (count > 0)
+ msg += ", ";
+ end
+ msg += dateFormat;
+
+ begin
+ sdf = SimpleDateFormat.new(dateFormat);
+ date = sdf.parse(yyyymmdd);
+ rescue NativeException
+ else
+ return date;
+ end
+ count = count + 1;
+ end
+ raise HBaseClientException.new("日付は以下のフォーマットで入力してください。" + msg);
+ end
+ end
+
+ #
+ #===java.util.Dateを指定したフォーマットの文字列に変換
+ #
+ #==== args
+ #value :: java.util.Dateオブジェクト
+ #format :: フォーマット文字列
+ #==== return
+ #指定したフォーマットの日付文字列
+ def self.JavaDate2String(value, format)
+ import 'java.util.Date';
+ import 'java.text.SimpleDateFormat';
+
+ date = SimpleDateFormat.new(format).format(value);
+
+ return date;
+ end
+
+ #
+ #===FixNum変換(nilチェックつき)
+ #
+ #==== args
+ #value :: 数値文字列
+ #==== return
+ #FixNumに変換された文字列。文字列がnilの場合はnil
+ def self.to_i_with_nil_check(value)
+ ret = nil;
+ if (value != nil)
+ ret = value.to_i;
+ end
+ return ret;
+ end
+
+ #
+ #===配列の要素の最大長を取得
+ #
+ #==== args
+ #array :: 配列
+ #==== return
+ #配列内の要素の最大長
+ def self.arrayMaxLength(array)
+ maxLength = 0;
+ array.each do |value|
+ length = value.length;
+ if (length > maxLength)
+ maxLength = length;
+ end
+ end
+ return maxLength;
+ end
+
+ #
+ #===データクラスの名前を取得する
+ #
+ #==== args
+ #tableClassName :: テーブルを表すクラスの名前
+ #==== return
+ #データクラス名
+ def self.getDataClassName(tableClassName)
+ dataClassName = Marshal.load(Marshal.dump(tableClassName));
+ dataClassName[0, 1] = "";
+ return dataClassName;
+ end
+
+ #
+ #===rubyオブジェクトをJavaオブジェクトに変換
+ #
+ #==== args
+ #value :: 値
+ #className :: Javaクラス名
+ #==== return
+ #Javaオブジェクトにキャストされた値
+ def self.toJavaClass(value, className)
+ ret = nil;
+
+ case className
+ when "java.util.Date"
+ ret = self.createJavaUtilDate(value);
+ when "int"
+ ret = self.to_i_with_nil_check(value);
+ when "java.lang.String"
+ ret = value.to_s;
+ when "byte"
+ ret = self.to_i_with_nil_check(value);
+ end
+ return ret;
+ end
+
+ #
+ #===フィールドの型を取得
+ #
+ #==== args
+ #fieldInfoList :: 検索対象のフィールド一覧
+ #fieldName :: フィールド名
+ #==== return
+ #指定したフィールドの型名
+ def self.getType(fieldInfoList, fieldName)
+ className = nil;
+ fieldInfoList.each do |fieldInfo|
+ if (fieldInfo.fieldName() == fieldName)
+ className = fieldInfo.canonicalName();
+ end
+ end
+ return className;
+ end
+end
52 framework/ruby/classes/commands/Command.rb
@@ -0,0 +1,52 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CLAASES_DIR + "TableMap.rb";
+
+#
+#=HBaseClientのコマンドを定義する
+#
+#
+class Command
+ #
+ #===コマンドを実行する
+ #
+ #==== args
+ #conf :: org.apache.hadoop.conf.Configuration
+ #query :: Query
+ #tableName :: テーブル名
+ def execute(query, tableName)
+ tableClassName = TableMap.getTableClassName(tableName);
+ clazz = TableBase.new(tableClassName, query);
+
+ operation = query.operation();
+
+ begin
+ # oprationに応じたメソッドを呼ぶ
+ eval("clazz." + operation + "();");
+ rescue NoMethodError => e
+ # 不正なコマンドの場合、helpファイルを表示することにしたので、エラー表示はなし
+ # raise HBaseClientException.new("コマンド: " + operation + "が不正です");
+ rescue SyntaxError => e
+ # すでにチェックを通過してきているので実装のミスがないとありえない
+ raise HBaseClientException.new("コマンド: " + operation + "が不正です");
+ end
+ end
+end
130 framework/ruby/classes/commands/CommandHistory.rb
@@ -0,0 +1,130 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require 'readline'
+require 'pathname'
+
+#
+#=コマンド履歴を定義する
+#
+#
+class CommandHistory
+
+ #コマンド履歴を保存するファイル
+ COMMAND_HISTORY_FILE = ".readline.history";
+ #コマンド履歴ファイルのディレクトリ
+ COMMAND_HISTORY_DIR = ".sculptor/";
+ #
+ #===Readlineを初期化する
+ #
+ #==== args
+ #*list :: (可変長)コマンド補完リストに追加する文字列の配列
+ def self.init(*lists)
+ # コンソールの補完リスト
+ words = Util.getCompletionWords();
+ # コマンド一覧
+ words = words.concat(CommandConst.getValues());
+ # オプション一覧
+ words = words.concat(OptionConst.getValues());
+ # 表示モード一覧
+ words = words.concat(ViewMode.getValues());
+ # 処理モード一覧
+ words = words.concat(ProcessMode.getValues());
+
+ lists.each do |list|
+ words = words.concat(list);
+ end
+
+ words = words.uniq();
+
+ Readline.completion_proc = proc {|word|
+ words.grep(/\A#{Regexp.quote word}/)
+ }
+ end
+
+ #
+ #===コンソールからユーザの入力を読み込む
+ #==== return
+ #ユーザの入力
+ def self.readCommand()
+ return Readline.readline("sculptor> ", true);
+ end
+
+ #
+ #===コマンド履歴をファイルから読み込む
+ #
+ #==== args
+ #userName :: ログインユーザ名
+ def self.readHistoryFile(userName)
+
+ userHomeDir = self.getHomeDir(userName);
+ userCommandHistoryFile = userHomeDir + COMMAND_HISTORY_DIR + COMMAND_HISTORY_FILE;
+
+ if (File.exist?(userCommandHistoryFile))
+ eputs "コマンド履歴を読み込んでいます...";
+ commandHistoryArray = [];
+ Pathname.new(userCommandHistoryFile).open("rb") do |f|
+ commandHistoryArray = Marshal.load(f);
+ end
+
+ commandHistoryArray.each do |commandHistory|
+ Readline::HISTORY.push(commandHistory);
+ end
+ end
+ end
+
+ #
+ #===コマンド履歴をファイルに書きこむ
+ #
+ #==== args
+ #userName :: ログインユーザ名
+ def self.writeCommandHistory(userName)
+
+ userHomeDir = self.getHomeDir(userName);
+ userCommandHitoryDir = userHomeDir + COMMAND_HISTORY_DIR;
+ if (!FileTest::directory?(userCommandHitoryDir))
+ Dir::mkdir(userCommandHitoryDir, 0777);
+ end
+
+ userCommandHistoryFile = userCommandHitoryDir + COMMAND_HISTORY_FILE;
+
+ Pathname.new(userCommandHistoryFile).open("wb") do |f|
+ Marshal.dump(Readline::HISTORY.to_a, f, 100);
+ end
+ end
+
+ #
+ #===最後に入力されたコマンドを履歴から削除する
+ #
+ def self.ignore()
+ Readline::HISTORY.pop;
+ end
+
+ private
+
+ #
+ #===ユーザのホームディレクトリを取得する
+ #
+ #==== args
+ #userName :: ログインユーザ名
+ def self.getHomeDir(userName)
+ return "/home/" + userName + "/";
+ end
+end
83 framework/ruby/classes/common/String.rb
@@ -0,0 +1,83 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+#=Stringクラスの拡張クラス
+#
+#
+class String
+ #
+ #===文字列が指定した文字列から始まっているかチェック
+ #要はJavaのstartsWithです
+ #
+ #==== args
+ #args :: 文字列
+ #==== return
+ #文字列が指定した文字列から始まっていればtrue
+ def startsWith(*args)
+ retult = false
+ for arg in args
+ result |= self[0, arg.length] == arg
+ break if result
+ end
+ result
+ end
+
+ #
+ #===文字列が指定した文字列で終わっているかチェック
+ #要はJavaのendsWithです
+ #
+ #==== args
+ #args :: 文字列
+ #==== return
+ #文字列が指定した文字列で終わっていればtrue
+ def endsWith(*args)
+ retult = false
+ for arg in args
+ result |= self[-arg.length, arg.length] == arg
+ break if result
+ end
+ result
+ end
+
+ #
+ #===キャメルケースをスネークに変換
+ #
+ def toSnake()
+ return self.split(/(?![a-z])(?=[A-Z])/).map{|s| s.downcase}.join('_')
+ end
+
+ #
+ #===スネークをキャメルケースに変換
+ #
+ def toCamel()
+ return self.split('_').map{|s| s.capitalize}.join('')
+ end
+
+ def encode(encode)
+ require 'kconv'
+
+ return self.kconv(encode, Kconv::UTF8);
+ end
+
+ def self.nvl(value, param)
+ return value == nil ? param : value;
+ end
+end
65 framework/ruby/classes/const/CommandConst.rb
@@ -0,0 +1,65 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+#
+require CONST_DIR + "ConstantsBase.rb"
+
+#
+#=コマンドを定義する
+#
+#
+class CommandConst < ConstantsBase
+ #コマンド :: set
+ SET = "set";
+ #コマンド :: get
+ GET = "get";
+ #コマンド :: put
+ PUT = "put";
+ #コマンド :: delete
+ DELETE = "delete";
+ #コマンド :: count
+ COUNT = "count";
+ #コマンド :: help
+ HELP = "help";
+ #コマンド :: exit
+ EXIT = "exit";
+ #
+ #===条件が必須なコマンド一覧を取得
+ #
+ #==== retuen
+ #条件が必須なコマンド一覧
+ def self.getIndispensableConditionCommand()
+ return [self::PUT, self::DELETE];
+ end
+
+ #
+ #===指定したコマンドが条件必須かどうかを返す
+ #
+ #==== args
+ #command :: コマンド
+ #==== return
+ #指定したコマンドが条件必須であればtrue、必須でなければfalse
+ def self.isIndispensableConditionCommand(command)
+ ret = false;
+ self.getIndispensableConditionCommand().each do |iCommand|
+ ret |= iCommand == command;
+ end
+ return ret;
+ end
+end
57 framework/ruby/classes/const/ConstantsBase.rb
@@ -0,0 +1,57 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+#
+
+#
+#=定数のベースクラス
+#
+#
+class ConstantsBase
+ #
+ #===指定した値が定義されているかどうかを返す
+ #
+ #==== args
+ #value :: 値
+ #==== return
+ #指定した値が定義されていればtrue
+ def self.isDefined(value)
+ ret = false;
+ value.gsub!(/"/, "\\\"");
+ self.constants.each do |constant|
+ eval("ret |= \"" + value.to_s + "\" == " + self.to_s + "::" + constant + ".to_s");
+ end
+ return ret;
+ end
+
+ #
+ #===定数の値一覧を返す
+ #
+ #==== return
+ #定数の値一覧
+ def self.getValues()
+ ret = [];
+
+ self.constants.each do |constant|
+ eval("ret << " + self.to_s + "::" + constant + ".to_s");
+ end
+
+ return ret;
+ end
+end
63 framework/ruby/classes/const/DateFormat.rb
@@ -0,0 +1,63 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+
+#
+#=日付フォーマットを定義する
+#
+#
+class DateFormat < ConstantsBase
+ FORMAT1 = "yyyy/MM/dd";
+ FORMAT2 = "yyyyMMdd";
+ FORMAT3 = "yyyy-MM-dd";
+
+ #
+ #===コンストラクタ
+ #
+ def initialize()
+ @index = 0;
+ @formatArray = [];
+ DateFormat.constants.each do |constant|
+ value = nil;
+ eval("value = DateFormat::" + constant + ";");
+ @formatArray << value;
+ end
+ end
+
+ #
+ #===次のindexの値を返す
+ #indexの範囲を超えるとnil
+ #
+ #==== return
+ #日付フォーマットを表す文字列
+ def next()
+ format = nil;
+
+ begin
+ format = @formatArray[@index];
+ @index = @index + 1;
+ rescue
+ format = nil;
+ end
+
+ return format;
+ end
+end
33 framework/ruby/classes/const/EncodeConst.rb
@@ -0,0 +1,33 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+require 'kconv'
+
+#
+#=オプションを定義する
+#
+#
+class EncodeConst < ConstantsBase
+ #shift_jis
+ SJIS = Kconv::SJIS;
+ #utf-8
+ UTF8 = Kconv::UTF8;
+end
80 framework/ruby/classes/const/OSConst.rb
@@ -0,0 +1,80 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+
+import APACHE_PACKAGE + 'commons.lang.SystemUtils';
+
+#
+#=OSの種類を定義する
+#
+#
+class OSConst < ConstantsBase
+ #windows XP
+ WINDOWS_XP = "windows";
+ #Linux
+ LINUX = "linux";
+ #
+ #===実行環境のOS名を取得する
+ #
+ #==== return
+ #OS名
+ def self.getOsName()
+ return SystemUtils::OS_NAME.downcase;
+ end
+
+ #
+ #===Windowsかどうか
+ #
+ #==== args
+ #os :: OSConst
+ #==== return
+ #windowsならtrue
+ def self.isWindows(os)
+ return os.downcase.startsWith(OSConst::WINDOWS_XP);
+ end
+
+ #
+ #===Linuxかどうか
+ #
+ #==== args
+ #os :: OSConst
+ #==== return
+ #linuxならtrue
+ def self.isLunux(os)
+ return os.downcase == OSConst::LINUX;
+ end
+
+ #
+ #===OSのデフォルトエンコードを取得
+ # TODO ちゃんとつくり直す
+ #
+ #==== args
+ #os :: OSConst
+ #==== return
+ #エンコード
+ def self.getDefaultEncode(os)
+ encode = EncodeConst::UTF8;
+ if (OSConst::isWindows(os))
+ encode = EncodeConst::SJIS;
+ end
+ return encode;
+ end
+end
32 framework/ruby/classes/const/OptionConst.rb
@@ -0,0 +1,32 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+
+#
+#=オプションを定義する
+#
+#
+class OptionConst < ConstantsBase
+ #offset
+ OFFSET = "offset";
+ #limit
+ LIMIT = "limit";
+end
32 framework/ruby/classes/const/ProcessMode.rb
@@ -0,0 +1,32 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+
+#
+#=処理モードを定義する
+#
+#
+class ProcessMode < ConstantsBase
+ #処理モード :: 通常
+ NORMAL = "normal";
+ #処理モード :: MapReduce
+ MAP_REDUCE = "mapreduce";
+end
32 framework/ruby/classes/const/ViewMode.rb
@@ -0,0 +1,32 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+require CONST_DIR + "ConstantsBase.rb"
+
+#
+#=表示モードを定義する
+#
+#
+class ViewMode < ConstantsBase
+ #表示モード :: ライン
+ LINE = "line";
+ #表示モード :: テーブル
+ TABLE = "table";
+end
46 framework/ruby/classes/exception/HBaseClientException.rb
@@ -0,0 +1,46 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+#=HBaseClient独自の例外を定義する
+#
+#
+class HBaseClientException < Exception
+ #独自のメッセージ
+ attr_accessor :message;
+
+ #
+ #===コンストラクタ
+ #
+ #==== args
+ #エラーメッセージ
+ def initialize(_message)
+ @message=(_message);
+ end
+
+ #
+ #===独自に設定したメッセージを取得する
+ #
+ #==== return
+ #エラーメッセージ
+ def getMessage()
+ return @message;
+ end
+end
525 framework/ruby/classes/tables/TableBase.rb
@@ -0,0 +1,525 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#require 'singleton'
+require CLAASES_DIR + "viewer/Viewer.rb";
+
+require 'pp'
+
+#
+#=データアクセスクラス
+#
+#
+class TableBase
+ # include Singleton
+
+ #テーブルのカラム名一覧
+ @columnNameArray = [];
+ @classInfo = nil;
+ @conditionHash = nil;
+
+ @query = nil;
+
+ @tableClassName = "";
+
+ public
+ #
+ #===コンストラクタ
+ #
+ def initialize(tableClassName, query)
+
+ @query = query;
+ @conditionHash = Hash.new;
+
+ @tableClassName = tableClassName;
+
+ # 結果データを保持するJavaクラス
+ begin
+ dataClass = Util.getDataClassName(@tableClassName);
+ import DATASTORE_PACKAGE + "." + dataClass;
+ import DATASTORE_PACKAGE + "." + tableClassName;
+ @dataCls = self.class.const_get(dataClass).new();
+
+ clazz = @dataCls.getClassInfo();
+
+ @classInfo = ClassInfo.new(clazz);
+ @columnNameArray = @classInfo.columnNameArray();
+ rescue => exception
+ pp exception
+ raise HBaseClientException.new("テーブル名が不正です");
+ end
+ end
+
+ #
+ #===apiのデータアクセスクラスを呼び出す
+ #
+ #==== args
+ #conf :: org.apache.hadoop.conf.Configuration
+ #==== return
+ #データアクセスクラス
+ def getInstance()
+ # if (@client == nil)
+ # new connection"
+ @client = self.class.const_get(@tableClassName).new();
+ # else
+ # # pooled connection
+ # end
+ return @client;
+ end
+
+ #
+ #===テーブルのカラム名一覧を取得
+ #
+ #==== return
+ #テーブルのカラム名一覧
+ def TableBase.GetColumnNameArray()
+ return @columnNameArray;
+ end
+
+ def get()
+ @client = self.getInstance();
+
+ setGetCondition();
+
+ isScan = validRowKey();
+
+ object = executeGet(isScan);
+
+ Viewer.getView(object, @query, isScan, @columnNameArray, @classInfo.fieldInfoList(), @client);
+
+ self.clearCondition();
+ end
+
+ def count()
+ @client = self.getInstance();
+
+ setGetCondition();
+
+ isScan = validRowKey();
+
+ count = 0;
+
+ if (isScan)
+ # scanが呼ばれた場合
+ if ($process_mode == ProcessMode::NORMAL)
+ object = executeGet(isScan);
+ if (object != nil)
+ while (object.next())
+ count = count + 1;
+ end
+ end
+ elsif ($process_mode == ProcessMode::MAP_REDUCE)
+ # 検索条件セット
+ setCondition();
+ count = @client.countMR(@dataCls, @conditionHash);
+ else
+ # モードおかしい
+ # チェック済みなのでありえないけど一応例外投げる
+ raise HBaseClientException.new("(´・ω・`)");
+ end
+ else
+ # getが呼ばれた場合
+ object = executeGet(isScan);
+ if (object != nil)
+ count = count + 1;
+ end
+ end
+
+ Viewer.countView(count);
+
+ self.clearCondition();
+ end
+
+ #
+ #===指定したレコードを削除する
+ #
+ #==== args
+ #conf ::org.apache.hadoop.conf.Configuration
+ def delete()
+
+ @client = self.getInstance();
+
+ setGetCondition();
+
+ isScan = validRowKey();
+ # まずは条件で検索する
+ object = executeGet(isScan);
+
+ # 検索結果からrowKeyを取得し、そのrowKeyでレコードを削除する
+ if (isScan)
+ # scanの場合
+ while (record = object.next())
+ rowKey = record.getRowkey();
+ @client.delete(rowKey);
+ end
+ else
+ # getの場合
+ rowKey = object.getRowkey();
+ @client.delete(rowKey);
+ end
+
+ self.clearCondition();
+ end
+
+ #
+ #===指定したレコードを挿入/更新する
+ #
+ #==== args
+ #conf ::org.apache.hadoop.conf.Configuration
+ #====raise
+ #HBaseClientException :: rowKeyが指定されていない、または不正なクエリが入力された場合
+ def put()
+
+ setGetCondition();
+
+ if (validRowKey())
+ errMgs = "";
+ count = 0;
+ @classInfo.fieldInfoList().each do |fieldInfo|
+ if (fieldInfo.rowkey)
+ condition = @conditionHash[fieldInfo.qualifier()];
+ if (condition == nil)
+ if (count > 0)
+ errMgs += ", ";
+ end
+ errMgs += fieldInfo.qualifier();
+ count = count + 1;
+ end
+ end
+ end
+ raise HBaseClientException.new("条件: " + errMgs + "は必須項目です");
+ end
+
+ @client = self.getInstance();
+
+ @query.conditionArray().each do |condition|
+
+ unless (condition.sign() == HCompareOp::EQUAL)
+ raise HBaseClientException.new("検索条件に不正な文字列があります");
+ end
+
+ fieldInfo = FieldInfo.getFieldInfoFromQualifier(@classInfo.fieldInfoList(), condition.columnName().downcase);
+ fName = fieldInfo.javaFieldName();
+
+
+ value = condition.value();
+ if (value.startsWith("\"") && value.endsWith("\""))
+ value = value.slice(1..value.length - 2);
+
+ end
+
+ className = Util.getType(@classInfo.fieldInfoList(), condition.columnName().downcase);
+
+ eval("@dataCls." + fName + " = Util.toJavaClass(value, className);");
+ end
+
+ @client.put(@dataCls);
+
+ self.clearCondition();
+ end
+
+ private
+
+ #
+ #===getの検索条件をセットする
+ #
+ #==== raise
+ #HBaseClientException
+ def setGetCondition()
+
+ @query.conditionArray().each do |condition|
+
+ begin
+ # 検索条件をセット
+ eval("@" + condition.columnName().downcase + " = \"" + condition.value() + "\";");
+ rescue SyntaxError
+ begin
+ eval("@" + condition.columnName().downcase + " = " + condition.value() + ";");
+ rescue SyntaxError
+ raise HBaseClientException.new("検索条件に不正な文字列があります");
+ end
+ end
+ @conditionHash[condition.columnName().downcase] = condition.sign();
+ end
+ end
+
+ def setCondition()
+ # 検索条件セット
+ @classInfo.fieldInfoList().each do |fieldInfo|
+ className = fieldInfo.canonicalName();
+ javaFieldName = fieldInfo.javaFieldName();
+ fieldName = fieldInfo.fieldName();
+ unless (fieldName == nil)
+ eval("@dataCls." + javaFieldName + " = Util.toJavaClass(@" + fieldName + ", className);");
+ end
+ end
+ end
+
+ #
+ #===検索を実行する
+ #
+ #==== args
+ #isScan :: apiのscanメソッドを呼ぶがどうか
+ def executeGet(isScan)
+ # 検索条件セット
+ setCondition();
+
+ return isScan ? scan() : getAndsearch();
+ end
+
+ def scan()
+ object = nil;
+ if ($process_mode == ProcessMode::NORMAL)
+ # nomalモードでは普通のscan
+ object = @client.scan(@dataCls, @conditionHash);
+ elsif ($process_mode == ProcessMode::MAP_REDUCE)
+ # mapreduceモードではscanMR
+ offset = @query.offset();
+ limit = @query.limit();
+ object = @client.scanMR(@dataCls, @conditionHash, offset, limit);
+ else
+ # モードおかしい
+ # チェック済みなのでありえないけど一応例外投げる
+ raise HBaseClientException.new("(´・ω・`)");
+ end
+
+ return object;
+ end
+
+ #
+ #===getでレコードを取得し、それに対して他の検索条件を当てていく
+ #
+ #==== return
+ #結果オブジェクト
+ def getAndsearch()
+ object = @client.get(@dataCls);
+
+ unless (object == nil)
+ # rowKey以外の項目を当てていく
+ @conditionHash.each do |key, value|
+ # 検索条件で指定したカラム名を元にJavaオブジェクトのフィールド名を取得
+ fieldInfo = FieldInfo.getFieldInfoFromQualifier(@classInfo.fieldInfoList(), key);
+ fieldName = fieldInfo.javaFieldName();
+
+ # 検索条件で指定したカラムに対応した検索結果
+ resultValue = nil;
+ eval("resultValue = object." + fieldName + ";");
+
+ # 検索条件で指定した値
+ searchValue = nil;
+ # Javaオブジェクトの型を取得
+ className = fieldInfo.canonicalName();
+
+ eval("searchValue = Util.toJavaClass(@" + key + ", className);");
+
+ # 検索条件を照らし合わせ、条件に合わない項目があれば検索結果を削除
+ unless (Condition.compare(resultValue, searchValue, value))
+ object = nil;
+ # 1件でもあればおしまい
+ break;
+ end
+ end
+ end
+
+ return object;
+ end
+
+ #
+ #===検索条件をクリアする
+ #
+ def clearCondition()
+ @classInfo.fieldInfoList().each do |fieldInfo|
+ eval("@" + fieldInfo.fieldName() + " = nil");
+ end
+
+ dataClass = Util.getDataClassName(@tableClassName);
+ @dataCls = self.class.const_get(dataClass).new();
+
+ end
+
+ #
+ #===rowkey項目が全て揃っているかどうかチェック
+ #
+ #==== return
+ #scanを呼ぶかどうか
+ def validRowKey()
+
+ isScan = false
+ isChecked = false;
+ @classInfo.fieldInfoList().each do |fieldInfo|
+ if (fieldInfo.rowkey)
+ isChecked = true;
+ isScan |= @conditionHash[fieldInfo.qualifier()] != HCompareOp::EQUAL;
+ end
+ end
+
+ if (!isChecked)
+ isScan = true;
+ end
+
+ return isScan;
+ end
+end
+
+#
+#===クラスの情報を保持する
+#
+#
+class ClassInfo
+ #クラス名
+ attr_accessor :className;
+ #クラスが表すテーブル
+ attr_accessor :table;
+ #クラスのフィールド一覧<FieldInfo>
+ attr_accessor :fieldInfoList;
+ #クラスが表すテーブルのカラム名一覧
+ attr_accessor :columnNameArray;
+ #
+ #===コンストラクタ
+ #
+ def initialize(hClassDescriptor)
+ @className=(hClassDescriptor.getClassName());
+ @table=(hClassDescriptor.getTable());
+
+ fields = hClassDescriptor.gethFieldDescriptors();
+
+ @columnNameArray = [];
+ @fieldInfoList = [];
+ fields.to_array.each_with_index do |hFieldDescriptor, index|
+
+ javaFieldName = hFieldDescriptor.getFieldName();
+ fieldName = hFieldDescriptor.getQualifier();
+ family = hFieldDescriptor.getFamily();
+ qualifier = hFieldDescriptor.getQualifier();
+ isRowkey = hFieldDescriptor.isRowkey().to_s;
+ canonicalName = hFieldDescriptor. getCanonicalName();
+
+ fieldInfo = FieldInfo.new(javaFieldName, fieldName, family, qualifier, isRowkey, canonicalName);
+
+ unless (fieldInfo.fieldName() == nil)
+ @columnNameArray << fieldName;
+ @fieldInfoList << fieldInfo;
+ end
+ end
+ end
+end
+
+#
+#===フィールドの情報を保持する
+#
+#
+class FieldInfo
+ #Javaクラスのフィールド名
+ attr_accessor :javaFieldName;
+ #フィールド名
+ attr_accessor :fieldName;
+ #データファミリー
+ attr_accessor :family;
+ #このフィールドを表す
+ attr_accessor :qualifier;
+ #このフィールドがrowKeyかどうか
+ attr_accessor :rowkey;
+ #このフィールドのJava型名(フル)
+ attr_accessor :canonicalName;
+ #
+ #===コンストラクタ
+ #
+ def initialize(_javaFieldName, _fieldName, _family, _qualifier, _isRowkey, _canonicalName)
+ @javaFieldName=(_javaFieldName);
+ @fieldName=(_fieldName);
+ @family=(_family);
+ @qualifier=(_qualifier);
+ @rowkey=(_isRowkey.to_s == "true");
+ @canonicalName=(_canonicalName);
+ end
+
+ #
+ #===qualifierから対応するフィールド名を取得する
+ #==== args
+ #fieldInfoList :: FieldInfoの配列
+ #qualifier :: qualifier
+ #==== return
+ #フィールド名
+ def self.getJavaFieldNameFromQualifier(fieldInfoList, qualifier)
+ retName = "";
+ fieldInfoList.each do |fieldInfo|
+ if (fieldInfo.qualifier() == qualifier)
+ retName = fieldInfo.javaFieldName();
+ break;
+ end
+ end
+ return retName;
+ end
+
+ #
+ #===qualifierから対応するフィールドの型を取得する
+ #
+ #==== args
+ #fieldInfoList :: FieldInfoの配列
+ #qualifier :: qualifier
+ #==== return
+ #フィールドの型名
+ def self.getCanonicalNameFromQualifier(fieldInfoList, qualifier)
+ retName = "";
+ fieldInfoList.each do |fieldInfo|
+ if (fieldInfo.qualifier() == qualifier)
+ retName = fieldInfo.canonicalName();
+ break;
+ end
+ end
+ return retName;
+ end
+
+ #
+ #===qualifierからそのフィールドがrowkeyかどうかを取得する
+ #==== args
+ #fieldInfoList :: FieldInfoの配列
+ #qualifier :: qualifier
+ #==== return
+ #rowkeyかどうか
+ def self.getRowkeyFromQualifier(fieldInfoList, qualifier)
+ ret = false;
+ fieldInfoList.each do |fieldInfo|
+ if (fieldInfo.qualifier() == qualifier)
+ ret = fieldInfo.rowkey();
+ break;
+ end
+ end
+ return ret;
+ end
+
+ #
+ #===qualifierからフィールドオブジェクトを取得する
+ #==== args
+ #fieldInfoList :: FieldInfoの配列
+ #qualifier :: qualifier
+ #==== return
+ #FieldInfo
+ def self.getFieldInfoFromQualifier(fieldInfoList, qualifier)
+ ret = false;
+ fieldInfoList.each do |fieldInfo|
+ if (fieldInfo.qualifier() == qualifier)
+ ret = fieldInfo;
+ break;
+ end
+ end
+ return ret;
+ end
+end
217 framework/ruby/classes/viewer/Viewer.rb
@@ -0,0 +1,217 @@
+#
+# Copyright 2010 The Apache Software Foundation
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+#=検索結果表示を定義する
+#
+#
+class Viewer
+ public
+ #
+ #===getコマンドの検索結果を表示する
+ #
+ #==== args
+ #obj :: frameworkから返ってきた結果オブジェクト
+ #query :: Queryオブジェクト
+ #isScan :: 検索時にscanを呼び出したかどうか
+ #columnNameArray :: 対象テーブルのカラム名一覧
+ #fieldInfoList :: 対象テーブルクラスのフィールド名一覧
+ #client ::
+ def self.getView(obj, query, isScan, columnNameArray, fieldInfoList, client)
+
+ count = 0;
+ mrOutputPath = nil;
+
+ eputs "-------- result --------";
+ if (obj == nil)
+ eputs "no data";
+ else
+ if (isScan)
+ # scanが呼ばれた場合
+ offset = query.offset();
+ limit = query.limit();
+
+ index = 1;
+ if ($process_mode == ProcessMode::NORMAL)
+ while (record = obj.next())
+ if (offset < index)
+ if (limit == -1 || index < offset + limit + 1)
+ # レコードの表示
+ eputs "----------------------";
+ self.showRecord(record, query, columnNameArray, fieldInfoList);
+ count = count + 1;
+ eputs "----------------------";
+ else
+ break;
+ end
+ end
+
+ index = index + 1;
+ end
+ elsif ($process_mode == ProcessMode::MAP_REDUCE)
+ if (obj.size() == 0)
+ eputs "no data";
+ else
+ count = obj.size();
+ if (count == 100)
+ mrOutputPath = client.getMROutputPath();
+ end
+
+ obj.each do |record|
+
+ # レコードの表示
+ eputs "----------------------";
+ self.showRecord(record, query, columnNameArray, fieldInfoList);
+ # count = count + 1;
+ eputs "----------------------";
+
+ index = index + 1;
+ end
+
+ end
+ else
+ # モードおかしい
+ # チェック済みなのでありえないけど一応例外投げる
+ raise HBaseClientException.new("(´・ω・`)");
+ end
+ else
+ # getが呼ばれた場合
+ # レコードの表示
+ self.showRecord(obj, query, columnNameArray, fieldInfoList);
+ count = count + 1;
+ end
+ end
+ eputs "-------- /result --------";
+ eputs count.to_s + " result";
+
+ unless (mrOutputPath == nil)
+ eputs "検索結果が100件を超えています。100件目以降のデータは以下をご確認ください";
+ eputs mrOutputPath;
+ end
+ end
+
+ #
+ #===countコマンドの検索結果を表示する
+ #
+ #==== args
+ #count :: 結果のカウント
+ def self.countView(count)
+
+ eputs "-------- result --------";
+ self.dispLine(CommandConst::COUNT, count, CommandConst::COUNT.length);
+ eputs "-------- /result --------";
+ eputs "1 result"
+
+ end
+
+ private
+
+ #
+ #===レコードの表示
+ #
+ #==== args
+ #record :: frameworkから返ってきた結果オブジェクト
+ #query :: Queryオブジェクト
+ #columnNameArray :: 対象テーブルのカラム名一覧
+ #fieldInfoList :: 対象テーブルクラスのフィールド名一覧
+ def self.showRecord(record, query, columnNameArray, fieldInfoList)
+
+ # ユーザが指定した表示カラム一覧
+ showColumnArray = query.showColumnArray();
+ if (showColumnArray == [])
+ # 表示カラムの指定がない場合は全カラム表示
+ showColumnArray = columnNameArray;
+ end
+ # padding用にカラム名の最大長を取得
+ maxColumnNameLength = Util.arrayMaxLength(showColumnArray);
+
+ # カラム名のリストをぐーるぐる
+ showColumnArray.each do |columnName|
+ value = "";
+ fieldInfo = FieldInfo.getFieldInfoFromQualifier(fieldInfoList, columnName);
+ fieldName = fieldInfo.javaFieldName();
+
+ begin
+ # 動的にItemRankingの変数を呼び出して値にセット
+ eval("value = record." + fieldName);
+ if (fieldInfo.rowkey())
+ columnName = "*" + columnName;
+ end
+ rescue SyntaxError
+ raise HBaseClientException.new("カラム名が不正です");
+ end
+ if ($view_mode == ViewMode::LINE)
+ # 表示モード:line
+ # 1件表示
+ self.dispLine(columnName, value, maxColumnNameLength);
+ else
+ # 1項目
+ self.dispLineOnTableMode(columnName, value, true);
+ end
+ end
+ end
+
+ #
+ #===[カラム名 => 値]を表示する
+ #カラム名は最長のものに合わせてpaddingされる
+ #
+ #==== args
+ #columnName :: カラム名
+ #value :: 値
+ #maxColumnNameLength :: カラム名の最大長
+ def self.dispLine(columnName, value, maxColumnNameLength)
+ if (value.kind_of?(Java::JavaUtil::Date))
+ # Date型の場合、yyyy/MM/ddに整形する
+ value = Util.JavaDate2String(value, DateFormat::FORMAT1);
+ elsif (value.kind_of?(Java::JavaUtil::List))
+ # List型の場合、展開し、カンマつなぎの文字列にする
+ tmpValue = "";