/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.jini.proxy; import java.io.InvalidObjectException; import java.lang.reflect.Method; import net.jini.constraint.BasicMethodConstraints.MethodDesc; import net.jini.constraint.BasicMethodConstraints; import net.jini.core.constraint.InvocationConstraints; import net.jini.core.constraint.MethodConstraints; import net.jini.core.constraint.RemoteMethodControl; /** * A collection of utility methods for use in implementing constrainable * proxies. This class cannot be instantiated. * * @author Sun Microsystems, Inc. * @since 2.0 */ public class ConstrainableProxyUtil { /** This class cannot be instantiated. */ private ConstrainableProxyUtil() { throw new AssertionError(); } /** * Creates a {@link MethodConstraints} using the constraints in * <code>methodConstraints</code>, but with the methods remapped according * to <code>mappings</code>, where the first element of each pair of * elements is mapped to the second. For example, if * <code>methodConstraints</code> returns constraints <code>C1</code> for * method <code>M1</code>, and the elements of mappings are methods * <code>M1</code> and <code>M2</code>, then the resulting method * constraints return <code>C1</code> for method <code>M2</code>. * * @param methodConstraints the method constraints whose methods should be * translated, or <code>null</code> for empty constraints * @param mappings the method mappings * @return the translated method constraints * @throws NullPointerException if <code>mappings</code> is * <code>null</code> or contains <code>null</code> elements * @throws IllegalArgumentException if <code>mappings</code> contains an * odd number of elements */ public static MethodConstraints translateConstraints( MethodConstraints methodConstraints, Method[] mappings) { if (mappings.length % 2 != 0) { throw new IllegalArgumentException("mappings has odd length"); } else if (methodConstraints == null) { return null; } int count = mappings.length / 2; MethodDesc[] descs = new MethodDesc[count]; for (int i = mappings.length - 1; i >= 0; i-= 2) { Method from = mappings[i - 1]; Method to = mappings[i]; descs[--count] = new MethodDesc( to.getName(), to.getParameterTypes(), methodConstraints.getConstraints(from)); } return new BasicMethodConstraints(descs); } /** * Test to see if two {@link MethodConstraints} instances are * equivalent given a method-to-method mapping. Only the * constraints for methods that appear in the mapping are * compared. The mapping is represented by an array, <code> * mappings</code>, of 2n {@link Method} objects. For all values * p less than n the constraints associated with * <code>mappings[2p]</code> in <code>methodConstraints1</code> * are compared to the constraints associated with * <code>mappings[2p+1]</code> in * <code>methodConstraints2</code>. If null is passed in for both * instances they are considered equivalent. * * @param methodConstraints1 the first <code>MethodConstraints</code> * object to compare. * @param methodConstraints2 the second <code>MethodConstraints</code> * object to compare. * @param mappings the method-to-method mapping. * @return <code>true</code> if the <code>MethodConstraints</code> * instances represent equivalent constraints, returns * <code>false</code> otherwise. * @throws NullPointerException if <code>mapping</code> is * <code>null</code> contains <code>null</code> elements. * @throws IllegalArgumentException if <code>mapping</code> contains an * odd number of elements */ public static boolean equivalentConstraints( MethodConstraints methodConstraints1, MethodConstraints methodConstraints2, Method[] mappings) { if (mappings.length % 2 != 0) { throw new IllegalArgumentException("mappings has odd length"); } // both null means they are equivalent. if (methodConstraints1 == null && methodConstraints2 == null) { return true; } // If only one is null they are not equivalent if (methodConstraints1 == null || methodConstraints2 == null) { return false; } // Both non-null need to run though map check final int count = mappings.length / 2; for (int i = 0; i < mappings.length; i+=2) { final InvocationConstraints c1 = methodConstraints1.getConstraints(mappings[i]); final InvocationConstraints c2 = methodConstraints2.getConstraints(mappings[i+1]); if (!c1.equals(c2)) { return false; } } return true; } /** * Verify that an object, <code>proxy</code>, is an instance of * {@link RemoteMethodControl} its {@link MethodConstraints} are * equivalent to another <code>MethodConstraints</code> instance, * <code>methodConstraints</code> once a mapping has been applied. * If <code>proxy</code> does not implement * <code>RemoteMethodControl</code> or the associated constraints are * not equivalent throw an {@link InvalidObjectException}. The * mapping is represented by an array, <code>mappings</code>, of * 2n {@link Method} objects. For all values p less than n the * constraints associated with <code>mappings[2p]</code> in * <code>methodConstraints</code> are compared to the constraints * associated with <code>mappings[2p+1]</code> in the * <code>MethodConstraints</code> returned by * <code>proxy.getConstraints</code>. Will also return normally if * both <code>methodConstraints</code> and the value returned by * <code>proxy.getConstraints</code> are <code>null</code>. * * @param methodConstraints the method constraints * <code>proxy</code> should have. * @param proxy the proxy to test, must implement * <code>RemoteMethodControl</code>. * @param mappings the method to method mapping * @throws NullPointerException if <code>mappings</code> or * <code>proxy</code> is <code>null</code> or if * <code>mapping</code> contains <code>null</code> elements * @throws IllegalArgumentException if <code>mappings</code> contains an * odd number of elements * @throws InvalidObjectException if <code>proxy</code> does * not implement <code>RemoteMethodControl</code>, or if * the constraints on <code>proxy</code> are not * equivalent to <code>methodConstraints</code>. */ public static void verifyConsistentConstraints( MethodConstraints methodConstraints, Object proxy, Method[] mappings) throws InvalidObjectException { if (!(proxy instanceof RemoteMethodControl)) throw new InvalidObjectException( "Proxy does not implement RemoteMethodControl"); final MethodConstraints proxyMethodConstraints = ((RemoteMethodControl) proxy).getConstraints(); if (!equivalentConstraints(methodConstraints, proxyMethodConstraints, mappings)) { // Not equivalent, complain. throw new InvalidObjectException( "Inconsistent constraints on proxy"); } // else everything is ok, normal return } }