org.wyona.yanel.impl.resources.usecase.thread.UsecaseThread.java Source code

Java tutorial

Introduction

Here is the source code for org.wyona.yanel.impl.resources.usecase.thread.UsecaseThread.java

Source

/*
 * Copyright 2007 Wyona
 *
 *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.resources.usecase.thread;

import java.io.Serializable;

import javax.servlet.http.HttpSession;

import org.wyona.yarep.core.Node;
import org.wyona.yarep.core.Repository;

import org.apache.log4j.Logger;

/**
 * A thread which can be executed by the ThreadUsecaseResource.
 */
public abstract class UsecaseThread extends Thread implements Serializable {

    private static Logger log = Logger.getLogger(UsecaseThread.class);

    protected String threadID;
    protected int progress = 0;
    protected boolean cancelled = false;
    protected boolean done = false;
    protected StringBuffer eventLog;

    /**
     * @param threadID Thread ID
     */
    public UsecaseThread(String threadID) {
        this.threadID = threadID;
        this.eventLog = new StringBuffer();
    }

    /**
     * Attaches this thread ID to the HTTP session of the 'user'.
     * @param session HTTP session of the 'user'
     * @throws IllegalStateException if a thread with the same key already exists in this session.
     */
    public void attachThreadToSession(HttpSession session) throws IllegalStateException {
        String attrName = getThreadKey(this.threadID);
        if (session.getAttribute(attrName) != null) {
            String errorMsg = "Thread with id '" + threadID + "' exists already within 'user' session!";
            log.error(errorMsg);
            throw new IllegalStateException(errorMsg);
        }
        session.setAttribute(attrName, this);
    }

    /**
     * Attach this thread ID to a repository.
     * @param repository Repository
     * @param directoryPath Collection path which contains the thread key
     * @throws IllegalStateException if a thread with the same key already exists in this repository.
     */
    public void attachThreadIDToRepository(org.wyona.yarep.core.Repository repository, String directoryPath)
            throws IllegalStateException, org.wyona.yarep.core.RepositoryException {
        // Also see http://grizzly.java.net/
        log.debug("Java thread ID: " + getId());
        String threadKey = getThreadKey(this.threadID);
        String threadKeyPath = directoryPath + "/" + threadKey;
        if (repository.existsNode(threadKeyPath)) {
            String errorMsg = "Thread with id '" + threadID + "' exists already within repository: "
                    + threadKeyPath;
            log.error(errorMsg);
            throw new IllegalStateException(errorMsg);
        }
        org.wyona.yarep.core.Node node = org.wyona.yarep.util.YarepUtil.addNodes(repository, threadKeyPath,
                org.wyona.yarep.core.NodeType.RESOURCE);
        try {
            org.apache.commons.io.IOUtils.copy(new java.io.StringBufferInputStream("" + getId()),
                    node.getOutputStream());
        } catch (java.io.IOException e) {
            log.error(e, e);
            throw new org.wyona.yarep.core.RepositoryException(e.getMessage());
        }
    }

    /**
     * Creates the key for this thread which is used to store and identify the thread in the session.
     * @param threadID
     */
    protected static String getThreadKey(String threadID) {
        return "yanel.thread." + threadID;
    }

    /**
     * Gets the thread with the given id from the session.
     * @param session
     * @param threadID
     * @return thread or null if there is no such thread attached to the session
     */
    public static UsecaseThread getThreadFromSession(HttpSession session, String threadID) {
        String attrName = getThreadKey(threadID);
        return (UsecaseThread) session.getAttribute(attrName);
    }

    /**
     * Get thread with the given id from repository.
     * @param repository Repository
     * @param directoryPath Collection path which contains the thread key
     * @param threadID
     * @return thread or null if there is no such thread attached to the repository
     */
    public static java.lang.management.ThreadInfo getThreadFromRepository(
            org.wyona.yarep.core.Repository repository, String directoryPath, String threadID)
            throws org.wyona.yarep.core.RepositoryException, java.io.IOException {
        //public static UsecaseThread getThreadFromRepository(org.wyona.yarep.core.Repository repository, String directoryPath, String threadID) throws org.wyona.yarep.core.RepositoryException, java.io.IOException {
        String threadKey = getThreadKey(threadID);
        String threadKeyPath = directoryPath + "/" + threadKey;
        if (repository.existsNode(threadKeyPath)) {
            Node node = repository.getNode(threadKeyPath);
            String javaThreadId = new java.io.BufferedReader(new java.io.InputStreamReader(node.getInputStream()))
                    .readLine();

            final java.lang.management.ThreadMXBean thbean = java.lang.management.ManagementFactory
                    .getThreadMXBean();
            long[] threadIDs = thbean.getAllThreadIds();
            for (int i = 0; i < threadIDs.length; i++) {
                log.debug("Thread ID: " + threadIDs[i]);
                if (javaThreadId.equals("" + threadIDs[i])) {
                    log.debug("Thread with id '" + javaThreadId + "' is running.");
                    return thbean.getThreadInfo(threadIDs[i]);
                    /*
                                        final Thread[] threads = getAllThreads();
                                        for (Thread thread : threads) {
                    if (thread.getId() == threadIDs[i]) {
                        return (UsecaseThread) thread;
                    }
                                        }
                                        log.error("No thread with id '" + threadIDs[i] + "' exists!");
                                        return null;
                    */
                }
            }
            log.info("No such thread running: " + threadID + ", " + javaThreadId);
            return null;
        } else {
            log.info("No such thread '" + threadID + "' within repository: " + threadKeyPath);
            return null;
        }
        //return (UsecaseThread)session.getAttribute(attrName); 
    }

    /**
     * Get threads for a specific state, e.g. "NEW" or "RUNNABLE"
     */
    private Thread[] getThreads(final Thread.State state) {
        log.warn("Not implemented yet!");
        return null;
    }

    /**
     * Also see http://nadeausoftware.com/articles/2008/04/java_tip_how_list_and_find_threads_and_thread_groups#GettingathreadbyID
     */
    private static Thread[] getAllThreads() {
        log.warn("Not implemented yet!");
        return null;
    }

    /**
     * Removes this thread from the given session.
     * If this thread does not exist in this session, this method does nothing.
     * @param session
     */
    public void detachThreadFromSession(HttpSession session) {
        String attrName = getThreadKey(this.threadID);
        session.removeAttribute(attrName);
    }

    /**
     * Removes this thread ID from the repository.
     * If this thread ID does not exist in this repository, this method does nothing except log a warning.
     * @param repository Repository
     * @param directoryPath Collection path which contains the thread key
     */
    public void detachThreadIDFromRepository(org.wyona.yarep.core.Repository repository, String directoryPath)
            throws org.wyona.yarep.core.RepositoryException, org.wyona.yarep.core.NoSuchNodeException {
        String threadKey = getThreadKey(this.threadID);
        String threadKeyPath = directoryPath + "/" + threadKey;
        if (repository.existsNode(threadKeyPath)) {
            repository.getNode(threadKeyPath).delete();
        } else {
            log.warn("No such thread '" + threadID + "' within repository: " + threadKeyPath);
        }
    }

    /**
     * Gets a progress indicator to show the progress of this thread.
     * It must be a number in the range from 0 to 100.
     * The returned value is only informational.
     * @return progress
     */
    public int getProgress() {
        return this.progress;
    }

    /**
     * Gets an informational string about the progress of this thread.
     * @return log
     */
    public String getLog() {
        return this.eventLog.toString();
    }

    /**
     * Indicates to the thread that it should be cancelled.
     * Note that it is the responsibility of the thread to check peridically if
     * it has been cancelled, and therefore should abort itself.
     */
    public void cancel() {
        this.cancelled = true;
    }

    /**
     * Indicates whether this thread has been cancelled.
     * @return true if this thread has been cancelled.
     */
    public boolean isCancelled() {
        return this.cancelled;
    }

    /**
     * Indicates whether this thread has finished.
     * @return true if finished.
     */
    public boolean isDone() {
        return this.done;
    }

    /**
     * Calls the doRun() method and sets the done flag to true afterwards.
     * @see java.lang.Thread#run()
     */
    public void run() {
        try {
            doRun();
        } catch (Exception e) {
            log.error(e, e);
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            this.done = true;
        }
    }

    /**
     * Implement this method in a subclass and put the actual code
     * of this thread there. This method should periodically check for the
     * cancel flag. Optionally it may periodically increase the value of the 
     * progress field. 
     * @throws Exception
     */
    public abstract void doRun() throws Exception;

}