/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.queue.test; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.logging.Logger; import net.sf.jame.core.util.Worker; import net.sf.jame.queue.spool.DistributedJobService; import net.sf.jame.queue.spool.JobData; import net.sf.jame.queue.spool.JobFactory; import net.sf.jame.queue.spool.JobIDFactory; import net.sf.jame.queue.spool.JobListener; import net.sf.jame.queue.spool.JobServiceListener; import net.sf.jame.twister.TwisterClip; /** * @author Andrea Medeghini */ public class DummyJobService<T extends DummyJob> implements DistributedJobService<T> { private static final Logger logger = Logger.getLogger(DummyJobService.class.getName()); private final HashMap<String, ScheduledJob> scheduledJobs = new HashMap<String, ScheduledJob>(); private final HashMap<String, ScheduledJob> startedJobs = new HashMap<String, ScheduledJob>(); private final HashMap<String, ScheduledJob> terminatedJobs = new HashMap<String, ScheduledJob>(); private final HashMap<String, ScheduledJob> spooledJobs = new HashMap<String, ScheduledJob>(); private final JobFactory<T> jobFactory; private final Object monitor = new Object(); private final String serviceName; private final int maxJobCount = 5; private final Worker worker; private Thread thread; private boolean running; private boolean dirty; private volatile int jobCount; /** * @param serviceName * @param jobFactory * @param worker */ public DummyJobService(final String serviceName, final JobFactory<T> jobFactory, final Worker worker) { this.worker = worker; this.jobFactory = jobFactory; this.serviceName = serviceName; } /** * @see net.sf.jame.queue.spool.JobService#getName() */ public String getName() { return serviceName; } /** * @see net.sf.jame.queue.spool.JobService#start() */ public void start() { if (thread == null) { thread = new Thread(new ServiceHandler(), "DummyJobService Thread"); thread.setDaemon(true); running = true; thread.start(); } } /** * @see net.sf.jame.queue.spool.JobService#stop() */ public void stop() { if (thread != null) { running = false; thread.interrupt(); try { thread.join(); } catch (final InterruptedException e) { } thread = null; } } /** * @see net.sf.jame.queue.spool.JobService#getJobCount() */ public int getJobCount() { synchronized (spooledJobs) { return spooledJobs.size(); } } /** * @see net.sf.jame.queue.spool.JobService#deleteJob(java.lang.String) */ public void deleteJob(final String jobId) { synchronized (spooledJobs) { synchronized (scheduledJobs) { synchronized (startedJobs) { synchronized (terminatedJobs) { scheduledJobs.remove(jobId); final ScheduledJob scheduledJob = terminatedJobs.remove(jobId); if (scheduledJob != null) { worker.addTask(new DeleteTask(scheduledJob)); } } } } } } /** * @see net.sf.jame.queue.spool.JobService#stopJob(java.lang.String) */ public void stopJob(final String jobId) { synchronized (spooledJobs) { synchronized (scheduledJobs) { synchronized (startedJobs) { scheduledJobs.remove(jobId); final ScheduledJob scheduledJob = startedJobs.remove(jobId); if (scheduledJob != null) { worker.addTask(new StopTask(scheduledJob)); } } } } } /** * @see net.sf.jame.queue.spool.JobService#abortJob(java.lang.String) */ public void abortJob(final String jobId) { synchronized (spooledJobs) { synchronized (scheduledJobs) { synchronized (startedJobs) { final ScheduledJob scheduledJob = startedJobs.get(jobId); if (scheduledJob != null) { worker.addTask(new AbortTask(scheduledJob)); } } } } } /** * @see net.sf.jame.queue.spool.JobService#createJob(net.sf.jame.queue.spool.JobListener) */ public String createJob(final JobListener listener) { synchronized (spooledJobs) { final T job = jobFactory.createJob(JobIDFactory.newJobId(), listener); spooledJobs.put(job.getJobId(), new ScheduledJob(job, System.currentTimeMillis() + 10 * 1000L)); return job.getJobId(); } } /** * @see net.sf.jame.queue.spool.JobService#setJobData(java.lang.String, JobData, int) */ public void setJobData(final String jobId, final JobData jobData, final int frameNumber) { synchronized (spooledJobs) { ScheduledJob job = spooledJobs.get(jobId); if (job != null) { job.getJob().setJobDataRow(jobData); job.getJob().setFirstFrameNumber(frameNumber); } } } /** * @see net.sf.jame.queue.spool.JobService#runJob(java.lang.String) */ public void runJob(final String jobId) { synchronized (spooledJobs) { synchronized (scheduledJobs) { synchronized (startedJobs) { synchronized (terminatedJobs) { if (terminatedJobs.get(jobId) == null) { if (startedJobs.get(jobId) == null) { final ScheduledJob scheduledJob = scheduledJobs.get(jobId); if (scheduledJob != null) { worker.addTask(new ResetTask(scheduledJob)); } else { final ScheduledJob job = spooledJobs.get(jobId); if ((job != null) && !scheduledJobs.containsKey(jobId)) { scheduledJobs.put(jobId, job); } } } } } } } } synchronized (monitor) { dirty = true; monitor.notify(); } } private class ServiceHandler implements Runnable { /** * @see java.lang.Runnable#run() */ public void run() { try { Iterator<ScheduledJob> jobIterator = null; while (running) { synchronized (scheduledJobs) { synchronized (startedJobs) { while (jobIterator.hasNext()) { final ScheduledJob scheduledJob = jobIterator.next(); if (scheduledJob.getJob().isStarted() && (System.currentTimeMillis() > scheduledJob.time)) { worker.addTask(new UpdateTask(scheduledJob)); } else if (scheduledJob.getJob().isStarted() && (System.currentTimeMillis() > scheduledJob.time + 30 * 1000L)) { jobIterator.remove(); worker.addTask(new StopTask(scheduledJob)); } else if (!scheduledJob.isAborted() && ((System.currentTimeMillis() - scheduledJob.getJob().getLastUpdate()) > 60 * 1000L)) { jobIterator.remove(); worker.addTask(new ResetTask(scheduledJob)); } } jobIterator = scheduledJobs.values().iterator(); while (jobIterator.hasNext()) { final ScheduledJob scheduledJob = jobIterator.next(); if (scheduledJob.isTerminated()) { jobIterator.remove(); } else if (!scheduledJob.isAborted() && !startedJobs.containsKey(scheduledJob.getJob().getJobId()) && (startedJobs.size() < maxJobCount)) { startedJobs.put(scheduledJob.getJob().getJobId(), scheduledJob); worker.addTask(new StartTask(scheduledJob)); } } } } synchronized (spooledJobs) { synchronized (terminatedJobs) { jobIterator = terminatedJobs.values().iterator(); while (jobIterator.hasNext()) { final ScheduledJob scheduledJob = jobIterator.next(); if ((System.currentTimeMillis() - scheduledJob.getJob().getLastUpdate()) > 120 * 1000L) { jobIterator.remove(); spooledJobs.remove(scheduledJob.getJob().getJobId()); worker.addTask(new DeleteTask(scheduledJob)); } } } } synchronized (monitor) { if (!dirty) { monitor.wait(10000); } dirty = false; } } } catch (final InterruptedException e) { Thread.currentThread().interrupt(); } } } private class DeleteTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected DeleteTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.dispose(); logger.info(serviceName + ": Job deleted " + job.getJob() + " (jobs = " + jobCount + ")"); } } private class StartTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected StartTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.start(); jobCount += 1; logger.info(serviceName + ": Job started " + job.getJob() + " (jobs = " + jobCount + ")"); } } private class StopTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected StopTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.stop(); if (jobCount > 0) { jobCount -= 1; } logger.info(serviceName + ": Job stopped " + job.getJob() + " (jobs = " + jobCount + ")"); synchronized (terminatedJobs) { terminatedJobs.put(job.getJob().getJobId(), job); } } } private class AbortTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected AbortTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.abort(); logger.info(serviceName + ": Job aborted " + job.getJob() + " (jobs = " + jobCount + ")"); } } private class UpdateTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected UpdateTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.setFrameNumber(0); logger.info(serviceName + ": Job updated " + job.getJob() + " (jobs = " + jobCount + ")"); } } private class ResetTask implements Runnable { private final ScheduledJob job; /** * @param job */ protected ResetTask(final ScheduledJob job) { this.job = job; } /** * @see java.lang.Runnable#run() */ public void run() { job.reset(); if (jobCount > 0) { jobCount -= 1; } logger.info(serviceName + ": Job resetted " + job.getJob() + " (jobs = " + jobCount + ")"); } } private class ScheduledJob { private final T job; private long time; /** * @param job * @param time */ public ScheduledJob(final T job, final long time) { this.job = job; this.time = time; } /** * @return */ public boolean isAborted() { return job.isAborted(); } /** * @return */ public boolean isTerminated() { return job.isStarted() && (System.currentTimeMillis() > time); } /** * @param frameNumber */ public void setFrameNumber(final int frameNumber) { job.setFrameNumber(frameNumber); } /** * */ public void start() { job.start(); } /** * */ public void stop() { time = 0; job.abort(); job.stop(); } /** * */ public void abort() { job.abort(); } /** * */ public void reset() { time = 0; job.abort(); job.stop(); job.reset(); } /** * @return the job */ public T getJob() { return job; } /** * @return the time */ public long getTime() { return time; } /** * */ public void dispose() { job.dispose(); } } public void addServiceListener(final JobServiceListener listener) { } public void removeServiceListener(final JobServiceListener listener) { } public byte[] getJobFrame(final String jobId, final int frameNumber) throws IOException { return null; } public void setJobFrame(final String jobId, final TwisterClip clip, final byte[] data) throws IOException { } }