PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RowSpec.java

https://github.com/haoyuan/hbase
Java | 408 lines | 344 code | 33 blank | 31 comment | 74 complexity | 6ab65705690c26b100d1d33341f1299f MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. package org.apache.hadoop.hbase.rest;
  20. import java.io.UnsupportedEncodingException;
  21. import java.net.URLDecoder;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.List;
  25. import java.util.TreeSet;
  26. import org.apache.hadoop.classification.InterfaceAudience;
  27. import org.apache.hadoop.hbase.HConstants;
  28. import org.apache.hadoop.hbase.util.Bytes;
  29. /**
  30. * Parses a path based row/column/timestamp specification into its component
  31. * elements.
  32. * <p>
  33. *
  34. */
  35. @InterfaceAudience.Private
  36. public class RowSpec {
  37. public static final long DEFAULT_START_TIMESTAMP = 0;
  38. public static final long DEFAULT_END_TIMESTAMP = Long.MAX_VALUE;
  39. private byte[] row = HConstants.EMPTY_START_ROW;
  40. private byte[] endRow = null;
  41. private TreeSet<byte[]> columns =
  42. new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
  43. private List<String> labels = new ArrayList<String>();
  44. private long startTime = DEFAULT_START_TIMESTAMP;
  45. private long endTime = DEFAULT_END_TIMESTAMP;
  46. private int maxVersions = 1;
  47. private int maxValues = Integer.MAX_VALUE;
  48. public RowSpec(String path) throws IllegalArgumentException {
  49. int i = 0;
  50. while (path.charAt(i) == '/') {
  51. i++;
  52. }
  53. i = parseRowKeys(path, i);
  54. i = parseColumns(path, i);
  55. i = parseTimestamp(path, i);
  56. i = parseQueryParams(path, i);
  57. }
  58. private int parseRowKeys(final String path, int i)
  59. throws IllegalArgumentException {
  60. String startRow = null, endRow = null;
  61. try {
  62. StringBuilder sb = new StringBuilder();
  63. char c;
  64. while (i < path.length() && (c = path.charAt(i)) != '/') {
  65. sb.append(c);
  66. i++;
  67. }
  68. i++;
  69. String row = startRow = sb.toString();
  70. int idx = startRow.indexOf(',');
  71. if (idx != -1) {
  72. startRow = URLDecoder.decode(row.substring(0, idx),
  73. HConstants.UTF8_ENCODING);
  74. endRow = URLDecoder.decode(row.substring(idx + 1),
  75. HConstants.UTF8_ENCODING);
  76. } else {
  77. startRow = URLDecoder.decode(row, HConstants.UTF8_ENCODING);
  78. }
  79. } catch (IndexOutOfBoundsException e) {
  80. throw new IllegalArgumentException(e);
  81. } catch (UnsupportedEncodingException e) {
  82. throw new RuntimeException(e);
  83. }
  84. // HBase does not support wildcards on row keys so we will emulate a
  85. // suffix glob by synthesizing appropriate start and end row keys for
  86. // table scanning
  87. if (startRow.charAt(startRow.length() - 1) == '*') {
  88. if (endRow != null)
  89. throw new IllegalArgumentException("invalid path: start row "+
  90. "specified with wildcard");
  91. this.row = Bytes.toBytes(startRow.substring(0,
  92. startRow.lastIndexOf("*")));
  93. this.endRow = new byte[this.row.length + 1];
  94. System.arraycopy(this.row, 0, this.endRow, 0, this.row.length);
  95. this.endRow[this.row.length] = (byte)255;
  96. } else {
  97. this.row = Bytes.toBytes(startRow.toString());
  98. if (endRow != null) {
  99. this.endRow = Bytes.toBytes(endRow.toString());
  100. }
  101. }
  102. return i;
  103. }
  104. private int parseColumns(final String path, int i) throws IllegalArgumentException {
  105. if (i >= path.length()) {
  106. return i;
  107. }
  108. try {
  109. char c;
  110. StringBuilder column = new StringBuilder();
  111. while (i < path.length() && (c = path.charAt(i)) != '/') {
  112. if (c == ',') {
  113. if (column.length() < 1) {
  114. throw new IllegalArgumentException("invalid path");
  115. }
  116. String s = URLDecoder.decode(column.toString(), HConstants.UTF8_ENCODING);
  117. this.columns.add(Bytes.toBytes(s));
  118. column.setLength(0);
  119. i++;
  120. continue;
  121. }
  122. column.append(c);
  123. i++;
  124. }
  125. i++;
  126. // trailing list entry
  127. if (column.length() > 0) {
  128. String s = URLDecoder.decode(column.toString(), HConstants.UTF8_ENCODING);
  129. this.columns.add(Bytes.toBytes(s));
  130. }
  131. } catch (IndexOutOfBoundsException e) {
  132. throw new IllegalArgumentException(e);
  133. } catch (UnsupportedEncodingException e) {
  134. // shouldn't happen
  135. throw new RuntimeException(e);
  136. }
  137. return i;
  138. }
  139. private int parseTimestamp(final String path, int i)
  140. throws IllegalArgumentException {
  141. if (i >= path.length()) {
  142. return i;
  143. }
  144. long time0 = 0, time1 = 0;
  145. try {
  146. char c = 0;
  147. StringBuilder stamp = new StringBuilder();
  148. while (i < path.length()) {
  149. c = path.charAt(i);
  150. if (c == '/' || c == ',') {
  151. break;
  152. }
  153. stamp.append(c);
  154. i++;
  155. }
  156. try {
  157. time0 = Long.valueOf(URLDecoder.decode(stamp.toString(),
  158. HConstants.UTF8_ENCODING));
  159. } catch (NumberFormatException e) {
  160. throw new IllegalArgumentException(e);
  161. }
  162. if (c == ',') {
  163. stamp = new StringBuilder();
  164. i++;
  165. while (i < path.length() && ((c = path.charAt(i)) != '/')) {
  166. stamp.append(c);
  167. i++;
  168. }
  169. try {
  170. time1 = Long.valueOf(URLDecoder.decode(stamp.toString(),
  171. HConstants.UTF8_ENCODING));
  172. } catch (NumberFormatException e) {
  173. throw new IllegalArgumentException(e);
  174. }
  175. }
  176. if (c == '/') {
  177. i++;
  178. }
  179. } catch (IndexOutOfBoundsException e) {
  180. throw new IllegalArgumentException(e);
  181. } catch (UnsupportedEncodingException e) {
  182. // shouldn't happen
  183. throw new RuntimeException(e);
  184. }
  185. if (time1 != 0) {
  186. startTime = time0;
  187. endTime = time1;
  188. } else {
  189. endTime = time0;
  190. }
  191. return i;
  192. }
  193. private int parseQueryParams(final String path, int i) {
  194. if (i >= path.length()) {
  195. return i;
  196. }
  197. StringBuilder query = new StringBuilder();
  198. try {
  199. query.append(URLDecoder.decode(path.substring(i),
  200. HConstants.UTF8_ENCODING));
  201. } catch (UnsupportedEncodingException e) {
  202. // should not happen
  203. throw new RuntimeException(e);
  204. }
  205. i += query.length();
  206. int j = 0;
  207. while (j < query.length()) {
  208. char c = query.charAt(j);
  209. if (c != '?' && c != '&') {
  210. break;
  211. }
  212. if (++j > query.length()) {
  213. throw new IllegalArgumentException("malformed query parameter");
  214. }
  215. char what = query.charAt(j);
  216. if (++j > query.length()) {
  217. break;
  218. }
  219. c = query.charAt(j);
  220. if (c != '=') {
  221. throw new IllegalArgumentException("malformed query parameter");
  222. }
  223. if (++j > query.length()) {
  224. break;
  225. }
  226. switch (what) {
  227. case 'm': {
  228. StringBuilder sb = new StringBuilder();
  229. while (j <= query.length()) {
  230. c = query.charAt(j);
  231. if (c < '0' || c > '9') {
  232. j--;
  233. break;
  234. }
  235. sb.append(c);
  236. }
  237. maxVersions = Integer.valueOf(sb.toString());
  238. } break;
  239. case 'n': {
  240. StringBuilder sb = new StringBuilder();
  241. while (j <= query.length()) {
  242. c = query.charAt(j);
  243. if (c < '0' || c > '9') {
  244. j--;
  245. break;
  246. }
  247. sb.append(c);
  248. }
  249. maxValues = Integer.valueOf(sb.toString());
  250. } break;
  251. default:
  252. throw new IllegalArgumentException("unknown parameter '" + c + "'");
  253. }
  254. }
  255. return i;
  256. }
  257. public RowSpec(byte[] startRow, byte[] endRow, byte[][] columns,
  258. long startTime, long endTime, int maxVersions) {
  259. this.row = startRow;
  260. this.endRow = endRow;
  261. if (columns != null) {
  262. for (byte[] col: columns) {
  263. this.columns.add(col);
  264. }
  265. }
  266. this.startTime = startTime;
  267. this.endTime = endTime;
  268. this.maxVersions = maxVersions;
  269. }
  270. public RowSpec(byte[] startRow, byte[] endRow, Collection<byte[]> columns,
  271. long startTime, long endTime, int maxVersions, Collection<String> labels) {
  272. this(startRow, endRow, columns, startTime, endTime, maxVersions);
  273. if(labels != null) {
  274. this.labels.addAll(labels);
  275. }
  276. }
  277. public RowSpec(byte[] startRow, byte[] endRow, Collection<byte[]> columns,
  278. long startTime, long endTime, int maxVersions) {
  279. this.row = startRow;
  280. this.endRow = endRow;
  281. if (columns != null) {
  282. this.columns.addAll(columns);
  283. }
  284. this.startTime = startTime;
  285. this.endTime = endTime;
  286. this.maxVersions = maxVersions;
  287. }
  288. public boolean isSingleRow() {
  289. return endRow == null;
  290. }
  291. public int getMaxVersions() {
  292. return maxVersions;
  293. }
  294. public void setMaxVersions(final int maxVersions) {
  295. this.maxVersions = maxVersions;
  296. }
  297. public int getMaxValues() {
  298. return maxValues;
  299. }
  300. public void setMaxValues(final int maxValues) {
  301. this.maxValues = maxValues;
  302. }
  303. public boolean hasColumns() {
  304. return !columns.isEmpty();
  305. }
  306. public boolean hasLabels() {
  307. return !labels.isEmpty();
  308. }
  309. public byte[] getRow() {
  310. return row;
  311. }
  312. public byte[] getStartRow() {
  313. return row;
  314. }
  315. public boolean hasEndRow() {
  316. return endRow != null;
  317. }
  318. public byte[] getEndRow() {
  319. return endRow;
  320. }
  321. public void addColumn(final byte[] column) {
  322. columns.add(column);
  323. }
  324. public byte[][] getColumns() {
  325. return columns.toArray(new byte[columns.size()][]);
  326. }
  327. public List<String> getLabels() {
  328. return labels;
  329. }
  330. public boolean hasTimestamp() {
  331. return (startTime == 0) && (endTime != Long.MAX_VALUE);
  332. }
  333. public long getTimestamp() {
  334. return endTime;
  335. }
  336. public long getStartTime() {
  337. return startTime;
  338. }
  339. public void setStartTime(final long startTime) {
  340. this.startTime = startTime;
  341. }
  342. public long getEndTime() {
  343. return endTime;
  344. }
  345. public void setEndTime(long endTime) {
  346. this.endTime = endTime;
  347. }
  348. public String toString() {
  349. StringBuilder result = new StringBuilder();
  350. result.append("{startRow => '");
  351. if (row != null) {
  352. result.append(Bytes.toString(row));
  353. }
  354. result.append("', endRow => '");
  355. if (endRow != null) {
  356. result.append(Bytes.toString(endRow));
  357. }
  358. result.append("', columns => [");
  359. for (byte[] col: columns) {
  360. result.append(" '");
  361. result.append(Bytes.toString(col));
  362. result.append("'");
  363. }
  364. result.append(" ], startTime => ");
  365. result.append(Long.toString(startTime));
  366. result.append(", endTime => ");
  367. result.append(Long.toString(endTime));
  368. result.append(", maxVersions => ");
  369. result.append(Integer.toString(maxVersions));
  370. result.append(", maxValues => ");
  371. result.append(Integer.toString(maxValues));
  372. result.append("}");
  373. return result.toString();
  374. }
  375. }