/*
* Copyright (c) 2012 Mike Heath. All rights reserved.
*
* 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 cloudeventbus.codec;
import cloudeventbus.pki.CertificateStoreLoader;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.CharsetUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
/**
* @author Mike Heath <elcapo@gmail.com>
*/
public class Encoder extends MessageToByteEncoder<Frame> {
private static final Logger LOGGER = LoggerFactory.getLogger(Encoder.class);
@Override
public void encode(ChannelHandlerContext ctx, Frame frame, ByteBuf out) throws Exception {
LOGGER.debug("Encoding frame {}", frame);
switch (frame.getFrameType()) {
case AUTHENTICATE:
final AuthenticationRequestFrame authenticationRequestFrame = (AuthenticationRequestFrame) frame;
out.writeByte(FrameType.AUTHENTICATE.getOpcode());
out.writeByte(' ');
final String challenge = Base64.encodeBase64String(authenticationRequestFrame.getChallenge());
writeString(out, challenge);
break;
case AUTH_RESPONSE:
final AuthenticationResponseFrame authenticationResponseFrame = (AuthenticationResponseFrame) frame;
out.writeByte(FrameType.AUTH_RESPONSE.getOpcode());
out.writeByte(' ');
// Write certificate chain
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final OutputStream base64Out = new Base64OutputStream(outputStream, true, Integer.MAX_VALUE, new byte[0]);
CertificateStoreLoader.store(base64Out, authenticationResponseFrame.getCertificates());
out.writeBytes(outputStream.toByteArray());
out.writeByte(' ');
// Write salt
final byte[] encodedSalt = Base64.encodeBase64(authenticationResponseFrame.getSalt());
out.writeBytes(encodedSalt);
out.writeByte(' ');
// Write signature
final byte[] encodedDigitalSignature = Base64.encodeBase64(authenticationResponseFrame.getDigitalSignature());
out.writeBytes(encodedDigitalSignature);
break;
case ERROR:
final ErrorFrame errorFrame = (ErrorFrame) frame;
out.writeByte(FrameType.ERROR.getOpcode());
out.writeByte(' ');
writeString(out, Integer.toString(errorFrame.getCode().getErrorNumber()));
if (errorFrame.getMessage() != null) {
out.writeByte(' ');
writeString(out, errorFrame.getMessage());
}
break;
case GREETING:
final GreetingFrame greetingFrame = (GreetingFrame) frame;
out.writeByte(FrameType.GREETING.getOpcode());
out.writeByte(' ');
writeString(out, Integer.toString(greetingFrame.getVersion()));
out.writeByte(' ');
writeString(out, greetingFrame.getAgent());
out.writeByte(' ');
writeString(out, Long.toString(greetingFrame.getId()));
break;
case PING:
out.writeByte(FrameType.PING.getOpcode());
break;
case PONG:
out.writeByte(FrameType.PONG.getOpcode());
break;
case PUBLISH:
final PublishFrame publishFrame = (PublishFrame) frame;
out.writeByte(FrameType.PUBLISH.getOpcode());
out.writeByte(' ');
writeString(out, publishFrame.getSubject().toString());
if (publishFrame.getReplySubject() != null) {
out.writeByte(' ');
writeString(out, publishFrame.getReplySubject().toString());
}
out.writeByte(' ');
final ByteBuf body = Unpooled.wrappedBuffer(publishFrame.getBody().getBytes(CharsetUtil.UTF_8));
writeString(out, Integer.toString(body.readableBytes()));
out.writeBytes(Codec.DELIMITER);
out.writeBytes(body);
break;
case SERVER_READY:
out.writeByte(FrameType.SERVER_READY.getOpcode());
break;
case SUBSCRIBE:
final SubscribeFrame subscribeFrame = (SubscribeFrame) frame;
out.writeByte(FrameType.SUBSCRIBE.getOpcode());
out.writeByte(' ');
writeString(out, subscribeFrame.getSubject().toString());
break;
case UNSUBSCRIBE:
final UnsubscribeFrame unsubscribeFrame = (UnsubscribeFrame) frame;
out.writeByte(FrameType.UNSUBSCRIBE.getOpcode());
out.writeByte(' ');
writeString(out, unsubscribeFrame.getSubject().toString());
break;
default:
throw new EncodingException("Don't know how to encode message of type " + frame.getClass().getName());
}
out.writeBytes(Codec.DELIMITER);
}
private void writeString(ByteBuf out, String string) {
out.writeBytes(string.getBytes(CharsetUtil.UTF_8));
}
}