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

com4j.ComThread Maven / Gradle / Ivy

There is a newer version: 20110320
Show newest version
package com4j;

import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;


/**
 * Thread managed by com4j.
 *
 * 

* For each user thread that works with COM objects, * one {@link ComThread} is created to manage those objects. * * @author Kohsuke Kawaguchi ([email protected]) */ final class ComThread extends Thread { /** * Used to associate a {@link ComThread} for every thread. */ private static final ThreadLocal map = new ThreadLocal() { public ComThread initialValue() { if( isComThread() ) return (ComThread)Thread.currentThread(); else return new ComThread(Thread.currentThread()); } }; /** * Gets the {@link ComThread} associated with the current thread. */ static ComThread get() { return map.get(); } static void detach() { map.get().kill(); map.remove(); } private ComThread(Thread peer) { super("ComThread for "+peer.getName()); this.peer = peer; setDaemon(true); // we don't want to block the JVM from exiting start(); } /** * The peer thread. */ private final Thread peer; /** * {@link Wrapper}s that are no longer referenced from anybody else * are kept in this linked list, so that this thread can dispose them. */ private Wrapper freeList; /** * Tasks that need to be processed. */ private Task taskList; /** * Number of {@link Wrapper} objects that this thread manages. */ private int liveObjects = 0; /** * Listeners attached to this thread. */ private final List listeners = new ArrayList(); /** * If set to true, this thread will commit suicide. */ private boolean die = false; /** * Used instead of the monitor of an object, so that we can run * a message loop while waiting. */ private final Win32Lock lock = new Win32Lock(); /** * Returns true if this thread can exit. */ private boolean canExit() { // lhs:forcible death <-> rhs:natural death return die || (!peer.isAlive() && liveObjects==0); } /** * Kills this {@link ComThread} gracefully * and blocks until a thread dies. */ public void kill() { new Task() { public Void call() { // this thread is going to shut down. // if the master thread needs a ComThread again, // we'll create a new thread. die = true; return null; } }.execute(this); // wait for it to die. if someone interrupts us, process that later. try { join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public void run() { threads.add(this); try { run0(); } finally { threads.remove(this); } } private void run0() { Native.coInitialize(); while(!canExit()) { lock.suspend(); synchronized(this) { // dispose unused objects if any while(freeList!=null) { if(freeList.dispose0()) liveObjects--; freeList = freeList.next; } // do any scheduled tasks that need to be done while(taskList!=null) { Task task = taskList; taskList = task.next; task.invoke(); } } } Native.coUninitialize(); } /** * Adds the given object to the free list */ synchronized void addToFreeList(Wrapper wrapper) { assert wrapper.next==null; wrapper.next = freeList; freeList = wrapper; } /** * Executes a {link Task} in a {@link ComThread} * and returns its result. */ public T execute(Task task) { synchronized(task) { synchronized(this) { // add it to the link task.next = taskList; taskList = task; } // invoke the execution lock.activate(); // wait for the completion try { task.wait(); } catch (InterruptedException e) {} if(task.exception!=null) { Throwable e = task.exception; task.exception = null; throw new ExecutionException(e); } else { T r = task.result; task.result = null; return r; } } } public synchronized void addLiveObject( Com4jObject r ) { liveObjects++; if(!listeners.isEmpty()) { for( int i=listeners.size()-1; i>=0; i-- ) listeners.get(i).onNewObject(r); } } /** * Checks if the current thread is a COM thread. */ static boolean isComThread() { return Thread.currentThread() instanceof ComThread; } public void addListener(ComObjectListener listener) { if(listener==null) throw new IllegalArgumentException("listener is null"); if(listeners.contains(listener)) throw new IllegalArgumentException("can't register the same listener twice"); listeners.add(listener); } public void removeListener(ComObjectListener listener) { if(!listeners.remove(listener)) throw new IllegalArgumentException("listener isn't registered"); } /** * Live {@link ComThread}s. */ static final Set threads = Collections.synchronizedSet(new HashSet()); static { // before shut-down clean up all ComThreads Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { // move threads to array to avoid concurrent modification for (ComThread thread : threads.toArray(new ComThread[threads.size()]) ) { thread.kill(); } } }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy