1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 /** 34 * Grab-bag of utility functions useful when dealing with RPCs. 35 * 36 * @author kenton@google.com Kenton Varda 37 */ 38 public final class RpcUtil { RpcUtil()39 private RpcUtil() {} 40 41 /** 42 * Take an {@code RpcCallback<Message>} and convert it to an {@code RpcCallback} accepting a 43 * specific message type. This is always type-safe (parameter type contravariance). 44 */ 45 @SuppressWarnings("unchecked") specializeCallback( final RpcCallback<Message> originalCallback)46 public static <Type extends Message> RpcCallback<Type> specializeCallback( 47 final RpcCallback<Message> originalCallback) { 48 return (RpcCallback<Type>) originalCallback; 49 // The above cast works, but only due to technical details of the Java 50 // implementation. A more theoretically correct -- but less efficient -- 51 // implementation would be as follows: 52 // return new RpcCallback<Type>() { 53 // public void run(Type parameter) { 54 // originalCallback.run(parameter); 55 // } 56 // }; 57 } 58 59 /** 60 * Take an {@code RpcCallback} accepting a specific message type and convert it to an {@code 61 * RpcCallback<Message>}. The generalized callback will accept any message object which has the 62 * same descriptor, and will convert it to the correct class before calling the original callback. 63 * However, if the generalized callback is given a message with a different descriptor, an 64 * exception will be thrown. 65 */ generalizeCallback( final RpcCallback<Type> originalCallback, final Class<Type> originalClass, final Type defaultInstance)66 public static <Type extends Message> RpcCallback<Message> generalizeCallback( 67 final RpcCallback<Type> originalCallback, 68 final Class<Type> originalClass, 69 final Type defaultInstance) { 70 return new RpcCallback<Message>() { 71 @Override 72 public void run(final Message parameter) { 73 Type typedParameter; 74 try { 75 typedParameter = originalClass.cast(parameter); 76 } catch (ClassCastException ignored) { 77 typedParameter = copyAsType(defaultInstance, parameter); 78 } 79 originalCallback.run(typedParameter); 80 } 81 }; 82 } 83 84 /** 85 * Creates a new message of type "Type" which is a copy of "source". "source" must have the same 86 * descriptor but may be a different class (e.g. DynamicMessage). 87 */ 88 @SuppressWarnings("unchecked") 89 private static <Type extends Message> Type copyAsType( 90 final Type typeDefaultInstance, final Message source) { 91 return (Type) typeDefaultInstance.newBuilderForType().mergeFrom(source).build(); 92 } 93 94 /** 95 * Creates a callback which can only be called once. This may be useful for security, when passing 96 * a callback to untrusted code: most callbacks do not expect to be called more than once, so 97 * doing so may expose bugs if it is not prevented. 98 */ 99 public static <ParameterType> RpcCallback<ParameterType> newOneTimeCallback( 100 final RpcCallback<ParameterType> originalCallback) { 101 return new RpcCallback<ParameterType>() { 102 private boolean alreadyCalled = false; 103 104 @Override 105 public void run(final ParameterType parameter) { 106 synchronized (this) { 107 if (alreadyCalled) { 108 throw new AlreadyCalledException(); 109 } 110 alreadyCalled = true; 111 } 112 113 originalCallback.run(parameter); 114 } 115 }; 116 } 117 118 /** Exception thrown when a one-time callback is called more than once. */ 119 public static final class AlreadyCalledException extends RuntimeException { 120 private static final long serialVersionUID = 5469741279507848266L; 121 122 public AlreadyCalledException() { 123 super("This RpcCallback was already called and cannot be called multiple times."); 124 } 125 } 126 } 127