All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.crx.statistics.Statistics Maven / Gradle / Ivy

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show newest version
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
*  Copyright 1997 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.day.crx.statistics;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;

import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Statistics acts as a facade for adding entries and running
 * reports.
 *
 * @author mreutegg
 */
public class Statistics implements Runnable {

    private static final Logger log = LoggerFactory.getLogger(Statistics.class);

    /**
     * Set to false when stopped.
     */
    private volatile boolean running = true;

    /**
     * The writer thread, which writes back statistic entries.
     */
    private final Thread writerThread;

    /**
     * A shared Session. Access to this session must be synchronized!
     */
    private final Session session;

    /**
     * The task queue.
     */
    private final BlockingQueue tasks = new LinkedBlockingQueue();

    public Statistics(Session session) {
        this.session = session;
        this.writerThread = new Thread(this, "Statistics write back");
        this.writerThread.start();
    }

    /**
     * Stops the statistics instance and releases resource.
     */
    public void stop() {
        running = false;
        tasks.add(Task.SHUTDOWN);
        // wait at most ten seconds
        try {
            writerThread.join(10 * 1000);
        } catch (InterruptedException e) {
            // ignore
        }
        if (writerThread.isAlive()) {
            // if it is still alive interrupt it
            writerThread.interrupt();
            // then join again
            try {
                writerThread.join(10 * 1000);
            } catch (InterruptedException e) {
                // ignore
            }
        }
        synchronized (session) {
            // finally close session
            session.logout();
        }
    }

    /**
     * Runs a report and returns the result of the report. Please note that this
     * implementation serializes access to the underlying session that runs the
     * report. For improved concurrency, use {@link #runReport(Session, Report)}
     * instead and provide your own session.
     * 

* This method is thread-safe. * * @param report the report to run. * @return the result of the report. * @throws RepositoryException if an error occurs while reading from the * workspace. */ public Iterator runReport(Report report) throws RepositoryException { synchronized (session) { session.refresh(false); return report.getResult(session); } } /** * Runs a report and returns the result of the report. *

* This method is thread-safe. * * @param session The Session to access the data from the repository to * generate the report * @param report the report to run. * @return the result of the report. * @throws RepositoryException if an error occurs while reading from the * workspace. */ public Iterator runReport(Session session, Report report) throws RepositoryException { return report.getResult(session); } /** * Adds an entry to the statistics workspace. *

* This method is thread-safe. * * @param entry the entry to add. * @throws RepositoryException if an error occurs while writing to the * workspace. */ public void addEntry(Entry entry) throws RepositoryException { addEntryInternal(entry, false); } /** * Adds an entry to the statistics workspace but does not guarantee that the * entry is persisted when the method returns. The entry may be persisted * at some time in the future or may even fail (silently) because of an * exception. *

* This method is thread-safe. * * @param entry the entry to add. * @throws RepositoryException if an error occurs while writing to the * workspace. */ public void addEntryAsync(Entry entry) throws RepositoryException { addEntryInternal(entry, true); } //--------------------------------< Runnable >------------------------------ public void run() { List work = new ArrayList(); while (running) { work.clear(); // get all currently pending tasks try { Task t = tasks.take(); if (t == Task.SHUTDOWN) { return; } work.add(t); // loop until empty while (tasks.peek() != null) { t = tasks.take(); if (t == Task.SHUTDOWN) { return; } work.add(t); } } catch (InterruptedException e) { if (!running) { return; } } // perform the tasks RepositoryException exception = null; synchronized (session) { try { session.refresh(false); } catch (RepositoryException e) { log.warn("exception while refreshing session", e); } for (Task task : work) { try { task.performWork(); } catch (Throwable e) { if (e instanceof RepositoryException) { exception = (RepositoryException) e; } else { exception = new RepositoryException(e); } break; } } if (exception == null) { // success so far // try to save try { session.save(); log.debug("persisted {} entries", work.size()); } catch (Throwable e) { if (e instanceof RepositoryException) { exception = (RepositoryException) e; } else { exception = new RepositoryException(e); } } } } if (exception == null) { // successfully saved -> set all tasks done for (Task task : work) { task.setDone(); } } else { try { session.refresh(false); } catch (Throwable e) { log.warn("exception while refreshing session", e); } for (Task task : work) { task.setException(exception); } } } } //--------------------------------< internal >------------------------------ /** * Adds an entry to the statistics workspace. *

* This method is thread-safe. * * @param entry the entry to add. * @param async when set to false the method guarantees that * the entry is persisted when the call returns. * @throws RepositoryException if an error occurs while writing to the * workspace. */ private void addEntryInternal(Entry entry, boolean async) throws RepositoryException { if (!running) { throw new RepositoryException("Statistics stopped"); } Task task = new Task(session, entry); try { tasks.put(task); if (async) { return; } task.get(); } catch (InterruptedException e) { throw new RepositoryException("interrupted while waiting for write back of entry"); } catch (ExecutionException e) { if (e.getCause() instanceof RepositoryException) { throw (RepositoryException) e.getCause(); } else { throw new RepositoryException(e.getCause()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy