1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  package org.waarp.openr66.protocol.localhandler.packet;
21  
22  import io.netty.buffer.ByteBuf;
23  import io.netty.buffer.ByteBufAllocator;
24  import io.netty.buffer.Unpooled;
25  import io.netty.util.IllegalReferenceCountException;
26  import org.waarp.common.utility.WaarpNettyUtil;
27  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
28  import org.waarp.openr66.protocol.localhandler.LocalChannelReference;
29  import org.waarp.openr66.protocol.networkhandler.packet.NetworkPacket;
30  
31  import static org.waarp.openr66.protocol.networkhandler.packet.NetworkPacket.*;
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  public abstract class AbstractLocalPacket {
43    protected static final byte[] EMPTY_ARRAY = {};
44    protected static final int LOCAL_HEADER_SIZE = 4 * 3 + 1;
45  
46    protected ByteBuf header;
47  
48    protected ByteBuf middle;
49  
50    protected ByteBuf end;
51  
52    protected ByteBuf global = null;
53  
54    protected AbstractLocalPacket() {
55      header = null;
56      middle = null;
57      end = null;
58    }
59  
60    
61  
62  
63    public abstract boolean hasGlobalBuffer();
64  
65    
66  
67  
68  
69  
70    public abstract void createAllBuffers(final LocalChannelReference lcr,
71                                          final int networkHeader)
72        throws OpenR66ProtocolPacketException;
73  
74    
75  
76  
77  
78  
79    public void createHeader(final LocalChannelReference lcr)
80        throws OpenR66ProtocolPacketException {
81      throw new IllegalStateException("Should not be called");
82    }
83  
84    
85  
86  
87  
88  
89    public void createMiddle(final LocalChannelReference lcr)
90        throws OpenR66ProtocolPacketException {
91      throw new IllegalStateException("Should not be called");
92    }
93  
94    
95  
96  
97  
98  
99    public void createEnd(final LocalChannelReference lcr)
100       throws OpenR66ProtocolPacketException {
101     throw new IllegalStateException("Should not be called");
102   }
103 
104   
105 
106 
107   public abstract byte getType();
108 
109   @Override
110   public abstract String toString();
111 
112   
113 
114 
115 
116 
117 
118 
119   public final ByteBuf getLocalPacket(final LocalChannelReference lcr)
120       throws OpenR66ProtocolPacketException {
121     return getLocalPacketForNetworkPacket(lcr, null);
122   }
123 
124   
125 
126 
127 
128 
129 
130 
131   public final synchronized ByteBuf getLocalPacketForNetworkPacket(
132       final LocalChannelReference lcr, final NetworkPacket packet)
133       throws OpenR66ProtocolPacketException {
134     try {
135       final ByteBuf buf;
136       final int globalHeader;
137       if (packet != null) {
138         globalHeader = NETWORK_HEADER_SIZE;
139       } else {
140         globalHeader = 0;
141       }
142       if (hasGlobalBuffer()) {
143         if (global == null) {
144           createAllBuffers(lcr, globalHeader);
145         } else {
146           global.readerIndex(0);
147           global.writerIndex(0);
148         }
149         buf = global;
150       } else {
151         
152         buf =
153             ByteBufAllocator.DEFAULT.ioBuffer(globalHeader + LOCAL_HEADER_SIZE,
154                                               globalHeader + LOCAL_HEADER_SIZE);
155         if (header == null) {
156           createHeader(lcr);
157         }
158         if (middle == null) {
159           createMiddle(lcr);
160         }
161         if (end == null) {
162           createEnd(lcr);
163         }
164       }
165       if (packet != null) {
166         final int capacity =
167             LOCAL_HEADER_SIZE + (header != null? header.capacity() : 0) +
168             (middle != null? middle.capacity() : 0) +
169             (end != null? end.capacity() : 0);
170         packet.writeNetworkHeader(buf, capacity);
171       }
172       return getByteBuf(buf);
173     } catch (final IllegalReferenceCountException e) {
174       throw new OpenR66ProtocolPacketException(e);
175     }
176   }
177 
178   private ByteBuf getByteBuf(final ByteBuf buf) {
179     final ByteBuf newHeader = header != null? header : Unpooled.EMPTY_BUFFER;
180     final int headerLength = LOCAL_HEADER_SIZE - 4 + newHeader.readableBytes();
181     final ByteBuf newMiddle = middle != null? middle : Unpooled.EMPTY_BUFFER;
182     final int middleLength = newMiddle.readableBytes();
183     final ByteBuf newEnd = end != null? end : Unpooled.EMPTY_BUFFER;
184     final int endLength = newEnd.readableBytes();
185     buf.writeInt(headerLength);
186     buf.writeInt(middleLength);
187     buf.writeInt(endLength);
188     buf.writeByte(getType());
189     if (hasGlobalBuffer()) {
190       buf.writerIndex(buf.capacity());
191       return buf;
192     }
193     return ByteBufAllocator.DEFAULT.compositeDirectBuffer(4)
194                                    .addComponents(buf, newHeader, newMiddle,
195                                                   newEnd);
196   }
197 
198   public synchronized void clear() {
199     if (WaarpNettyUtil.release(global)) {
200       global = null;
201     }
202     if (hasGlobalBuffer()) {
203       return;
204     }
205     if (WaarpNettyUtil.release(header)) {
206       header = null;
207     }
208     if (WaarpNettyUtil.release(middle)) {
209       middle = null;
210     }
211     if (WaarpNettyUtil.release(end)) {
212       end = null;
213     }
214   }
215 
216   public final synchronized void retain() {
217     WaarpNettyUtil.retain(global);
218     if (hasGlobalBuffer()) {
219       return;
220     }
221     WaarpNettyUtil.retain(header);
222     WaarpNettyUtil.retain(middle);
223     WaarpNettyUtil.retain(end);
224   }
225 }