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.beans; 85 86import java.lang.invoke.MethodHandle; 87import jdk.dynalink.linker.GuardedInvocation; 88 89/** 90 * Represents one component for a GuardedInvocation of a potentially multi-namespace operation of an 91 * {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its 92 * guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz" 93 * expressions. This allows choosing the most restrictive guard as the guard for the composition of two components. 94 */ 95class GuardedInvocationComponent { 96 enum ValidationType { 97 NONE, // No guard; the operation can be linked unconditionally (quite rare); least strict. 98 INSTANCE_OF, // "validatorClass.isInstance(obj)" guard 99 EXACT_CLASS, // "obj.getClass() == validatorClass" guard; most strict. 100 IS_ARRAY, // "obj.getClass().isArray()" 101 } 102 103 private final GuardedInvocation guardedInvocation; 104 private final Validator validator; 105 106 GuardedInvocationComponent(final MethodHandle invocation) { 107 this(invocation, null, ValidationType.NONE); 108 } 109 110 GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final ValidationType validationType) { 111 this(invocation, guard, null, validationType); 112 } 113 114 GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass, 115 final ValidationType validationType) { 116 this(invocation, guard, new Validator(validatorClass, validationType)); 117 } 118 119 GuardedInvocationComponent(final GuardedInvocation guardedInvocation, final Class<?> validatorClass, 120 final ValidationType validationType) { 121 this(guardedInvocation, new Validator(validatorClass, validationType)); 122 } 123 124 GuardedInvocationComponent replaceInvocation(final MethodHandle newInvocation) { 125 return replaceInvocation(newInvocation, guardedInvocation.getGuard()); 126 } 127 128 GuardedInvocationComponent replaceInvocation(final MethodHandle newInvocation, final MethodHandle newGuard) { 129 return new GuardedInvocationComponent(guardedInvocation.replaceMethods(newInvocation, 130 newGuard), validator); 131 } 132 133 private GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final Validator validator) { 134 this(new GuardedInvocation(invocation, guard), validator); 135 } 136 137 private GuardedInvocationComponent(final GuardedInvocation guardedInvocation, final Validator validator) { 138 this.guardedInvocation = guardedInvocation; 139 this.validator = validator; 140 } 141 142 GuardedInvocation getGuardedInvocation() { 143 return guardedInvocation; 144 } 145 146 Class<?> getValidatorClass() { 147 return validator.validatorClass; 148 } 149 150 ValidationType getValidationType() { 151 return validator.validationType; 152 } 153 154 GuardedInvocationComponent compose(final MethodHandle compositeInvocation, final MethodHandle otherGuard, 155 final Class<?> otherValidatorClass, final ValidationType otherValidationType) { 156 final Validator compositeValidator = validator.compose(new Validator(otherValidatorClass, otherValidationType)); 157 final MethodHandle compositeGuard = compositeValidator == validator ? guardedInvocation.getGuard() : otherGuard; 158 return new GuardedInvocationComponent(compositeInvocation, compositeGuard, compositeValidator); 159 } 160 161 private static class Validator { 162 /*private*/ final Class<?> validatorClass; 163 /*private*/ final ValidationType validationType; 164 165 Validator(final Class<?> validatorClass, final ValidationType validationType) { 166 this.validatorClass = validatorClass; 167 this.validationType = validationType; 168 } 169 170 Validator compose(final Validator other) { 171 if(other.validationType == ValidationType.NONE) { 172 return this; 173 } 174 switch(validationType) { 175 case NONE: 176 return other; 177 case INSTANCE_OF: 178 switch(other.validationType) { 179 case INSTANCE_OF: 180 if(isAssignableFrom(other)) { 181 return other; 182 } else if(other.isAssignableFrom(this)) { 183 return this; 184 } 185 break; 186 case EXACT_CLASS: 187 if(isAssignableFrom(other)) { 188 return other; 189 } 190 break; 191 case IS_ARRAY: 192 if(validatorClass.isArray()) { 193 return this; 194 } 195 break; 196 default: 197 throw new AssertionError(); 198 } 199 break; 200 case EXACT_CLASS: 201 switch(other.validationType) { 202 case INSTANCE_OF: 203 if(other.isAssignableFrom(this)) { 204 return this; 205 } 206 break; 207 case EXACT_CLASS: 208 if(validatorClass == other.validatorClass) { 209 return this; 210 } 211 break; 212 case IS_ARRAY: 213 if(validatorClass.isArray()) { 214 return this; 215 } 216 break; 217 default: 218 throw new AssertionError(); 219 } 220 break; 221 case IS_ARRAY: 222 switch(other.validationType) { 223 case INSTANCE_OF: 224 case EXACT_CLASS: 225 if(other.validatorClass.isArray()) { 226 return other; 227 } 228 break; 229 case IS_ARRAY: 230 return this; 231 default: 232 throw new AssertionError(); 233 } 234 break; 235 default: 236 throw new AssertionError(); 237 } 238 throw new AssertionError("Incompatible composition " + this + " vs " + other); 239 } 240 241 private boolean isAssignableFrom(final Validator other) { 242 return validatorClass.isAssignableFrom(other.validatorClass); 243 } 244 245 @Override 246 public String toString() { 247 return "Validator[" + validationType + (validatorClass == null ? "" : (" " + validatorClass.getName())) + "]"; 248 } 249 } 250} 251