/* * 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 org.apache.nifi.controller; import org.apache.nifi.components.ConfigurableComponent; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyValue; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSessionFactory; import org.apache.nifi.processor.Processor; import org.apache.nifi.reporting.InitializationException; import org.apache.nifi.reporting.ReportingTask; /** * <p> * This interface provides a mechanism for creating services that are shared * among all {@link Processor}s, {@link ReportingTask}s, and other * {@code ControllerService}s. * </p> * * <p> * <code>ControllerService</code>s are discovered using Java's * <code>ServiceLoader</code> mechanism. As a result, all implementations must * follow these rules: * * <ul> * <li>The implementation must implement this interface.</li> * <li>The implementation must have a file named * org.apache.nifi.controller.ControllerService located within the jar's * <code>META-INF/services</code> directory. This file contains a list of * fully-qualified class names of all <code>ControllerService</code>s in the * jar, one-per-line. * <li>The implementation must support a default constructor.</li> * </ul> * </p> * * <p> * <b>All implementations of this interface must be thread-safe.</b> * </p> * * <h2>Accessing Controller Services</h2> * <p> * A ControllerService is accessible only through its interface. The framework * provides access to a ControllerService through two different mechanisms: * <ul> * <li> * A {@link PropertyDescriptor} can be created via the * {@link PropertyDescriptor.Builder} after calling the * {@link PropertyDescriptor.Builder#identifiesControllerService(Class) identifiesControllerService(Class)} * method and then the ControllerService is accessed via * {@link PropertyValue#asControllerService(Class)} method. * <p> * For example: * </p> * <p> * <code><pre> * public static final PropertyDescriptor MY_PROPERTY = new PropertyDescriptor.Builder() * .name("My Property") * .description("Example Property") * .identifiesControllerService( MyControllerServiceInterface.class ) * .build(); * * ... * public void onTrigger(ProcessContext context, ProcessSessionFactory sessionFactory) throws ProcessException { * // Obtain the user-selected controller service * final MyControllerServiceInterface service = context.getProperty(MY_PROPERTY).asControllerService( MyControllerServiceInterface.class ); * ... * } * * </pre></code></p> * </li> * <li>A Controller Service can be obtained via a * {@link ControllerServiceLookup}. This lookup may be obtained, for example, * from the {@link ProcessContext} that is provided to a {@link Processor}'s * {@link Processor#onTrigger(ProcessContext, ProcessSessionFactory) onTrigger} * method. * <p> * For example: * </p> * <p> * <code><pre> * public void onTrigger(ProcessContext context, ProcessSessionFactory sessionFactory) throws ProcessException { * final MyControllerServiceInterface service = (MyControllerServiceInterface) context.getControllerServiceLookup().getControllerService("service_identifier"); * } * </pre></code></p> * </li> * </ul> * </p> * * <h2>Defining a Controller Service</h2> * <p> * Note in both of the examples above, that the Controller Service was accessed * only by its interface, and this interface extends ControllerService. If we * have an implementation named MyServiceImpl, for example, that implements * MyControllerServiceInterface, we cannot, in either case, attempt to cast the * ControllerService to the desired implementation. Doing so will result in a * {@link ClassCastException}. This is by design and is done for the following * reasons: * * <ul> * <li> * It is a good coding practice to implement such a service as an interface in * general. * </li> * <li> * A Controller Service can be referenced from different NiFi Archives (NARs). * This means that the Controller Service may be defined in one ClassLoader and * referenced from another unrelated ClassLoader. In order to account for this, * NiFi will change the current thread's ClassLoader as appropriate when * entering the Controller Service's code and revert back to the previous * ClassLoader after exiting the Controller Service's code. * </li> * </ul> * </p> * * <h2>Controller Services and NARs</h2> * <p> * Due to the fact that a Controller Service may be referenced from a different * NAR than the one in which the implementation lives, it is crucial that both * the Controller Service's interface and the code referencing the interface * inherit from the same ClassLoader. This is accomplished by ensuring that the * NAR that contains the Controller Service interface is the parent (or * ancestor) of the NAR that references the Controller Service interface. * </p> * * <p> * Typically, this is done by creating a NAR structure as follows: * <pre> * + my-services-api-nar * +--- service-X-implementation-nar * +--- service-Y-implementation-nar * +--- service-Z-implementation-nar * +--- processor-A-nar * +--- processor-B-nar * </pre> * </p> * * <p> * In this case, the {@code MyControllerServiceInterface} interface, and any * other Controller Service interfaces, will be defined in the * {@code my-services-api-nar} NAR. Implementations are then encapsulated within * the {@code service-X-implementation-nar}, * {@code service-Y-implementation-nar}, and * {@code service-Z-implementation-nar} NARs. All Controller Services and all * Processors defined in these NARs are able to reference any other Controller * Services whose interfaces are provided in the {@code my-services-api-nar} * NAR. * </p> * * <p> * For more information on NARs, see the NiFi Developer Guide. * </p> */ public interface ControllerService extends ConfigurableComponent { /** * Provides the Controller Service with access to objects that may be of use * throughout the life of the service. This method will be called before any * properties are set * * @param context of initialization * @throws org.apache.nifi.reporting.InitializationException if unable to init */ void initialize(ControllerServiceInitializationContext context) throws InitializationException; }