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 43 * {@code RpcCallback} accepting a specific message type. This is always 44 * type-safe (parameter type contravariance). 45 */ 46 @SuppressWarnings("unchecked") 47 public static <Type extends Message> RpcCallback<Type> specializeCallback(final RpcCallback<Message> originalCallback)48 specializeCallback(final RpcCallback<Message> originalCallback) { 49 return (RpcCallback<Type>)originalCallback; 50 // The above cast works, but only due to technical details of the Java 51 // implementation. A more theoretically correct -- but less efficient -- 52 // implementation would be as follows: 53 // return new RpcCallback<Type>() { 54 // public void run(Type parameter) { 55 // originalCallback.run(parameter); 56 // } 57 // }; 58 } 59 60 /** 61 * Take an {@code RpcCallback} accepting a specific message type and convert 62 * it to an {@code RpcCallback<Message>}. The generalized callback will 63 * accept any message object which has the same descriptor, and will convert 64 * it to the correct class before calling the original callback. However, 65 * if the generalized callback is given a message with a different descriptor, 66 * an exception will be thrown. 67 */ 68 public static <Type extends Message> generalizeCallback( final RpcCallback<Type> originalCallback, final Class<Type> originalClass, final Type defaultInstance)69 RpcCallback<Message> generalizeCallback( 70 final RpcCallback<Type> originalCallback, 71 final Class<Type> originalClass, 72 final Type defaultInstance) { 73 return new RpcCallback<Message>() { 74 @Override 75 public void run(final Message parameter) { 76 Type typedParameter; 77 try { 78 typedParameter = originalClass.cast(parameter); 79 } catch (ClassCastException ignored) { 80 typedParameter = copyAsType(defaultInstance, parameter); 81 } 82 originalCallback.run(typedParameter); 83 } 84 }; 85 } 86 87 /** 88 * Creates a new message of type "Type" which is a copy of "source". "source" 89 * must have the same descriptor but may be a different class (e.g. 90 * DynamicMessage). 91 */ 92 @SuppressWarnings("unchecked") 93 private static <Type extends Message> Type copyAsType( 94 final Type typeDefaultInstance, final Message source) { 95 return (Type) typeDefaultInstance 96 .newBuilderForType().mergeFrom(source).build(); 97 } 98 99 /** 100 * Creates a callback which can only be called once. This may be useful for 101 * security, when passing a callback to untrusted code: most callbacks do 102 * not expect to be called more than once, so doing so may expose bugs if it 103 * is not prevented. 104 */ 105 public static <ParameterType> 106 RpcCallback<ParameterType> newOneTimeCallback( 107 final RpcCallback<ParameterType> originalCallback) { 108 return new RpcCallback<ParameterType>() { 109 private boolean alreadyCalled = false; 110 111 @Override 112 public void run(final ParameterType parameter) { 113 synchronized (this) { 114 if (alreadyCalled) { 115 throw new AlreadyCalledException(); 116 } 117 alreadyCalled = true; 118 } 119 120 originalCallback.run(parameter); 121 } 122 }; 123 } 124 125 /** 126 * Exception thrown when a one-time callback is called more than once. 127 */ 128 public static final class AlreadyCalledException extends RuntimeException { 129 private static final long serialVersionUID = 5469741279507848266L; 130 131 public AlreadyCalledException() { 132 super("This RpcCallback was already called and cannot be called " + 133 "multiple times."); 134 } 135 } 136 } 137