Package org.apache.sling.event.impl.jobs

Source Code of org.apache.sling.event.impl.jobs.JobSchedulerImpl$ReadResult

/*
* 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.sling.event.impl.jobs;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.jackrabbit.util.ISO8601;
import org.apache.jackrabbit.util.ISO9075;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.QuerySyntaxException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.scheduler.JobContext;
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.event.impl.jobs.config.ConfigurationChangeListener;
import org.apache.sling.event.impl.jobs.config.JobManagerConfiguration;
import org.apache.sling.event.impl.support.Environment;
import org.apache.sling.event.impl.support.ResourceHelper;
import org.apache.sling.event.impl.support.ScheduleInfoImpl;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.JobBuilder;
import org.apache.sling.event.jobs.JobUtil;
import org.apache.sling.event.jobs.NotificationConstants;
import org.apache.sling.event.jobs.ScheduleInfo;
import org.apache.sling.event.jobs.ScheduleInfo.ScheduleType;
import org.apache.sling.event.jobs.ScheduledJobInfo;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* A scheduler for scheduling jobs
*
*/
public class JobSchedulerImpl
    implements EventHandler, ConfigurationChangeListener, org.apache.sling.commons.scheduler.Job {

    private static final String TOPIC_READ_JOB = "org/apache/sling/event/impl/jobs/READSCHEDULEDJOB";

    private static final String PROPERTY_READ_JOB = "properties";

    private static final String PROPERTY_SCHEDULE_INDEX = "index";

    /** Default logger */
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /** Is the background task still running? */
    private volatile boolean running;

    /** Is this active? */
    private volatile boolean active;

    private final JobManagerConfiguration configuration;

    private final Scheduler scheduler;

    private final JobManagerImpl jobManager;

    /** A local queue for serializing the event processing. */
    private final BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();

    /** Unloaded events. */
    private final Set<String>unloadedEvents = new HashSet<String>();

    private final Map<String, ScheduledJobInfoImpl> scheduledJobs = new HashMap<String, ScheduledJobInfoImpl>();

    public JobSchedulerImpl(final JobManagerConfiguration configuration,
            final Scheduler scheduler,
            final JobManagerImpl jobManager) {
        this.configuration = configuration;
        this.scheduler = scheduler;
        this.running = true;
        this.jobManager = jobManager;

        final long now = System.currentTimeMillis();
        final Thread backgroundThread = new Thread(new Runnable() {
            @Override
            public void run() {
                loadScheduledJobs(now);
                try {
                    runInBackground();
                } catch (final Throwable t) { //NOSONAR
                    logger.error("Background thread stopped with exception: " + t.getMessage(), t);
                    running = false;
                }
            }
        });
        backgroundThread.start();
        this.configuration.addListener(this);
    }

    /**
     * Deactivate this component.
     */
    public void deactivate() {
        this.configuration.removeListener(this);
        this.running = false;
        this.stopScheduling();
        synchronized ( this.scheduledJobs ) {
            this.scheduledJobs.clear();
        }

        // stop background threads by putting empty objects into the queue
        this.queue.clear();
        try {
            this.queue.put(new Event(NotificationConstants.TOPIC_JOB_REMOVED, (Dictionary<String, Object>)null));
        } catch (final InterruptedException e) {
            this.ignoreException(e);
            Thread.currentThread().interrupt();
        }
    }

    private void stopScheduling() {
        if ( this.active ) {
            final Collection<ScheduledJobInfo> jobs = this.getScheduledJobs(null, -1, (Map<String, Object>[])null);
            for(final ScheduledJobInfo info : jobs) {
                this.stopScheduledJob((ScheduledJobInfoImpl)info);
            }
        }
    }

    private void startScheduling() {
        if ( this.active ) {
            final Collection<ScheduledJobInfo> jobs = this.getScheduledJobs(null, -1, (Map<String, Object>[])null);
            for(final ScheduledJobInfo info : jobs) {
                this.startScheduledJob(((ScheduledJobInfoImpl)info));
            }
        }
    }

    /**
     * @see org.apache.sling.event.impl.AbstractRepositoryEventHandler#runInBackground()
     */
    protected void runInBackground() {
        Event event = null;
        while ( this.running ) {
            // so let's wait/get the next event from the queue
            if ( event == null ) {
                try {
                    event = this.queue.take();
                } catch (final InterruptedException e) {
                    this.ignoreException(e);
                    Thread.currentThread().interrupt();
                    this.running = false;
                }
            }
            if ( event != null && this.running ) {
                Event nextEvent = null;

                // check event type
                if ( event.getTopic().equals(TOPIC_READ_JOB) ) {
                    @SuppressWarnings("unchecked")
                    final Map<String, Object> properties = (Map<String, Object>) event.getProperty(PROPERTY_READ_JOB);
                    final ScheduledJobInfoImpl info = this.addOrUpdateScheduledJob(properties);

                    if ( this.active ) {
                        this.startScheduledJob(info);
                    }
                }
                if ( event.getTopic().equals(SlingConstants.TOPIC_RESOURCE_ADDED)
                     || event.getTopic().equals(SlingConstants.TOPIC_RESOURCE_CHANGED)) {
                    final String path = (String)event.getProperty(SlingConstants.PROPERTY_PATH);
                    final ResourceResolver resolver = this.configuration.createResourceResolver();;
                    try {
                        final Resource eventResource = resolver.getResource(path);
                        if ( ResourceHelper.RESOURCE_TYPE_SCHEDULED_JOB.equals(eventResource.getResourceType()) ) {
                            final ReadResult result = this.readScheduledJob(eventResource);
                            if ( result != null ) {
                                if ( result.hasReadErrors ) {
                                    synchronized ( this.unloadedEvents ) {
                                        this.unloadedEvents.add(eventResource.getPath());
                                    }
                                } else {
                                    nextEvent = result.event;
                                }
                            }
                        }
                    } finally {
                        resolver.close();
                    }
                } else if ( event.getTopic().equals(SlingConstants.TOPIC_RESOURCE_REMOVED) ) {
                    final String path = (String)event.getProperty(SlingConstants.PROPERTY_PATH);
                    final String scheduleName = ResourceUtil.getName(path);
                    final ScheduledJobInfoImpl info;
                    synchronized ( this.scheduledJobs ) {
                        info = this.scheduledJobs.remove(scheduleName);
                    }
                    if ( info != null && this.active ) {
                        this.stopScheduledJob(info);
                    }
                }
                event = nextEvent;
            }
        }
    }

    private ScheduledJobInfoImpl addOrUpdateScheduledJob(final Map<String, Object> properties) {
        properties.remove(ResourceResolver.PROPERTY_RESOURCE_TYPE);
        properties.remove(Job.PROPERTY_JOB_CREATED);
        properties.remove(Job.PROPERTY_JOB_CREATED_INSTANCE);

        final String jobTopic = (String) properties.remove(ResourceHelper.PROPERTY_JOB_TOPIC);
        final String schedulerName = (String) properties.remove(ResourceHelper.PROPERTY_SCHEDULE_NAME);
        @SuppressWarnings("unchecked")
        final List<ScheduleInfo> scheduleInfos = (List<ScheduleInfo>) properties.remove(ResourceHelper.PROPERTY_SCHEDULE_INFO);
        final boolean isSuspended = properties.remove(ResourceHelper.PROPERTY_SCHEDULE_SUSPENDED) != null;
        // and now schedule
        final String key = ResourceHelper.filterName(schedulerName);
        ScheduledJobInfoImpl info;
        synchronized ( this.scheduledJobs ) {
            info = this.scheduledJobs.get(key);
            if ( info == null ) {
                info = new ScheduledJobInfoImpl(this, jobTopic,
                        properties, schedulerName);
                this.scheduledJobs.put(key, info);
            }
            info.update(isSuspended, scheduleInfos);
        }
        return info;
    }

    private void startScheduledJob(final ScheduledJobInfoImpl info) {
        if ( !info.isSuspended() ) {
            logger.debug("Adding scheduled job: {}", info.getName());
            int index = 0;
            for(final ScheduleInfo si : info.getSchedules()) {
                final String name = info.getSchedulerJobId() + "-" + String.valueOf(index);
                ScheduleOptions options = null;
                switch ( si.getType() ) {
                    case DAILY:
                    case WEEKLY:
                    case HOURLY:
                    case MONTHLY:
                    case YEARLY:
                    case CRON:
                        options = this.scheduler.EXPR(((ScheduleInfoImpl)si).getCronExpression());

                        break;
                    case DATE:
                        options = this.scheduler.AT(((ScheduleInfoImpl)si).getNextScheduledExecution());
                        break;
                }
                // Create configuration for scheduled job
                final Map<String, Serializable> config = new HashMap<String, Serializable>();
                config.put(PROPERTY_READ_JOB, info);
                config.put(PROPERTY_SCHEDULE_INDEX, index);
                this.scheduler.schedule(this, options.name(name).config(config).canRunConcurrently(false));
                index++;
            }
        }
    }

    private void stopScheduledJob(final ScheduledJobInfoImpl info) {
        logger.debug("Stopping scheduled job : {}", info.getName());
        for(int index = 0; index<info.getSchedules().size(); index++) {
            final String name = info.getSchedulerJobId() + "-" + String.valueOf(index);
            this.scheduler.unschedule(name);
        }
    }

    /**
     * @see org.apache.sling.commons.scheduler.Job#execute(org.apache.sling.commons.scheduler.JobContext)
     */
    @Override
    public void execute(final JobContext context) {
        final ScheduledJobInfoImpl info = (ScheduledJobInfoImpl) context.getConfiguration().get(PROPERTY_READ_JOB);

        this.jobManager.addJob(info.getJobTopic(), info.getJobProperties());
        int index = (Integer)context.getConfiguration().get(PROPERTY_SCHEDULE_INDEX);
        final Iterator<ScheduleInfo> iter = info.getSchedules().iterator();
        ScheduleInfo si = iter.next();
        for(int i=0; i<index; i++) {
            si = iter.next();
        }
        // if scheduled once (DATE), remove from schedule
        if ( si.getType() == ScheduleType.DATE ) {
            if ( index == 0 && info.getSchedules().size() == 1 ) {
                // remove
                unschedule(info);
            } else {
                // update schedule list
                final List<ScheduleInfoImpl> infos = new ArrayList<ScheduleInfoImpl>();
                for(final ScheduleInfo i : info.getSchedules() ) {
                    if ( i != si ) { // no need to use equals
                        infos.add((ScheduleInfoImpl)i);
                    }
                }
                try {
                    // no need to pass job name, it's in the job properties already
                    this.writeJob(info.getJobTopic(), null,
                            info.getJobProperties(), info.getName(), info.isSuspended(), infos);
                } catch ( final PersistenceException pe) {
                    logger.warn("Unable to update scheduled job", pe);
                }
            }
        }
    }

    public void unschedule(final ScheduledJobInfoImpl info) {
        final ResourceResolver resolver = this.configuration.createResourceResolver();
        try {
            final StringBuilder sb = new StringBuilder(this.configuration.getScheduledJobsPath(true));
            sb.append(ResourceHelper.filterName(info.getName()));
            final String path = sb.toString();

            final Resource eventResource = resolver.getResource(path);
            if ( eventResource != null ) {
                resolver.delete(eventResource);
                resolver.commit();
            }
        } catch (final PersistenceException pe) {
            // we ignore the exception if removing fails
            ignoreException(pe);
        } finally {
            resolver.close();
        }
    }

    /**
     * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
     */
    @Override
    public void handleEvent(final Event event) {
        if ( this.running ) {
            if ( ResourceHelper.BUNDLE_EVENT_STARTED.equals(event.getTopic())
              || ResourceHelper.BUNDLE_EVENT_UPDATED.equals(event.getTopic()) ) {
                // bundle event started or updated
                boolean doIt = false;
                synchronized ( this.unloadedEvents ) {
                    if ( this.unloadedEvents.size() > 0 ) {
                        doIt = true;
                    }
                }
                if ( doIt ) {
                    final Runnable t = new Runnable() {

                        @Override
                        public void run() {
                            synchronized (unloadedEvents) {
                                final ResourceResolver resolver = configuration.createResourceResolver();
                                final Set<String> newUnloadedEvents = new HashSet<String>();
                                newUnloadedEvents.addAll(unloadedEvents);
                                try {
                                    for(final String path : unloadedEvents ) {
                                        newUnloadedEvents.remove(path);
                                        final Resource eventResource = resolver.getResource(path);
                                        final ReadResult result = readScheduledJob(eventResource);
                                        if ( result != null ) {
                                            if ( result.hasReadErrors ) {
                                                newUnloadedEvents.add(path);
                                            } else {
                                                try {
                                                    queue.put(result.event);
                                                } catch (InterruptedException e) {
                                                    ignoreException(e);
                                                    Thread.currentThread().interrupt();
                                                }
                                            }
                                        }
                                    }
                                } finally {
                                    resolver.close();
                                    unloadedEvents.clear();
                                    unloadedEvents.addAll(newUnloadedEvents);
                                }
                            }
                        }

                    };
                    Environment.THREAD_POOL.execute(t);
                }
            } else {
                final String path = (String)event.getProperty(SlingConstants.PROPERTY_PATH);
                final String resourceType = (String)event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE);
                if ( path != null && path.startsWith(this.configuration.getScheduledJobsPath(true))
                     && (resourceType == null || ResourceHelper.RESOURCE_TYPE_SCHEDULED_JOB.equals(resourceType))) {
                    logger.debug("Received resource event for {} : {}", path, resourceType);
                    try {
                        this.queue.put(event);
                    } catch (final InterruptedException ignore) {
                        this.ignoreException(ignore);
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }

    /**
     * Load all scheduled jobs from the resource tree
     */
    private void loadScheduledJobs(final long startTime) {
        final ResourceResolver resolver = this.configuration.createResourceResolver();
        try {
            final Calendar startDate = Calendar.getInstance();
            startDate.setTimeInMillis(startTime);

            final StringBuilder buf = new StringBuilder(64);

            buf.append("//element(*,");
            buf.append(ResourceHelper.RESOURCE_TYPE_SCHEDULED_JOB);
            buf.append(")[@");
            buf.append(ISO9075.encode(org.apache.sling.event.jobs.Job.PROPERTY_JOB_CREATED));
            buf.append(" < xs:dateTime('");
            buf.append(ISO8601.format(startDate));
            buf.append("')] order by @");
            buf.append(ISO9075.encode(org.apache.sling.event.jobs.Job.PROPERTY_JOB_CREATED));
            buf.append(" ascending");
            final Iterator<Resource> result = resolver.findResources(buf.toString(), "xpath");

            while ( result.hasNext() ) {
                final Resource eventResource = result.next();
                // sanity check for the path
                if ( eventResource.getPath().startsWith(this.configuration.getScheduledJobsPath(true)) ) {
                    final ReadResult readResult = this.readScheduledJob(eventResource);
                    if ( readResult != null ) {
                        if ( readResult.hasReadErrors ) {
                            synchronized ( this.unloadedEvents ) {
                                this.unloadedEvents.add(eventResource.getPath());
                            }
                        } else {
                            try {
                                this.queue.put(readResult.event);
                            } catch (final InterruptedException e) {
                                this.ignoreException(e);
                                Thread.currentThread().interrupt();
                            }
                        }
                    }
                }
            }

        } catch (final QuerySyntaxException qse) {
            this.ignoreException(qse);
        } finally {
            resolver.close();
        }
    }

    private static final class ReadResult {
        public Event event;
        public boolean hasReadErrors;
    }

    /**
     * Read a scheduled job from the resource
     * @return The job or <code>null</code>
     */
    private ReadResult readScheduledJob(final Resource eventResource) {
        if ( eventResource != null ) {
            try {
                final ValueMap vm = ResourceHelper.getValueMap(eventResource);
                final Map<String, Object> properties = ResourceHelper.cloneValueMap(vm);
                final ReadResult result = new ReadResult();
                @SuppressWarnings("unchecked")
                final List<Exception> readErrorList = (List<Exception>) properties.remove(ResourceHelper.PROPERTY_MARKER_READ_ERROR_LIST);
                result.hasReadErrors = readErrorList != null;
                if ( readErrorList != null ) {
                    for(final Exception e : readErrorList) {
                        logger.warn("Unable to read scheduled job from " + eventResource.getPath(), e);
                    }
                }
                final Map<String, Object> eventProps = Collections.singletonMap(PROPERTY_READ_JOB, (Object)properties);
                result.event = new Event(TOPIC_READ_JOB, eventProps);

                return result;
            } catch (final InstantiationException ie) {
                // something happened with the resource in the meantime
                this.ignoreException(ie);
            }
        }
        return null;
    }

    /**
     * Write a schedule job to the resource tree.
     * @throws PersistenceException
     */
    public ScheduledJobInfoImpl writeJob(
            final String jobTopic,
            final String jobName,
            final Map<String, Object> jobProperties,
            final String scheduleName,
            final boolean suspend,
            final List<ScheduleInfoImpl> scheduleInfos)
    throws PersistenceException {
        final ResourceResolver resolver = this.configuration.createResourceResolver();
        try {

            // create properties
            final Map<String, Object> properties = new HashMap<String, Object>();

            if ( jobProperties != null ) {
                for(final Map.Entry<String, Object> entry : jobProperties.entrySet() ) {
                    final String propName = entry.getKey();
                    if ( !ResourceHelper.ignoreProperty(propName) ) {
                        properties.put(propName, entry.getValue());
                    }
                }
            }

            properties.put(ResourceHelper.PROPERTY_JOB_TOPIC, jobTopic);
            if ( jobName != null ) {
                properties.put(JobUtil.PROPERTY_JOB_NAME, jobName);
            }
            properties.put(Job.PROPERTY_JOB_CREATED, Calendar.getInstance());
            properties.put(Job.PROPERTY_JOB_CREATED_INSTANCE, Environment.APPLICATION_ID);

            // put scheduler name and scheduler info
            properties.put(ResourceHelper.PROPERTY_SCHEDULE_NAME, scheduleName);
            final String[] infoArray = new String[scheduleInfos.size()];
            int index = 0;
            for(final ScheduleInfoImpl info : scheduleInfos) {
                infoArray[index] = info.getSerializedString();
                index++;
            }
            properties.put(ResourceHelper.PROPERTY_SCHEDULE_INFO, infoArray);
            if ( suspend ) {
                properties.put(ResourceHelper.PROPERTY_SCHEDULE_SUSPENDED, Boolean.TRUE);
            }

            // create path and resource
            properties.put(ResourceResolver.PROPERTY_RESOURCE_TYPE, ResourceHelper.RESOURCE_TYPE_SCHEDULED_JOB);

            final String path = this.configuration.getScheduledJobsPath(true) + ResourceHelper.filterName(scheduleName);

            // update existing resource
            final Resource existingInfo = resolver.getResource(path);
            if ( existingInfo != null ) {
                resolver.delete(existingInfo);
                if ( logger.isDebugEnabled() ) {
                    logger.debug("Updating scheduled job {} at {}", properties, path);
                }
            } else {
                if ( logger.isDebugEnabled() ) {
                    logger.debug("Storing new scheduled job {} at {}", properties, path);
                }
            }
            ResourceHelper.getOrCreateResource(resolver,
                    path,
                    properties);
            // put back real schedule infos
            properties.put(ResourceHelper.PROPERTY_SCHEDULE_INFO, scheduleInfos);

            return this.addOrUpdateScheduledJob(properties);
        } finally {
            resolver.close();
        }
    }

    /**
     * Helper method which just logs the exception in debug mode.
     * @param e
     */
    private void ignoreException(final Exception e) {
        if ( this.logger.isDebugEnabled() ) {
            this.logger.debug("Ignored exception " + e.getMessage(), e);
        }
    }

    @Override
    public void configurationChanged(final boolean active) {
        if ( !active ) {
            this.active = false;
            this.stopScheduling();
        } else {
            final boolean previouslyActive = this.active;
            final JobManagerConfiguration config = this.configuration;
            if ( config != null ) {
                this.active = config.getTopologyCapabilities().isLeader();
                if ( this.active && !previouslyActive ) {
                    this.startScheduling();
                }
                if ( !this.active && previouslyActive ) {
                    this.stopScheduling();
                }
            }
        }
    }

    /**
     * Create a schedule builder for a currently scheduled job
     */
    public JobBuilder.ScheduleBuilder createJobBuilder(final ScheduledJobInfoImpl info) {
        final JobBuilderImpl builder = (JobBuilderImpl)this.jobManager.createJob(info.getJobTopic()).properties(info.getJobProperties());
        final JobBuilder.ScheduleBuilder sb = builder.schedule(info.getName());
        return (info.isSuspended() ? sb.suspend() : sb);
    }

    private enum Operation {
        LESS,
        LESS_OR_EQUALS,
        EQUALS,
        GREATER_OR_EQUALS,
        GREATER
    }

    /**
     * Check if the job matches the template
     */
    private boolean match(final ScheduledJobInfoImpl job, final Map<String, Object> template) {
        if ( template != null ) {
            for(final Map.Entry<String, Object> current : template.entrySet()) {
                final String key = current.getKey();
                final char firstChar = key.length() > 0 ? key.charAt(0) : 0;
                final String propName;
                final Operation op;
                if ( firstChar == '=' ) {
                    propName = key.substring(1);
                    op  = Operation.EQUALS;
                } else if ( firstChar == '<' ) {
                    final char secondChar = key.length() > 1 ? key.charAt(1) : 0;
                    if ( secondChar == '=' ) {
                        op = Operation.LESS_OR_EQUALS;
                        propName = key.substring(2);
                    } else {
                        op = Operation.LESS;
                        propName = key.substring(1);
                    }
                } else if ( firstChar == '>' ) {
                    final char secondChar = key.length() > 1 ? key.charAt(1) : 0;
                    if ( secondChar == '=' ) {
                        op = Operation.GREATER_OR_EQUALS;
                        propName = key.substring(2);
                    } else {
                        op = Operation.GREATER;
                        propName = key.substring(1);
                    }
                } else {
                    propName = key;
                    op  = Operation.EQUALS;
                }
                final Object value = current.getValue();

                if ( op == Operation.EQUALS ) {
                    if ( !value.equals(job.getJobProperties().get(propName)) ) {
                        return false;
                    }
                } else {
                    if ( value instanceof Comparable ) {
                        @SuppressWarnings({ "unchecked", "rawtypes" })
                        final int result = ((Comparable)value).compareTo(job.getJobProperties().get(propName));
                        if ( op == Operation.LESS && result != -1 ) {
                            return false;
                        } else if ( op == Operation.LESS_OR_EQUALS && result == 1 ) {
                            return false;
                        } else if ( op == Operation.GREATER_OR_EQUALS && result == -1 ) {
                            return false;
                        } else if ( op == Operation.GREATER && result != 1 ) {
                            return false;
                        }
                    } else {
                        // if the value is not comparable we simply don't match
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * Get all scheduled jobs
     */
    public Collection<ScheduledJobInfo> getScheduledJobs(final String topic,
            final long limit,
            final Map<String, Object>... templates) {
        final List<ScheduledJobInfo> jobs = new ArrayList<ScheduledJobInfo>();
        long count = 0;
        synchronized ( this.scheduledJobs ) {
            for(final ScheduledJobInfoImpl job : this.scheduledJobs.values() ) {
                boolean add = true;
                if ( topic != null && !topic.equals(job.getJobTopic()) ) {
                    add = false;
                }
                if ( add && templates != null && templates.length != 0 ) {
                    add = false;
                    for (Map<String,Object> template : templates) {
                        add = this.match(job, template);
                        if ( add ) {
                            break;
                        }
                    }
                }
                if ( add ) {
                    jobs.add(job);
                    count++;
                    if ( limit > 0 && count == limit ) {
                        break;
                    }
                }
            }
        }
        return jobs;
    }

    public void setSuspended(final ScheduledJobInfoImpl info, final boolean flag) {
        final ResourceResolver resolver = configuration.createResourceResolver();
        try {
            final StringBuilder sb = new StringBuilder(this.configuration.getScheduledJobsPath(true));
            sb.append(ResourceHelper.filterName(info.getName()));
            final String path = sb.toString();

            final Resource eventResource = resolver.getResource(path);
            if ( eventResource != null ) {
                final ModifiableValueMap mvm = eventResource.adaptTo(ModifiableValueMap.class);
                if ( flag ) {
                    mvm.put(ResourceHelper.PROPERTY_SCHEDULE_SUSPENDED, Boolean.TRUE);
                } else {
                    mvm.remove(ResourceHelper.PROPERTY_SCHEDULE_SUSPENDED);
                }
                resolver.commit();
            }
        } catch (final PersistenceException pe) {
            // we ignore the exception if removing fails
            ignoreException(pe);
        } finally {
            resolver.close();
        }
    }
}
TOP

Related Classes of org.apache.sling.event.impl.jobs.JobSchedulerImpl$ReadResult

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.