001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.transport.amqp.message; 018 019import java.util.Arrays; 020import java.util.Collection; 021 022import org.apache.qpid.proton.codec.DecoderImpl; 023import org.apache.qpid.proton.codec.EncoderImpl; 024import org.apache.qpid.proton.codec.EncodingCodes; 025import org.apache.qpid.proton.codec.PrimitiveType; 026import org.apache.qpid.proton.codec.PrimitiveTypeEncoding; 027import org.apache.qpid.proton.codec.TypeEncoding; 028import org.apache.qpid.proton.codec.WritableBuffer; 029import org.fusesource.hawtbuf.UTF8Buffer; 030 031/** 032 * AMQP Type used to allow to proton-j codec to deal with UTF8Buffer types as if 033 * they were String elements. 034 */ 035public class UTF8BufferType implements PrimitiveType<UTF8Buffer> { 036 037 private final UTF8BufferEncoding largeBufferEncoding; 038 private final UTF8BufferEncoding smallBufferEncoding; 039 040 public UTF8BufferType(EncoderImpl encoder, DecoderImpl decoder) { 041 this.largeBufferEncoding = new LargeUTF8BufferEncoding(encoder, decoder); 042 this.smallBufferEncoding = new SmallUTF8BufferEncoding(encoder, decoder); 043 } 044 045 @Override 046 public Class<UTF8Buffer> getTypeClass() { 047 return UTF8Buffer.class; 048 } 049 050 @Override 051 public PrimitiveTypeEncoding<UTF8Buffer> getEncoding(UTF8Buffer value) { 052 return value.getLength() <= 255 ? smallBufferEncoding : largeBufferEncoding; 053 } 054 055 @Override 056 public PrimitiveTypeEncoding<UTF8Buffer> getCanonicalEncoding() { 057 return largeBufferEncoding; 058 } 059 060 @Override 061 public Collection<? extends PrimitiveTypeEncoding<UTF8Buffer>> getAllEncodings() { 062 return Arrays.asList(smallBufferEncoding, largeBufferEncoding); 063 } 064 065 @Override 066 public void write(UTF8Buffer value) { 067 final TypeEncoding<UTF8Buffer> encoding = getEncoding(value); 068 encoding.writeConstructor(); 069 encoding.writeValue(value); 070 } 071 072 public abstract class UTF8BufferEncoding implements PrimitiveTypeEncoding<UTF8Buffer> { 073 074 private final EncoderImpl encoder; 075 private final DecoderImpl decoder; 076 077 public UTF8BufferEncoding(EncoderImpl encoder, DecoderImpl decoder) { 078 this.encoder = encoder; 079 this.decoder = decoder; 080 } 081 082 @Override 083 public int getConstructorSize() { 084 return 1; 085 } 086 087 @Override 088 public boolean isFixedSizeVal() { 089 return false; 090 } 091 092 @Override 093 public boolean encodesJavaPrimitive() { 094 return false; 095 } 096 097 /** 098 * @return the number of bytes the size portion of the encoded value requires. 099 */ 100 public abstract int getSizeBytes(); 101 102 @Override 103 public void writeConstructor() { 104 getEncoder().writeRaw(getEncodingCode()); 105 } 106 107 @Override 108 public void writeValue(UTF8Buffer value) { 109 writeSize(value); 110 WritableBuffer buffer = getEncoder().getBuffer(); 111 buffer.put(value.getData(), value.getOffset(), value.getLength()); 112 } 113 114 /** 115 * Write the size of the buffer using the appropriate type (byte or int) depending 116 * on the encoding type being used. 117 * 118 * @param value 119 * The UTF8Buffer value that is being encoded. 120 */ 121 public abstract void writeSize(UTF8Buffer value); 122 123 @Override 124 public int getValueSize(UTF8Buffer value) { 125 return getSizeBytes() + value.getLength(); 126 } 127 128 @Override 129 public Class<UTF8Buffer> getTypeClass() { 130 return UTF8Buffer.class; 131 } 132 133 @Override 134 public PrimitiveType<UTF8Buffer> getType() { 135 return UTF8BufferType.this; 136 } 137 138 @Override 139 public boolean encodesSuperset(TypeEncoding<UTF8Buffer> encoding) { 140 return (getType() == encoding.getType()); 141 } 142 143 @Override 144 public UTF8Buffer readValue() { 145 throw new UnsupportedOperationException("No decoding to UTF8Buffer exists"); 146 } 147 148 @Override 149 public void skipValue() { 150 throw new UnsupportedOperationException("No decoding to UTF8Buffer exists"); 151 } 152 153 public DecoderImpl getDecoder() { 154 return decoder; 155 } 156 157 public EncoderImpl getEncoder() { 158 return encoder; 159 } 160 } 161 162 public class LargeUTF8BufferEncoding extends UTF8BufferEncoding { 163 164 public LargeUTF8BufferEncoding(EncoderImpl encoder, DecoderImpl decoder) { 165 super(encoder, decoder); 166 } 167 168 @Override 169 public byte getEncodingCode() { 170 return EncodingCodes.STR32; 171 } 172 173 @Override 174 public int getSizeBytes() { 175 return Integer.BYTES; 176 } 177 178 @Override 179 public void writeSize(UTF8Buffer value) { 180 getEncoder().getBuffer().putInt(value.getLength()); 181 } 182 } 183 184 public class SmallUTF8BufferEncoding extends UTF8BufferEncoding { 185 186 public SmallUTF8BufferEncoding(EncoderImpl encoder, DecoderImpl decoder) { 187 super(encoder, decoder); 188 } 189 190 @Override 191 public byte getEncodingCode() { 192 return EncodingCodes.STR8; 193 } 194 195 @Override 196 public int getSizeBytes() { 197 return Byte.BYTES; 198 } 199 200 @Override 201 public void writeSize(UTF8Buffer value) { 202 getEncoder().getBuffer().put((byte) value.getLength()); 203 } 204 } 205}