/**
* Copyright 2011 Membase, 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;
import com.google.gson.JsonObject;
import org.couchbase.mock.util.Base64;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Date;
/**
* @author Trond Norbye
*/
public class Item {
private final KeySpec keySpec;
private final int flags;
private int expiryTime;
private byte[] xattr;
private byte[] value;
private String cached_UTF8 = null;
private String cached_B64 = null;
private long cas;
private long modificationTime;
final static private Charset UTF8_CHARSET = Charset.forName("UTF-8");
/** When the lock expires, if any */
private int lockExpiryTime;
public Item(KeySpec ks, int flags, int expiryTime, byte[] value, byte[] xattr, long cas) {
this.keySpec = ks;
this.flags = flags;
this.value = value;
this.xattr = xattr;
this.cas = cas;
this.expiryTime = VBucketStore.convertExpiryTime(expiryTime);
}
public Item(KeySpec ks) {
this.keySpec = ks;
this.flags = -1;
this.expiryTime = -1;
this.value = null;
this.xattr = null;
this.cas = -1;
this.modificationTime = -1;
}
/**
* Copy constructor
* @param src Item whose contents we should copy
*/
public Item(Item src) {
this.keySpec = src.keySpec;
this.flags = src.flags;
this.expiryTime = src.expiryTime;
this.value = src.value;
this.cas = src.cas;
this.modificationTime = src.modificationTime;
this.lockExpiryTime = src.lockExpiryTime;
this.cached_B64 = src.cached_B64;
this.cached_UTF8 = src.cached_UTF8;
this.xattr = src.xattr;
}
public int getExpiryTime() {
return expiryTime;
}
public long getExpiryTimeInMillis() {
return (long) expiryTime * 1000L;
}
public void setExpiryTime(int e) {
expiryTime = VBucketStore.convertExpiryTime(e);
}
public long getModificationTime() {
return modificationTime;
}
public int getFlags() {
return flags;
}
public KeySpec getKeySpec() {
return this.keySpec;
}
public byte[] getValue() {
return value;
}
public byte[] getXattr() {
return xattr;
}
public String getUtf8() throws CharacterCodingException {
if (cached_UTF8 != null) {
return cached_UTF8;
}
CharsetDecoder dec = UTF8_CHARSET.newDecoder();
cached_UTF8 = dec.decode(ByteBuffer.wrap(value)).toString();
return cached_UTF8;
}
public String getBase64() {
if (cached_B64 != null) {
return cached_B64;
} else {
cached_B64 = Base64.encode(value);
return cached_B64;
}
}
public long getCas() {
return cas;
}
void setCas(long l) {
modificationTime = new Date().getTime();
cas = l;
}
void setLockExpiryTime(int e) {
lockExpiryTime = VBucketStore.convertExpiryTime(e);
}
int getLockExpiryTime() {
return lockExpiryTime;
}
public boolean isLocked() {
if (lockExpiryTime == 0) {
return false;
}
long now = new Date().getTime() / 1000;
return now <= lockExpiryTime;
}
/**
* Given a cas, ensure that the item is unlocked.
* Will succeed if cas matches the existing cas, or if the item is not
* locked
* @param cas the cas value used to perform the operation
* @return true if item is *not* locked.
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean ensureUnlocked(long cas)
{
if (cas == this.cas) {
lockExpiryTime = 0;
return true;
} else {
return !isLocked();
}
}
public void append(Item i) {
byte[] s1 = value;
byte[] s2 = i.getValue();
byte[] dst = new byte[s1.length + s2.length];
System.arraycopy(s1, 0, dst, 0, s1.length);
System.arraycopy(s2, 0, dst, s1.length, s2.length);
value = dst;
}
public void prepend(Item i) {
byte[] s1 = value;
byte[] s2 = i.getValue();
byte[] dst = new byte[s1.length + s2.length];
System.arraycopy(s2, 0, dst, 0, s2.length);
System.arraycopy(s1, 0, dst, s2.length, s1.length);
value = dst;
}
}