/** Copyright (c) 2012 Delcyon, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package com.delcyon.capo.tasks; import java.io.OutputStream; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import com.delcyon.capo.CapoApplication; import com.delcyon.capo.CapoApplication.ApplicationState; import com.delcyon.capo.ContextThread; import com.delcyon.capo.resourcemanager.ResourceDescriptor; import com.delcyon.capo.resourcemanager.ResourceDescriptor.Action; import com.delcyon.capo.server.CapoServer; import com.delcyon.capo.tasks.TaskManagerThread.Preferences; /** * @author jeremiah * */ public class TaskManagerDocumentUpdaterThread extends ContextThread { private ConcurrentLinkedQueue<DocumentUpdate> documentUpdateQueue = new ConcurrentLinkedQueue<DocumentUpdate>(); private volatile ApplicationState state = ApplicationState.NONE; private Transformer transformer; private ReentrantLock lock; private boolean runAsService; public TaskManagerDocumentUpdaterThread(ReentrantLock lock, boolean runAsService) throws Exception { super("TaskDocumentUpdater"+" - "+CapoApplication.getApplication().getApplicationDirectoryName().toUpperCase()); this.lock = lock; this.runAsService = runAsService; Document identityDocument = CapoApplication.getDefaultDocument("identity_transform.xsl"); TransformerFactory tFactory = TransformerFactory.newInstance(); transformer = tFactory.newTransformer(new DOMSource(identityDocument)); transformer.setOutputProperty(OutputKeys.INDENT, "no"); } @Override public void interrupt() { CapoServer.logger.log(Level.INFO, "Interrupting TaskDocumentUpdater Thread"); synchronized (this) { //only set us to stopping if we're running or something earlier, this can happen when we don't run the client as a service if (this.state.ordinal() < ApplicationState.STOPPING.ordinal()) { this.state = ApplicationState.STOPPING; } super.interrupt(); } } @Override public void run() { this.state = ApplicationState.READY; while(getUpdaterState().ordinal() < ApplicationState.STOPPING.ordinal() || documentUpdateQueue.isEmpty() == false) { try { lock.lock(); while (documentUpdateQueue.isEmpty() == false) { DocumentUpdate documentUpdate = documentUpdateQueue.poll(); if (documentUpdate == null) { continue; } Document taskManagerDocument = documentUpdate.getDocument(); ResourceDescriptor taskManagerDocumentFileDescriptor = documentUpdate.getDocumentResourceDescriptor(); //if we're reprocessing the document, it'll be released from below, so we need to reset it. if(taskManagerDocumentFileDescriptor.getResourceState() == com.delcyon.capo.resourcemanager.ResourceDescriptor.State.RELEASED) { taskManagerDocumentFileDescriptor.reset(com.delcyon.capo.resourcemanager.ResourceDescriptor.State.OPEN); } if (taskManagerDocumentFileDescriptor.getResourceMetaData(null).exists() == false) { taskManagerDocumentFileDescriptor.performAction(null, Action.CREATE); } CapoServer.logger.log(Level.FINE, "updating task file: "+taskManagerDocumentFileDescriptor.getResourceURI().getBaseURI()); taskManagerDocument.normalizeDocument(); taskManagerDocument.normalize(); taskManagerDocumentFileDescriptor.open(null); OutputStream taskDocumentOutputStream = taskManagerDocumentFileDescriptor.getOutputStream(null); transformer.setOutputProperty("method", "xml"); transformer.setOutputProperty("indent", "yes"); transformer.transform(new DOMSource(taskManagerDocument), new StreamResult(taskDocumentOutputStream)); taskDocumentOutputStream.close(); taskManagerDocumentFileDescriptor.release(null); } } catch (Exception exception) { CapoServer.logger.log(Level.WARNING, "error processing task document update",exception); } finally //make sure we always unlock things if we're bailing out { while(lock.isHeldByCurrentThread()) { lock.unlock(); //unlock everything since we;re now done and about to sleep or finish } } if (runAsService == true && getUpdaterState().ordinal() < ApplicationState.STOPPING.ordinal()) { try { Thread.sleep(CapoApplication.getConfiguration().getLongValue(Preferences.TASK_INTERVAL)/2l); } catch (InterruptedException interruptedException) { continue; } } else { break; } } this.state = ApplicationState.STOPPED; } public void add(ResourceDescriptor resourceDescriptor, Document taskDocument) { documentUpdateQueue.add(new DocumentUpdate(resourceDescriptor, taskDocument)); } public ApplicationState getUpdaterState() { return this.state; } //DONE private class DocumentUpdate { private Document document; private ResourceDescriptor documentResourceDescriptor; public DocumentUpdate(ResourceDescriptor documentResourceDescriptor, Document document) { this.documentResourceDescriptor = documentResourceDescriptor; this.document = document; } public Document getDocument() { return document; } public ResourceDescriptor getDocumentResourceDescriptor() { return documentResourceDescriptor; } } }