1/*
2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package sun.nio.cs;
28
29import java.nio.charset.*;
30
31
32/**
33 * Utility class for caching per-thread decoders and encoders.
34 */
35
36public class ThreadLocalCoders {
37
38    private static final int CACHE_SIZE = 3;
39
40    private abstract static class Cache {
41
42        // Thread-local reference to array of cached objects, in LRU order
43        private ThreadLocal<Object[]> cache = new ThreadLocal<>();
44        private final int size;
45
46        Cache(int size) {
47            this.size = size;
48        }
49
50        abstract Object create(Object name);
51
52        private void moveToFront(Object[] oa, int i) {
53            Object ob = oa[i];
54            for (int j = i; j > 0; j--)
55                oa[j] = oa[j - 1];
56            oa[0] = ob;
57        }
58
59        abstract boolean hasName(Object ob, Object name);
60
61        Object forName(Object name) {
62            Object[] oa = cache.get();
63            if (oa == null) {
64                oa = new Object[size];
65                cache.set(oa);
66            } else {
67                for (int i = 0; i < oa.length; i++) {
68                    Object ob = oa[i];
69                    if (ob == null)
70                        continue;
71                    if (hasName(ob, name)) {
72                        if (i > 0)
73                            moveToFront(oa, i);
74                        return ob;
75                    }
76                }
77            }
78
79            // Create a new object
80            Object ob = create(name);
81            oa[oa.length - 1] = ob;
82            moveToFront(oa, oa.length - 1);
83            return ob;
84        }
85
86    }
87
88    private static Cache decoderCache = new Cache(CACHE_SIZE) {
89            boolean hasName(Object ob, Object name) {
90                if (name instanceof String)
91                    return (((CharsetDecoder)ob).charset().name().equals(name));
92                if (name instanceof Charset)
93                    return ((CharsetDecoder)ob).charset().equals(name);
94                return false;
95            }
96            Object create(Object name) {
97                if (name instanceof String)
98                    return Charset.forName((String)name).newDecoder();
99                if (name instanceof Charset)
100                    return ((Charset)name).newDecoder();
101                assert false;
102                return null;
103            }
104        };
105
106    public static CharsetDecoder decoderFor(Object name) {
107        CharsetDecoder cd = (CharsetDecoder)decoderCache.forName(name);
108        cd.reset();
109        return cd;
110    }
111
112    private static Cache encoderCache = new Cache(CACHE_SIZE) {
113            boolean hasName(Object ob, Object name) {
114                if (name instanceof String)
115                    return (((CharsetEncoder)ob).charset().name().equals(name));
116                if (name instanceof Charset)
117                    return ((CharsetEncoder)ob).charset().equals(name);
118                return false;
119            }
120            Object create(Object name) {
121                if (name instanceof String)
122                    return Charset.forName((String)name).newEncoder();
123                if (name instanceof Charset)
124                    return ((Charset)name).newEncoder();
125                assert false;
126                return null;
127            }
128        };
129
130    public static CharsetEncoder encoderFor(Object name) {
131        CharsetEncoder ce = (CharsetEncoder)encoderCache.forName(name);
132        ce.reset();
133        return ce;
134    }
135
136}
137