ddf.platform.scheduler.CommandJob.java Source code

Java tutorial

Introduction

Here is the source code for ddf.platform.scheduler.CommandJob.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package ddf.platform.scheduler;

import ddf.security.Subject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.apache.karaf.shell.api.console.Session;
import org.apache.karaf.shell.api.console.SessionFactory;
import org.apache.shiro.subject.ExecutionException;
import org.codice.ddf.security.common.Security;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Executes Felix/Karaf commands when called as a Quartz {@link Job}
 *
 * @author Ashraf Barakat
 */
public class CommandJob implements Job {

    private static final Logger LOGGER = LoggerFactory.getLogger(CommandJob.class);

    public static final String COMMAND_KEY = "command";

    private static final Security SECURITY = Security.getInstance();

    protected Subject getSystemSubject() {
        return SECURITY.getSystemSubject();
    }

    @Override
    public void execute(final JobExecutionContext context) {
        final String commandString = getCommandString(context);
        if (StringUtils.isNotBlank(commandString)) {
            try {
                SECURITY.runAsAdmin(() -> {
                    final Subject subject = getSystemSubject();

                    if (subject != null) {
                        try {
                            subject.execute(() -> {
                                doExecute(commandString);
                                return null;
                            });
                        } catch (ExecutionException e) {
                            logWarningMessage(commandString);
                            LOGGER.debug("Unable to execute as subject.", e);
                        }
                    } else {
                        // This might happen when the system is very slow to start up where not all of the
                        // required security bundles are started yet.
                        logWarningMessage(commandString);
                        LOGGER.debug("Unable to get system subject.");
                    }

                    return null;
                });
            } catch (RuntimeException e) {
                // This might happen when the system is very slow to start up where not all of the required
                // security bundles are started yet.
                logWarningMessage(commandString);
                LOGGER.debug("Could not execute command as admin.", e);
            }
        } else {
            LOGGER.warn(
                    "Could not execute command. Unable to get non-blank command string from job execution context.");
        }
    }

    @Nullable
    private Bundle getBundle() {
        return FrameworkUtil.getBundle(getClass());
    }

    @Nullable
    protected SessionFactory getSessionFactory() {
        final Bundle bundle = getBundle();
        if (bundle != null) {
            final BundleContext bundleContext = bundle.getBundleContext();
            if (bundleContext != null) {
                return bundleContext.getService(bundleContext.getServiceReference(SessionFactory.class));
            }
        }

        return null;
    }

    private void doExecute(final String commandString) {
        final SessionFactory sessionFactory = getSessionFactory();
        if (sessionFactory != null) {
            try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    final PrintStream output = createPrintStream(byteArrayOutputStream);
                    // TODO DDF-3280 remove work-around for NPE when creating session with a null "in"
                    // parameter from a SessionFactory
                    final InputStream emptyInputStream = new InputStream() {
                        @Override
                        public int read() throws IOException {
                            LOGGER.error(
                                    "This method implementation of an InputStream is just a work-around for a Karaf bug and should never be called. There is an issue with the Platform Command Scheduler implementation.");
                            return -1;
                        }
                    };
                    final Session session = sessionFactory.create(emptyInputStream, output, output)) {
                if (session != null) {
                    LOGGER.trace("Executing command \"{}\"", commandString);
                    try {
                        session.execute(commandString);

                        try {
                            final String commandOutput = byteArrayOutputStream
                                    .toString(StandardCharsets.UTF_8.name());

                            LOGGER.info("Execution output for command \"{}\": {}", commandString, commandOutput);
                        } catch (UnsupportedEncodingException e) {
                            LOGGER.debug("Unable to get command output.", e);
                        }
                    } catch (Exception e) {
                        logWarningMessage(commandString);
                        LOGGER.debug("Unable to execute command.", e);
                    }
                } else {
                    logWarningMessage(commandString);
                    LOGGER.debug("Unable to create session.");
                }
            } catch (IOException e) {
                logWarningMessage(commandString);
                LOGGER.debug("Unable to create session.", e);
            }
        } else {
            logWarningMessage(commandString);
            LOGGER.debug("Unable to create session factory.");
        }
    }

    private PrintStream createPrintStream(ByteArrayOutputStream byteArrayOutputStream)
            throws UnsupportedEncodingException {
        return new PrintStream(byteArrayOutputStream, false, StandardCharsets.UTF_8.name());
    }

    @Nullable
    private static String getCommandString(JobExecutionContext context) {
        if (context != null) {
            final JobDataMap mergedJobDataMap = context.getMergedJobDataMap();

            if (mergedJobDataMap != null) {
                return mergedJobDataMap.getString(COMMAND_KEY);
            }
        }

        return null;
    }

    private void logWarningMessage(String commandString) {
        LOGGER.warn(
                "Unable to execute command \"{}\". See debug log for more details. The command is still scheduled for execution according to the configured interval.",
                commandString);
    }
}