/** *Copyright [2010-2011] [dennis zhuang(killme2008@gmail.com)] *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 com.google.code.hs4j.command.text; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.google.code.hs4j.Filter; import com.google.code.hs4j.FindOperator; import com.google.code.hs4j.impl.ResultSetImpl; import com.google.code.hs4j.network.buffer.IoBuffer; import com.google.code.hs4j.network.hs.HandlerSocketSession; import com.google.code.hs4j.utils.HSUtils; /** * A find command * * @author dennis * @date 2010-11-27 */ public class FindCommand extends AbstractCommand { private static final Filter[] EMPTY_FILTER = new Filter[0]; private final String id; private final String operator; private final String[] keys; private final int limit; private final int offset; private final String[] fieldList; private Filter[] filters; public FindCommand(String id, FindOperator operator, String[] keys, int limit, int offset, String[] fieldList){ this(id, operator, keys, limit, offset, fieldList, null); } public FindCommand(String id, FindOperator operator, String[] keys, int limit, int offset, String[] fieldList, Filter[] filters) { super(); this.id = id; this.operator = operator.getValue(); this.keys = keys; this.limit = limit; this.offset = offset; this.fieldList = fieldList; if(filters !=null) this.filters = filters; else this.filters = EMPTY_FILTER; } @Override protected void onDone() { if (this.result == null) { this.result = new ResultSetImpl(Collections .<List<byte[]>> emptyList(), this.fieldList, this.encoding); } } @Override protected void decodeBody(HandlerSocketSession session, byte[] data, int index) { List<List<byte[]>> rows = new ArrayList<List<byte[]>>(this .getNumColumns()); int colOffset = 0; int cols = this.fieldList.length; List<byte[]> currentRow = new ArrayList<byte[]>(this.fieldList.length); int currentCols = 0; int colBytesSize = 0; for (int i = 0; i < data.length; i++) { if (data[i] == TOKEN_SEPARATOR || data[i] == COMMAND_TERMINATE) { /** * Patched by sam.tingleff * "A character in the range [0x00 - 0x0f] is prefixed by 0x01 and shifted by 0x40" */ byte[] colData = new byte[colBytesSize]; boolean shift = false; int colDataIndex = 0; // j must be less than i for (int j = colOffset; j < i; ++j) { byte b = data[j]; if (b == 0x01) shift = true; else { colData[colDataIndex] = (shift) ? (byte) (b & ~0x40) : b; shift = false; ++colDataIndex; } } currentRow.add(colData); colBytesSize = 0; // colBytesSize must reset to zero currentCols++; colOffset = i + 1; if (currentCols == cols) { currentCols = 0; rows.add(currentRow); currentRow = new ArrayList<byte[]>(this.fieldList.length); } } else if (data[i] != 0x01) { ++colBytesSize; } } if (!currentRow.isEmpty()) { rows.add(currentRow); } this.result = new ResultSetImpl(rows, this.fieldList, this.encoding); } public void encode() { String kenLen = String.valueOf(this.keys.length); String limitStr = String.valueOf(this.limit); String offsetStr = String.valueOf(this.offset); byte[][] keyBytes = HSUtils.getByteArrayFromStringArray(keys,this.encoding); int flen = filters.length; String ftype[] = new String[flen]; String fop[] = new String[flen]; String fcol[] = new String[flen]; byte fval[][] = new byte[flen][]; int filterAllLength=0; for(int i=0; i< flen;i++) { Filter f = filters[i]; ftype[i] = f.getType().getValue(); fop[i] = f.getOperator().getValue(); fcol[i] = String.valueOf(f.getColumn()); fval[i] = HSUtils.decodeString(f.getValue(),this.encoding); filterAllLength += ftype[i].length()+1 + fop.length+1 + fcol[i].length()+1 + fval[i].length+1; } int capacity = this.id.length() + 1 + this.operator.length() + 1 + kenLen.length() + 1 + this.length(keyBytes) + this.keys.length + limitStr.length() + 1 + offsetStr.length() + 1 + filterAllLength+1; IoBuffer buf = IoBuffer.allocate(capacity); buf.setAutoExpand(true); // id this.writeToken(buf, this.id); this.writeTokenSeparator(buf); // operator this.writeToken(buf, this.operator); this.writeTokenSeparator(buf); // value nums this.writeToken(buf, kenLen); this.writeTokenSeparator(buf); for (byte[] data : keyBytes) { this.writeToken(buf, data); this.writeTokenSeparator(buf); } // limit this.writeToken(buf, limitStr); this.writeTokenSeparator(buf); // offset this.writeToken(buf, offsetStr); // filter for(int i=0; i< flen;i++) { this.writeTokenSeparator(buf); // filter type this.writeToken(buf, ftype[i]); this.writeTokenSeparator(buf); // filter operator this.writeToken(buf, fop[i]); this.writeTokenSeparator(buf); // filter column this.writeToken(buf, fcol[i]); this.writeTokenSeparator(buf); // filter value this.writeToken(buf, fval[i]); } this.writeCommandTerminate(buf); buf.flip(); this.buffer = buf; } }