home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / edtplug / classes / netscape / plugin / composer / PluginManager.java < prev    next >
Encoding:
Java Source  |  1998-04-08  |  21.5 KB  |  563 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. package netscape.plugin.composer;
  20.  
  21. import java.util.*;
  22. import java.awt.image.ImageProducer;
  23. import java.awt.image.MemoryImageSource;
  24. import java.io.*;
  25. import java.net.URL;
  26. import netscape.javascript.JSObject;
  27.  
  28. /* This class is private to the composer. It manages the plugins.
  29.  */
  30.  
  31. class PluginManager {
  32.     public PluginManager(){
  33.     }
  34.  
  35.     public void registerPlugin(String pluginFileName, String iniContents){
  36.         Properties properties = new Properties();
  37.         File pluginFile = new File(pluginFileName);
  38.         try {
  39.             InputStream stream = new StringBufferInputStream(iniContents);
  40.             properties.load(stream);
  41.             stream.close();
  42.         } catch ( IOException e) {
  43.             System.err.println("Caught exception while parsing .ini contents:\n" + iniContents);
  44.             e.printStackTrace();
  45.         }
  46.         registerPlugins(pluginFile, properties);
  47.         registerEncoders(pluginFile, properties);
  48.         registerEvents(properties);
  49.     }
  50.  
  51.     public void registerPlugins(File pluginFile, Properties properties){
  52.         Enumeration plugins = null;
  53.         String factoryName = null;
  54.         try {
  55.             factoryName = trimWhitespace(properties.getProperty("netscape.plugin.composer.Factory",
  56.                 "netscape.plugin.composer.Factory"));
  57.             Factory factory = (Factory) Class.forName(factoryName).newInstance();
  58.             plugins = factory.getPlugins(pluginFile, properties);
  59.         } catch ( Throwable t ) {
  60.             System.err.println("Caught exception while instantiating " + factoryName);
  61.             t.printStackTrace();
  62.         }
  63.         registerPlugins(categories, plugins);
  64.     }
  65.  
  66.     public static Enumeration instantiateClassList(String classNames){
  67.         Vector result = new Vector();
  68.         if ( classNames != null ) {
  69.             StringTokenizer tokenizer = new StringTokenizer(classNames, ":");
  70.             while( tokenizer.hasMoreTokens() ){
  71.                 String className = PluginManager.trimWhitespace(tokenizer.nextToken());
  72.                 try {
  73.                     Object object = Class.forName(className).newInstance();
  74.                     result.addElement(object);
  75.                 } catch (Throwable t) {
  76.                     System.err.println("Caught exception while instantiating " + className);
  77.                     t.printStackTrace();
  78.                 }
  79.             }
  80.         }
  81.         return result.elements();
  82.     }
  83.  
  84.     protected void registerEvents(Properties properties){
  85.         String eventHandlers =
  86.             properties.getProperty("netscape.plugin.composer.eventHandlers", "");
  87.         // System.err.println("registerEvents " + eventHandlers);
  88.         registerPlugins(events, eventHandlers);
  89.     }
  90.  
  91.     protected static void registerPlugins(SortedStringTable table, String classNames) {
  92.         registerPlugins(table, instantiateClassList(classNames));
  93.     }
  94.  
  95.     protected static void registerPlugins(SortedStringTable table, Enumeration plugins){
  96.         if ( plugins != null ) {
  97.             while(plugins.hasMoreElements()){
  98.                 Plugin plugin = (Plugin) plugins.nextElement();
  99.                 if ( plugin != null ) {
  100.                     try {
  101.                         table.getOrCreateTable(plugin.getCategory()).put(
  102.                             plugin.getName(), plugin);
  103.                     } catch(Throwable t){
  104.                         System.err.println("Trouble registering plugin:" + plugin);
  105.                         t.printStackTrace();
  106.                     }
  107.                 }
  108.             }
  109.         }
  110.     }
  111.     public static String trimWhitespace(String string){
  112.         int length = string.length();
  113.         StringBuffer out = new StringBuffer(length);
  114.         for(int i = 0; i < length; i++ ){
  115.             char c = string.charAt(i);
  116.             if ( !Character.isSpace(c) ) {
  117.                 out.append(c);
  118.             }
  119.         }
  120.         return out.toString();
  121.     }
  122.     public void registerEncoders(File pluginFile, Properties properties){
  123.         Enumeration encoderList = null;
  124.         String factoryName = null;
  125.         try {
  126.             factoryName = trimWhitespace(properties.getProperty("netscape.plugin.composer.ImageEncoderFactory",
  127.                 "netscape.plugin.composer.ImageEncoderFactory"));
  128.             ImageEncoderFactory factory = (ImageEncoderFactory) Class.forName(factoryName).newInstance();
  129.             encoderList = factory.getImageEncoders(pluginFile, properties);
  130.         } catch ( Throwable t ) {
  131.             System.err.println("Caught exception while instantiating " + factoryName);
  132.             t.printStackTrace();
  133.         }
  134.         if ( encoderList != null ) {
  135.             while(encoderList.hasMoreElements()){
  136.                 Object object = null;
  137.                 try {
  138.                     object = encoderList.nextElement();
  139.                     ImageEncoder encoder = (ImageEncoder) object;
  140.                     registerEncoderInstance(encoder);
  141.                 } catch ( Throwable t ) {
  142.                     System.err.println("Caught exception while processing "
  143.                         + object);
  144.                     t.printStackTrace();
  145.                 }
  146.             }
  147.         }
  148.     }
  149.  
  150.     private void registerEncoderInstance(ImageEncoder encoder){
  151.         ImageEncoder.register(encoder);
  152.         String name = encoder.getName();
  153.         encoders.put(name, encoder);
  154.     }
  155.  
  156.     public int getNumberOfCategories(){
  157.         return categories.length();
  158.     }
  159.  
  160.     public int getNumberOfPlugins(int category){
  161.         SortedStringTable categoryTable = (SortedStringTable) categories.get(category);
  162.         if ( categoryTable == null ) {
  163.             return 0;
  164.         }
  165.         return categoryTable.length();
  166.     }
  167.     public String getCategoryName(int category){
  168.         return categories.getKey(category);
  169.     }
  170.     public String getPluginName(int type, int index){
  171.         return getPlugin(type, index).getName();
  172.     }
  173.     public String getPluginHint(int type, int index){
  174.         return getPlugin(type, index).getHint();
  175.     }
  176.  
  177.     /** Start a plugin operation.
  178.      */
  179.     public boolean performPlugin(Composer composer, int category, int index,
  180.         String in, String base, String workDirectory, String workDirectoryURL,
  181.         JSObject jsobject){
  182.         return performPlugin2(composer, getPlugin(category, index), in, base,
  183.             workDirectory, workDirectoryURL, null, null,jsobject);
  184.     }
  185.  
  186.     public boolean performPluginByName(Composer composer, String pluginName,
  187.         String in, String base, String workDirectory, String workDirectoryURL,
  188.         JSObject jsobject){
  189.         Plugin plugin = null;
  190.         String destinationURL = null;
  191.         String eventName = null;
  192.         try {
  193.             int eventMarker = pluginName.indexOf(':');
  194.             if ( eventMarker >= 0 ) {
  195.                 eventName = pluginName.substring(0,eventMarker);
  196.                 destinationURL = pluginName.substring(eventMarker + 1);
  197.                 if ( destinationURL.length() == 0 ) {
  198.                     destinationURL = null;
  199.                 }
  200.                 SortedStringTable table = events;
  201.                 // System.err.println("Executing plug-ins for event " + eventName + " " + table);
  202.                 if ( table != null ) {
  203.                     plugin = new GroupPlugin(table);
  204.                 }
  205.             }
  206.             else {
  207.                 plugin = (Plugin) Class.forName(pluginName).newInstance();
  208.             }
  209.             if ( plugin != null ) {
  210.                 return performPlugin2(composer, plugin, in, base,
  211.                     workDirectory, workDirectoryURL, eventName, destinationURL, jsobject);
  212.             }
  213.         }
  214.         catch(Throwable t){
  215.             t.printStackTrace();
  216.         }
  217.         return false;
  218.     }
  219.  
  220.     public boolean performPlugin2(Composer composer, Plugin plugin,
  221.         String in, String base, String workDirectory, String workDirectoryURL,
  222.         String eventName, String destinationURL, JSObject jsobject){
  223.         String result = in;
  224.         if ( plugin != null ){
  225.             try {
  226.                 URL baseURL = base != null ? new URL(base) : null;
  227.                 URL workDirectoryURLURL = null;
  228.                 URL destinationURLURL = null;
  229.                 if ( workDirectoryURL != null ) {
  230.                     String slash = "/";
  231.                     // The workDirectoryURL needs to end in a "/" so that
  232.                     // relative URLs work.
  233.                     if ( ! workDirectoryURL.endsWith(slash) ){
  234.                         workDirectoryURL = workDirectoryURL + slash;
  235.                     }
  236.                     // Netscape on Windows likes urls of the form
  237.                     // file:///C|/temp/
  238.                     // But this freaks out the URL parser in java.
  239.                     // Try to work around this by matching the file:
  240.                     // part.
  241.                     String prefix = "file:";
  242.                     if ( workDirectoryURL.indexOf(prefix) == 0 ){
  243.                         workDirectoryURLURL = new URL("file","",
  244.                             workDirectoryURL.substring(prefix.length()));
  245.                     }
  246.                     else {
  247.                        workDirectoryURLURL = new URL(workDirectoryURL);
  248.                     }
  249.                     //System.err.println("Source: " + workDirectoryURL);
  250.                     //System.err.println("Simple result: " + workDirectoryURLURL );
  251.                     //System.err.println("URL(file,,///C|/temp) = "+ new URL("file","","///C|/temp"));
  252.                     //System.err.println("Relative URL: " + new URL(workDirectoryURLURL, "Floop.jpg"));
  253.                 }
  254.  
  255.                 if ( destinationURL != null ) {
  256.                     // Netscape on Windows likes urls of the form
  257.                     // file:///C|/temp/
  258.                     // But this freaks out the URL parser in java.
  259.                     // Try to work around this by matching the file:
  260.                     // part.
  261.                     String prefix = "file:";
  262.                     if ( destinationURL.indexOf(prefix) == 0 ){
  263.                         destinationURLURL = new URL("file","",
  264.                             destinationURL.substring(prefix.length()));
  265.                     }
  266.                     else {
  267.                        destinationURLURL = new URL(destinationURL);
  268.                     }
  269.                 }
  270.                 ComposerDocument document = new ComposerDocument(composer, in, baseURL,
  271.                     workDirectory, workDirectoryURLURL, eventName, destinationURLURL,
  272.                     jsobject);
  273.                 SecurityManager.enablePrivilege("SuperUser");
  274.                 ThreadGroup threadGroup = new ThreadGroup(
  275.                     Thread.currentThread().getThreadGroup(),
  276.                     plugin.getName());
  277.                 Thread thread = new Thread(threadGroup, new PluginRunner(plugin, document, this),
  278.                     plugin.getName());
  279.                 thread.start();
  280.                 pluginThreads.put(composer, threadGroup);
  281.             } catch (IOException e) {
  282.               System.err.println("Composer plugin runner threw this exception:");
  283.                e.printStackTrace();
  284.                 return false;
  285.             }
  286.         }
  287.         else {
  288.             return false;
  289.         }
  290.         return true;
  291.     }
  292.  
  293.     /** Stop a plugin operation
  294.      */
  295.  
  296.     public void stopPlugin(Composer composer){
  297.         killGroup(composer);
  298.     }
  299.  
  300.     public int getNumberOfEncoders(){
  301.         return encoders.length();
  302.     }
  303.     public String getEncoderName(int index){
  304.         return getEncoder(index).getName();
  305.     }
  306.     public String getEncoderFileType(int index){
  307.         byte[] fileType = new byte[4];
  308.         getEncoder(index).getFileType(fileType);
  309.         return new String(fileType, 0);
  310.     }
  311.     public boolean getEncoderNeedsQuantizedSource(int index){
  312.         return getEncoder(index).needsQuantizedSource();
  313.     }
  314.     public String getEncoderFileExtension(int index){
  315.         return getEncoder(index).getFileExtension();
  316.     }
  317.     public String getEncoderHint(int index){
  318.         return getEncoder(index).getHint();
  319.     }
  320.  
  321.     protected ImageEncoder getEncoder(int index) {
  322.         return (ImageEncoder) encoders.get(index);
  323.     }
  324.  
  325.     /** Start an encoder operation.
  326.      */
  327.     public boolean startEncoder(Composer composer, int index,
  328.         int width, int height, byte[][] pixels,
  329.         String fileName){
  330.         Plugin encoderPlugin = new ImageEncoderPlugin(getEncoder(index),
  331.             width, height, pixels, fileName);
  332.         return performPlugin2(composer, encoderPlugin, null, null, null, null, null, null,null);
  333.     }
  334.  
  335.     protected Plugin getPlugin(int category, int index){
  336.         Plugin result = null;
  337.         SortedStringTable categoryTable = (SortedStringTable) categories.get(category);
  338.         if ( categoryTable != null ) {
  339.             result = (Plugin) categoryTable.get(index);
  340.         }
  341.         return result;
  342.     }
  343.  
  344.     void pluginFinished(Composer composer, int status, Object argument){
  345.         composer.pluginFinished(status, argument);
  346.         killGroup(composer);
  347.     }
  348.  
  349.     void killGroup(Composer composer){
  350.         ThreadGroup group = (ThreadGroup) pluginThreads.remove(composer);
  351.         if ( group != null ) {
  352.             pluginKiller.kill(group);
  353.         }
  354.     }
  355.     private SortedStringTable categories = new SortedStringTable();
  356.     private SortedStringTable encoders = new SortedStringTable();
  357.     private SortedStringTable events = new SortedStringTable();
  358.     private Hashtable pluginThreads = new Hashtable(); // Composer composer, Thread
  359.     private PluginKiller pluginKiller = new PluginKiller();
  360. }
  361.  
  362. class PluginRunner implements Runnable {
  363.     public PluginRunner(Plugin plugin, ComposerDocument document,
  364.         PluginManager manager){
  365.         this.plugin = plugin;
  366.         this.document = document;
  367.         this.manager = manager;
  368.     }
  369.     public void run() {
  370.         Composer composer = document.getComposer();
  371.         // Take this out someday when security manager works better.
  372.         // SecurityManager.enablePrivilege("SuperUser");
  373.         try {
  374.             boolean result = plugin.perform(document);
  375.             manager.pluginFinished(composer, result ? Composer.PLUGIN_OK : Composer.PLUGIN_CANCEL, null);
  376.         } catch( ThreadDeath t) {
  377.             System.err.println("Composer plugin " + plugin + " was killed.");
  378.         } catch (Throwable t){
  379.             System.err.println("Composer plugin " + plugin + " threw this exception:");
  380.             t.printStackTrace();
  381.             manager.pluginFinished(composer, Composer.PLUGIN_FAIL, t.toString());
  382.         }
  383.     }
  384.     private Plugin plugin;
  385.     private ComposerDocument document;
  386.     private PluginManager manager;
  387. }
  388.  
  389. class ImageEncoderPlugin extends Plugin {
  390.     public ImageEncoderPlugin(ImageEncoder encoder,
  391.         int width, int height, byte[][] pixels,
  392.         String fileName) {
  393.         this.encoder = encoder;
  394.         this.width = width;
  395.         this.height = height;
  396.         this.pixels = pixels;
  397.         this.fileName = fileName;
  398.     }
  399.     public boolean perform(Document document) throws IOException {
  400.         // Create the image.
  401.         int length = width * height;
  402.         int[] pixels2 = new int[length];
  403.         int i = 0;
  404.         for(int y = 0; y < height; y++) {
  405.             int j = 0;
  406.             byte[] line = pixels[y];
  407.             for(int x = 0; x < width; x++ ) {
  408.                 pixels2[i++] = (0xff << 24)
  409.                     | ((0xff & line[j]) << 16)
  410.                     | ((0xff & line[j+1]) << 8)
  411.                     | ((0xff & line[j+2]));
  412.                 j += 3;
  413.             }
  414.         }
  415.         ImageProducer source = new MemoryImageSource(width, height, pixels2, 0, width);
  416.         ByteArrayOutputStream temp = new ByteArrayOutputStream(width*height/2);
  417.         boolean result = encoder.encode(source, temp);
  418.         if ( result ) {
  419.            // Create the output
  420.            SecurityManager.enablePrivilege("SuperUser");
  421.            OutputStream output = new FileOutputStream(new File(fileName));
  422.            output.write(temp.toByteArray());
  423.            output.close();
  424.         }
  425.         return result;
  426.     }
  427.     private ImageEncoder encoder;
  428.     private int width;
  429.     private int height;
  430.     private byte[][] pixels;
  431.     private String fileName;
  432. }
  433.  
  434. /** Processes a sequence of plugins.
  435.  */
  436.  
  437. class GroupPlugin extends Plugin {
  438.     public GroupPlugin(SortedStringTable table){
  439.         table_ = table;
  440.     }
  441.     public boolean perform(Document document) throws IOException {
  442.         // Perform each of the plug-ins in order
  443.         boolean result = true;
  444.         // System.err.println("GroupPlugin ready to go! " + table_);
  445.         if ( table_ != null ) {
  446.             Enumeration categories = table_.values();
  447.             while ( categories.hasMoreElements() && result ){
  448.                 try {
  449.                     SortedStringTable category =
  450.                         (SortedStringTable) categories.nextElement();
  451.                     Enumeration plugins = category.values();
  452.                     while ( plugins.hasMoreElements() && result ){
  453.                         Plugin plugin = null;
  454.                         try {
  455.                             plugin = (Plugin) plugins.nextElement();
  456.                             result = plugin.perform(document);
  457.                         }
  458.                         catch(Throwable t){
  459.                             System.err.print("Exception while executing " + plugin);
  460.                             t.printStackTrace();
  461.                             result = false;
  462.                         }
  463.                     }
  464.  
  465.                 }
  466.                 catch(Throwable t){
  467.                     t.printStackTrace();
  468.                     result = false;
  469.                 }
  470.             }
  471.         }
  472.         return result;
  473.     }
  474.     SortedStringTable table_;
  475. }
  476.  
  477. class PluginKiller implements Runnable {
  478.     PluginKiller() {
  479.         list = new Vector();
  480.         // Temporary security work-around for pre-4.0PR3
  481.         SecurityManager.enablePrivilege("SuperUser");
  482.         Thread killer = new Thread(this, "Composer Plug-in Killer");
  483.         killer.start();
  484.     }
  485.  
  486.     synchronized void kill(ThreadGroup group) {
  487.         list.addElement(group);
  488.         notifyAll();
  489.     }
  490.  
  491.     synchronized ThreadGroup getPluginThreadGroup() {
  492.         while (list.isEmpty()) {
  493.             try {
  494.                 wait();
  495.             } catch (InterruptedException e) {
  496.             }
  497.         }
  498.  
  499.         int last = list.size() - 1;
  500.         ThreadGroup threadGroup = (ThreadGroup) list.elementAt(last);
  501.         list.removeElementAt(last);
  502.         return threadGroup;
  503.     }
  504.  
  505.     public void run() {
  506.         while (true) {
  507.  
  508.             // this thread cannot die for any reason.
  509.             // Catch any exception and keep killing
  510.             try {
  511.                 ThreadGroup group = getPluginThreadGroup();
  512.  
  513.                 synchronized (group) {
  514.                     //System.err.println("killing threadgroup " + group);
  515.  
  516.                     // Give the thread some time to exit. If it exits
  517.                     // sooner then we will be notified when the group runs
  518.                     // out of threads.
  519.                     try {
  520.                         group.wait(300);
  521.                     } catch (InterruptedException e) {
  522.                     }
  523.  
  524.                     // Check and see if thread is really gone
  525.                     if (group.activeCount() > 0) {
  526.                         // Gun down the remaining threads.
  527.                         try {
  528.                             SecurityManager.enablePrivilege("SuperUser");
  529.                             group.stop();
  530.                             group.wait(5000);
  531.                         } catch (InterruptedException e) {
  532.                         }
  533.                         finally {
  534.                             SecurityManager.revertPrivilege();
  535.                         }
  536.                     }
  537.  
  538.                     // Finally, destroy the thread group
  539.                     try {
  540.                         SecurityManager.enablePrivilege("SuperUser");
  541.                         group.destroy();
  542.                     } catch (Exception e) {
  543.                     }
  544.                     finally {
  545.                         SecurityManager.revertPrivilege();
  546.                     }
  547.                 }
  548.             } catch (Exception e) {
  549.                 System.out.println("Exception occurred while deleting Composer Plug-in thread group: ");
  550.                 e.printStackTrace();
  551.             }
  552.         }
  553.     }
  554.  
  555.     public String toString() {
  556.         return new String("Plugin thread killer! Composer plugins to be disposed of: " + list);
  557.     }
  558.  
  559.     // the list of composer plug-in groups to finish
  560.     private Vector list; // Of ThreadGroup
  561.  
  562. }
  563.