1 /*
2  * Copyright 2013 The Netty Project
3  *
4  * The Netty Project licenses this file to you under the Apache License,
5  * version 2.0 (the "License"); you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at:
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */

16
17 package io.netty.buffer;
18
19 import io.netty.util.ResourceLeakDetector;
20 import io.netty.util.ResourceLeakTracker;
21 import io.netty.util.internal.ObjectUtil;
22
23 import java.nio.ByteOrder;
24
25 class SimpleLeakAwareByteBuf extends WrappedByteBuf {
26
27     /**
28      * This object's is associated with the {@link ResourceLeakTracker}. When {@link ResourceLeakTracker#close(Object)}
29      * is called this object will be used as the argument. It is also assumed that this object is used when
30      * {@link ResourceLeakDetector#track(Object)} is called to create {@link #leak}.
31      */

32     private final ByteBuf trackedByteBuf;
33     final ResourceLeakTracker<ByteBuf> leak;
34
35     SimpleLeakAwareByteBuf(ByteBuf wrapped, ByteBuf trackedByteBuf, ResourceLeakTracker<ByteBuf> leak) {
36         super(wrapped);
37         this.trackedByteBuf = ObjectUtil.checkNotNull(trackedByteBuf, "trackedByteBuf");
38         this.leak = ObjectUtil.checkNotNull(leak, "leak");
39     }
40
41     SimpleLeakAwareByteBuf(ByteBuf wrapped, ResourceLeakTracker<ByteBuf> leak) {
42         this(wrapped, wrapped, leak);
43     }
44
45     @Override
46     public ByteBuf slice() {
47         return newSharedLeakAwareByteBuf(super.slice());
48     }
49
50     @Override
51     public ByteBuf retainedSlice() {
52         return unwrappedDerived(super.retainedSlice());
53     }
54
55     @Override
56     public ByteBuf retainedSlice(int index, int length) {
57         return unwrappedDerived(super.retainedSlice(index, length));
58     }
59
60     @Override
61     public ByteBuf retainedDuplicate() {
62         return unwrappedDerived(super.retainedDuplicate());
63     }
64
65     @Override
66     public ByteBuf readRetainedSlice(int length) {
67         return unwrappedDerived(super.readRetainedSlice(length));
68     }
69
70     @Override
71     public ByteBuf slice(int index, int length) {
72         return newSharedLeakAwareByteBuf(super.slice(index, length));
73     }
74
75     @Override
76     public ByteBuf duplicate() {
77         return newSharedLeakAwareByteBuf(super.duplicate());
78     }
79
80     @Override
81     public ByteBuf readSlice(int length) {
82         return newSharedLeakAwareByteBuf(super.readSlice(length));
83     }
84
85     @Override
86     public ByteBuf asReadOnly() {
87         return newSharedLeakAwareByteBuf(super.asReadOnly());
88     }
89
90     @Override
91     public ByteBuf touch() {
92         return this;
93     }
94
95     @Override
96     public ByteBuf touch(Object hint) {
97         return this;
98     }
99
100     @Override
101     public boolean release() {
102         if (super.release()) {
103             closeLeak();
104             return true;
105         }
106         return false;
107     }
108
109     @Override
110     public boolean release(int decrement) {
111         if (super.release(decrement)) {
112             closeLeak();
113             return true;
114         }
115         return false;
116     }
117
118     private void closeLeak() {
119         // Close the ResourceLeakTracker with the tracked ByteBuf as argument. This must be the same that was used when
120         // calling DefaultResourceLeak.track(...).
121         boolean closed = leak.close(trackedByteBuf);
122         assert closed;
123     }
124
125     @Override
126     public ByteBuf order(ByteOrder endianness) {
127         if (order() == endianness) {
128             return this;
129         } else {
130             return newSharedLeakAwareByteBuf(super.order(endianness));
131         }
132     }
133
134     private ByteBuf unwrappedDerived(ByteBuf derived) {
135         // We only need to unwrap SwappedByteBuf implementations as these will be the only ones that may end up in
136         // the AbstractLeakAwareByteBuf implementations beside slices / duplicates and "real" buffers.
137         ByteBuf unwrappedDerived = unwrapSwapped(derived);
138
139         if (unwrappedDerived instanceof AbstractPooledDerivedByteBuf) {
140             // Update the parent to point to this buffer so we correctly close the ResourceLeakTracker.
141             ((AbstractPooledDerivedByteBuf) unwrappedDerived).parent(this);
142
143             ResourceLeakTracker<ByteBuf> newLeak = AbstractByteBuf.leakDetector.track(derived);
144             if (newLeak == null) {
145                 // No leak detection, just return the derived buffer.
146                 return derived;
147             }
148             return newLeakAwareByteBuf(derived, newLeak);
149         }
150         return newSharedLeakAwareByteBuf(derived);
151     }
152
153     @SuppressWarnings("deprecation")
154     private static ByteBuf unwrapSwapped(ByteBuf buf) {
155         if (buf instanceof SwappedByteBuf) {
156             do {
157                 buf = buf.unwrap();
158             } while (buf instanceof SwappedByteBuf);
159
160             return buf;
161         }
162         return buf;
163     }
164
165     private SimpleLeakAwareByteBuf newSharedLeakAwareByteBuf(
166             ByteBuf wrapped) {
167         return newLeakAwareByteBuf(wrapped, trackedByteBuf, leak);
168     }
169
170     private SimpleLeakAwareByteBuf newLeakAwareByteBuf(
171             ByteBuf wrapped, ResourceLeakTracker<ByteBuf> leakTracker) {
172         return newLeakAwareByteBuf(wrapped, wrapped, leakTracker);
173     }
174
175     protected SimpleLeakAwareByteBuf newLeakAwareByteBuf(
176             ByteBuf buf, ByteBuf trackedByteBuf, ResourceLeakTracker<ByteBuf> leakTracker) {
177         return new SimpleLeakAwareByteBuf(buf, trackedByteBuf, leakTracker);
178     }
179 }
180