org.apache.sling.distribution.queue.impl.simple.SimpleDistributionQueueProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.distribution.queue.impl.simple.SimpleDistributionQueueProvider.java

Source

/*
 * 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.distribution.queue.impl.simple;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.json.JSONTokener;
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.distribution.queue.DistributionQueue;
import org.apache.sling.distribution.queue.DistributionQueueItem;
import org.apache.sling.distribution.queue.DistributionQueueProcessor;
import org.apache.sling.distribution.queue.DistributionQueueProvider;
import org.apache.sling.distribution.queue.DistributionQueueType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * a queue provider {@link org.apache.sling.distribution.queue.DistributionQueueProvider} for simple in memory
 * {@link org.apache.sling.distribution.queue.DistributionQueue}s
 */
public class SimpleDistributionQueueProvider implements DistributionQueueProvider {

    public static final String TYPE = "simple";
    public static final String TYPE_CHECKPOINT = "simple-checkpoint";

    private final Logger log = LoggerFactory.getLogger(getClass());

    private final String name;
    private final Scheduler scheduler;

    private final Map<String, SimpleDistributionQueue> queueMap = new ConcurrentHashMap<String, SimpleDistributionQueue>();
    private final boolean checkpoint;
    private File checkpointDirectory;

    public SimpleDistributionQueueProvider(Scheduler scheduler, String name, boolean checkpoint) {
        this.checkpoint = checkpoint;
        if (name == null || scheduler == null) {
            throw new IllegalArgumentException("all arguments are required");
        }

        if (checkpoint) {
            this.checkpointDirectory = new File(name + "-simple-queues-checkpoints");
            log.info("creating checkpoint directory {}", checkpointDirectory.getAbsoluteFile());
            if (checkpointDirectory.exists() && !checkpointDirectory.isDirectory()) {
                assert checkpointDirectory.delete();
            }
            boolean created = false;
            if (!checkpointDirectory.exists()) {
                created = checkpointDirectory.mkdir();
            }
            log.info("checkpoint directory created: {}, exists {}", created,
                    checkpointDirectory.isDirectory() && checkpointDirectory.exists());
        }

        this.scheduler = scheduler;
        this.name = name;
    }

    @Nonnull
    public DistributionQueue getQueue(@Nonnull String queueName) {
        String key = name + queueName;

        SimpleDistributionQueue queue = queueMap.get(key);
        if (queue == null) {
            log.debug("creating a queue with key {}", key);
            queue = new SimpleDistributionQueue(name, queueName);
            queueMap.put(key, queue);
            log.debug("queue created {}", queue);
        }
        return queue;
    }

    @Override
    public DistributionQueue getQueue(@Nonnull String queueName, @Nonnull DistributionQueueType type) {
        return getQueue(queueName);
    }

    Collection<SimpleDistributionQueue> getQueues() {
        return queueMap.values();
    }

    public void enableQueueProcessing(@Nonnull DistributionQueueProcessor queueProcessor, String... queueNames) {

        if (checkpoint) {
            // recover from checkpoints
            log.debug("recovering from checkpoints if needed");
            for (final String queueName : queueNames) {
                log.debug("recovering for queue {}", queueName);
                DistributionQueue queue = getQueue(queueName);
                FilenameFilter filenameFilter = new FilenameFilter() {
                    @Override
                    public boolean accept(File file, String name) {
                        return name.equals(queueName + "-checkpoint");
                    }
                };
                for (File qf : checkpointDirectory.listFiles(filenameFilter)) {
                    log.info("recovering from checkpoint {}", qf);
                    try {
                        LineIterator lineIterator = IOUtils.lineIterator(new FileReader(qf));
                        while (lineIterator.hasNext()) {
                            String s = lineIterator.nextLine();
                            String[] split = s.split(" ");
                            String id = split[0];
                            String infoString = split[1];
                            Map<String, Object> info = new HashMap<String, Object>();
                            JSONTokener jsonTokener = new JSONTokener(infoString);
                            JSONObject jsonObject = new JSONObject(jsonTokener);
                            Iterator<String> keys = jsonObject.keys();
                            while (keys.hasNext()) {
                                String key = keys.next();
                                JSONArray v = jsonObject.optJSONArray(key);
                                if (v != null) {
                                    String[] a = new String[v.length()];
                                    for (int i = 0; i < a.length; i++) {
                                        a[i] = v.getString(i);
                                    }
                                    info.put(key, a);
                                } else {
                                    info.put(key, jsonObject.getString(key));
                                }
                            }
                            queue.add(new DistributionQueueItem(id, info));
                        }
                        log.info("recovered {} items from queue {}", queue.getStatus().getItemsCount(), queueName);
                    } catch (FileNotFoundException e) {
                        log.warn("could not read checkpoint file {}", qf.getAbsolutePath());
                    } catch (JSONException e) {
                        log.warn("could not parse info from checkpoint file {}", qf.getAbsolutePath());
                    }
                }
            }

            // enable checkpointing
            for (String queueName : queueNames) {
                ScheduleOptions options = scheduler.NOW(-1, 15).canRunConcurrently(false)
                        .name(getJobName(queueName + "-checkpoint"));
                scheduler.schedule(new SimpleDistributionQueueCheckpoint(getQueue(queueName), checkpointDirectory),
                        options);
            }
        }

        // enable processing
        for (String queueName : queueNames) {
            ScheduleOptions options = scheduler.NOW(-1, 1).canRunConcurrently(false).name(getJobName(queueName));
            scheduler.schedule(new SimpleDistributionQueueProcessor(getQueue(queueName), queueProcessor), options);
        }

    }

    public void disableQueueProcessing() {
        for (DistributionQueue queue : getQueues()) {
            String queueName = queue.getName();
            // disable queue processing
            if (scheduler.unschedule(getJobName(queueName))) {
                log.debug("queue processing on {} stopped", queue);
            } else {
                log.warn("could not disable queue processing on {}", queue);
            }
            if (checkpoint) {
                // disable checkpointing
                if (scheduler.unschedule(getJobName(queueName) + "-checkpoint")) {
                    log.debug("checkpoint on {} stopped", queue);
                } else {
                    log.warn("could not disable checkpoint on {}", queue);
                }
            }
        }
    }

    private String getJobName(String queueName) {
        return "simple-queueProcessor-" + name + "-" + queueName;
    }
}