Implementing the Binary Memcache protocol
This changeset implements the full memcache binary protocol spec, including a first batch of tests. Ascii protocol and more coverage and helper classes will follow.
This commit is contained in:
parent
ebc78dab1d
commit
20f6f7e018
45
codec-memcache/pom.xml
Normal file
45
codec-memcache/pom.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2013 The Netty Project
|
||||||
|
~
|
||||||
|
~ The Netty Project 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 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-parent</artifactId>
|
||||||
|
<version>4.0.16.Final-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>netty-codec-memcache</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Netty/Codec/Memcache</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>netty-codec</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>netty-handler</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation for the {@link LastMemcacheContent}.
|
||||||
|
*/
|
||||||
|
public class DefaultLastMemcacheContent extends DefaultMemcacheContent implements LastMemcacheContent {
|
||||||
|
|
||||||
|
public DefaultLastMemcacheContent() {
|
||||||
|
super(Unpooled.buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultLastMemcacheContent(ByteBuf content) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent retain() {
|
||||||
|
super.retain();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent retain(int increment) {
|
||||||
|
super.retain(increment);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent copy() {
|
||||||
|
return new DefaultLastMemcacheContent(content().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent duplicate() {
|
||||||
|
return new DefaultLastMemcacheContent(content().duplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default {@link MemcacheContent} implementation.
|
||||||
|
*/
|
||||||
|
public class DefaultMemcacheContent extends DefaultMemcacheObject implements MemcacheContent {
|
||||||
|
|
||||||
|
private final ByteBuf content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance with the specified content.
|
||||||
|
*/
|
||||||
|
public DefaultMemcacheContent(ByteBuf content) {
|
||||||
|
if (content == null) {
|
||||||
|
throw new NullPointerException("Content cannot be null.");
|
||||||
|
}
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf content() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemcacheContent copy() {
|
||||||
|
return new DefaultMemcacheContent(content.copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemcacheContent duplicate() {
|
||||||
|
return new DefaultMemcacheContent(content.duplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int refCnt() {
|
||||||
|
return content.refCnt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemcacheContent retain() {
|
||||||
|
content.retain();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemcacheContent retain(int increment) {
|
||||||
|
content.retain(increment);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release() {
|
||||||
|
return content.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(int decrement) {
|
||||||
|
return content.release(decrement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "(data: " + content() + ", getDecoderResult: " + getDecoderResult() + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
import io.netty.util.AbstractReferenceCounted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default {@link MemcacheObject} implementation.
|
||||||
|
*/
|
||||||
|
public abstract class DefaultMemcacheObject implements MemcacheObject {
|
||||||
|
|
||||||
|
private DecoderResult decoderResult = DecoderResult.SUCCESS;
|
||||||
|
|
||||||
|
protected DefaultMemcacheObject() {
|
||||||
|
// Disallow direct instantiation
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecoderResult getDecoderResult() {
|
||||||
|
return decoderResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDecoderResult(DecoderResult result) {
|
||||||
|
if (result == null) {
|
||||||
|
throw new NullPointerException("DecoderResult should not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
decoderResult = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines {@link MemcacheMessage} and {@link LastMemcacheContent} into one
|
||||||
|
* message. So it represent a <i>complete</i> memcache message.
|
||||||
|
*/
|
||||||
|
public interface FullMemcacheMessage extends MemcacheMessage, LastMemcacheContent {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullMemcacheMessage copy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullMemcacheMessage retain(int increment);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullMemcacheMessage retain();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullMemcacheMessage duplicate();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MemcacheContent} which signals the end of the content batch.
|
||||||
|
* <p/>
|
||||||
|
* Note that by design, even when no content is emitted by the protocol, an
|
||||||
|
* empty {@link LastMemcacheContent} is issued to make the upstream parsing
|
||||||
|
* easier.
|
||||||
|
*/
|
||||||
|
public interface LastMemcacheContent extends MemcacheContent {
|
||||||
|
|
||||||
|
LastMemcacheContent EMPTY_LAST_CONTENT = new LastMemcacheContent() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent copy() {
|
||||||
|
return EMPTY_LAST_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent retain(int increment) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent retain() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LastMemcacheContent duplicate() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf content() {
|
||||||
|
return Unpooled.EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecoderResult getDecoderResult() {
|
||||||
|
return DecoderResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDecoderResult(DecoderResult result) {
|
||||||
|
throw new UnsupportedOperationException("read only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int refCnt() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(int decrement) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LastMemcacheContent copy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LastMemcacheContent retain(int increment);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LastMemcacheContent retain();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LastMemcacheContent duplicate();
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Memcache content chunk.
|
||||||
|
* <p/>
|
||||||
|
* A MemcacheObjectDecoder generates {@link MemcacheContent} after
|
||||||
|
* {@link MemcacheMessage} when the content is large. If you prefer not to
|
||||||
|
* receive {@link MemcacheContent} in your handler, place a aggregator
|
||||||
|
* after MemcacheObjectDecoder in the {@link io.netty.channel.ChannelPipeline}.
|
||||||
|
*/
|
||||||
|
public interface MemcacheContent extends MemcacheObject, ByteBufHolder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MemcacheContent copy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MemcacheContent duplicate();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MemcacheContent retain();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MemcacheContent retain(int increment);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.util.ReferenceCounted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for both ascii and binary messages.
|
||||||
|
*/
|
||||||
|
public interface MemcacheMessage extends MemcacheObject, ReferenceCounted {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the reference count by {@code 1}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
MemcacheMessage retain();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the reference count by the specified {@code increment}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
MemcacheMessage retain(int increment);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a common interface for all {@link MemcacheObject} implementations.
|
||||||
|
*/
|
||||||
|
public interface MemcacheObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of decoding this message.
|
||||||
|
*/
|
||||||
|
DecoderResult getDecoderResult();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the result of decoding this message.
|
||||||
|
* <p/>
|
||||||
|
* <p>Do not call this method unless you know what you are doing.</p>
|
||||||
|
*/
|
||||||
|
void setDecoderResult(DecoderResult result);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link io.netty.channel.ChannelHandler} that aggregates an {@link MemcacheMessage}
|
||||||
|
* and its following {@link MemcacheContent}s into a single {@link MemcacheMessage} with
|
||||||
|
* no following {@link MemcacheContent}s. It is useful when you don't want to take
|
||||||
|
* care of memcache messages where the content comes along in chunks. Insert this
|
||||||
|
* handler after a MemcacheObjectDecoder in the {@link io.netty.channel.ChannelPipeline}.
|
||||||
|
* <p/>
|
||||||
|
* For example, here for the binary protocol:
|
||||||
|
* <p/>
|
||||||
|
* <pre>
|
||||||
|
* {@link io.netty.channel.ChannelPipeline} p = ...;
|
||||||
|
* ...
|
||||||
|
* p.addLast("decoder", new {@link io.netty.handler.codec.memcache.binary.BinaryMemcacheRequestDecoder}());
|
||||||
|
* p.addLast("aggregator", <b>new {@link MemcacheObjectAggregator}(1048576)</b>);
|
||||||
|
* ...
|
||||||
|
* p.addLast("encoder", new {@link io.netty.handler.codec.memcache.binary.BinaryMemcacheResponseEncoder}());
|
||||||
|
* p.addLast("handler", new YourMemcacheRequestHandler());
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public abstract class MemcacheObjectAggregator extends MessageToMessageDecoder<MemcacheObject> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the current message that gets aggregated.
|
||||||
|
*/
|
||||||
|
protected FullMemcacheMessage currentMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the current channel handler context if set.
|
||||||
|
*/
|
||||||
|
protected ChannelHandlerContext ctx;
|
||||||
|
|
||||||
|
public static final int DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS = 1024;
|
||||||
|
|
||||||
|
private int maxCumulationBufferComponents = DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS;
|
||||||
|
|
||||||
|
private final int maxContentLength;
|
||||||
|
|
||||||
|
public MemcacheObjectAggregator(int maxContentLength) {
|
||||||
|
if (maxContentLength <= 0) {
|
||||||
|
throw new IllegalArgumentException("maxContentLength must be a positive integer: " + maxContentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maxContentLength = maxContentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of components in the cumulation buffer. If the number of
|
||||||
|
* the components in the cumulation buffer exceeds this value, the components of the
|
||||||
|
* cumulation buffer are consolidated into a single component, involving memory copies.
|
||||||
|
* The default value of this property is {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS}.
|
||||||
|
*/
|
||||||
|
public final int getMaxCumulationBufferComponents() {
|
||||||
|
return maxCumulationBufferComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of components in the cumulation buffer. If the number of
|
||||||
|
* the components in the cumulation buffer exceeds this value, the components of the
|
||||||
|
* cumulation buffer are consolidated into a single component, involving memory copies.
|
||||||
|
* The default value of this property is {@link #DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS}
|
||||||
|
* and its minimum allowed value is {@code 2}.
|
||||||
|
*/
|
||||||
|
public final void setMaxCumulationBufferComponents(int maxCumulationBufferComponents) {
|
||||||
|
if (maxCumulationBufferComponents < 2) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"maxCumulationBufferComponents: " + maxCumulationBufferComponents +
|
||||||
|
" (expected: >= 2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx == null) {
|
||||||
|
this.maxCumulationBufferComponents = maxCumulationBufferComponents;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"decoder properties cannot be changed once the decoder is added to a pipeline.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxContentLength() {
|
||||||
|
return maxContentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
|
||||||
|
if (currentMessage != null) {
|
||||||
|
currentMessage.release();
|
||||||
|
currentMessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.handlerRemoved(ctx);
|
||||||
|
|
||||||
|
if (currentMessage != null) {
|
||||||
|
currentMessage.release();
|
||||||
|
currentMessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract super class for both ascii and binary decoders.
|
||||||
|
* <p/>
|
||||||
|
* Currently it just acts as a common denominator, but will certainly include methods once the ascii protocol
|
||||||
|
* is implemented.
|
||||||
|
*/
|
||||||
|
public abstract class MemcacheObjectDecoder extends ByteToMessageDecoder {
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.FileRegion;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A general purpose {@link MemcacheObjectEncoder} that encodes {@link MemcacheMessage}s.
|
||||||
|
* <p/>
|
||||||
|
* <p>Note that this class is designed to be extended, especially because both the binary and ascii protocol
|
||||||
|
* require different treatment of their messages. Since the content chunk writing is the same for both, the encoder
|
||||||
|
* abstracts this right away.</p>
|
||||||
|
*/
|
||||||
|
public abstract class MemcacheObjectEncoder<M extends MemcacheMessage> extends MessageToMessageEncoder<Object> {
|
||||||
|
|
||||||
|
private boolean expectingMoreContent;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
|
||||||
|
if (msg instanceof MemcacheMessage) {
|
||||||
|
if (expectingMoreContent) {
|
||||||
|
throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
out.add(encodeMessage(ctx, (M) msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg instanceof MemcacheContent || msg instanceof ByteBuf || msg instanceof FileRegion) {
|
||||||
|
int contentLength = contentLength(msg);
|
||||||
|
if (contentLength > 0) {
|
||||||
|
out.add(encodeAndRetain(msg));
|
||||||
|
} else {
|
||||||
|
out.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
expectingMoreContent = !(msg instanceof LastMemcacheContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptOutboundMessage(Object msg) throws Exception {
|
||||||
|
return msg instanceof MemcacheObject || msg instanceof ByteBuf || msg instanceof FileRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the given {@link MemcacheMessage} and encode it into a writable {@link ByteBuf}.
|
||||||
|
*
|
||||||
|
* @param ctx the channel handler context.
|
||||||
|
* @param msg the message to encode.
|
||||||
|
* @return the {@link ByteBuf} representation of the message.
|
||||||
|
*/
|
||||||
|
protected abstract ByteBuf encodeMessage(ChannelHandlerContext ctx, M msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the content length of the given object.
|
||||||
|
*
|
||||||
|
* @param msg the object to determine the length of.
|
||||||
|
* @return the determined content length.
|
||||||
|
*/
|
||||||
|
private static int contentLength(Object msg) {
|
||||||
|
if (msg instanceof MemcacheContent) {
|
||||||
|
return ((MemcacheContent) msg).content().readableBytes();
|
||||||
|
}
|
||||||
|
if (msg instanceof ByteBuf) {
|
||||||
|
return ((ByteBuf) msg).readableBytes();
|
||||||
|
}
|
||||||
|
if (msg instanceof FileRegion) {
|
||||||
|
return (int) ((FileRegion) msg).count();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the content, depending on the object type.
|
||||||
|
*
|
||||||
|
* @param msg the object to encode.
|
||||||
|
* @return the encoded object.
|
||||||
|
*/
|
||||||
|
private static Object encodeAndRetain(Object msg) {
|
||||||
|
if (msg instanceof ByteBuf) {
|
||||||
|
return ((ByteBuf) msg).retain();
|
||||||
|
}
|
||||||
|
if (msg instanceof MemcacheContent) {
|
||||||
|
return ((MemcacheContent) msg).content().retain();
|
||||||
|
}
|
||||||
|
if (msg instanceof FileRegion) {
|
||||||
|
return ((FileRegion) msg).retain();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.CombinedChannelDuplexHandler;
|
||||||
|
import io.netty.handler.codec.PrematureChannelClosureException;
|
||||||
|
import io.netty.handler.codec.memcache.LastMemcacheContent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client codec that combines the proper encoder and decoder.
|
||||||
|
* <p/>
|
||||||
|
* Use this codec if you want to implement a memcache client that speaks the binary protocol. It
|
||||||
|
* combines both the {@link BinaryMemcacheResponseDecoder} and the {@link BinaryMemcacheRequestEncoder}.
|
||||||
|
* <p/>
|
||||||
|
* Optionally, it counts the number of outstanding responses and raises an exception if - on connection
|
||||||
|
* close - the list is not 0 (this is turned off by default). You can also define a chunk size for the
|
||||||
|
* content, which defaults to 8192. This chunk size is the maximum, so if smaller chunks arrive they
|
||||||
|
* will be passed up the pipeline and not queued up to the chunk size.
|
||||||
|
*/
|
||||||
|
public final class BinaryMemcacheClientCodec
|
||||||
|
extends CombinedChannelDuplexHandler<BinaryMemcacheResponseDecoder, BinaryMemcacheRequestEncoder> {
|
||||||
|
|
||||||
|
private final boolean failOnMissingResponse;
|
||||||
|
private final AtomicLong requestResponseCounter = new AtomicLong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheClientCodec} with the default settings applied.
|
||||||
|
*/
|
||||||
|
public BinaryMemcacheClientCodec() {
|
||||||
|
this(Decoder.DEFAULT_MAX_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheClientCodec} and set a custom chunk size.
|
||||||
|
*
|
||||||
|
* @param decodeChunkSize the maximum chunk size.
|
||||||
|
*/
|
||||||
|
public BinaryMemcacheClientCodec(int decodeChunkSize) {
|
||||||
|
this(decodeChunkSize, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheClientCodec} with custom settings.
|
||||||
|
*
|
||||||
|
* @param decodeChunkSize the maximum chunk size.
|
||||||
|
* @param failOnMissingResponse report if after close there are outstanding requests.
|
||||||
|
*/
|
||||||
|
public BinaryMemcacheClientCodec(int decodeChunkSize, boolean failOnMissingResponse) {
|
||||||
|
this.failOnMissingResponse = failOnMissingResponse;
|
||||||
|
init(new Decoder(decodeChunkSize), new Encoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class Encoder extends BinaryMemcacheRequestEncoder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
|
||||||
|
super.encode(ctx, msg, out);
|
||||||
|
|
||||||
|
if (failOnMissingResponse && msg instanceof LastMemcacheContent) {
|
||||||
|
requestResponseCounter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class Decoder extends BinaryMemcacheResponseDecoder {
|
||||||
|
|
||||||
|
public Decoder(int chunkSize) {
|
||||||
|
super(chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||||
|
int oldSize = out.size();
|
||||||
|
super.decode(ctx, in, out);
|
||||||
|
|
||||||
|
if (failOnMissingResponse) {
|
||||||
|
int size = out.size();
|
||||||
|
for (int i = oldSize; i < size; size++) {
|
||||||
|
Object msg = out.get(i);
|
||||||
|
if (msg != null && msg instanceof LastMemcacheContent) {
|
||||||
|
requestResponseCounter.decrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
|
||||||
|
if (failOnMissingResponse) {
|
||||||
|
long missingResponses = requestResponseCounter.get();
|
||||||
|
if (missingResponses > 0) {
|
||||||
|
ctx.fireExceptionCaught(new PrematureChannelClosureException(
|
||||||
|
"channel gone inactive with " + missingResponses +
|
||||||
|
" missing response(s)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.memcache.DefaultLastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.DefaultMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.LastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheObjectDecoder;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static io.netty.buffer.ByteBufUtil.readBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoder for both {@link BinaryMemcacheRequest} and {@link BinaryMemcacheResponse}.
|
||||||
|
* <p/>
|
||||||
|
* The difference in the protocols (header) is implemented by the subclasses.
|
||||||
|
*/
|
||||||
|
public abstract class BinaryMemcacheDecoder<M extends BinaryMemcacheMessage, H extends BinaryMemcacheMessageHeader>
|
||||||
|
extends MemcacheObjectDecoder {
|
||||||
|
|
||||||
|
public static final int DEFAULT_MAX_CHUNK_SIZE = 8192;
|
||||||
|
|
||||||
|
private final int chunkSize;
|
||||||
|
|
||||||
|
private H currentHeader;
|
||||||
|
private ByteBuf currentExtras;
|
||||||
|
private String currentKey;
|
||||||
|
private int alreadyReadChunkSize;
|
||||||
|
|
||||||
|
private State state = State.READ_HEADER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheDecoder} with default settings.
|
||||||
|
*/
|
||||||
|
public BinaryMemcacheDecoder() {
|
||||||
|
this(DEFAULT_MAX_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheDecoder} with custom settings.
|
||||||
|
*
|
||||||
|
* @param chunkSize the maximum chunk size of the payload.
|
||||||
|
*/
|
||||||
|
public BinaryMemcacheDecoder(int chunkSize) {
|
||||||
|
if (chunkSize < 0) {
|
||||||
|
throw new IllegalArgumentException("chunkSize must be a positive integer: " + chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chunkSize = chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||||
|
switch (state) {
|
||||||
|
case READ_HEADER:
|
||||||
|
if (in.readableBytes() < 24) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resetDecoder();
|
||||||
|
|
||||||
|
currentHeader = decodeHeader(in);
|
||||||
|
state = State.READ_EXTRAS;
|
||||||
|
case READ_EXTRAS:
|
||||||
|
byte extrasLength = currentHeader.getExtrasLength();
|
||||||
|
if (extrasLength > 0) {
|
||||||
|
if (in.readableBytes() < extrasLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentExtras = readBytes(ctx.alloc(), in, extrasLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = State.READ_KEY;
|
||||||
|
case READ_KEY:
|
||||||
|
short keyLength = currentHeader.getKeyLength();
|
||||||
|
if (keyLength > 0) {
|
||||||
|
if (in.readableBytes() < keyLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentKey = readBytes(ctx.alloc(), in, keyLength).toString(CharsetUtil.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.add(buildMessage(currentHeader, currentExtras, currentKey));
|
||||||
|
currentExtras = null;
|
||||||
|
state = State.READ_VALUE;
|
||||||
|
case READ_VALUE:
|
||||||
|
int valueLength = currentHeader.getTotalBodyLength()
|
||||||
|
- currentHeader.getKeyLength()
|
||||||
|
- currentHeader.getExtrasLength();
|
||||||
|
int toRead = in.readableBytes();
|
||||||
|
if (valueLength > 0) {
|
||||||
|
if (toRead == 0) {
|
||||||
|
return;
|
||||||
|
} else if (toRead > chunkSize) {
|
||||||
|
toRead = chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRead > valueLength) {
|
||||||
|
toRead = valueLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf chunkBuffer = readBytes(ctx.alloc(), in, toRead);
|
||||||
|
boolean isLast = (alreadyReadChunkSize + toRead) >= valueLength;
|
||||||
|
MemcacheContent chunk = isLast
|
||||||
|
? new DefaultLastMemcacheContent(chunkBuffer)
|
||||||
|
: new DefaultMemcacheContent(chunkBuffer);
|
||||||
|
alreadyReadChunkSize += toRead;
|
||||||
|
|
||||||
|
out.add(chunk);
|
||||||
|
if (alreadyReadChunkSize < valueLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.add(LastMemcacheContent.EMPTY_LAST_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = State.READ_HEADER;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown state reached: " + state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the channel goes inactive, release all frames to prevent data leaks.
|
||||||
|
*
|
||||||
|
* @param ctx handler context
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
|
||||||
|
if (currentExtras != null) {
|
||||||
|
currentExtras.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare for next decoding iteration.
|
||||||
|
*/
|
||||||
|
protected void resetDecoder() {
|
||||||
|
currentHeader = null;
|
||||||
|
currentExtras = null;
|
||||||
|
currentKey = null;
|
||||||
|
alreadyReadChunkSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode and return the parsed {@link BinaryMemcacheMessageHeader}.
|
||||||
|
*
|
||||||
|
* @param in the incoming buffer.
|
||||||
|
* @return the decoded header.
|
||||||
|
*/
|
||||||
|
protected abstract H decodeHeader(ByteBuf in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the complete message, based on the information decoded.
|
||||||
|
*
|
||||||
|
* @param header the header of the message.
|
||||||
|
* @param extras possible extras.
|
||||||
|
* @param key possible key.
|
||||||
|
* @return the decoded message.
|
||||||
|
*/
|
||||||
|
protected abstract M buildMessage(H header, ByteBuf extras, String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all states this decoder can possibly be in.
|
||||||
|
* <p/>
|
||||||
|
* Note that most of the states can be optional, the only one required is reading
|
||||||
|
* the header ({@link #READ_HEADER}. All other steps depend on the length fields
|
||||||
|
* in the header and will be executed conditionally.
|
||||||
|
*/
|
||||||
|
enum State {
|
||||||
|
/**
|
||||||
|
* Currently reading the header portion.
|
||||||
|
*/
|
||||||
|
READ_HEADER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently reading the extras portion (optional).
|
||||||
|
*/
|
||||||
|
READ_EXTRAS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently reading the key portion (optional).
|
||||||
|
*/
|
||||||
|
READ_KEY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently reading the value chunks (optional).
|
||||||
|
*/
|
||||||
|
READ_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheObjectEncoder;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link io.netty.handler.codec.MessageToByteEncoder} that encodes binary memache messages into bytes.
|
||||||
|
*/
|
||||||
|
public abstract class BinaryMemcacheEncoder<M extends BinaryMemcacheMessage, H extends BinaryMemcacheMessageHeader>
|
||||||
|
extends MemcacheObjectEncoder<M> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuf encodeMessage(ChannelHandlerContext ctx, M msg) {
|
||||||
|
ByteBuf buf = ctx.alloc().buffer();
|
||||||
|
|
||||||
|
encodeHeader(buf, (H) msg.getHeader());
|
||||||
|
encodeExtras(buf, msg.getExtras());
|
||||||
|
encodeKey(buf, msg.getKey());
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the extras.
|
||||||
|
*
|
||||||
|
* @param buf the {@link ByteBuf} to write into.
|
||||||
|
* @param extras the extras to encode.
|
||||||
|
*/
|
||||||
|
private void encodeExtras(ByteBuf buf, ByteBuf extras) {
|
||||||
|
if (extras == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.writeBytes(extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the key.
|
||||||
|
*
|
||||||
|
* @param buf the {@link ByteBuf} to write into.
|
||||||
|
* @param key the key to encode.
|
||||||
|
*/
|
||||||
|
private void encodeKey(ByteBuf buf, String key) {
|
||||||
|
if (key == null || key.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.writeBytes(Unpooled.copiedBuffer(key, CharsetUtil.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the header.
|
||||||
|
* <p/>
|
||||||
|
* This methods needs to be implemented by a sub class because the header is different
|
||||||
|
* for both requests and responses.
|
||||||
|
*
|
||||||
|
* @param buf the {@link ByteBuf} to write into.
|
||||||
|
* @param header the header to encode.
|
||||||
|
*/
|
||||||
|
protected abstract void encodeHeader(ByteBuf buf, H header);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheMessage;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that defines a binary Memcache message, providing common properties for
|
||||||
|
* {@link BinaryMemcacheRequest} and {@link BinaryMemcacheResponse}.
|
||||||
|
* <p/>
|
||||||
|
* A {@link BinaryMemcacheMessage} always consists of a header and optional extras or/and
|
||||||
|
* a key.
|
||||||
|
*
|
||||||
|
* @see BinaryMemcacheMessageHeader
|
||||||
|
* @see BinaryMemcacheRequest
|
||||||
|
* @see BinaryMemcacheResponse
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheMessage<H extends BinaryMemcacheMessageHeader> extends MemcacheMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link BinaryMemcacheMessageHeader} which contains the full required header.
|
||||||
|
*
|
||||||
|
* @return the required header.
|
||||||
|
*/
|
||||||
|
H getHeader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the optional key of the document.
|
||||||
|
*
|
||||||
|
* @return the key of the document.
|
||||||
|
*/
|
||||||
|
String getKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link ByteBuf} representation of the optional extras.
|
||||||
|
*
|
||||||
|
* @return the optional extras.
|
||||||
|
*/
|
||||||
|
ByteBuf getExtras();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the reference count by {@code 1}.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessage retain();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the reference count by the specified {@code increment}.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessage retain(int increment);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all common header fields in a {@link BinaryMemcacheMessage}.
|
||||||
|
* <p/>
|
||||||
|
* <p>Since the header is different for a {@link BinaryMemcacheRequest} and {@link BinaryMemcacheResponse}, see
|
||||||
|
* {@link BinaryMemcacheRequestHeader} and {@link BinaryMemcacheResponseHeader}.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>The {@link BinaryMemcacheMessageHeader} is always 24 bytes in length and needs to be filled up if values are
|
||||||
|
* not set.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>Fore more information, see the official protocol specification
|
||||||
|
* <a href="https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol">here</a>.</p>
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheMessageHeader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the magic byte for the message.
|
||||||
|
*
|
||||||
|
* @return the magic byte.
|
||||||
|
*/
|
||||||
|
byte getMagic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the magic byte.
|
||||||
|
*
|
||||||
|
* @param magic the magic byte to use.
|
||||||
|
* @see io.netty.handler.codec.memcache.binary.util.BinaryMemcacheOpcodes for typesafe opcodes.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setMagic(byte magic);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the opcode for the message.
|
||||||
|
*
|
||||||
|
* @return the opcode.
|
||||||
|
*/
|
||||||
|
byte getOpcode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the opcode for the message.
|
||||||
|
*
|
||||||
|
* @param code the opcode to use.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setOpcode(byte code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key length of the message.
|
||||||
|
* <p/>
|
||||||
|
* This may return 0, since the key is optional.
|
||||||
|
*
|
||||||
|
* @return the key length.
|
||||||
|
*/
|
||||||
|
short getKeyLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the key length of the message.
|
||||||
|
* <p/>
|
||||||
|
* This may be 0, since the key is optional.
|
||||||
|
*
|
||||||
|
* @param keyLength the key length to use.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setKeyLength(short keyLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the extras length of the message.
|
||||||
|
* <p/>
|
||||||
|
* This may be 0, since the extras content is optional.
|
||||||
|
*
|
||||||
|
* @return the extras length.
|
||||||
|
*/
|
||||||
|
byte getExtrasLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the extras length of the message.
|
||||||
|
* <p/>
|
||||||
|
* This may be 0, since the extras content is optional.
|
||||||
|
*
|
||||||
|
* @param extrasLength the extras length.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setExtrasLength(byte extrasLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data type of the message.
|
||||||
|
*
|
||||||
|
* @return the data type of the message.
|
||||||
|
*/
|
||||||
|
byte getDataType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data type of the message.
|
||||||
|
*
|
||||||
|
* @param dataType the data type of the message.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setDataType(byte dataType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total body length.
|
||||||
|
* <p/>
|
||||||
|
* Note that this may be 0, since the body is optional.
|
||||||
|
*
|
||||||
|
* @return the total body length.
|
||||||
|
*/
|
||||||
|
int getTotalBodyLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the total body length.
|
||||||
|
* <p/>
|
||||||
|
* Note that this may be 0, since the body length is optional.
|
||||||
|
*
|
||||||
|
* @param totalBodyLength the total body length.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setTotalBodyLength(int totalBodyLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the opaque value.
|
||||||
|
*
|
||||||
|
* @return the opaque value.
|
||||||
|
*/
|
||||||
|
int getOpaque();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the opaque value.
|
||||||
|
*
|
||||||
|
* @param opaque the opqaue value to use.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setOpaque(int opaque);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CAS identifier.
|
||||||
|
*
|
||||||
|
* @return the CAS identifier.
|
||||||
|
*/
|
||||||
|
long getCAS();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the CAS identifier.
|
||||||
|
*
|
||||||
|
* @param cas the CAS identifier to use.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheMessageHeader setCAS(long cas);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.CompositeByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.DecoderResult;
|
||||||
|
import io.netty.handler.codec.TooLongFrameException;
|
||||||
|
import io.netty.handler.codec.memcache.FullMemcacheMessage;
|
||||||
|
import io.netty.handler.codec.memcache.LastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheMessage;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheObject;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheObjectAggregator;
|
||||||
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link MemcacheObjectAggregator} for the binary protocol.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheObjectAggregator extends MemcacheObjectAggregator {
|
||||||
|
|
||||||
|
private boolean tooLongFrameFound;
|
||||||
|
|
||||||
|
public BinaryMemcacheObjectAggregator(int maxContentLength) {
|
||||||
|
super(maxContentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, MemcacheObject msg, List<Object> out) throws Exception {
|
||||||
|
FullMemcacheMessage currentMessage = this.currentMessage;
|
||||||
|
|
||||||
|
if (msg instanceof MemcacheMessage) {
|
||||||
|
tooLongFrameFound = false;
|
||||||
|
MemcacheMessage m = (MemcacheMessage) msg;
|
||||||
|
|
||||||
|
if (!m.getDecoderResult().isSuccess()) {
|
||||||
|
this.currentMessage = null;
|
||||||
|
out.add(ReferenceCountUtil.retain(m));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg instanceof BinaryMemcacheRequest) {
|
||||||
|
BinaryMemcacheRequest request = (BinaryMemcacheRequest) msg;
|
||||||
|
this.currentMessage = new DefaultFullBinaryMemcacheRequest(request.getHeader(), request.getKey(),
|
||||||
|
request.getExtras(), Unpooled.compositeBuffer(getMaxCumulationBufferComponents()));
|
||||||
|
} else if (msg instanceof BinaryMemcacheResponse) {
|
||||||
|
BinaryMemcacheResponse response = (BinaryMemcacheResponse) msg;
|
||||||
|
this.currentMessage = new DefaultFullBinaryMemcacheResponse(response.getHeader(), response.getKey(),
|
||||||
|
response.getExtras(), Unpooled.compositeBuffer(getMaxCumulationBufferComponents()));
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} else if (msg instanceof MemcacheContent) {
|
||||||
|
if (tooLongFrameFound) {
|
||||||
|
if (msg instanceof LastMemcacheContent) {
|
||||||
|
this.currentMessage = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemcacheContent chunk = (MemcacheContent) msg;
|
||||||
|
CompositeByteBuf content = (CompositeByteBuf) currentMessage.content();
|
||||||
|
|
||||||
|
if (content.readableBytes() > getMaxContentLength() - chunk.content().readableBytes()) {
|
||||||
|
tooLongFrameFound = true;
|
||||||
|
|
||||||
|
currentMessage.release();
|
||||||
|
this.currentMessage = null;
|
||||||
|
|
||||||
|
throw new TooLongFrameException("Memcache content length exceeded " + getMaxContentLength()
|
||||||
|
+ " bytes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.content().isReadable()) {
|
||||||
|
chunk.retain();
|
||||||
|
content.addComponent(chunk.content());
|
||||||
|
content.writerIndex(content.writerIndex() + chunk.content().readableBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean last;
|
||||||
|
if (!chunk.getDecoderResult().isSuccess()) {
|
||||||
|
currentMessage.setDecoderResult(
|
||||||
|
DecoderResult.failure(chunk.getDecoderResult().cause()));
|
||||||
|
last = true;
|
||||||
|
} else {
|
||||||
|
last = chunk instanceof LastMemcacheContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last) {
|
||||||
|
this.currentMessage = null;
|
||||||
|
out.add(currentMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a full {@link BinaryMemcacheRequest}, which contains the header and optional key and extras.
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheRequest extends BinaryMemcacheMessage<BinaryMemcacheRequestHeader> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link BinaryMemcacheRequestHeader} which contains the full required request header.
|
||||||
|
*
|
||||||
|
* @return the required request header.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheRequestHeader getHeader();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoder part which takes care of decoding the request-specific headers.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheRequestDecoder
|
||||||
|
extends BinaryMemcacheDecoder<BinaryMemcacheRequest, BinaryMemcacheRequestHeader> {
|
||||||
|
|
||||||
|
public BinaryMemcacheRequestDecoder() {
|
||||||
|
this(DEFAULT_MAX_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryMemcacheRequestDecoder(int chunkSize) {
|
||||||
|
super(chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BinaryMemcacheRequestHeader decodeHeader(ByteBuf in) {
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
header.setMagic(in.readByte());
|
||||||
|
header.setOpcode(in.readByte());
|
||||||
|
header.setKeyLength(in.readShort());
|
||||||
|
header.setExtrasLength(in.readByte());
|
||||||
|
header.setDataType(in.readByte());
|
||||||
|
header.setReserved(in.readShort());
|
||||||
|
header.setTotalBodyLength(in.readInt());
|
||||||
|
header.setOpaque(in.readInt());
|
||||||
|
header.setCAS(in.readLong());
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BinaryMemcacheRequest buildMessage(BinaryMemcacheRequestHeader header, ByteBuf extras, String key) {
|
||||||
|
return new DefaultBinaryMemcacheRequest(header, key, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoder part which takes care of encoding the request headers.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheRequestEncoder
|
||||||
|
extends BinaryMemcacheEncoder<BinaryMemcacheRequest, BinaryMemcacheRequestHeader> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encodeHeader(ByteBuf buf, BinaryMemcacheRequestHeader header) {
|
||||||
|
buf.writeByte(header.getMagic());
|
||||||
|
buf.writeByte(header.getOpcode());
|
||||||
|
buf.writeShort(header.getKeyLength());
|
||||||
|
buf.writeByte(header.getExtrasLength());
|
||||||
|
buf.writeByte(header.getDataType());
|
||||||
|
buf.writeShort(header.getReserved());
|
||||||
|
buf.writeInt(header.getTotalBodyLength());
|
||||||
|
buf.writeInt(header.getOpaque());
|
||||||
|
buf.writeLong(header.getCAS());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the common {@link BinaryMemcacheMessageHeader} header fields with hose who can only show up in
|
||||||
|
* {@link BinaryMemcacheRequest} messages.
|
||||||
|
* <p/>
|
||||||
|
* <p>Note that while the additional field in the request is called "reserved", it can still be used for a custom
|
||||||
|
* memcached implementation. It will not be mirrored back like the
|
||||||
|
* {@link io.netty.handler.codec.memcache.binary.BinaryMemcacheRequestHeader#getOpaque()} field, because in the
|
||||||
|
* {@link BinaryMemcacheResponseHeader}, the status field is set there instead.</p>
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheRequestHeader extends BinaryMemcacheMessageHeader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reserved field value.
|
||||||
|
*
|
||||||
|
* @return the reserved field value.
|
||||||
|
*/
|
||||||
|
short getReserved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reserved field value.
|
||||||
|
*
|
||||||
|
* @param reserved the reserved field value.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheRequestHeader setReserved(short reserved);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a full {@link BinaryMemcacheResponse}, which contains the header and optional key and extras.
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheResponse extends BinaryMemcacheMessage<BinaryMemcacheResponseHeader> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link BinaryMemcacheResponseHeader} which contains the full required response header.
|
||||||
|
*
|
||||||
|
* @return the required response header.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheResponseHeader getHeader();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoder which takes care of decoding the response headers.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheResponseDecoder
|
||||||
|
extends BinaryMemcacheDecoder<BinaryMemcacheResponse, BinaryMemcacheResponseHeader> {
|
||||||
|
|
||||||
|
public BinaryMemcacheResponseDecoder() {
|
||||||
|
this(DEFAULT_MAX_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryMemcacheResponseDecoder(int chunkSize) {
|
||||||
|
super(chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BinaryMemcacheResponseHeader decodeHeader(ByteBuf in) {
|
||||||
|
BinaryMemcacheResponseHeader header = new DefaultBinaryMemcacheResponseHeader();
|
||||||
|
header.setMagic(in.readByte());
|
||||||
|
header.setOpcode(in.readByte());
|
||||||
|
header.setKeyLength(in.readShort());
|
||||||
|
header.setExtrasLength(in.readByte());
|
||||||
|
header.setDataType(in.readByte());
|
||||||
|
header.setStatus(in.readShort());
|
||||||
|
header.setTotalBodyLength(in.readInt());
|
||||||
|
header.setOpaque(in.readInt());
|
||||||
|
header.setCAS(in.readLong());
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BinaryMemcacheResponse buildMessage(BinaryMemcacheResponseHeader header, ByteBuf extras, String key) {
|
||||||
|
return new DefaultBinaryMemcacheResponse(header, key, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoder which takes care of encoding the response headers.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheResponseEncoder
|
||||||
|
extends BinaryMemcacheEncoder<BinaryMemcacheResponse, BinaryMemcacheResponseHeader> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encodeHeader(ByteBuf buf, BinaryMemcacheResponseHeader header) {
|
||||||
|
buf.writeByte(header.getMagic());
|
||||||
|
buf.writeByte(header.getOpcode());
|
||||||
|
buf.writeShort(header.getKeyLength());
|
||||||
|
buf.writeByte(header.getExtrasLength());
|
||||||
|
buf.writeByte(header.getDataType());
|
||||||
|
buf.writeShort(header.getStatus());
|
||||||
|
buf.writeInt(header.getTotalBodyLength());
|
||||||
|
buf.writeInt(header.getOpaque());
|
||||||
|
buf.writeLong(header.getCAS());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the common {@link BinaryMemcacheMessageHeader} header fields with hose who can only show up in
|
||||||
|
* {@link BinaryMemcacheResponse} messages.
|
||||||
|
*
|
||||||
|
* @see io.netty.handler.codec.memcache.binary.util.BinaryMemcacheResponseStatus
|
||||||
|
*/
|
||||||
|
public interface BinaryMemcacheResponseHeader extends BinaryMemcacheMessageHeader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the response.
|
||||||
|
*
|
||||||
|
* @return the status of the response.
|
||||||
|
*/
|
||||||
|
short getStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of the response.
|
||||||
|
*
|
||||||
|
* @param status the status to set.
|
||||||
|
*/
|
||||||
|
BinaryMemcacheResponseHeader setStatus(short status);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.channel.CombinedChannelDuplexHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The full server codec that combines the correct encoder and decoder.
|
||||||
|
* <p/>
|
||||||
|
* Use this codec if you need to implement a server that speaks the memache binary protocol.
|
||||||
|
* Internally, it combines the {@link BinaryMemcacheRequestDecoder} and the
|
||||||
|
* {@link BinaryMemcacheResponseEncoder} to request decoding and response encoding.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheServerCodec
|
||||||
|
extends CombinedChannelDuplexHandler<BinaryMemcacheRequestDecoder, BinaryMemcacheResponseEncoder> {
|
||||||
|
|
||||||
|
public BinaryMemcacheServerCodec() {
|
||||||
|
this(BinaryMemcacheRequestDecoder.DEFAULT_MAX_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryMemcacheServerCodec(int decodeChunkSize) {
|
||||||
|
init(new BinaryMemcacheRequestDecoder(decodeChunkSize), new BinaryMemcacheResponseEncoder());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.memcache.DefaultMemcacheObject;
|
||||||
|
import io.netty.util.AbstractReferenceCounted;
|
||||||
|
import io.netty.util.ReferenceCounted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of a {@link BinaryMemcacheMessage}.
|
||||||
|
*/
|
||||||
|
public abstract class DefaultBinaryMemcacheMessage<H extends BinaryMemcacheMessageHeader>
|
||||||
|
extends DefaultMemcacheObject
|
||||||
|
implements BinaryMemcacheMessage<H> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the message header.
|
||||||
|
*/
|
||||||
|
private final H header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the optional key.
|
||||||
|
*/
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the optional extras.
|
||||||
|
*/
|
||||||
|
private final ByteBuf extras;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance with all properties set.
|
||||||
|
*
|
||||||
|
* @param header the message header.
|
||||||
|
* @param key the message key.
|
||||||
|
* @param extras the message extras.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheMessage(H header, String key, ByteBuf extras) {
|
||||||
|
this.header = header;
|
||||||
|
this.key = key;
|
||||||
|
this.extras = extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public H getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf getExtras() {
|
||||||
|
return extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int refCnt() {
|
||||||
|
if (extras != null) {
|
||||||
|
return extras.refCnt();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessage retain() {
|
||||||
|
if (extras != null) {
|
||||||
|
extras.retain();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessage retain(int increment) {
|
||||||
|
if (extras != null) {
|
||||||
|
extras.retain(increment);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release() {
|
||||||
|
if (extras != null) {
|
||||||
|
return extras.release();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(int decrement) {
|
||||||
|
if (extras != null) {
|
||||||
|
return extras.release(decrement);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of a {@link BinaryMemcacheMessageHeader}.
|
||||||
|
*/
|
||||||
|
public abstract class DefaultBinaryMemcacheMessageHeader implements BinaryMemcacheMessageHeader {
|
||||||
|
|
||||||
|
private byte magic;
|
||||||
|
private byte opcode;
|
||||||
|
private short keyLength;
|
||||||
|
private byte extrasLength;
|
||||||
|
private byte dataType;
|
||||||
|
private int totalBodyLength;
|
||||||
|
private int opaque;
|
||||||
|
private long cas;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getMagic() {
|
||||||
|
return magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setMagic(byte magic) {
|
||||||
|
this.magic = magic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCAS() {
|
||||||
|
return cas;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setCAS(long cas) {
|
||||||
|
this.cas = cas;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOpaque() {
|
||||||
|
return opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setOpaque(int opaque) {
|
||||||
|
this.opaque = opaque;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalBodyLength() {
|
||||||
|
return totalBodyLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setTotalBodyLength(int totalBodyLength) {
|
||||||
|
this.totalBodyLength = totalBodyLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getDataType() {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setDataType(byte dataType) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getExtrasLength() {
|
||||||
|
return extrasLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setExtrasLength(byte extrasLength) {
|
||||||
|
this.extrasLength = extrasLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getKeyLength() {
|
||||||
|
return keyLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setKeyLength(short keyLength) {
|
||||||
|
this.keyLength = keyLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getOpcode() {
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheMessageHeader setOpcode(byte opcode) {
|
||||||
|
this.opcode = opcode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of the {@link BinaryMemcacheRequest}.
|
||||||
|
*/
|
||||||
|
public class DefaultBinaryMemcacheRequest extends DefaultBinaryMemcacheMessage<BinaryMemcacheRequestHeader>
|
||||||
|
implements BinaryMemcacheRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header only.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheRequest(BinaryMemcacheRequestHeader header) {
|
||||||
|
this(header, null, Unpooled.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header and key.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheRequest(BinaryMemcacheRequestHeader header, String key) {
|
||||||
|
this(header, key, Unpooled.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header and extras.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheRequest(BinaryMemcacheRequestHeader header, ByteBuf extras) {
|
||||||
|
this(header, null, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header only.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheRequest(BinaryMemcacheRequestHeader header, String key, ByteBuf extras) {
|
||||||
|
super(header, key, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of a {@link BinaryMemcacheRequestHeader}.
|
||||||
|
*/
|
||||||
|
public class DefaultBinaryMemcacheRequestHeader extends DefaultBinaryMemcacheMessageHeader
|
||||||
|
implements BinaryMemcacheRequestHeader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default magic byte for a request.
|
||||||
|
*/
|
||||||
|
public static final byte REQUEST_MAGIC_BYTE = (byte) 0x80;
|
||||||
|
|
||||||
|
private short reserved;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheRequestHeader} and apply default values.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheRequestHeader() {
|
||||||
|
setMagic(REQUEST_MAGIC_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getReserved() {
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheRequestHeader setReserved(short reserved) {
|
||||||
|
this.reserved = reserved;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of the {@link BinaryMemcacheResponse}.
|
||||||
|
*/
|
||||||
|
public class DefaultBinaryMemcacheResponse extends DefaultBinaryMemcacheMessage<BinaryMemcacheResponseHeader>
|
||||||
|
implements BinaryMemcacheResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheResponse} with the header only.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheResponse(BinaryMemcacheResponseHeader header) {
|
||||||
|
this(header, null, Unpooled.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheResponse} with the header and key.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheResponse(BinaryMemcacheResponseHeader header, String key) {
|
||||||
|
this(header, key, Unpooled.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheResponse} with the header and extras.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheResponse(BinaryMemcacheResponseHeader header, ByteBuf extras) {
|
||||||
|
this(header, null, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheResponse} with the header, key and extras.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheResponse(BinaryMemcacheResponseHeader header, String key, ByteBuf extras) {
|
||||||
|
super(header, key, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of a {@link BinaryMemcacheResponseHeader}.
|
||||||
|
*/
|
||||||
|
public class DefaultBinaryMemcacheResponseHeader extends DefaultBinaryMemcacheMessageHeader
|
||||||
|
implements BinaryMemcacheResponseHeader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default magic byte for a request.
|
||||||
|
*/
|
||||||
|
public static final byte RESPONSE_MAGIC_BYTE = (byte) 0x81;
|
||||||
|
|
||||||
|
private short status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BinaryMemcacheRequestHeader} and apply default values.
|
||||||
|
*/
|
||||||
|
public DefaultBinaryMemcacheResponseHeader() {
|
||||||
|
setMagic(RESPONSE_MAGIC_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMemcacheResponseHeader setStatus(short status) {
|
||||||
|
this.status = status;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of a {@link FullBinaryMemcacheRequest}.
|
||||||
|
*/
|
||||||
|
public class DefaultFullBinaryMemcacheRequest extends DefaultBinaryMemcacheRequest
|
||||||
|
implements FullBinaryMemcacheRequest {
|
||||||
|
|
||||||
|
private final ByteBuf content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header, key and extras.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultFullBinaryMemcacheRequest(BinaryMemcacheRequestHeader header, String key, ByteBuf extras) {
|
||||||
|
this(header, key, extras, Unpooled.buffer(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultBinaryMemcacheRequest} with the header, key, extras and content.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
* @param content the content of the full request.
|
||||||
|
*/
|
||||||
|
public DefaultFullBinaryMemcacheRequest(BinaryMemcacheRequestHeader header, String key, ByteBuf extras,
|
||||||
|
ByteBuf content) {
|
||||||
|
super(header, key, extras);
|
||||||
|
if (content == null) {
|
||||||
|
throw new NullPointerException("Supplied content is null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf content() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int refCnt() {
|
||||||
|
return content.refCnt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheRequest retain() {
|
||||||
|
content.retain();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheRequest retain(int increment) {
|
||||||
|
content.retain(increment);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release() {
|
||||||
|
return content.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(int decrement) {
|
||||||
|
return content.release(decrement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheRequest copy() {
|
||||||
|
return new DefaultFullBinaryMemcacheRequest(getHeader(), getKey(), getExtras(), content().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheRequest duplicate() {
|
||||||
|
return new DefaultFullBinaryMemcacheRequest(getHeader(), getKey(), getExtras(), content().duplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of a {@link FullBinaryMemcacheResponse}.
|
||||||
|
*/
|
||||||
|
public class DefaultFullBinaryMemcacheResponse extends DefaultBinaryMemcacheResponse
|
||||||
|
implements FullBinaryMemcacheResponse {
|
||||||
|
|
||||||
|
private final ByteBuf content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultFullBinaryMemcacheResponse} with the header, key and extras.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
*/
|
||||||
|
public DefaultFullBinaryMemcacheResponse(BinaryMemcacheResponseHeader header, String key, ByteBuf extras) {
|
||||||
|
this(header, key, extras, Unpooled.buffer(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DefaultFullBinaryMemcacheResponse} with the header, key, extras and content.
|
||||||
|
*
|
||||||
|
* @param header the header to use.
|
||||||
|
* @param key the key to use.
|
||||||
|
* @param extras the extras to use.
|
||||||
|
* @param content the content of the full request.
|
||||||
|
*/
|
||||||
|
public DefaultFullBinaryMemcacheResponse(BinaryMemcacheResponseHeader header, String key, ByteBuf extras,
|
||||||
|
ByteBuf content) {
|
||||||
|
super(header, key, extras);
|
||||||
|
if (content == null) {
|
||||||
|
throw new NullPointerException("Supplied content is null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuf content() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int refCnt() {
|
||||||
|
return content.refCnt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheResponse retain() {
|
||||||
|
content.retain();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheResponse retain(int increment) {
|
||||||
|
content.retain(increment);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release() {
|
||||||
|
return content.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(int decrement) {
|
||||||
|
return content.release(decrement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheResponse copy() {
|
||||||
|
return new DefaultFullBinaryMemcacheResponse(getHeader(), getKey(), getExtras(), content().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FullBinaryMemcacheResponse duplicate() {
|
||||||
|
return new DefaultFullBinaryMemcacheResponse(getHeader(), getKey(), getExtras(), content().duplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.memcache.FullMemcacheMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BinaryMemcacheRequest} that also includes the content.
|
||||||
|
*/
|
||||||
|
public interface FullBinaryMemcacheRequest extends BinaryMemcacheRequest, FullMemcacheMessage {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheRequest copy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheRequest retain(int increment);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheRequest retain();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheRequest duplicate();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.memcache.FullMemcacheMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BinaryMemcacheResponse} that also includes the content.
|
||||||
|
*/
|
||||||
|
public interface FullBinaryMemcacheResponse extends BinaryMemcacheResponse, FullMemcacheMessage {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheResponse copy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheResponse retain(int increment);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheResponse retain();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
FullBinaryMemcacheResponse duplicate();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations and Interfaces for the Memcache Binary protocol.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents all Opcodes that can occur in a {@link io.netty.handler.codec.memcache.binary.BinaryMemcacheMessage}.
|
||||||
|
* <p/>
|
||||||
|
* This class can be extended if a custom application needs to implement a superset of the normally supported
|
||||||
|
* operations by a vanilla memcached protocol.
|
||||||
|
*/
|
||||||
|
public final class BinaryMemcacheOpcodes {
|
||||||
|
|
||||||
|
private BinaryMemcacheOpcodes() {
|
||||||
|
// disallow construction
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final byte GET = 0x00;
|
||||||
|
public static final byte SET = 0x01;
|
||||||
|
public static final byte ADD = 0x02;
|
||||||
|
public static final byte REPLACE = 0x03;
|
||||||
|
public static final byte DELETE = 0x04;
|
||||||
|
public static final byte INCREMENT = 0x05;
|
||||||
|
public static final byte DECREMENT = 0x06;
|
||||||
|
public static final byte QUIT = 0x07;
|
||||||
|
public static final byte FLUSH = 0x08;
|
||||||
|
public static final byte GETQ = 0x09;
|
||||||
|
public static final byte NOOP = 0x0a;
|
||||||
|
public static final byte VERSION = 0x0b;
|
||||||
|
public static final byte GETK = 0x0c;
|
||||||
|
public static final byte GETKQ = 0x0d;
|
||||||
|
public static final byte APPEND = 0x0e;
|
||||||
|
public static final byte PREPEND = 0x0f;
|
||||||
|
public static final byte STAT = 0x10;
|
||||||
|
public static final byte SETQ = 0x11;
|
||||||
|
public static final byte ADDQ = 0x12;
|
||||||
|
public static final byte REPLACEQ = 0x13;
|
||||||
|
public static final byte DELETEQ = 0x14;
|
||||||
|
public static final byte INCREMENTQ = 0x15;
|
||||||
|
public static final byte DECREMENTQ = 0x16;
|
||||||
|
public static final byte QUITQ = 0x17;
|
||||||
|
public static final byte FLUSHQ = 0x18;
|
||||||
|
public static final byte APPENDQ = 0x19;
|
||||||
|
public static final byte PREPENDQ = 0x1a;
|
||||||
|
public static final byte TOUCH = 0x1c;
|
||||||
|
public static final byte GAT = 0x1d;
|
||||||
|
public static final byte GATQ = 0x1e;
|
||||||
|
public static final byte GATK = 0x23;
|
||||||
|
public static final byte GATKQ = 0x24;
|
||||||
|
public static final byte SASL_LIST_MECHS = 0x20;
|
||||||
|
public static final byte SASL_AUTH = 0x21;
|
||||||
|
public static final byte SASL_STEP = 0x22;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all possible status values a
|
||||||
|
* {@link io.netty.handler.codec.memcache.binary.BinaryMemcacheResponseHeader} can return.
|
||||||
|
*/
|
||||||
|
public final class BinaryMemcacheResponseStatus {
|
||||||
|
|
||||||
|
private BinaryMemcacheResponseStatus() {
|
||||||
|
// disallow construction
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final short SUCCESS = 0x00;
|
||||||
|
public static final short KEY_ENOENT = 0x01;
|
||||||
|
public static final short KEY_EEXISTS = 0x02;
|
||||||
|
public static final short E2BIG = 0x03;
|
||||||
|
public static final short EINVA = 0x04;
|
||||||
|
public static final short NOT_STORED = 0x05;
|
||||||
|
public static final short DELTA_BADVAL = 0x06;
|
||||||
|
public static final short AUTH_ERROR = 0x20;
|
||||||
|
public static final short AUTH_CONTINUE = 0x21;
|
||||||
|
public static final short UNKNOWN_COMMAND = 0x81;
|
||||||
|
public static final short ENOMEM = 0x82;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility helpers for the binary protocol.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary.util;
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common superset of ascii and binary classes.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache;
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.embedded.EmbeddedChannel;
|
||||||
|
import io.netty.handler.codec.memcache.LastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheContent;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.core.IsNull.notNullValue;
|
||||||
|
import static org.hamcrest.core.IsNull.nullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the correct functionality of the {@link BinaryMemcacheDecoder}.
|
||||||
|
* <p/>
|
||||||
|
* While technically there are both a {@link BinaryMemcacheRequestDecoder} and a {@link BinaryMemcacheResponseDecoder}
|
||||||
|
* they implement the same basics and just differ in the type of headers returned.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheDecoderTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a GET request header with a key size of three.
|
||||||
|
*/
|
||||||
|
private static final byte[] GET_REQUEST = new byte[]{
|
||||||
|
(byte) 0x80, 0x00, 0x00, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x6f, 0x6f
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final byte[] SET_REQUEST_WITH_CONTENT = new byte[]{
|
||||||
|
(byte) 0x80, 0x01, 0x00, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x0B,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x6f, 0x6f,
|
||||||
|
0x01, 0x02, 0x03, 0x04,
|
||||||
|
0x05, 0x06, 0x07, 0x08
|
||||||
|
};
|
||||||
|
|
||||||
|
private EmbeddedChannel channel;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
channel = new EmbeddedChannel(new BinaryMemcacheRequestDecoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests a simple GET request with a key as the value.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldDecodeRequestWithSimpleValue() {
|
||||||
|
ByteBuf incoming = Unpooled.buffer();
|
||||||
|
incoming.writeBytes(GET_REQUEST);
|
||||||
|
channel.writeInbound(incoming);
|
||||||
|
|
||||||
|
BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();
|
||||||
|
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(request.getHeader(), notNullValue());
|
||||||
|
assertThat(request.getKey(), notNullValue());
|
||||||
|
assertThat(request.getExtras(), nullValue());
|
||||||
|
|
||||||
|
BinaryMemcacheRequestHeader header = request.getHeader();
|
||||||
|
assertThat(header.getKeyLength(), is((short) 3));
|
||||||
|
assertThat(header.getExtrasLength(), is((byte) 0));
|
||||||
|
assertThat(header.getTotalBodyLength(), is(3));
|
||||||
|
|
||||||
|
request.release();
|
||||||
|
assertThat(channel.readInbound(), instanceOf(LastMemcacheContent.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test makes sure that large content is emitted in chunks.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldDecodeRequestWithChunkedContent() {
|
||||||
|
int smallBatchSize = 2;
|
||||||
|
channel = new EmbeddedChannel(new BinaryMemcacheRequestDecoder(smallBatchSize));
|
||||||
|
|
||||||
|
ByteBuf incoming = Unpooled.buffer();
|
||||||
|
incoming.writeBytes(SET_REQUEST_WITH_CONTENT);
|
||||||
|
channel.writeInbound(incoming);
|
||||||
|
|
||||||
|
BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();
|
||||||
|
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(request.getHeader(), notNullValue());
|
||||||
|
assertThat(request.getKey(), notNullValue());
|
||||||
|
assertThat(request.getExtras(), nullValue());
|
||||||
|
|
||||||
|
BinaryMemcacheRequestHeader header = request.getHeader();
|
||||||
|
assertThat(header.getKeyLength(), is((short) 3));
|
||||||
|
assertThat(header.getExtrasLength(), is((byte) 0));
|
||||||
|
assertThat(header.getTotalBodyLength(), is(11));
|
||||||
|
|
||||||
|
int expectedContentChunks = 4;
|
||||||
|
for (int i = 1; i <= expectedContentChunks; i++) {
|
||||||
|
MemcacheContent content = (MemcacheContent) channel.readInbound();
|
||||||
|
if (i < expectedContentChunks) {
|
||||||
|
assertThat(content, instanceOf(MemcacheContent.class));
|
||||||
|
} else {
|
||||||
|
assertThat(content, instanceOf(LastMemcacheContent.class));
|
||||||
|
}
|
||||||
|
assertThat(content.content().readableBytes(), is(2));
|
||||||
|
}
|
||||||
|
assertThat(channel.readInbound(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test makes sure that even when the decoder is confronted with various chunk
|
||||||
|
* sizes in the middle of decoding, it can recover and decode all the time eventually.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldHandleNonUniformNetworkBatches() {
|
||||||
|
ByteBuf incoming = Unpooled.copiedBuffer(SET_REQUEST_WITH_CONTENT);
|
||||||
|
while (incoming.isReadable()) {
|
||||||
|
channel.writeInbound(incoming.readBytes(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();
|
||||||
|
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(request.getHeader(), notNullValue());
|
||||||
|
assertThat(request.getKey(), notNullValue());
|
||||||
|
assertThat(request.getExtras(), nullValue());
|
||||||
|
|
||||||
|
MemcacheContent content1 = (MemcacheContent) channel.readInbound();
|
||||||
|
MemcacheContent content2 = (MemcacheContent) channel.readInbound();
|
||||||
|
|
||||||
|
assertThat(content1, instanceOf(MemcacheContent.class));
|
||||||
|
assertThat(content2, instanceOf(LastMemcacheContent.class));
|
||||||
|
|
||||||
|
assertThat(content1.content().readableBytes(), is(3));
|
||||||
|
assertThat(content2.content().readableBytes(), is(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test makes sure that even when more requests arrive in the same batch, they
|
||||||
|
* get emitted as separate messages.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldHandleTwoMessagesInOneBatch() {
|
||||||
|
channel.writeInbound(Unpooled.buffer().writeBytes(GET_REQUEST).writeBytes(GET_REQUEST));
|
||||||
|
|
||||||
|
BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();
|
||||||
|
assertThat(request, instanceOf(BinaryMemcacheRequest.class));
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(channel.readInbound(), instanceOf(LastMemcacheContent.class));
|
||||||
|
|
||||||
|
request = (BinaryMemcacheRequest) channel.readInbound();
|
||||||
|
assertThat(request, instanceOf(BinaryMemcacheRequest.class));
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(channel.readInbound(), instanceOf(LastMemcacheContent.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.embedded.EmbeddedChannel;
|
||||||
|
import io.netty.handler.codec.EncoderException;
|
||||||
|
import io.netty.handler.codec.memcache.DefaultLastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.DefaultMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.binary.util.BinaryMemcacheOpcodes;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the correct functionality of the {@link BinaryMemcacheEncoder}.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheEncoderTest {
|
||||||
|
|
||||||
|
public static int DEFAULT_HEADER_SIZE = 24;
|
||||||
|
|
||||||
|
private EmbeddedChannel channel;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
channel = new EmbeddedChannel(new BinaryMemcacheRequestEncoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldEncodeDefaultHeader() {
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
BinaryMemcacheRequest request = new DefaultBinaryMemcacheRequest(header);
|
||||||
|
|
||||||
|
boolean result = channel.writeOutbound(request);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
|
||||||
|
ByteBuf written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(DEFAULT_HEADER_SIZE));
|
||||||
|
assertThat(written.readByte(), is((byte) 0x80));
|
||||||
|
assertThat(written.readByte(), is((byte) 0x00));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldEncodeCustomHeader() {
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
header.setMagic((byte) 0xAA);
|
||||||
|
header.setOpcode(BinaryMemcacheOpcodes.GET);
|
||||||
|
BinaryMemcacheRequest request = new DefaultBinaryMemcacheRequest(header);
|
||||||
|
|
||||||
|
boolean result = channel.writeOutbound(request);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
|
||||||
|
ByteBuf written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(DEFAULT_HEADER_SIZE));
|
||||||
|
assertThat(written.readByte(), is((byte) 0xAA));
|
||||||
|
assertThat(written.readByte(), is(BinaryMemcacheOpcodes.GET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldEncodeExtras() {
|
||||||
|
String extrasContent = "netty<3memcache";
|
||||||
|
ByteBuf extras = Unpooled.copiedBuffer(extrasContent, CharsetUtil.UTF_8);
|
||||||
|
int extrasLength = extras.readableBytes();
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
header.setExtrasLength((byte) extrasLength);
|
||||||
|
BinaryMemcacheRequest request = new DefaultBinaryMemcacheRequest(header, extras);
|
||||||
|
|
||||||
|
boolean result = channel.writeOutbound(request);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
|
||||||
|
ByteBuf written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(DEFAULT_HEADER_SIZE + extrasLength));
|
||||||
|
written.readBytes(DEFAULT_HEADER_SIZE);
|
||||||
|
assertThat(written.readBytes(extrasLength).toString(CharsetUtil.UTF_8), equalTo(extrasContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldEncodeKey() {
|
||||||
|
String key = "netty";
|
||||||
|
int keyLength = key.length();
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
header.setKeyLength((byte) keyLength);
|
||||||
|
BinaryMemcacheRequest request = new DefaultBinaryMemcacheRequest(header, key);
|
||||||
|
|
||||||
|
boolean result = channel.writeOutbound(request);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
|
||||||
|
ByteBuf written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(DEFAULT_HEADER_SIZE + keyLength));
|
||||||
|
written.readBytes(DEFAULT_HEADER_SIZE);
|
||||||
|
assertThat(written.readBytes(keyLength).toString(CharsetUtil.UTF_8), equalTo(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldEncodeContent() {
|
||||||
|
DefaultMemcacheContent content1 =
|
||||||
|
new DefaultMemcacheContent(Unpooled.copiedBuffer("Netty", CharsetUtil.UTF_8));
|
||||||
|
DefaultLastMemcacheContent content2 =
|
||||||
|
new DefaultLastMemcacheContent(Unpooled.copiedBuffer(" Rocks!", CharsetUtil.UTF_8));
|
||||||
|
int totalBodyLength = content1.content().readableBytes() + content2.content().readableBytes();
|
||||||
|
|
||||||
|
BinaryMemcacheRequestHeader header = new DefaultBinaryMemcacheRequestHeader();
|
||||||
|
header.setTotalBodyLength(totalBodyLength);
|
||||||
|
BinaryMemcacheRequest request = new DefaultBinaryMemcacheRequest(header);
|
||||||
|
|
||||||
|
boolean result = channel.writeOutbound(request);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
result = channel.writeOutbound(content1);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
result = channel.writeOutbound(content2);
|
||||||
|
assertThat(result, is(true));
|
||||||
|
|
||||||
|
ByteBuf written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(DEFAULT_HEADER_SIZE));
|
||||||
|
written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(content1.content().readableBytes()));
|
||||||
|
assertThat(
|
||||||
|
written.readBytes(content1.content().readableBytes()).toString(CharsetUtil.UTF_8),
|
||||||
|
is("Netty")
|
||||||
|
);
|
||||||
|
written = (ByteBuf) channel.readOutbound();
|
||||||
|
assertThat(written.readableBytes(), is(content2.content().readableBytes()));
|
||||||
|
assertThat(
|
||||||
|
written.readBytes(content2.content().readableBytes()).toString(CharsetUtil.UTF_8),
|
||||||
|
is(" Rocks!")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = EncoderException.class)
|
||||||
|
public void shouldFailWithoutLastContent() {
|
||||||
|
channel.writeOutbound(new DefaultMemcacheContent(Unpooled.EMPTY_BUFFER));
|
||||||
|
channel.writeOutbound(
|
||||||
|
new DefaultBinaryMemcacheRequest(new DefaultBinaryMemcacheRequestHeader()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.embedded.EmbeddedChannel;
|
||||||
|
import io.netty.handler.codec.memcache.LastMemcacheContent;
|
||||||
|
import io.netty.handler.codec.memcache.MemcacheContent;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.core.IsNull.notNullValue;
|
||||||
|
import static org.hamcrest.core.IsNull.nullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the correct functionality of the {@link BinaryMemcacheObjectAggregator}.
|
||||||
|
*/
|
||||||
|
public class BinaryMemcacheObjectAggregatorTest {
|
||||||
|
|
||||||
|
private static final byte[] SET_REQUEST_WITH_CONTENT = new byte[]{
|
||||||
|
(byte) 0x80, 0x01, 0x00, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x0B,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x6f, 0x6f,
|
||||||
|
0x01, 0x02, 0x03, 0x04,
|
||||||
|
0x05, 0x06, 0x07, 0x08
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int MAX_CONTENT_SIZE = 2 << 10;
|
||||||
|
|
||||||
|
private EmbeddedChannel channel;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAggregateChunksOnDecode() {
|
||||||
|
int smallBatchSize = 2;
|
||||||
|
channel = new EmbeddedChannel(
|
||||||
|
new BinaryMemcacheRequestDecoder(smallBatchSize),
|
||||||
|
new BinaryMemcacheObjectAggregator(MAX_CONTENT_SIZE));
|
||||||
|
|
||||||
|
ByteBuf incoming = Unpooled.buffer();
|
||||||
|
incoming.writeBytes(SET_REQUEST_WITH_CONTENT);
|
||||||
|
channel.writeInbound(incoming);
|
||||||
|
|
||||||
|
FullBinaryMemcacheRequest request = (FullBinaryMemcacheRequest) channel.readInbound();
|
||||||
|
|
||||||
|
assertThat(request, instanceOf(FullBinaryMemcacheRequest.class));
|
||||||
|
assertThat(request, notNullValue());
|
||||||
|
assertThat(request.getHeader(), notNullValue());
|
||||||
|
assertThat(request.getKey(), notNullValue());
|
||||||
|
assertThat(request.getExtras(), nullValue());
|
||||||
|
|
||||||
|
assertThat(request.content().readableBytes(), is(8));
|
||||||
|
assertThat(request.content().readByte(), is((byte) 0x01));
|
||||||
|
assertThat(request.content().readByte(), is((byte) 0x02));
|
||||||
|
|
||||||
|
assertThat(channel.readInbound(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
pom.xml
1
pom.xml
@ -144,6 +144,7 @@
|
|||||||
<module>buffer</module>
|
<module>buffer</module>
|
||||||
<module>codec</module>
|
<module>codec</module>
|
||||||
<module>codec-http</module>
|
<module>codec-http</module>
|
||||||
|
<module>codec-memcache</module>
|
||||||
<module>codec-socks</module>
|
<module>codec-socks</module>
|
||||||
<module>transport</module>
|
<module>transport</module>
|
||||||
<module>transport-rxtx</module>
|
<module>transport-rxtx</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user