CompositeTypeBasedGuardingDynamicLinker.java revision 1551:f3b883bec2d0
1/*
2 * Copyright (c) 2010, 2013, 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/*
27 * This file is available under and governed by the GNU General Public
28 * License version 2 only, as published by the Free Software Foundation.
29 * However, the following notice accompanied the original version of this
30 * file, and Oracle licenses the original version of this file under the BSD
31 * license:
32 */
33/*
34   Copyright 2009-2013 Attila Szegedi
35
36   Licensed under both the Apache License, Version 2.0 (the "Apache License")
37   and the BSD License (the "BSD License"), with licensee being free to
38   choose either of the two at their discretion.
39
40   You may not use this file except in compliance with either the Apache
41   License or the BSD License.
42
43   If you choose to use this file in compliance with the Apache License, the
44   following notice applies to you:
45
46       You may obtain a copy of the Apache License at
47
48           http://www.apache.org/licenses/LICENSE-2.0
49
50       Unless required by applicable law or agreed to in writing, software
51       distributed under the License is distributed on an "AS IS" BASIS,
52       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
53       implied. See the License for the specific language governing
54       permissions and limitations under the License.
55
56   If you choose to use this file in compliance with the BSD License, the
57   following notice applies to you:
58
59       Redistribution and use in source and binary forms, with or without
60       modification, are permitted provided that the following conditions are
61       met:
62       * Redistributions of source code must retain the above copyright
63         notice, this list of conditions and the following disclaimer.
64       * Redistributions in binary form must reproduce the above copyright
65         notice, this list of conditions and the following disclaimer in the
66         documentation and/or other materials provided with the distribution.
67       * Neither the name of the copyright holder nor the names of
68         contributors may be used to endorse or promote products derived from
69         this software without specific prior written permission.
70
71       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
72       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
74       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
75       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
78       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
80       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
81       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82*/
83
84package jdk.dynalink.linker.support;
85
86import java.util.Collections;
87import java.util.LinkedList;
88import java.util.List;
89import java.util.Objects;
90import jdk.dynalink.linker.GuardedInvocation;
91import jdk.dynalink.linker.GuardingDynamicLinker;
92import jdk.dynalink.linker.LinkRequest;
93import jdk.dynalink.linker.LinkerServices;
94import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
95
96/**
97 * A composite type-based guarding dynamic linker. When a receiver of a not yet
98 * seen class is encountered, all linkers are queried sequentially on their
99 * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers
100 * returning true are then bound to the class, and next time a receiver of same
101 * type is encountered, the linking is delegated to those linkers only, speeding
102 * up dispatch.
103 */
104public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker {
105    // Using a separate static class instance so there's no strong reference from the class value back to the composite
106    // linker.
107    private static class ClassToLinker extends ClassValue<List<TypeBasedGuardingDynamicLinker>> {
108        private static final List<TypeBasedGuardingDynamicLinker> NO_LINKER = Collections.emptyList();
109        private final TypeBasedGuardingDynamicLinker[] linkers;
110        private final List<TypeBasedGuardingDynamicLinker>[] singletonLinkers;
111
112        @SuppressWarnings({"unchecked", "rawtypes"})
113        ClassToLinker(final TypeBasedGuardingDynamicLinker[] linkers) {
114            this.linkers = linkers;
115            singletonLinkers = new List[linkers.length];
116            for(int i = 0; i < linkers.length; ++i) {
117                singletonLinkers[i] = Collections.singletonList(linkers[i]);
118            }
119        }
120
121        @SuppressWarnings("fallthrough")
122        @Override
123        protected List<TypeBasedGuardingDynamicLinker> computeValue(final Class<?> clazz) {
124            List<TypeBasedGuardingDynamicLinker> list = NO_LINKER;
125            for(int i = 0; i < linkers.length; ++i) {
126                final TypeBasedGuardingDynamicLinker linker = linkers[i];
127                if(linker.canLinkType(clazz)) {
128                    switch(list.size()) {
129                        case 0: {
130                            list = singletonLinkers[i];
131                            break;
132                        }
133                        case 1: {
134                            list = new LinkedList<>(list);
135                        }
136                        default: {
137                            list.add(linker);
138                        }
139                    }
140                }
141            }
142            return list;
143        }
144    }
145
146    private final ClassValue<List<TypeBasedGuardingDynamicLinker>> classToLinker;
147
148    /**
149     * Creates a new composite type-based linker.
150     *
151     * @param linkers the component linkers
152     * @throws NullPointerException if {@code linkers} or any of its elements
153     * are null.
154     */
155    public CompositeTypeBasedGuardingDynamicLinker(final Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
156        final List<TypeBasedGuardingDynamicLinker> l = new LinkedList<>();
157        for(final TypeBasedGuardingDynamicLinker linker: linkers) {
158            l.add(Objects.requireNonNull(linker));
159        }
160        this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()]));
161    }
162
163    /**
164     * Returns true if at least one of the composite linkers returns true from
165     * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} for the type.
166     * @param type the type to link
167     * @return true true if at least one of the composite linkers returns true
168     * from {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)}, false
169     * otherwise.
170     */
171    @Override
172    public boolean canLinkType(final Class<?> type) {
173        return !classToLinker.get(type).isEmpty();
174    }
175
176    @Override
177    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
178            throws Exception {
179        final Object obj = linkRequest.getReceiver();
180        if(obj == null) {
181            return null;
182        }
183        for(final TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) {
184            final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);
185            if(invocation != null) {
186                return invocation;
187            }
188        }
189        return null;
190    }
191
192    /**
193     * Optimizes a list of type-based linkers. If a group of adjacent linkers in
194     * the list all implement {@link TypeBasedGuardingDynamicLinker}, they will
195     * be replaced with a single instance of
196     * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them.
197     *
198     * @param linkers the list of linkers to optimize
199     * @return the optimized list
200     * @throws NullPointerException if {@code linkers} or any of its elements
201     * are null.
202     */
203    public static List<GuardingDynamicLinker> optimize(final Iterable<? extends GuardingDynamicLinker> linkers) {
204        final List<GuardingDynamicLinker> llinkers = new LinkedList<>();
205        final List<TypeBasedGuardingDynamicLinker> tblinkers = new LinkedList<>();
206        for(final GuardingDynamicLinker linker: linkers) {
207            Objects.requireNonNull(linker);
208            if(linker instanceof TypeBasedGuardingDynamicLinker) {
209                tblinkers.add((TypeBasedGuardingDynamicLinker)linker);
210            } else {
211                addTypeBased(llinkers, tblinkers);
212                llinkers.add(linker);
213            }
214        }
215        addTypeBased(llinkers, tblinkers);
216        return llinkers;
217    }
218
219    private static void addTypeBased(final List<GuardingDynamicLinker> llinkers,
220            final List<TypeBasedGuardingDynamicLinker> tblinkers) {
221        switch(tblinkers.size()) {
222            case 0: {
223                break;
224            }
225            case 1: {
226                llinkers.addAll(tblinkers);
227                tblinkers.clear();
228                break;
229            }
230            default: {
231                llinkers.add(new CompositeTypeBasedGuardingDynamicLinker(tblinkers));
232                tblinkers.clear();
233                break;
234            }
235        }
236    }
237}
238