/* * Copyright 2015 Couchbase, Inc. * * 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 org.couchbase.mock.memcached.protocol; import org.couchbase.mock.memcached.SubdocItem; import org.couchbase.mock.subdoc.Operation; import java.net.ProtocolException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; public class BinarySubdocCommand extends BinaryCommand { private final Operation subdocOp; public final static byte PATHFLAG_MKDIR_P = 0x01; public final static byte PATHFLAG_XATTR = 0x04; public final static byte PATHFLAG_EXPAND_MACROS = 0x10; public final static byte DOCFLAG_MKDOC = 0x01; public final static byte DOCFLAG_ADD = 0x02; public final static byte DOCFLAG_CREATEMASK = DOCFLAG_MKDOC | DOCFLAG_ADD; public final static byte DOCFLAG_ACCESS_DELETED = 0x04; private final static Map<CommandCode, Operation> opMap = new HashMap<CommandCode, Operation>(); static { opMap.put(CommandCode.SUBDOC_GET, Operation.GET); opMap.put(CommandCode.SUBDOC_EXISTS, Operation.EXISTS); opMap.put(CommandCode.SUBDOC_DICT_ADD, Operation.DICT_ADD); opMap.put(CommandCode.SUBDOC_DICT_UPSERT, Operation.DICT_UPSERT); opMap.put(CommandCode.SUBDOC_DELETE, Operation.REMOVE); opMap.put(CommandCode.SUBDOC_REPLACE, Operation.REPLACE); opMap.put(CommandCode.SUBDOC_ARRAY_PUSH_LAST, Operation.ARRAY_APPEND); opMap.put(CommandCode.SUBDOC_ARRAY_PUSH_FIRST, Operation.ARRAY_PREPEND); opMap.put(CommandCode.SUBDOC_ARRAY_INSERT, Operation.ARRAY_INSERT); opMap.put(CommandCode.SUBDOC_ARRAY_ADD_UNIQUE, Operation.ADD_UNIQUE); opMap.put(CommandCode.SUBDOC_COUNTER, Operation.COUNTER); opMap.put(CommandCode.SUBDOC_GET_COUNT, Operation.GET_COUNT); } BinarySubdocCommand(ByteBuffer header) throws ProtocolException { super(header); switch (extraLength) { case 3: // standard header(3) [path + pathflags] case 4: // standard header(3) + docflags(1) case 7: // standard header(3) + expiry(4) case 8: // standard header(3) + expiry(4) + docflags(1) break; default: throw new ProtocolException("Extras must be 3, 4, 7, or 8"); } subdocOp = toSubdocOpcode(getComCode()); if (subdocOp == null) { throw new ProtocolException("Unhandled opcode: " + getComCode()); } } public static Operation toSubdocOpcode(CommandCode op) { return opMap.get(op); } public byte getSubdocPathFlags() { return bodyBuffer.get(2); } public byte getSubdocDocFlags() { switch (extraLength) { case 3: // Path,PathFlags return 0; case 4: // Path, PathFlags, DocFlags return bodyBuffer.get(3); case 7: // Path, PathFlags, Expiry return 0; case 8: // Path, PathFlags, Expiry, DocFlags return bodyBuffer.get(7); default: return 0; } } public Operation getSubdocOp() { return subdocOp; } public SubdocItem getItem() { int expiryTime = 0; if (extraLength == 7) { expiryTime = bodyBuffer.getInt(3); } int pathLength = bodyBuffer.getShort(0); byte[] path = new byte[pathLength]; // Seek and read into buffer for path bodyBuffer.position(extraLength + keyLength); bodyBuffer.get(path); int valueLength = bodyLength - (keyLength + pathLength + extraLength); byte[] value = new byte[valueLength]; bodyBuffer.position(extraLength + keyLength + pathLength); bodyBuffer.get(value); return new SubdocItem(getKeySpec(), 0, expiryTime, path, value, cas); } }