source: vlo/branches/vlo-3.1/vlo-web-app/src/main/java/eu/clarin/cmdi/vlo/wicket/CachingConverter.java @ 6041

Last change on this file since 6041 was 6041, checked in by Twan Goosen, 9 years ago

Merged fixes to #553 from trunk

File size: 4.8 KB
Line 
1/*
2 * Copyright (C) 2015 CLARIN
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17package eu.clarin.cmdi.vlo.wicket;
18
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.CacheLoader;
21import com.google.common.cache.LoadingCache;
22import java.util.Locale;
23import java.util.Objects;
24import java.util.concurrent.ExecutionException;
25import org.apache.wicket.util.convert.ConversionException;
26import org.apache.wicket.util.convert.IConverter;
27
28/**
29 * Converter that wraps an arbitrary converter and caches the conversion output
30 * so that each conversion in a certain direction given a set of a value and
31 * locale or string representation and locale happens only once.
32 *
33 * @author Twan Goosen <twan.goosen@mpi.nl>
34 * @param <C> The object to convert from and to String
35 * @see Cache
36 */
37public class CachingConverter<C> implements IConverter<C> {
38
39    private final IConverter<C> inner;
40
41    private final LoadingCache<Key<String, Locale>, C> toObjectCache = CacheBuilder.newBuilder().
42            build(
43                    new CacheLoader<Key<String, Locale>, C>() {
44
45                        @Override
46                        public C load(Key<String, Locale> key) throws Exception {
47                            return inner.convertToObject(key.getKey1(), key.getKey2());
48                        }
49                    }
50            );
51
52    private final LoadingCache<Key<C, Locale>, String> toStringCache = CacheBuilder.newBuilder().
53            build(
54                    new CacheLoader<Key<C, Locale>, String>() {
55
56                        @Override
57                        public String load(Key<C, Locale> key) throws Exception {
58                            return inner.convertToString(key.getKey1(), key.getKey2());
59                        }
60                    }
61            );
62
63    /**
64     *
65     * @param converter converter to cache conversion results for
66     */
67    public CachingConverter(IConverter<C> converter) {
68        this.inner = converter;
69    }
70
71    /**
72     * Convenience factory method for wrapping a converter
73     *
74     * @param <C> The object to convert from and to String
75     * @param inner converter to wrap, can be null
76     * @return a new {@link CachingConverter} instance wrapping the inner
77     * converter, or null if inner is null
78     */
79    public static <C> IConverter<C> wrap(IConverter<C> inner) {
80        if (inner == null) {
81            return null;
82        } else {
83            return new CachingConverter(inner);
84        }
85    }
86
87    @Override
88    public C convertToObject(String value, Locale locale) throws ConversionException {
89        try {
90            return toObjectCache.get(new Key<>(value, locale));
91        } catch (ExecutionException ex) {
92            throw new ConversionException(ex);
93        }
94    }
95
96    @Override
97    public String convertToString(C value, Locale locale) {
98        try {
99            return toStringCache.get(new Key<>(value, locale));
100        } catch (ExecutionException ex) {
101            throw new ConversionException(ex);
102        }
103    }
104
105    private static class Key<K1, K2> {
106
107        private final K1 key1;
108        private final K2 key2;
109
110        public Key(K1 key1, K2 key2) {
111            this.key1 = key1;
112            this.key2 = key2;
113        }
114
115        public K1 getKey1() {
116            return key1;
117        }
118
119        public K2 getKey2() {
120            return key2;
121        }
122
123        @Override
124        public int hashCode() {
125            int hash = 7;
126            hash = 41 * hash + Objects.hashCode(this.key1);
127            hash = 41 * hash + Objects.hashCode(this.key2);
128            return hash;
129        }
130
131        @Override
132        public boolean equals(Object obj) {
133            if (obj == null) {
134                return false;
135            }
136            if (getClass() != obj.getClass()) {
137                return false;
138            }
139            final Key<?, ?> other = (Key<?, ?>) obj;
140            if (!Objects.equals(this.key1, other.key1)) {
141                return false;
142            }
143            if (!Objects.equals(this.key2, other.key2)) {
144                return false;
145            }
146            return true;
147        }
148
149        @Override
150        public String toString() {
151            return String.format("{%s, %s}", key1.toString(), key2.toString());
152        }
153
154    }
155
156}
Note: See TracBrowser for help on using the repository browser.