/*
* 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.web.contextlistener;
import org.apache.nifi.authentication.LoginIdentityProvider;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.repository.RepositoryPurgeException;
import org.apache.nifi.services.FlowService;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiCoreException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.IOException;
/**
* Application context listener for starting the application. If the application is configured for a standalone environment or the application is a node in a clustered environment then a flow
* controller is created and managed. Otherwise, we assume the application is running as the cluster manager in a clustered environment. In this case, the cluster manager is created and managed.
*
*/
public class ApplicationStartupContextListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(ApplicationStartupContextListener.class);
private FlowController flowController = null;
private FlowService flowService = null;
private RequestReplicator requestReplicator = null;
@Override
public void contextInitialized(ServletContextEvent sce) {
final ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
final NiFiProperties properties = ctx.getBean("nifiProperties", NiFiProperties.class);
try {
flowService = ctx.getBean("flowService", FlowService.class);
flowController = ctx.getBean("flowController", FlowController.class);
requestReplicator = ctx.getBean("requestReplicator", RequestReplicator.class);
// start and load the flow if we're not clustered (clustered flow loading should
// happen once the application (wars) is fully loaded and initialized). non clustered
// nifi instance need to load the flow before the application (wars) are fully loaded.
// during the flow loading (below) the flow controller is lazily initialized. when the
// flow is loaded after the application is completely initialized (wars deploy), as
// required with a clustered node, users are able to make web requests before the flow
// is loaded (and the flow controller is initialized) which shouldn't be allowed. moving
// the flow loading here when not clustered resolves this.
if (!properties.isNode()) {
logger.info("Starting Flow Controller...");
// start and load the flow
flowService.start();
flowService.load(null);
/*
* Start up all processors if specified.
*
* When operating as the node, the cluster manager controls
* which processors should start. As part of the flow
* reloading actions, the node will start the necessary
* processors.
*/
flowController.onFlowInitialized(properties.getAutoResumeState());
logger.info("Flow Controller started successfully.");
}
} catch (BeansException | RepositoryPurgeException | IOException e) {
shutdown();
throw new NiFiCoreException("Unable to start Flow Controller.", e);
}
try {
// attempt to get a few beans that we want to to ensure properly created since they are lazily initialized
ctx.getBean("loginIdentityProvider", LoginIdentityProvider.class);
ctx.getBean("authorizer", Authorizer.class);
} catch (final BeansException e) {
shutdown();
throw new NiFiCoreException("Unable to start Flow Controller.", e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
logger.info("Initiating shutdown of flow service...");
shutdown();
logger.info("Flow service termination completed.");
}
private void shutdown() {
try {
// ensure the flow service is terminated
if (flowService != null && flowService.isRunning()) {
flowService.stop(false);
}
} catch (final Exception e) {
final String msg = "Problem occurred ensuring flow controller or repository was properly terminated due to " + e;
if (logger.isDebugEnabled()) {
logger.warn(msg, e);
} else {
logger.warn(msg);
}
}
try {
// ensure the request replicator is shutdown
if (requestReplicator != null) {
requestReplicator.shutdown();
}
} catch (final Exception e) {
final String msg = "Problem occurred ensuring request replicator was properly terminated due to " + e;
if (logger.isDebugEnabled()) {
logger.warn(msg, e);
} else {
logger.warn(msg);
}
}
}
}