Free the lizard
git-svn-id: svn://10.0.0.236/trunk@10 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -0,0 +1,562 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
package netscape.plugin.composer;
|
||||
|
||||
import java.util.*;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.MemoryImageSource;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import netscape.javascript.JSObject;
|
||||
|
||||
/* This class is private to the composer. It manages the plugins.
|
||||
*/
|
||||
|
||||
class PluginManager {
|
||||
public PluginManager(){
|
||||
}
|
||||
|
||||
public void registerPlugin(String pluginFileName, String iniContents){
|
||||
Properties properties = new Properties();
|
||||
File pluginFile = new File(pluginFileName);
|
||||
try {
|
||||
InputStream stream = new StringBufferInputStream(iniContents);
|
||||
properties.load(stream);
|
||||
stream.close();
|
||||
} catch ( IOException e) {
|
||||
System.err.println("Caught exception while parsing .ini contents:\n" + iniContents);
|
||||
e.printStackTrace();
|
||||
}
|
||||
registerPlugins(pluginFile, properties);
|
||||
registerEncoders(pluginFile, properties);
|
||||
registerEvents(properties);
|
||||
}
|
||||
|
||||
public void registerPlugins(File pluginFile, Properties properties){
|
||||
Enumeration plugins = null;
|
||||
String factoryName = null;
|
||||
try {
|
||||
factoryName = trimWhitespace(properties.getProperty("netscape.plugin.composer.Factory",
|
||||
"netscape.plugin.composer.Factory"));
|
||||
Factory factory = (Factory) Class.forName(factoryName).newInstance();
|
||||
plugins = factory.getPlugins(pluginFile, properties);
|
||||
} catch ( Throwable t ) {
|
||||
System.err.println("Caught exception while instantiating " + factoryName);
|
||||
t.printStackTrace();
|
||||
}
|
||||
registerPlugins(categories, plugins);
|
||||
}
|
||||
|
||||
public static Enumeration instantiateClassList(String classNames){
|
||||
Vector result = new Vector();
|
||||
if ( classNames != null ) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(classNames, ":");
|
||||
while( tokenizer.hasMoreTokens() ){
|
||||
String className = PluginManager.trimWhitespace(tokenizer.nextToken());
|
||||
try {
|
||||
Object object = Class.forName(className).newInstance();
|
||||
result.addElement(object);
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Caught exception while instantiating " + className);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.elements();
|
||||
}
|
||||
|
||||
protected void registerEvents(Properties properties){
|
||||
String eventHandlers =
|
||||
properties.getProperty("netscape.plugin.composer.eventHandlers", "");
|
||||
// System.err.println("registerEvents " + eventHandlers);
|
||||
registerPlugins(events, eventHandlers);
|
||||
}
|
||||
|
||||
protected static void registerPlugins(SortedStringTable table, String classNames) {
|
||||
registerPlugins(table, instantiateClassList(classNames));
|
||||
}
|
||||
|
||||
protected static void registerPlugins(SortedStringTable table, Enumeration plugins){
|
||||
if ( plugins != null ) {
|
||||
while(plugins.hasMoreElements()){
|
||||
Plugin plugin = (Plugin) plugins.nextElement();
|
||||
if ( plugin != null ) {
|
||||
try {
|
||||
table.getOrCreateTable(plugin.getCategory()).put(
|
||||
plugin.getName(), plugin);
|
||||
} catch(Throwable t){
|
||||
System.err.println("Trouble registering plugin:" + plugin);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static String trimWhitespace(String string){
|
||||
int length = string.length();
|
||||
StringBuffer out = new StringBuffer(length);
|
||||
for(int i = 0; i < length; i++ ){
|
||||
char c = string.charAt(i);
|
||||
if ( !Character.isSpace(c) ) {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
public void registerEncoders(File pluginFile, Properties properties){
|
||||
Enumeration encoderList = null;
|
||||
String factoryName = null;
|
||||
try {
|
||||
factoryName = trimWhitespace(properties.getProperty("netscape.plugin.composer.ImageEncoderFactory",
|
||||
"netscape.plugin.composer.ImageEncoderFactory"));
|
||||
ImageEncoderFactory factory = (ImageEncoderFactory) Class.forName(factoryName).newInstance();
|
||||
encoderList = factory.getImageEncoders(pluginFile, properties);
|
||||
} catch ( Throwable t ) {
|
||||
System.err.println("Caught exception while instantiating " + factoryName);
|
||||
t.printStackTrace();
|
||||
}
|
||||
if ( encoderList != null ) {
|
||||
while(encoderList.hasMoreElements()){
|
||||
Object object = null;
|
||||
try {
|
||||
object = encoderList.nextElement();
|
||||
ImageEncoder encoder = (ImageEncoder) object;
|
||||
registerEncoderInstance(encoder);
|
||||
} catch ( Throwable t ) {
|
||||
System.err.println("Caught exception while processing "
|
||||
+ object);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerEncoderInstance(ImageEncoder encoder){
|
||||
ImageEncoder.register(encoder);
|
||||
String name = encoder.getName();
|
||||
encoders.put(name, encoder);
|
||||
}
|
||||
|
||||
public int getNumberOfCategories(){
|
||||
return categories.length();
|
||||
}
|
||||
|
||||
public int getNumberOfPlugins(int category){
|
||||
SortedStringTable categoryTable = (SortedStringTable) categories.get(category);
|
||||
if ( categoryTable == null ) {
|
||||
return 0;
|
||||
}
|
||||
return categoryTable.length();
|
||||
}
|
||||
public String getCategoryName(int category){
|
||||
return categories.getKey(category);
|
||||
}
|
||||
public String getPluginName(int type, int index){
|
||||
return getPlugin(type, index).getName();
|
||||
}
|
||||
public String getPluginHint(int type, int index){
|
||||
return getPlugin(type, index).getHint();
|
||||
}
|
||||
|
||||
/** Start a plugin operation.
|
||||
*/
|
||||
public boolean performPlugin(Composer composer, int category, int index,
|
||||
String in, String base, String workDirectory, String workDirectoryURL,
|
||||
JSObject jsobject){
|
||||
return performPlugin2(composer, getPlugin(category, index), in, base,
|
||||
workDirectory, workDirectoryURL, null, null,jsobject);
|
||||
}
|
||||
|
||||
public boolean performPluginByName(Composer composer, String pluginName,
|
||||
String in, String base, String workDirectory, String workDirectoryURL,
|
||||
JSObject jsobject){
|
||||
Plugin plugin = null;
|
||||
String destinationURL = null;
|
||||
String eventName = null;
|
||||
try {
|
||||
int eventMarker = pluginName.indexOf(':');
|
||||
if ( eventMarker >= 0 ) {
|
||||
eventName = pluginName.substring(0,eventMarker);
|
||||
destinationURL = pluginName.substring(eventMarker + 1);
|
||||
if ( destinationURL.length() == 0 ) {
|
||||
destinationURL = null;
|
||||
}
|
||||
SortedStringTable table = events;
|
||||
// System.err.println("Executing plug-ins for event " + eventName + " " + table);
|
||||
if ( table != null ) {
|
||||
plugin = new GroupPlugin(table);
|
||||
}
|
||||
}
|
||||
else {
|
||||
plugin = (Plugin) Class.forName(pluginName).newInstance();
|
||||
}
|
||||
if ( plugin != null ) {
|
||||
return performPlugin2(composer, plugin, in, base,
|
||||
workDirectory, workDirectoryURL, eventName, destinationURL, jsobject);
|
||||
}
|
||||
}
|
||||
catch(Throwable t){
|
||||
t.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean performPlugin2(Composer composer, Plugin plugin,
|
||||
String in, String base, String workDirectory, String workDirectoryURL,
|
||||
String eventName, String destinationURL, JSObject jsobject){
|
||||
String result = in;
|
||||
if ( plugin != null ){
|
||||
try {
|
||||
URL baseURL = base != null ? new URL(base) : null;
|
||||
URL workDirectoryURLURL = null;
|
||||
URL destinationURLURL = null;
|
||||
if ( workDirectoryURL != null ) {
|
||||
String slash = "/";
|
||||
// The workDirectoryURL needs to end in a "/" so that
|
||||
// relative URLs work.
|
||||
if ( ! workDirectoryURL.endsWith(slash) ){
|
||||
workDirectoryURL = workDirectoryURL + slash;
|
||||
}
|
||||
// Netscape on Windows likes urls of the form
|
||||
// file:///C|/temp/
|
||||
// But this freaks out the URL parser in java.
|
||||
// Try to work around this by matching the file:
|
||||
// part.
|
||||
String prefix = "file:";
|
||||
if ( workDirectoryURL.indexOf(prefix) == 0 ){
|
||||
workDirectoryURLURL = new URL("file","",
|
||||
workDirectoryURL.substring(prefix.length()));
|
||||
}
|
||||
else {
|
||||
workDirectoryURLURL = new URL(workDirectoryURL);
|
||||
}
|
||||
//System.err.println("Source: " + workDirectoryURL);
|
||||
//System.err.println("Simple result: " + workDirectoryURLURL );
|
||||
//System.err.println("URL(file,,///C|/temp) = "+ new URL("file","","///C|/temp"));
|
||||
//System.err.println("Relative URL: " + new URL(workDirectoryURLURL, "Floop.jpg"));
|
||||
}
|
||||
|
||||
if ( destinationURL != null ) {
|
||||
// Netscape on Windows likes urls of the form
|
||||
// file:///C|/temp/
|
||||
// But this freaks out the URL parser in java.
|
||||
// Try to work around this by matching the file:
|
||||
// part.
|
||||
String prefix = "file:";
|
||||
if ( destinationURL.indexOf(prefix) == 0 ){
|
||||
destinationURLURL = new URL("file","",
|
||||
destinationURL.substring(prefix.length()));
|
||||
}
|
||||
else {
|
||||
destinationURLURL = new URL(destinationURL);
|
||||
}
|
||||
}
|
||||
ComposerDocument document = new ComposerDocument(composer, in, baseURL,
|
||||
workDirectory, workDirectoryURLURL, eventName, destinationURLURL,
|
||||
jsobject);
|
||||
SecurityManager.enablePrivilege("SuperUser");
|
||||
ThreadGroup threadGroup = new ThreadGroup(
|
||||
Thread.currentThread().getThreadGroup(),
|
||||
plugin.getName());
|
||||
Thread thread = new Thread(threadGroup, new PluginRunner(plugin, document, this),
|
||||
plugin.getName());
|
||||
thread.start();
|
||||
pluginThreads.put(composer, threadGroup);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Composer plugin runner threw this exception:");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Stop a plugin operation
|
||||
*/
|
||||
|
||||
public void stopPlugin(Composer composer){
|
||||
killGroup(composer);
|
||||
}
|
||||
|
||||
public int getNumberOfEncoders(){
|
||||
return encoders.length();
|
||||
}
|
||||
public String getEncoderName(int index){
|
||||
return getEncoder(index).getName();
|
||||
}
|
||||
public String getEncoderFileType(int index){
|
||||
byte[] fileType = new byte[4];
|
||||
getEncoder(index).getFileType(fileType);
|
||||
return new String(fileType, 0);
|
||||
}
|
||||
public boolean getEncoderNeedsQuantizedSource(int index){
|
||||
return getEncoder(index).needsQuantizedSource();
|
||||
}
|
||||
public String getEncoderFileExtension(int index){
|
||||
return getEncoder(index).getFileExtension();
|
||||
}
|
||||
public String getEncoderHint(int index){
|
||||
return getEncoder(index).getHint();
|
||||
}
|
||||
|
||||
protected ImageEncoder getEncoder(int index) {
|
||||
return (ImageEncoder) encoders.get(index);
|
||||
}
|
||||
|
||||
/** Start an encoder operation.
|
||||
*/
|
||||
public boolean startEncoder(Composer composer, int index,
|
||||
int width, int height, byte[][] pixels,
|
||||
String fileName){
|
||||
Plugin encoderPlugin = new ImageEncoderPlugin(getEncoder(index),
|
||||
width, height, pixels, fileName);
|
||||
return performPlugin2(composer, encoderPlugin, null, null, null, null, null, null,null);
|
||||
}
|
||||
|
||||
protected Plugin getPlugin(int category, int index){
|
||||
Plugin result = null;
|
||||
SortedStringTable categoryTable = (SortedStringTable) categories.get(category);
|
||||
if ( categoryTable != null ) {
|
||||
result = (Plugin) categoryTable.get(index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void pluginFinished(Composer composer, int status, Object argument){
|
||||
composer.pluginFinished(status, argument);
|
||||
killGroup(composer);
|
||||
}
|
||||
|
||||
void killGroup(Composer composer){
|
||||
ThreadGroup group = (ThreadGroup) pluginThreads.remove(composer);
|
||||
if ( group != null ) {
|
||||
pluginKiller.kill(group);
|
||||
}
|
||||
}
|
||||
private SortedStringTable categories = new SortedStringTable();
|
||||
private SortedStringTable encoders = new SortedStringTable();
|
||||
private SortedStringTable events = new SortedStringTable();
|
||||
private Hashtable pluginThreads = new Hashtable(); // Composer composer, Thread
|
||||
private PluginKiller pluginKiller = new PluginKiller();
|
||||
}
|
||||
|
||||
class PluginRunner implements Runnable {
|
||||
public PluginRunner(Plugin plugin, ComposerDocument document,
|
||||
PluginManager manager){
|
||||
this.plugin = plugin;
|
||||
this.document = document;
|
||||
this.manager = manager;
|
||||
}
|
||||
public void run() {
|
||||
Composer composer = document.getComposer();
|
||||
// Take this out someday when security manager works better.
|
||||
// SecurityManager.enablePrivilege("SuperUser");
|
||||
try {
|
||||
boolean result = plugin.perform(document);
|
||||
manager.pluginFinished(composer, result ? Composer.PLUGIN_OK : Composer.PLUGIN_CANCEL, null);
|
||||
} catch( ThreadDeath t) {
|
||||
System.err.println("Composer plugin " + plugin + " was killed.");
|
||||
} catch (Throwable t){
|
||||
System.err.println("Composer plugin " + plugin + " threw this exception:");
|
||||
t.printStackTrace();
|
||||
manager.pluginFinished(composer, Composer.PLUGIN_FAIL, t.toString());
|
||||
}
|
||||
}
|
||||
private Plugin plugin;
|
||||
private ComposerDocument document;
|
||||
private PluginManager manager;
|
||||
}
|
||||
|
||||
class ImageEncoderPlugin extends Plugin {
|
||||
public ImageEncoderPlugin(ImageEncoder encoder,
|
||||
int width, int height, byte[][] pixels,
|
||||
String fileName) {
|
||||
this.encoder = encoder;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.pixels = pixels;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
public boolean perform(Document document) throws IOException {
|
||||
// Create the image.
|
||||
int length = width * height;
|
||||
int[] pixels2 = new int[length];
|
||||
int i = 0;
|
||||
for(int y = 0; y < height; y++) {
|
||||
int j = 0;
|
||||
byte[] line = pixels[y];
|
||||
for(int x = 0; x < width; x++ ) {
|
||||
pixels2[i++] = (0xff << 24)
|
||||
| ((0xff & line[j]) << 16)
|
||||
| ((0xff & line[j+1]) << 8)
|
||||
| ((0xff & line[j+2]));
|
||||
j += 3;
|
||||
}
|
||||
}
|
||||
ImageProducer source = new MemoryImageSource(width, height, pixels2, 0, width);
|
||||
ByteArrayOutputStream temp = new ByteArrayOutputStream(width*height/2);
|
||||
boolean result = encoder.encode(source, temp);
|
||||
if ( result ) {
|
||||
// Create the output
|
||||
SecurityManager.enablePrivilege("SuperUser");
|
||||
OutputStream output = new FileOutputStream(new File(fileName));
|
||||
output.write(temp.toByteArray());
|
||||
output.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private ImageEncoder encoder;
|
||||
private int width;
|
||||
private int height;
|
||||
private byte[][] pixels;
|
||||
private String fileName;
|
||||
}
|
||||
|
||||
/** Processes a sequence of plugins.
|
||||
*/
|
||||
|
||||
class GroupPlugin extends Plugin {
|
||||
public GroupPlugin(SortedStringTable table){
|
||||
table_ = table;
|
||||
}
|
||||
public boolean perform(Document document) throws IOException {
|
||||
// Perform each of the plug-ins in order
|
||||
boolean result = true;
|
||||
// System.err.println("GroupPlugin ready to go! " + table_);
|
||||
if ( table_ != null ) {
|
||||
Enumeration categories = table_.values();
|
||||
while ( categories.hasMoreElements() && result ){
|
||||
try {
|
||||
SortedStringTable category =
|
||||
(SortedStringTable) categories.nextElement();
|
||||
Enumeration plugins = category.values();
|
||||
while ( plugins.hasMoreElements() && result ){
|
||||
Plugin plugin = null;
|
||||
try {
|
||||
plugin = (Plugin) plugins.nextElement();
|
||||
result = plugin.perform(document);
|
||||
}
|
||||
catch(Throwable t){
|
||||
System.err.print("Exception while executing " + plugin);
|
||||
t.printStackTrace();
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch(Throwable t){
|
||||
t.printStackTrace();
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
SortedStringTable table_;
|
||||
}
|
||||
|
||||
class PluginKiller implements Runnable {
|
||||
PluginKiller() {
|
||||
list = new Vector();
|
||||
// Temporary security work-around for pre-4.0PR3
|
||||
SecurityManager.enablePrivilege("SuperUser");
|
||||
Thread killer = new Thread(this, "Composer Plug-in Killer");
|
||||
killer.start();
|
||||
}
|
||||
|
||||
synchronized void kill(ThreadGroup group) {
|
||||
list.addElement(group);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
synchronized ThreadGroup getPluginThreadGroup() {
|
||||
while (list.isEmpty()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
int last = list.size() - 1;
|
||||
ThreadGroup threadGroup = (ThreadGroup) list.elementAt(last);
|
||||
list.removeElementAt(last);
|
||||
return threadGroup;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (true) {
|
||||
|
||||
// this thread cannot die for any reason.
|
||||
// Catch any exception and keep killing
|
||||
try {
|
||||
ThreadGroup group = getPluginThreadGroup();
|
||||
|
||||
synchronized (group) {
|
||||
//System.err.println("killing threadgroup " + group);
|
||||
|
||||
// Give the thread some time to exit. If it exits
|
||||
// sooner then we will be notified when the group runs
|
||||
// out of threads.
|
||||
try {
|
||||
group.wait(300);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
// Check and see if thread is really gone
|
||||
if (group.activeCount() > 0) {
|
||||
// Gun down the remaining threads.
|
||||
try {
|
||||
SecurityManager.enablePrivilege("SuperUser");
|
||||
group.stop();
|
||||
group.wait(5000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
finally {
|
||||
SecurityManager.revertPrivilege();
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, destroy the thread group
|
||||
try {
|
||||
SecurityManager.enablePrivilege("SuperUser");
|
||||
group.destroy();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
finally {
|
||||
SecurityManager.revertPrivilege();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception occurred while deleting Composer Plug-in thread group: ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new String("Plugin thread killer! Composer plugins to be disposed of: " + list);
|
||||
}
|
||||
|
||||
// the list of composer plug-in groups to finish
|
||||
private Vector list; // Of ThreadGroup
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user