/*
* Copyright 2016 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.reactivex.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import java.util.LinkedList;
import java.util.List;
/**
* A holder for all transformations that are applied on a channel. Out of the box, it comes with a {@code String} and
* {@code byte[]} transformer to {@code ByteBuf}. Additional transformations can be applied using
* {@link #appendTransformer(AllocatingTransformer)}.
*/
public class WriteTransformations {
private TransformerChain transformers;
public boolean transform(Object msg, ByteBufAllocator allocator, List<Object> out) {
boolean transformed = false;
if (msg instanceof String) {
out.add(allocator.buffer().writeBytes(((String) msg).getBytes()));
transformed = true;
} else if (msg instanceof byte[]) {
out.add(allocator.buffer().writeBytes((byte[]) msg));
transformed = true;
} else if (null != transformers && transformers.acceptMessage(msg)) {
out.addAll(transformers.transform(msg, allocator));
transformed = true;
}
return transformed;
}
public <T, TT> void appendTransformer(AllocatingTransformer<T, TT> transformer) {
transformers = new TransformerChain(transformer, transformers);
}
public void resetTransformations() {
transformers = null;
}
public boolean acceptMessage(Object msg) {
return msg instanceof String || msg instanceof byte[] || null != transformers && transformers.acceptMessage(msg);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static class TransformerChain extends AllocatingTransformer {
private final AllocatingTransformer start;
private final AllocatingTransformer next;
public TransformerChain(AllocatingTransformer start, AllocatingTransformer next) {
this.start = start;
this.next = next;
}
@Override
public List transform(Object toTransform, ByteBufAllocator allocator) {
if (null == next) {
return start.transform(toTransform, allocator);
}
List transformed = start.transform(toTransform, allocator);
if (transformed.size() == 1) {
return next.transform(transformed.get(0), allocator);
} else {
final LinkedList toReturn = new LinkedList();
for (Object nextItem : transformed) {
toReturn.addAll(next.transform(nextItem, allocator));
}
return toReturn;
}
}
@Override
protected boolean acceptMessage(Object msg) {
return start.acceptMessage(msg);
}
}
}