1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 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 (at) google.com Kenton Varda 37 */ 38 public final class 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> 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> 69 RpcCallback<Message> generalizeCallback( 70 final RpcCallback<Type> originalCallback, 71 final Class<Type> originalClass, 72 final Type defaultInstance) { 73 return new RpcCallback<Message>() { 74 public void run(final Message parameter) { 75 Type typedParameter; 76 try { 77 typedParameter = originalClass.cast(parameter); 78 } catch (ClassCastException ignored) { 79 typedParameter = copyAsType(defaultInstance, parameter); 80 } 81 originalCallback.run(typedParameter); 82 } 83 }; 84 } 85 86 /** 87 * Creates a new message of type "Type" which is a copy of "source". "source" 88 * must have the same descriptor but may be a different class (e.g. 89 * DynamicMessage). 90 */ 91 @SuppressWarnings("unchecked") 92 private static <Type extends Message> Type copyAsType( 93 final Type typeDefaultInstance, final Message source) { 94 return (Type)typeDefaultInstance.newBuilderForType() 95 .mergeFrom(source) 96 .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 public void run(final ParameterType parameter) { 112 synchronized(this) { 113 if (alreadyCalled) { 114 throw new AlreadyCalledException(); 115 } 116 alreadyCalled = true; 117 } 118 119 originalCallback.run(parameter); 120 } 121 }; 122 } 123 124 /** 125 * Exception thrown when a one-time callback is called more than once. 126 */ 127 public static final class AlreadyCalledException extends RuntimeException { 128 private static final long serialVersionUID = 5469741279507848266L; 129 130 public AlreadyCalledException() { 131 super("This RpcCallback was already called and cannot be called " + 132 "multiple times."); 133 } 134 } 135 } 136