<commit_before>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.scheduler;

import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.xwiki.script.service.ScriptServiceManager;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.TextAreaClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiResponse;
import com.xpn.xwiki.web.XWikiServletRequest;

/**
 * See {@link com.xpn.xwiki.plugin.scheduler.SchedulerPluginApi} for documentation.
 * 
 * @version $Id$
 */
public class SchedulerPlugin extends XWikiDefaultPlugin
{
    /**
     * Log object to log messages in this class.
     */
    private static final Log LOG = LogFactory.getLog(SchedulerPlugin.class);

    /**
     * Fullname of the XWiki Scheduler Job Class representing a job that can be scheduled by this plugin.
     */
    public static final String XWIKI_JOB_CLASS = "XWiki.SchedulerJobClass";

    /**
     * Default Quartz scheduler instance.
     */
    private Scheduler scheduler;

    /**
     * Default plugin constructor.
     * 
     * @see XWikiDefaultPlugin#XWikiDefaultPlugin(String,String,com.xpn.xwiki.XWikiContext)
     */
    public SchedulerPlugin(String name, String className, XWikiContext context)
    {
        super(name, className, context);
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.xpn.xwiki.plugin.XWikiPluginInterface#init(com.xpn.xwiki.XWikiContext)
     */
    @Override
    public void init(XWikiContext context)
    {
        try {
            String initialDb = !context.getDatabase().equals("") ? context.getDatabase() : context.getMainXWiki();
            List<String> wikiServers = Collections.emptyList();

            if (context.getWiki().isVirtualMode()) {
                try {
                    wikiServers = context.getWiki().getVirtualWikisDatabaseNames(context);
                    if (!wikiServers.contains(context.getMainXWiki())) {
                        wikiServers.add(context.getMainXWiki());
                    }
                } catch (Exception e) {
                    LOG.error("error getting list of wiki servers!", e);
                }
            } else {
                wikiServers = new ArrayList<String>();
                wikiServers.add(context.getMainXWiki());
            }

            try {
                for (String wikiName : wikiServers) {
                    context.setDatabase(wikiName);
                    updateSchedulerJobClass(context);
                }
            } finally {
                context.setDatabase(initialDb);
            }

            // Before we start the thread ensure that Quartz will create daemon threads so that
            // the JVM can exit properly.
            System.setProperty("org.quartz.scheduler.makeSchedulerThreadDaemon", "true");
            System.setProperty("org.quartz.threadPool.makeThreadsDaemons", "true");

            setScheduler(getDefaultSchedulerInstance());
            setStatusListener();
            getScheduler().start();

            try {
                // Iterate on all virtual wikis
                for (String wikiName : wikiServers) {
                    context.setDatabase(wikiName);
                    restoreExistingJobs(context);
                }
            } finally {
                context.setDatabase(initialDb);
            }
        } catch (SchedulerException e) {
            LOG.error("Failed to start the scheduler", e);
        } catch (SchedulerPluginException e) {
            LOG.error("Failed to initialize the scheduler", e);
        }
        super.init(context);
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.xpn.xwiki.plugin.XWikiPluginInterface#virtualInit(com.xpn.xwiki.XWikiContext)
     */
    @Override
    public void virtualInit(XWikiContext context)
    {
        super.virtualInit(context);
    }

    /**<commit_msg>XASCH-15: In virtual mode, If a server document has no db associated with it, the scheduler will not initialize properly<commit_after>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.scheduler;

import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.xwiki.script.service.ScriptServiceManager;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.TextAreaClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiResponse;
import com.xpn.xwiki.web.XWikiServletRequest;

/**
 * See {@link com.xpn.xwiki.plugin.scheduler.SchedulerPluginApi} for documentation.
 * 
 * @version $Id$
 */
public class SchedulerPlugin extends XWikiDefaultPlugin
{
    /**
     * Log object to log messages in this class.
     */
    private static final Log LOG = LogFactory.getLog(SchedulerPlugin.class);

    /**
     * Fullname of the XWiki Scheduler Job Class representing a job that can be scheduled by this plugin.
     */
    public static final String XWIKI_JOB_CLASS = "XWiki.SchedulerJobClass";

    /**
     * Default Quartz scheduler instance.
     */
    private Scheduler scheduler;

    /**
     * Default plugin constructor.
     * 
     * @see XWikiDefaultPlugin#XWikiDefaultPlugin(String,String,com.xpn.xwiki.XWikiContext)
     */
    public SchedulerPlugin(String name, String className, XWikiContext context)
    {
        super(name, className, context);
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.xpn.xwiki.plugin.XWikiPluginInterface#init(com.xpn.xwiki.XWikiContext)
     */
    @Override
    public void init(XWikiContext context)
    {
        try {
            String initialDb = !context.getDatabase().equals("") ? context.getDatabase() : context.getMainXWiki();

            List<String> wikiServers;
            if (context.getWiki().isVirtualMode()) {
                try {
                    wikiServers = context.getWiki().getVirtualWikisDatabaseNames(context);
                } catch (Exception e) {
                    LOG.error("error getting list of wiki servers!", e);
                    wikiServers = new ArrayList<String>();
                }
            } else {
                wikiServers = new ArrayList<String>();
            }

            if (!wikiServers.contains(context.getMainXWiki())) {
                wikiServers.add(context.getMainXWiki());
            }

            // Init class
            
            try {
                for (String wikiName : new ArrayList<String>(wikiServers)) {
                    context.setDatabase(wikiName);
                    try {
                        updateSchedulerJobClass(context);
                    } catch (Exception e) {
                        LOG.error("Failed to update scheduler job class for in wiki [" + wikiName + "]", e);

                        // Removing the wiki from the list since it will be impossible start jobs for it
                        wikiServers.remove(wikiName);
                    }
                }
            } finally {
                context.setDatabase(initialDb);
            }

            // Before we start the thread ensure that Quartz will create daemon threads so that
            // the JVM can exit properly.
            System.setProperty("org.quartz.scheduler.makeSchedulerThreadDaemon", "true");
            System.setProperty("org.quartz.threadPool.makeThreadsDaemons", "true");

            setScheduler(getDefaultSchedulerInstance());
            setStatusListener();
            getScheduler().start();

            // Restore jobs
            
            try {
                // Iterate on all virtual wikis
                for (String wikiName : wikiServers) {
                    context.setDatabase(wikiName);
                    restoreExistingJobs(context);
                }
            } finally {
                context.setDatabase(initialDb);
            }
        } catch (SchedulerException e) {
            LOG.error("Failed to start the scheduler", e);
        } catch (SchedulerPluginException e) {
            LOG.error("Failed to initialize the scheduler", e);
        }

        super.init(context);
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.xpn.xwiki.plugin.XWikiPluginInterface#virtualInit(com.xpn.xwiki.XWikiContext)
     */
    @Override
    public void virtualInit(XWikiContext context)
    {
        super.virtualInit(context);
    }

    /**
{'fraction_non_alphanumeric': 0.09474598349978289, 'fraction_numerical': 0.0024316109422492403, 'mean_word_length': 2.4161969741916347, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3878241', 'n_tokens_mistral': 3302, 'n_tokens_neox': 3158, 'n_words': 826}