Line data Source code
1 : // Copyright (C) 2018 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.plugincontext; 16 : 17 : import static java.util.Objects.requireNonNull; 18 : 19 : import com.google.gerrit.extensions.registration.DynamicMap; 20 : import com.google.gerrit.extensions.registration.Extension; 21 : import com.google.gerrit.server.plugincontext.PluginContext.CheckedExtensionFunction; 22 : import com.google.gerrit.server.plugincontext.PluginContext.ExtensionConsumer; 23 : import com.google.gerrit.server.plugincontext.PluginContext.ExtensionFunction; 24 : import com.google.gerrit.server.plugincontext.PluginContext.PluginMetrics; 25 : 26 : /** 27 : * Context to invoke an extension from {@link DynamicMap}. 28 : * 29 : * <p>When the plugin extension is invoked a logging tag with the plugin name is set. This way any 30 : * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is 31 : * called by the plugin extension) can be easily attributed to the plugin. 32 : * 33 : * <p>The run* methods execute the extension but don't deliver a result back to the caller. 34 : * Exceptions can be caught and logged. 35 : * 36 : * <p>The call* methods execute the extension and deliver a result back to the caller. 37 : * 38 : * <pre>{@code 39 : * Map<String, Object> results = new HashMap<>(); 40 : * fooPluginMapEntryContext.run( 41 : * extension -> results.put(extension.getExportName(), extension.get().getFoo()); 42 : * }</pre> 43 : * 44 : * <p>Example if all exceptions, but one, should be caught and logged: 45 : * 46 : * <pre>{@code 47 : * Map<String, Object> results = new HashMap<>(); 48 : * try { 49 : * fooPluginMapEntryContext.run( 50 : * extension -> results.put(extension.getExportName(), extension.get().getFoo(), 51 : * MyException.class); 52 : * } catch (MyException e) { 53 : * // handle the exception 54 : * } 55 : * }</pre> 56 : * 57 : * <p>Example if return values should be handled: 58 : * 59 : * <pre>{@code 60 : * Object result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo()); 61 : * }</pre> 62 : * 63 : * <p>Example if return values and a single exception should be handled: 64 : * 65 : * <pre>{@code 66 : * Object result; 67 : * try { 68 : * result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo(), MyException.class); 69 : * } catch (MyException e) { 70 : * // handle the exception 71 : * } 72 : * }</pre> 73 : * 74 : * <p>Example if several exceptions should be handled: 75 : * 76 : * <pre>{@code 77 : * for (Extension<Foo> fooExtension : fooDynamicMap) { 78 : * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) { 79 : * fooExtension.get().doFoo(); 80 : * } catch (MyException1 | MyException2 | MyException3 e) { 81 : * // handle the exception 82 : * } 83 : * } 84 : * }</pre> 85 : */ 86 : public class PluginMapEntryContext<T> { 87 : private final Extension<T> extension; 88 : private final PluginMetrics pluginMetrics; 89 : 90 0 : PluginMapEntryContext(Extension<T> extension, PluginMetrics pluginMetrics) { 91 0 : requireNonNull(extension); 92 0 : requireNonNull(extension.getExportName(), "export name must be set for plugin map entries"); 93 0 : this.extension = extension; 94 0 : this.pluginMetrics = pluginMetrics; 95 0 : } 96 : 97 : /** 98 : * Returns the name of the plugin that registered this map entry. 99 : * 100 : * @return the plugin name 101 : */ 102 : public String getPluginName() { 103 0 : return extension.getPluginName(); 104 : } 105 : 106 : /** 107 : * Returns the export name for which this map entry was registered. 108 : * 109 : * @return the export name 110 : */ 111 : public String getExportName() { 112 0 : return extension.getExportName(); 113 : } 114 : 115 : /** 116 : * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged. 117 : * 118 : * <p>The consumer get the {@link Extension} provided that should be invoked. The extension 119 : * provides access to the plugin name and the export name. 120 : * 121 : * @param extensionConsumer consumer that invokes the extension 122 : */ 123 : public void run(ExtensionConsumer<Extension<T>> extensionConsumer) { 124 0 : PluginContext.runLogExceptions(pluginMetrics, extension, extensionConsumer); 125 0 : } 126 : 127 : /** 128 : * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged. 129 : * 130 : * <p>The consumer get the {@link Extension} provided that should be invoked. The extension 131 : * provides access to the plugin name and the export name. 132 : * 133 : * @param extensionConsumer consumer that invokes the extension 134 : * @param exceptionClass type of the exceptions that should be thrown 135 : * @throws X expected exception from the plugin extension 136 : */ 137 : public <X extends Exception> void run( 138 : ExtensionConsumer<Extension<T>> extensionConsumer, Class<X> exceptionClass) throws X { 139 0 : PluginContext.runLogExceptions(pluginMetrics, extension, extensionConsumer, exceptionClass); 140 0 : } 141 : 142 : /** 143 : * Calls the plugin extension and returns the result from the plugin extension call. 144 : * 145 : * <p>The consumer get the {@link Extension} provided that should be invoked. The extension 146 : * provides access to the plugin name and the export name. 147 : * 148 : * @param extensionFunction function that invokes the extension 149 : * @return the result from the plugin extension 150 : */ 151 : public <R> R call(ExtensionFunction<Extension<T>, R> extensionFunction) { 152 0 : return PluginContext.call(pluginMetrics, extension, extensionFunction); 153 : } 154 : 155 : /** 156 : * Calls the plugin extension and returns the result from the plugin extension call. Exceptions of 157 : * the specified type are thrown and must be handled by the caller. 158 : * 159 : * <p>The consumer get the {@link Extension} provided that should be invoked. The extension 160 : * provides access to the plugin name and the export name. 161 : * 162 : * @param checkedExtensionFunction function that invokes the extension 163 : * @param exceptionClass type of the exceptions that should be thrown 164 : * @return the result from the plugin extension 165 : * @throws X expected exception from the plugin extension 166 : */ 167 : public <R, X extends Exception> R call( 168 : CheckedExtensionFunction<Extension<T>, R, X> checkedExtensionFunction, 169 : Class<X> exceptionClass) 170 : throws X { 171 0 : return PluginContext.call(pluginMetrics, extension, checkedExtensionFunction, exceptionClass); 172 : } 173 : }