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