Ignore:
Timestamp:
Sep 24, 2014, 9:34:21 PM (11 years ago)
Author:
dmik
Message:

icedtea-web: Merge version 1.5.1 from vendor to trunk.

Location:
trunk/icedtea-web/plugin/icedteanp
Files:
3 deleted
25 edited
5 copied

Legend:

Unmodified
Added
Removed
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc

    r418 r429  
    8383                                }
    8484
    85                                 printf("Error on Java side: %s\n", result->error_msg->c_str());
     85                                PLUGIN_ERROR("Error on Java side: %s\n", result->error_msg->c_str());
    8686
    8787                                result->error_occurred = true;
     
    136136                        {
    137137
    138                             if (!message_parts->at(5)->find("literalreturn"))
     138                            if (!message_parts->at(5)->find("literalreturn") || !message_parts->at(5)->find("jsobject"))
    139139                {
    140140                                // literal returns don't have a corresponding jni id
     
    768768                                  std::vector<std::string> args)
    769769{
    770         JavaRequestProcessor* java_request;
    771         std::string message = std::string();
    772     std::string* signature;
    773 
    774     signature = new std::string();
    775     *signature += "(";
     770        std::string message, signature = "(";
    776771
    777772    // FIXME: Need to determine how to extract array types and complex java objects
    778773    for (int i=0; i < args.size(); i++)
    779774    {
    780         *signature += args[i];
     775        signature += args[i];
    781776    }
    782777
    783     *signature += ")";
     778    signature += ")";
    784779
    785780        this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
     
    787782
    788783        IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
    789         message += " GetMethodID ";
    790         message += classID;
    791         message += " ";
    792         message += browser_functions.utf8fromidentifier(methodName);
    793         message += " ";
    794         message += *signature;
     784        message += " GetMethodID " + classID + " ";
     785        message += IcedTeaPluginUtilities::NPIdentifierAsString(methodName) + " ";
     786        message += signature;
    795787
    796788        postAndWaitForResponse(message);
    797789
    798790        IcedTeaPluginUtilities::releaseReference();
    799         delete signature;
    800791
    801792        return result;
     
    806797                                  std::vector<std::string> args)
    807798{
    808     JavaRequestProcessor* java_request;
    809     std::string message = std::string();
    810     std::string* signature;
    811 
    812     signature = new std::string();
    813     *signature += "(";
     799    std::string message, signature = "(";
    814800
    815801    // FIXME: Need to determine how to extract array types and complex java objects
    816802    for (int i=0; i < args.size(); i++)
    817803    {
    818         *signature += args[i];
     804        signature += args[i];
    819805    }
    820806
    821     *signature += ")";
     807    signature += ")";
    822808
    823809    this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
     
    825811
    826812    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
    827     message += " GetStaticMethodID ";
    828     message += classID;
    829     message += " ";
    830     message += browser_functions.utf8fromidentifier(methodName);
    831     message += " ";
    832     message += *signature;
    833 
    834     postAndWaitForResponse(message);
    835 
    836     IcedTeaPluginUtilities::releaseReference();
    837     delete signature;
     813    message += " GetStaticMethodID " + classID + " ";
     814    message += IcedTeaPluginUtilities::NPIdentifierAsString(methodName) + " ";
     815    message += signature;
     816
     817    postAndWaitForResponse(message);
     818
     819    IcedTeaPluginUtilities::releaseReference();
    838820
    839821    return result;
     
    982964
    983965                if (java_result->error_occurred) {
    984                     printf("Unable to create array\n");
     966                    PLUGIN_ERROR("Unable to create array\n");
    985967                    id->append("-1");
    986968                    return;
     
    1001983
    1002984                    if (value_id == "-1") {
    1003                         printf("Unable to populate array\n");
     985                        PLUGIN_ERROR("Unable to populate array\n");
    1004986                        id->clear();
    1005987                        id->append("-1");
     
    10371019                if (java_result->error_occurred)
    10381020                {
    1039                     printf("Unable to get JSObject class id\n");
     1021                    PLUGIN_ERROR("Unable to get JSObject class id\n");
    10401022                    id->clear();
    10411023                    id->append("-1");
     
    10531035                if (java_result->error_occurred)
    10541036                {
    1055                     printf("Unable to get JSObject constructor id\n");
     1037                    PLUGIN_ERROR("Unable to get JSObject constructor id\n");
    10561038                    id->clear();
    10571039                    id->append("-1");
     
    10771059                if (java_result->error_occurred)
    10781060                {
    1079                     printf("Unable to create JSObject\n");
     1061                    PLUGIN_ERROR("Unable to create JSObject\n");
    10801062                    id->clear();
    10811063                    id->append("-1");
     
    10941076                // the result we want is in result_string (assuming there was no error)
    10951077                if (java_result->error_occurred) {
    1096                         printf("Unable to find classid for %s\n", className.c_str());
     1078                        PLUGIN_ERROR("Unable to find classid for %s\n", className.c_str());
    10971079                        id->append("-1");
    10981080                        return;
     
    11091091                // the result we want is in result_string (assuming there was no error)
    11101092                if (java_result->error_occurred) {
    1111                         printf("Unable to find string constructor for %s\n", className.c_str());
     1093                        PLUGIN_ERROR("Unable to find string constructor for %s\n", className.c_str());
    11121094                        id->append("-1");
    11131095            return;
     
    11211103
    11221104                if (java_result->error_occurred) {
    1123                         printf("Unable to create requested object\n");
     1105                        PLUGIN_ERROR("Unable to create requested object\n");
    11241106                        id->append("-1");
    11251107            return;
     
    11341116
    11351117        if (java_result->error_occurred) {
    1136             printf("Unable to create requested object\n");
     1118            PLUGIN_ERROR("Unable to create requested object\n");
    11371119            id->append("-1");
    11381120            return;
     
    13141296        JavaResultData* java_result;
    13151297        JavaRequestProcessor* java_request = new JavaRequestProcessor();
    1316         std::string message = std::string();
    13171298        std::string plugin_instance_id_str = std::string();
    13181299        IcedTeaPluginUtilities::itoa(plugin_instance_id, &plugin_instance_id_str);
     
    13231304        this->reference = IcedTeaPluginUtilities::getReference();
    13241305
     1306        std::string message;
    13251307        IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
    1326         message.append(" HasPackage ");
    1327     message.append(plugin_instance_id_str);
    1328     message.append(" ");
    1329         message.append(java_result->return_string->c_str());
     1308        message += " HasPackage " + plugin_instance_id_str + " " + *java_result->return_string;
    13301309
    13311310        postAndWaitForResponse(message);
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaJavaRequestProcessor.h

    r348 r429  
    4242#include <errno.h>
    4343#include <stdlib.h>
     44#include <unistd.h>
    4445#include <vector>
    4546
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaNPPlugin.cc

    r419 r429  
    4646#include <sys/socket.h>
    4747#include <fcntl.h>
     48#include <sstream>
    4849#include "OS_OS2.h"
    4950#endif
     
    5152// System includes.
    5253#include <dlfcn.h>
     54#include <unistd.h>
     55#include <fcntl.h>
     56#include <dirent.h>
    5357#include <errno.h>
    5458#include <libgen.h>
     
    5660#include <stdlib.h>
    5761#include <string.h>
     62#include <string>
    5863#include <sys/stat.h>
    5964#include <sys/types.h>
    6065#include <unistd.h>
    61 
     66#include <new>
     67
     68//IcedTea-plugin includes
     69#include "IcedTeaPluginUtils.h"
     70#include "IcedTeaParseProperties.h"
    6271// Liveconnect extension
    6372#include "IcedTeaScriptablePluginObject.h"
     
    6978#define DT_SOCKET_DLL "dt_socket"
    7079#endif
    71 
    72 #if MOZILLA_VERSION_COLLAPSED < 1090100
    73 // Documentbase retrieval includes.
    74 #include <nsIPluginInstance.h>
    75 #include <nsIPluginInstancePeer.h>
    76 #include <nsIPluginTagInfo2.h>
    77 
    78 // API's into Mozilla
    79 #include <nsCOMPtr.h>
    80 #include <nsICookieService.h>
    81 #include <nsIDNSRecord.h>
    82 #include <nsIDNSService.h>
    83 #include <nsINetUtil.h>
    84 #include <nsIProxyInfo.h>
    85 #include <nsIProtocolProxyService.h>
    86 #include <nsIScriptSecurityManager.h>
    87 #include <nsIIOService.h>
    88 #include <nsIURI.h>
    89 #include <nsNetCID.h>
    90 #include <nsStringAPI.h>
    91 #include <nsServiceManagerUtils.h>
    92 #endif
    93 
    94 // Error reporting macros.
    95 #define PLUGIN_ERROR(message)                                       \
    96   g_printerr ("%s:%d: thread %p: Error: %s\n", __FILE__, __LINE__,  \
    97               g_thread_self (), message)
    98 
    99 #define PLUGIN_ERROR_TWO(first, second)                                 \
    100   g_printerr ("%s:%d: thread %p: Error: %s: %s\n", __FILE__, __LINE__,  \
    101               g_thread_self (), first, second)
    102 
    103 #define PLUGIN_ERROR_THREE(first, second, third)                        \
    104   g_printerr ("%s:%d: thread %p: Error: %s: %s: %s\n", __FILE__,        \
    105               __LINE__, g_thread_self (), first, second, third)
    10680
    10781// Plugin information passed to about:plugins.
     
    167141  "  For more detail rerun \"firefox -g\" in a terminal window."
    168142
    169 #if MOZILLA_VERSION_COLLAPSED < 1090100
    170 // Documentbase retrieval required definition.
    171 static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
    172 #endif
    173 
    174143// Data directory for plugin.
    175 static gchar* data_directory = NULL;
    176 
    177 // Fully-qualified appletviewer executable.
    178 static gchar* appletviewer_executable = NULL;
     144static std::string data_directory;
     145static DIR *data_directory_descriptor;
     146
     147// Fully-qualified appletviewer default  executable and rt.jar
     148static const char* appletviewer_default_executable = ICEDTEA_WEB_JRE "/bin/java";
     149static const char* appletviewer_default_rtjar = ICEDTEA_WEB_JRE "/lib/rt.jar";
    179150
    180151// Applet viewer input channel (needs to be static because it is used in plugin_in_pipe_callback)
     
    202173#endif
    203174
     175// Applet viewer debug pipe name.
     176gchar* debug_pipe_name = NULL;
     177
    204178// Applet viewer output watch source.
    205179gint out_watch_source;
     
    211185pthread_mutex_t pluginAsyncCallMutex;
    212186
     187/*to sync pipe to apletviewer console*/
     188pthread_mutex_t debug_pipe_lock = PTHREAD_MUTEX_INITIALIZER;
     189
    213190// Applet viewer output channel.
    214191GIOChannel* out_to_appletviewer;
     192
     193// Applet viewer debug channel.
     194GIOChannel* debug_to_appletviewer = NULL;
    215195
    216196// Tracks jvm status
     
    235215JavaMessageSender* java_req_proc;
    236216
    237 #if MOZILLA_VERSION_COLLAPSED < 1090100
    238 // Documentbase retrieval type-punning union.
    239 typedef union
    240 {
    241   void** void_field;
    242   nsIPluginTagInfo2** info_field;
    243 } info_union;
     217// Queue processing threads
     218static pthread_t plugin_request_processor_thread1;
     219static pthread_t plugin_request_processor_thread2;
     220static pthread_t plugin_request_processor_thread3;
     221
     222#ifdef __OS2__
     223struct QueueProcessorData
     224{
     225    PluginRequestProcessor *processor;
     226    bool stopRequested;
     227};
     228
     229static QueueProcessorData queue_processor_data1 = { NULL, false };
     230static QueueProcessorData queue_processor_data2 = { NULL, false };
     231static QueueProcessorData queue_processor_data3 = { NULL, false };
    244232#endif
    245233
    246234// Static instance helper functions.
    247 // Have the browser allocate a new ITNPPluginData structure.
    248 static void plugin_data_new (ITNPPluginData** data);
    249235// Retrieve the current document's documentbase.
    250 static gchar* plugin_get_documentbase (NPP instance);
    251 // Notify the user that the appletviewer is not installed correctly.
    252 static void plugin_display_failure_dialog ();
     236static std::string plugin_get_documentbase (NPP instance);
    253237// Callback used to monitor input pipe status.
    254238static gboolean plugin_in_pipe_callback (GIOChannel* source,
     
    259243                                          GIOCondition condition,
    260244                                          gpointer plugin_data);
    261 static NPError plugin_start_appletviewer (ITNPPluginData* data);
    262 static gchar* plugin_create_applet_tag (int16_t argc, char* argn[],
    263                                         char* argv[]);
     245std::string plugin_parameters_string (int argc, char* argn[], char* argv[]);
    264246static void plugin_stop_appletviewer ();
    265 // Uninitialize ITNPPluginData structure
    266 static void plugin_data_destroy (NPP instance);
    267247
    268248NPError get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len);
    269249NPError get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len);
    270250void consume_message(gchar* message);
    271 void start_jvm_if_needed();
    272251static void appletviewer_monitor(GPid pid, gint status, gpointer data);
    273252void plugin_send_initialization_message(char* instance, gulong handle,
    274253                                               int width, int height,
    275254                                               char* url);
     255/* Returns JVM options set in itw-settings */
     256std::vector<std::string*>* get_jvm_args();
    276257
    277258// Global instance counter.
     
    288269static guint appletviewer_watch_id = -1;
    289270
     271bool debug_initiated = false;
    290272int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
     273bool plugin_debug_headers = false;
     274bool plugin_debug_to_file = false ;
     275bool plugin_debug_to_streams = true ;
     276bool plugin_debug_to_system = false;
     277bool plugin_debug_to_console = true;
     278FILE *  plugin_file_log;
     279std::string plugin_file_log_name;
     280
    291281int plugin_debug_suspend = (getenv("ICEDTEAPLUGIN_DEBUG") != NULL) &&
    292282        (strcmp(getenv("ICEDTEAPLUGIN_DEBUG"), "suspend") == 0);
    293 
    294 pthread_cond_t cond_message_available = PTHREAD_COND_INITIALIZER;
    295283
    296284
     
    316304#endif
    317305
    318 
     306static std::string get_plugin_executable(){
     307      std::string custom_jre;
     308      bool custom_jre_defined = find_custom_jre(custom_jre);
     309      if (custom_jre_defined) {
     310            if (IcedTeaPluginUtilities::file_exists(custom_jre+"/bin/java")){
     311                  return custom_jre+"/bin/java";
     312            } else {
     313                 PLUGIN_ERROR("Your custom jre (/bin/java check) %s is not valid. Please fix %s in your %s. In attempt to run using default one. \n", custom_jre.c_str(), custom_jre_key.c_str(), default_file_ITW_deploy_props_name.c_str());
     314            }
     315      }
     316      return appletviewer_default_executable;     
     317}
     318
     319static std::string get_plugin_rt_jar(){
     320      std::string custom_jre;
     321      bool custom_jre_defined = find_custom_jre(custom_jre);
     322      if (custom_jre_defined) {
     323            if (IcedTeaPluginUtilities::file_exists(custom_jre+"/lib/rt.jar")){
     324                  return custom_jre+"/lib/rt.jar";
     325            } else {
     326                  PLUGIN_ERROR("Your custom jre (/lib/rt.jar check) %s is not valid. Please fix %s in your %s. In attempt to run using default one. \n", custom_jre.c_str(), custom_jre_key.c_str(), default_file_ITW_deploy_props_name.c_str());
     327            }
     328      }
     329      return appletviewer_default_rtjar;     
     330}
     331
     332static void cleanUpDir(){
     333  //free data_directory descriptor
     334  if (data_directory_descriptor != NULL) {
     335    closedir(data_directory_descriptor);
     336  }
     337  //clean up pipes directory
     338  PLUGIN_DEBUG ("Removing runtime directory %s \n", data_directory.c_str());
     339  int removed = rmdir(data_directory.c_str());
     340  if (removed != 0) {
     341    PLUGIN_ERROR ("Failed to remove runtime directory %s, because of  %s \n", data_directory.c_str(), strerror(errno));
     342  } else {
     343    PLUGIN_DEBUG ("Removed runtime directory %s \n", data_directory.c_str());
     344  }
     345  data_directory_descriptor = NULL;
     346}
    319347/*
    320348 * Find first member in GHashTable* depending on version of glib
     
    344372// Creates a new icedtea np plugin instance.  This function creates a
    345373// ITNPPluginData* and stores it in instance->pdata.  The following
    346 // ITNPPluginData fiels are initialized: instance_id, in_pipe_name,
     374// ITNPPluginData fields are initialized: instance_id, in_pipe_name,
    347375// in_from_appletviewer, in_watch_source, out_pipe_name,
    348376// out_to_appletviewer, out_watch_source, appletviewer_mutex, owner,
     
    366394  if (!browser_functions.hasproperty(instance, window_ptr, identifier))
    367395  {
    368         printf("%s not found!\n", "document");
     396        PLUGIN_ERROR("%s not found!\n", "document");
    369397  }
    370398  browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
     
    372400  PLUGIN_DEBUG("Got variant %p\n", &member_ptr);
    373401
    374 
    375   NPError np_error = NPERR_NO_ERROR;
    376   ITNPPluginData* data = NULL;
    377 
    378   gchar* documentbase = NULL;
    379   gchar* read_message = NULL;
    380   gchar* applet_tag = NULL;
    381   gchar* cookie_info = NULL;
    382 
    383   NPObject* npPluginObj = NULL;
    384 
    385402  if (!instance)
    386     {
    387       PLUGIN_ERROR ("Browser-provided instance pointer is NULL.");
    388       np_error = NPERR_INVALID_INSTANCE_ERROR;
    389       goto cleanup_done;
    390     }
     403  {
     404      PLUGIN_ERROR ("Browser-provided instance pointer is NULL.\n");
     405      return NPERR_INVALID_INSTANCE_ERROR;
     406  }
    391407
    392408  // data
    393   plugin_data_new (&data);
     409  ITNPPluginData* data = plugin_data_new ();
    394410  if (data == NULL)
    395     {
    396       PLUGIN_ERROR ("Failed to allocate plugin data.");
    397       np_error = NPERR_OUT_OF_MEMORY_ERROR;
    398       goto cleanup_done;
     411  {
     412      PLUGIN_ERROR ("Failed to allocate plugin data.\n");
     413      return NPERR_OUT_OF_MEMORY_ERROR;
    399414    }
    400415
    401416  // start the jvm if needed
    402   start_jvm_if_needed();
     417   NPError startup_error = start_jvm_if_needed();
     418   if (startup_error != NPERR_NO_ERROR) {
     419           PLUGIN_ERROR ("Failed to start JVM\n");
     420           return startup_error;
     421   }
    403422
    404423  // Initialize data->instance_id.
     
    422441  g_mutex_lock (data->appletviewer_mutex);
    423442
     443  std::string documentbase = plugin_get_documentbase (instance);
    424444  // Documentbase retrieval.
    425   documentbase = plugin_get_documentbase (instance);
    426   if (documentbase && argc != 0)
    427     {
    428       // Send applet tag message to appletviewer.
    429       applet_tag = plugin_create_applet_tag (argc, argn, argv);
    430 
    431       data->applet_tag = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32);
    432       g_sprintf(data->applet_tag, "tag %s %s", documentbase, applet_tag);
     445  if (argc != 0)
     446  {
     447      // Send parameters to appletviewer.
     448      std::string params_string = plugin_parameters_string(argc, argn, argv);
     449
     450      data->parameters_string =  g_strdup_printf("tag %s %s", documentbase.c_str(), params_string.c_str());
    433451
    434452      data->is_applet_instance = true;
    435     }
    436 
    437   if (argc == 0)
    438     {
     453  }
     454  else
     455  {
    439456      data->is_applet_instance = false;
    440     }
     457  }
    441458
    442459  g_mutex_unlock (data->appletviewer_mutex);
     
    454471
    455472  instance->pdata = data;
    456 
    457   goto cleanup_done;
    458 
    459  cleanup_appletviewer_mutex:
    460   g_mutex_free (data->appletviewer_mutex);
    461   data->appletviewer_mutex = NULL;
    462 
    463   // cleanup_instance_string:
    464   g_free (data->instance_id);
    465   data->instance_id = NULL;
    466 
    467   // cleanup applet tag:
    468   g_free (data->applet_tag);
    469   data->applet_tag = NULL;
    470 
    471   // cleanup_data:
    472   // Eliminate back-pointer to plugin instance.
    473   data->owner = NULL;
    474   (*browser_functions.memfree) (data);
    475   data = NULL;
    476 
    477   // Initialization failed so return a NULL pointer for the browser
    478   // data.
    479   instance->pdata = NULL;
    480 
    481  cleanup_done:
    482   g_free (applet_tag);
    483   applet_tag = NULL;
    484   g_free (read_message);
    485   read_message = NULL;
    486   g_free (documentbase);
    487   documentbase = NULL;
    488473
    489474  // store an identifier for this plugin
     
    495480  PLUGIN_DEBUG ("ITNP_New return\n");
    496481
    497   return np_error;
     482  return NPERR_NO_ERROR;
    498483}
    499484
    500485// Starts the JVM if it is not already running
    501 void start_jvm_if_needed()
     486NPError start_jvm_if_needed()
    502487{
    503488
     
    514499  {
    515500      PLUGIN_DEBUG("JVM is up. Returning.\n");
    516       return;
     501      return  NPERR_NO_ERROR;
    517502  }
    518503
     
    536521  // in_pipe_name
    537522  in_pipe_name = g_strdup_printf ("%s/%d-icedteanp-appletviewer-to-plugin",
    538                                          data_directory, getpid());
     523                                         data_directory.c_str(), getpid());
    539524  if (!in_pipe_name)
    540525    {
    541       PLUGIN_ERROR ("Failed to create input pipe name.");
     526      PLUGIN_ERROR ("Failed to create input pipe name.\n");
    542527      np_error = NPERR_OUT_OF_MEMORY_ERROR;
    543528      // If in_pipe_name is NULL then the g_free at
     
    552537  if (mkfifo (in_pipe_name, 0600) == -1 && errno != EEXIST)
    553538    {
    554       PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno));
     539      PLUGIN_ERROR ("Failed to create input pipe\n", strerror (errno));
    555540      np_error = NPERR_GENERIC_ERROR;
    556541      goto cleanup_in_pipe_name;
     
    573558  // out_pipe_name
    574559  out_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-to-appletviewer",
    575                                          data_directory, getpid());
     560                                         data_directory.c_str(), getpid());
    576561
    577562  if (!out_pipe_name)
    578563    {
    579       PLUGIN_ERROR ("Failed to create output pipe name.");
     564      PLUGIN_ERROR ("Failed to create output pipe name.\n");
    580565      np_error = NPERR_OUT_OF_MEMORY_ERROR;
    581566      goto cleanup_out_pipe_name;
     
    588573  if (mkfifo (out_pipe_name, 0600) == -1 && errno != EEXIST)
    589574    {
    590       PLUGIN_ERROR_TWO ("Failed to create output pipe", strerror (errno));
     575      PLUGIN_ERROR ("Failed to create output pipe\n", strerror (errno));
    591576      np_error = NPERR_GENERIC_ERROR;
    592577      goto cleanup_out_pipe_name;
     
    594579  PLUGIN_DEBUG ("ITNP_New: created output fifo: %s\n", out_pipe_name);
    595580#endif
     581
     582  // Create plugin-debug-to-appletviewer pipe which we refer to as the
     583  // debug pipe.
     584  initialize_debug();//should be already initialized, but...
     585  if (plugin_debug_to_console){
     586    // debug_pipe_name
     587    debug_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-debug-to-appletviewer",
     588                                         data_directory.c_str(), getpid());
     589
     590    if (!debug_pipe_name)
     591      {
     592        PLUGIN_ERROR ("Failed to create debug pipe name.\n");
     593        np_error = NPERR_OUT_OF_MEMORY_ERROR;
     594        goto cleanup_debug_pipe_name;
     595      }
     596
     597    // clean up any older pip
     598    unlink (debug_pipe_name);
     599
     600    PLUGIN_DEBUG ("ITNP_New: creating debug fifo: %s\n", debug_pipe_name);
     601    if (mkfifo (debug_pipe_name, 0600) == -1 && errno != EEXIST)
     602      {
     603        PLUGIN_ERROR ("Failed to create debug pipe\n", strerror (errno));
     604        np_error = NPERR_GENERIC_ERROR;
     605        goto cleanup_debug_pipe_name;
     606      }
     607    PLUGIN_DEBUG ("ITNP_New: created debug fifo: %s\n", debug_pipe_name);
     608  }
    596609
    597610  // Start a separate appletviewer process for each applet, even if
     
    628641      if (channel_error)
    629642        {
    630           PLUGIN_ERROR_TWO ("Failed to create output channel",
     643          PLUGIN_ERROR ("Failed to create output channel, '%s'\n",
    631644                            channel_error->message);
    632645          g_error_free (channel_error);
     
    634647        }
    635648      else
    636         PLUGIN_ERROR ("Failed to create output channel");
     649        PLUGIN_ERROR ("Failed to create output channel\n");
    637650
    638651      np_error = NPERR_GENERIC_ERROR;
     
    659672      if (channel_error)
    660673        {
    661           PLUGIN_ERROR_TWO ("Failed to create input channel",
     674          PLUGIN_ERROR ("Failed to create input channel, '%s'\n",
    662675                            channel_error->message);
    663676          g_error_free (channel_error);
     
    665678        }
    666679      else
    667         PLUGIN_ERROR ("Failed to create input channel");
     680        PLUGIN_ERROR ("Failed to create input channel\n");
    668681
    669682      np_error = NPERR_GENERIC_ERROR;
     
    676689                    (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP),
    677690                    plugin_in_pipe_callback, (gpointer) in_from_appletviewer);
     691                   
     692  // Create plugin-to-appletviewer console debug channel.  The default encoding for
     693  // the file is UTF-8.
     694  // debug_to_appletviewer
     695  if (plugin_debug_to_console){
     696    debug_to_appletviewer = g_io_channel_new_file (debug_pipe_name,
     697                                                 "w", &channel_error);
     698    if (!debug_to_appletviewer)
     699      {
     700        if (channel_error)
     701          {
     702            PLUGIN_ERROR ("Failed to debug output channel, '%s'\n",
     703                              channel_error->message);
     704            g_error_free (channel_error);
     705            channel_error = NULL;
     706          }
     707        else
     708          PLUGIN_ERROR ("Failed to create debug channel\n");
     709
     710        np_error = NPERR_GENERIC_ERROR;
     711        goto cleanup_debug_to_appletviewer;
     712     }
     713  }
    678714
    679715  jvm_up = TRUE;
    680 
     716 
     717  if (plugin_debug_to_console){
     718    //jvm is up, we can start console producer thread
     719    pthread_t debug_to_console_consumer;
     720    pthread_create(&debug_to_console_consumer,NULL,&flush_pre_init_messages,NULL);
     721  }
    681722  goto done;
    682723
    683   // Free allocated data
     724  // Free allocated data in case of error
     725 cleanup_debug_to_appletviewer:
     726  if (plugin_debug_to_console){
     727    if (debug_to_appletviewer)
     728      g_io_channel_unref (debug_to_appletviewer);
     729    debug_to_appletviewer = NULL;
     730  }
    684731
    685732 cleanup_in_watch_source:
     
    702749    g_io_channel_unref (out_to_appletviewer);
    703750  out_to_appletviewer = NULL;
     751
     752  if (plugin_debug_to_console){
     753    // cleanup_debug_pipe:
     754    // Delete output pipe.
     755    PLUGIN_DEBUG ("ITNP_New: deleting debug fifo: %s\n", debug_pipe_name);
     756    unlink (debug_pipe_name);
     757    PLUGIN_DEBUG ("ITNP_New: deleted debug fifo: %s\n", debug_pipe_name);
     758  }
     759 cleanup_debug_pipe_name:
     760  if (plugin_debug_to_console){
     761    g_free (debug_pipe_name);
     762    debug_pipe_name = NULL;
     763  }
     764
     765
    704766
    705767  // cleanup_out_pipe:
     
    735797#endif
    736798
     799  cleanUpDir();
    737800 done:
    738801
     802  IcedTeaPluginUtilities::printDebugStatus();
    739803  // Now other threads may re-enter.. unlock the mutex
    740804  g_mutex_unlock(vm_start_mutex);
     805  return np_error;
    741806
    742807}
     
    765830      break;
    766831    default:
    767       PLUGIN_ERROR ("Unknown plugin value requested.");
     832      PLUGIN_ERROR ("Unknown plugin value requested.\n");
    768833      np_error = NPERR_GENERIC_ERROR;
    769834      break;
     
    814879  if (instance == NULL)
    815880    {
    816       PLUGIN_ERROR ("Invalid instance.");
     881      PLUGIN_ERROR ("Invalid instance.\n");
    817882
    818883      return NPERR_INVALID_INSTANCE_ERROR;
     
    927992      plugin_send_initialization_message(
    928993                  data->instance_id, (gulong) data->window_handle,
    929                   data->window_width, data->window_height, data->applet_tag);
     994                  data->window_width, data->window_height, data->parameters_string);
    930995
    931996      g_mutex_unlock (data->appletviewer_mutex);
     
    10231088    return NPERR_GENERIC_ERROR;
    10241089  }
    1025 #if MOZILLA_VERSION_COLLAPSED < 1090100
    1026   nsresult rv;
    1027   nsCOMPtr<nsIScriptSecurityManager> sec_man =
    1028     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    1029 
    1030   if (!sec_man) {
    1031     return NPERR_GENERIC_ERROR;
    1032   }
    1033 
    1034   nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
    1035 
    1036   if (NS_FAILED(rv) || !io_svc) {
    1037     return NPERR_GENERIC_ERROR;
    1038   }
    1039 
    1040   nsCOMPtr<nsIURI> uri;
    1041   io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
    1042 
    1043   nsCOMPtr<nsICookieService> cookie_svc = do_GetService("@mozilla.org/cookieService;1", &rv);
    1044 
    1045   if (NS_FAILED(rv) || !cookie_svc) {
    1046     return NPERR_GENERIC_ERROR;
    1047   }
    1048 
    1049   rv = cookie_svc->GetCookieString(uri, NULL, cookieString);
    1050 
    1051   if (NS_FAILED(rv) || !*cookieString) {
    1052     return NPERR_GENERIC_ERROR;
    1053   }
    1054 
    1055 #else
    1056 
    10571090  // getvalueforurl needs an NPP instance. Quite frankly, there is no easy way
    10581091  // to know which instance needs the information, as applets on Java side can
     
    10731106  }
    10741107
    1075 #endif
    1076 
    10771108  return NPERR_NO_ERROR;
    10781109}
     
    10951126// HELPER FUNCTIONS
    10961127
    1097 static void
    1098 plugin_data_new (ITNPPluginData** data)
     1128ITNPPluginData*
     1129plugin_data_new ()
    10991130{
    11001131  PLUGIN_DEBUG ("plugin_data_new\n");
    11011132
    1102   *data = (ITNPPluginData*)
    1103     (*browser_functions.memalloc) (sizeof (struct ITNPPluginData));
    1104 
    1105   // appletviewer_alive is false until the applet viewer is spawned.
    1106   if (*data)
    1107     memset (*data, 0, sizeof (struct ITNPPluginData));
    1108 
     1133  ITNPPluginData* data = (ITNPPluginData*)browser_functions.memalloc(sizeof (struct ITNPPluginData));
     1134
     1135  if (data)
     1136  {
     1137      // Call constructor on allocated data
     1138      new (data) ITNPPluginData();
     1139  }
    11091140  PLUGIN_DEBUG ("plugin_data_new return\n");
     1141
     1142  return data;
    11101143}
    11111144
     
    11151148// documentbase.  This function relies on browser-private data so it
    11161149// will only work when the plugin is loaded in a Mozilla-based
    1117 // browser.  We could not find a way to retrieve the documentbase
    1118 // using the original Netscape plugin API so we use the XPCOM API
    1119 // instead.
    1120 #if MOZILLA_VERSION_COLLAPSED < 1090100
    1121 static gchar*
     1150// browser.
     1151static std::string
    11221152plugin_get_documentbase (NPP instance)
    11231153{
    11241154  PLUGIN_DEBUG ("plugin_get_documentbase\n");
    1125 
    1126   nsIPluginInstance* xpcom_instance = NULL;
    1127   nsIPluginInstancePeer* peer = NULL;
    1128   nsresult result = 0;
    1129   nsIPluginTagInfo2* pluginTagInfo2 = NULL;
    1130   info_union u = { NULL };
    1131   char const* documentbase = NULL;
    1132   gchar* documentbase_copy = NULL;
    1133 
    1134   xpcom_instance = (nsIPluginInstance*) (instance->ndata);
    1135   if (!xpcom_instance)
    1136     {
    1137       PLUGIN_ERROR ("xpcom_instance is NULL.");
    1138       goto cleanup_done;
    1139     }
    1140 
    1141   xpcom_instance->GetPeer (&peer);
    1142   if (!peer)
    1143     {
    1144       PLUGIN_ERROR ("peer is NULL.");
    1145       goto cleanup_done;
    1146     }
    1147 
    1148   u.info_field = &pluginTagInfo2;
    1149 
    1150   result = peer->QueryInterface (kIPluginTagInfo2IID,
    1151                                  u.void_field);
    1152   if (result || !pluginTagInfo2)
    1153     {
    1154       PLUGIN_ERROR ("pluginTagInfo2 retrieval failed.");
    1155       goto cleanup_peer;
    1156     }
    1157 
    1158   pluginTagInfo2->GetDocumentBase (&documentbase);
    1159 
    1160   if (!documentbase)
    1161     {
    1162       // NULL => dummy instantiation for LiveConnect
    1163       goto cleanup_plugintaginfo2;
    1164     }
    1165 
    1166   documentbase_copy = g_strdup (documentbase);
    1167 
    1168   // Release references.
    1169  cleanup_plugintaginfo2:
    1170   NS_RELEASE (pluginTagInfo2);
    1171 
    1172  cleanup_peer:
    1173   NS_RELEASE (peer);
    1174 
    1175  cleanup_done:
    1176   PLUGIN_DEBUG ("plugin_get_documentbase return\n");
    1177 
    1178   PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
    1179   return documentbase_copy;
    1180 }
    1181 #else
    1182 static gchar*
    1183 plugin_get_documentbase (NPP instance)
    1184 {
    1185   PLUGIN_DEBUG ("plugin_get_documentbase\n");
    1186 
    1187   char const* documentbase = NULL;
    1188   gchar* documentbase_copy = NULL;
    11891155
    11901156  // FIXME: This method is not ideal, but there are no known NPAPI call
     
    12071173
    12081174  std::string href_str = IcedTeaPluginUtilities::NPVariantAsString(href);
    1209   documentbase_copy = g_strdup (href_str.c_str());
    12101175
    12111176  // Release references.
    12121177  browser_functions.releasevariantvalue(&href);
    12131178  browser_functions.releasevariantvalue(&location);
    1214  cleanup_done:
     1179
    12151180  PLUGIN_DEBUG ("plugin_get_documentbase return\n");
    1216   PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
    1217 
    1218   return documentbase_copy;
    1219 }
    1220 #endif
    1221 
    1222 // This function displays an error message if the appletviewer has not
    1223 // been installed correctly.
    1224 static void
    1225 plugin_display_failure_dialog ()
    1226 {
    1227 #ifdef __OS2__
    1228   gchar *msg = NULL;
    1229 
    1230   PLUGIN_DEBUG ("plugin_display_failure_dialog\n");
    1231 
    1232   msg = g_strdup_printf (FAILURE_MESSAGE, appletviewer_executable);
    1233   WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
    1234                  msg, "Error", 0, MB_ERROR | MB_OK | MB_MOVEABLE);
    1235   g_free(msg);
    1236 #else
    1237   GtkWidget* dialog = NULL;
    1238 
    1239   PLUGIN_DEBUG ("plugin_display_failure_dialog\n");
    1240 
    1241   dialog = gtk_message_dialog_new (NULL,
    1242                                    GTK_DIALOG_DESTROY_WITH_PARENT,
    1243                                    GTK_MESSAGE_ERROR,
    1244                                    GTK_BUTTONS_CLOSE,
    1245                                    FAILURE_MESSAGE,
    1246                                    appletviewer_executable);
    1247   gtk_widget_show_all (dialog);
    1248   gtk_dialog_run (GTK_DIALOG (dialog));
    1249   gtk_widget_destroy (dialog);
    1250 #endif
    1251 
    1252   PLUGIN_DEBUG ("plugin_display_failure_dialog return\n");
    1253 }
    1254 
    1255 
     1181  PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", href_str.c_str());
     1182
     1183  return href_str;
     1184}
    12561185
    12571186// plugin_in_pipe_callback is called when data is available on the
     
    12791208          if (channel_error)
    12801209            {
    1281               PLUGIN_ERROR_TWO ("Failed to read line from input channel",
     1210              PLUGIN_ERROR ("Failed to read line from input channel, %s\n",
    12821211                                channel_error->message);
    12831212              g_error_free (channel_error);
     
    12851214            }
    12861215          else
    1287             PLUGIN_ERROR ("Failed to read line from input channel");
     1216            PLUGIN_ERROR ("Failed to read line from input channel\n");
    12881217#ifdef __OS2__
    12891218          // G_IO_ERR/HUP is not reported on file/pipe handles, simulate it
     
    13181247  if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
    13191248  {
    1320     gchar* proxy;
     1249    gchar* proxy = NULL;
    13211250    uint32_t len;
    13221251
     
    13261255
    13271256    gchar* proxy_info;
    1328 
    1329 #if MOZILLA_VERSION_COLLAPSED < 1090100
    1330         proxy = (char*) malloc(sizeof(char)*2048);
    1331 #endif
    13321257
    13331258    proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
     
    13451270    proxy_info = NULL;
    13461271
    1347 #if MOZILLA_VERSION_COLLAPSED < 1090100
    1348         g_free(proxy);
    1349         proxy = NULL;
    1350 #endif
     1272    g_free(proxy);
     1273    proxy = NULL;
    13511274
    13521275  } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
     
    13561279
    13571280    gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
    1358     gchar* cookie_string;
     1281    gchar* cookie_string = NULL;
    13591282    uint32_t len;
    13601283    if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
     
    13701293    g_free(cookie_info);
    13711294    cookie_info = NULL;
     1295    g_free(cookie_string);
     1296    cookie_string = NULL;
    13721297  } else if (g_str_has_prefix(parts[1], "PluginSetCookie"))
    13731298  {
     
    14981423          return NPERR_GENERIC_ERROR;
    14991424  }
    1500 #if MOZILLA_VERSION_COLLAPSED < 1090100
    1501   nsresult rv;
    1502 
    1503   // Initialize service variables
    1504   nsCOMPtr<nsIProtocolProxyService> proxy_svc = do_GetService("@mozilla.org/network/protocol-proxy-service;1", &rv);
    1505 
    1506   if (!proxy_svc) {
    1507       printf("Cannot initialize proxy service\n");
    1508       return NPERR_GENERIC_ERROR;
    1509   }
    1510 
    1511   nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
    1512 
    1513   if (NS_FAILED(rv) || !io_svc) {
    1514     printf("Cannot initialize io service\n");
    1515     return NPERR_GENERIC_ERROR;
    1516   }
    1517 
    1518   // uri which needs to be accessed
    1519   nsCOMPtr<nsIURI> uri;
    1520   io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
    1521 
    1522   // find the proxy address if any
    1523   nsCOMPtr<nsIProxyInfo> info;
    1524   proxy_svc->Resolve(uri, 0, getter_AddRefs(info));
    1525 
    1526   // if there is no proxy found, return immediately
    1527   if (!info) {
    1528      PLUGIN_DEBUG("%s does not need a proxy\n", siteAddr);
    1529      return NPERR_GENERIC_ERROR;
    1530   }
    1531 
    1532   // if proxy info is available, extract it
    1533   nsCString phost;
    1534   PRInt32 pport;
    1535   nsCString ptype;
    1536 
    1537   info->GetHost(phost);
    1538   info->GetPort(&pport);
    1539   info->GetType(ptype);
    1540 
    1541   // resolve the proxy address to an IP
    1542   nsCOMPtr<nsIDNSService> dns_svc = do_GetService("@mozilla.org/network/dns-service;1", &rv);
    1543 
    1544   if (!dns_svc) {
    1545       printf("Cannot initialize DNS service\n");
    1546       return NPERR_GENERIC_ERROR;
    1547   }
    1548 
    1549   nsCOMPtr<nsIDNSRecord> record;
    1550   dns_svc->Resolve(phost, 0U, getter_AddRefs(record));
    1551 
    1552   // TODO: Add support for multiple ips
    1553   nsDependentCString ipAddr;
    1554   record->GetNextAddrAsString(ipAddr);
    1555 
    1556   if (!strcmp(ptype.get(), "http"))
    1557   {
    1558       snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "PROXY", ipAddr.get(), pport);
    1559   } else
    1560   {
    1561       snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "SOCKS", ipAddr.get(), pport);
    1562   }
    1563 
    1564   *len = strlen(*proxy);
    1565 
    1566   PLUGIN_DEBUG("Proxy info for %s: %s\n", siteAddr, *proxy);
    1567 
    1568 #else
    1569 
    15701425  if (browser_functions.getvalueforurl)
    15711426  {
     
    15781433      return NPERR_GENERIC_ERROR;
    15791434  }
    1580 #endif
    15811435
    15821436  return NPERR_NO_ERROR;
     
    16781532plugin_test_appletviewer ()
    16791533{
    1680   PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", appletviewer_executable);
     1534
     1535  PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", get_plugin_executable().c_str());
    16811536  NPError error = NPERR_NO_ERROR;
    16821537
     
    16841539  gchar** environment;
    16851540
    1686   command_line[0] = g_strdup (appletviewer_executable);
     1541  command_line[0] = g_strdup (get_plugin_executable().c_str());
    16871542  command_line[1] = g_strdup("-version");
    16881543  command_line[2] = NULL;
     
    16961551      if (channel_error)
    16971552        {
    1698           PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
     1553          PLUGIN_ERROR ("Failed to spawn applet viewer %s\n",
    16991554                            channel_error->message);
    17001555          g_error_free (channel_error);
     
    17021557        }
    17031558      else
    1704         PLUGIN_ERROR ("Failed to spawn applet viewer");
     1559        PLUGIN_ERROR ("Failed to spawn applet viewer\n");
    17051560      error = NPERR_GENERIC_ERROR;
    17061561    }
     
    17191574}
    17201575
    1721 static NPError
     1576NPError
    17221577plugin_start_appletviewer (ITNPPluginData* data)
    17231578{
     
    17251580  NPError error = NPERR_NO_ERROR;
    17261581
    1727   gchar** command_line;
    1728   gchar** environment;
    1729 
    1730   int cmd_num = 0;
     1582  std::vector<std::string> command_line;
     1583  gchar** environment = NULL;
     1584  std::vector<std::string*>* jvm_args = get_jvm_args();
     1585
     1586  // Construct command line parameters
     1587
     1588  command_line.push_back(get_plugin_executable());
     1589
     1590  //Add JVM args to command_line
     1591  for (int i = 0; i < jvm_args->size(); i++)
     1592  {
     1593    command_line.push_back(*jvm_args->at(i));
     1594  }
     1595
     1596  command_line.push_back(PLUGIN_BOOTCLASSPATH);
     1597  // set the classpath to avoid using the default (cwd).
     1598  command_line.push_back("-classpath");
     1599  command_line.push_back(get_plugin_rt_jar());
     1600
     1601  // Enable coverage agent if we are running instrumented plugin
     1602#ifdef COVERAGE_AGENT
     1603  command_line.push_back(COVERAGE_AGENT);
     1604#endif
     1605
    17311606  if (plugin_debug)
    17321607  {
    1733       command_line = (gchar**) malloc(sizeof(gchar*)*11);
    1734       command_line[cmd_num++] = g_strdup(appletviewer_executable);
    1735       command_line[cmd_num++] = g_strdup_printf(PLUGIN_BOOTCLASSPATH);
    1736       // set the classpath to avoid using the default (cwd).
    1737       command_line[cmd_num++] = g_strdup("-classpath");
    1738       command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
    1739       command_line[cmd_num++] = g_strdup("-Xdebug");
    1740       command_line[cmd_num++] = g_strdup("-Xnoagent");
    1741       if (plugin_debug_suspend)
    1742       {
    1743           command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,suspend=y");
    1744       } else
    1745       {
    1746           command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,suspend=n");
    1747       }
    1748       command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
    1749 #ifdef __OS2__
    1750       command_line[cmd_num++] = g_strdup_printf("%d", out_pipe [1]);
    1751       command_line[cmd_num++] = g_strdup_printf("%d", in_pipe [1]);
     1608    command_line.push_back("-Xdebug");
     1609    command_line.push_back("-Xnoagent");
     1610
     1611    //Debug flags
     1612    std::string debug_flags = "-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,";
     1613    debug_flags += plugin_debug_suspend ? "suspend=y" : "suspend=n";
     1614    command_line.push_back(debug_flags);
     1615  }
     1616
     1617  command_line.push_back("sun.applet.PluginMain");
     1618#ifdef __OS2__
     1619  command_line.push_back((std::ostrstream() << out_pipe[1]).str());
     1620  command_line.push_back((std::ostrstream() << in_pipe[1]).str());
    17521621#else
    1753       command_line[cmd_num++] = g_strdup(out_pipe_name);
    1754       command_line[cmd_num++] = g_strdup(in_pipe_name);
    1755 #endif
    1756       command_line[cmd_num] = NULL;
    1757   } else
    1758   {
    1759       command_line = (gchar**) malloc(sizeof(gchar*)*8);
    1760       command_line[cmd_num++] = g_strdup(appletviewer_executable);
    1761       command_line[cmd_num++] = g_strdup_printf(PLUGIN_BOOTCLASSPATH);
    1762       command_line[cmd_num++] = g_strdup("-classpath");
    1763       command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
    1764       command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
    1765 #ifdef __OS2__
    1766       command_line[cmd_num++] = g_strdup_printf("%d", out_pipe [1]);
    1767       command_line[cmd_num++] = g_strdup_printf("%d", in_pipe [1]);
     1622  command_line.push_back(out_pipe_name);
     1623  command_line.push_back(in_pipe_name);
     1624#endif
     1625  if (plugin_debug_to_console){
     1626      command_line.push_back(debug_pipe_name);
     1627  }
     1628
     1629  // Finished command line parameters
     1630
     1631  environment = plugin_filter_environment();
     1632  std::vector<gchar*> vector_gchar = IcedTeaPluginUtilities::vectorStringToVectorGchar(&command_line);
     1633  gchar **command_line_args = &vector_gchar[0];
     1634
     1635  if (!g_spawn_async (NULL, command_line_args, environment,
     1636#ifdef __OS2__
     1637                      (GSpawnFlags) (G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD),
    17681638#else
    1769       command_line[cmd_num++] = g_strdup(out_pipe_name);
    1770       command_line[cmd_num++] = g_strdup(in_pipe_name);
    1771 #endif
    1772       command_line[cmd_num] = NULL;
    1773   }
    1774 
    1775   environment = plugin_filter_environment();
    1776 
    1777 #ifdef __OS2__
    1778   int flags = G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD;
    1779 #else
    1780   int flags = G_SPAWN_DO_NOT_REAP_CHILD;
    1781 #endif
    1782 
    1783   if (!g_spawn_async (NULL, command_line, environment,
    1784                       (GSpawnFlags) flags,
     1639                      (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
     1640#endif
    17851641                      NULL, NULL, &appletviewer_pid, &channel_error))
    17861642    {
    17871643      if (channel_error)
    17881644        {
    1789           PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
     1645          PLUGIN_ERROR ("Failed to spawn applet viewer %s\n",
    17901646                            channel_error->message);
    17911647          g_error_free (channel_error);
     
    17931649        }
    17941650      else
    1795         PLUGIN_ERROR ("Failed to spawn applet viewer");
     1651        PLUGIN_ERROR ("Failed to spawn applet viewer\n");
    17961652      error = NPERR_GENERIC_ERROR;
    17971653    }
     
    18021658  signal (SIGPIPE, SIG_IGN);
    18031659
    1804   g_strfreev (environment);
    1805 
    1806   for (int i = 0; i < cmd_num; i++) {
    1807     g_free (command_line[i]);
    1808     command_line[i] = NULL;
    1809   }
    1810 
    1811   g_free(command_line);
    1812   command_line = NULL;
     1660  //Free memory
     1661  g_strfreev(environment);
     1662  IcedTeaPluginUtilities::freeStringPtrVector(jvm_args);
     1663  jvm_args = NULL;
     1664  command_line_args = NULL;
    18131665
    18141666  if (appletviewer_pid)
     
    18241676
    18251677/*
    1826  * Replaces certain characters (\r, \n, etc) with HTML escape equivalents.
    1827  *
    1828  * Return string is allocated on the heap. Caller assumes responsibility
    1829  * for freeing the memory via free()
     1678 * Returns JVM options set in itw-settings
    18301679 */
    1831 static char*
    1832 encode_string(char* to_encode)
    1833 {
    1834 
    1835   // Do nothing for an empty string
    1836   if (to_encode == '\0')
    1837       return to_encode;
    1838 
    1839   // worst case scenario -> all characters are newlines or
    1840   // returns, each of which translates to 5 substitutions
    1841   char* encoded = (char*) calloc(((strlen(to_encode)*5)+1), sizeof(char));
    1842 
    1843   strcpy(encoded, "");
    1844 
    1845   for (int i=0; i < strlen(to_encode); i++)
    1846   {
    1847       if (to_encode[i] == '\r')
    1848           encoded = strcat(encoded, "&#13;");
    1849       else if (to_encode[i] == '\n')
    1850           encoded = strcat(encoded, "&#10;");
    1851       else if (to_encode[i] == '>')
    1852           encoded = strcat(encoded, "&gt;");
    1853       else if (to_encode[i] == '<')
    1854           encoded = strcat(encoded, "&lt;");
    1855       else if (to_encode[i] == '&')
    1856           encoded = strcat(encoded, "&amp;");
    1857       else if (to_encode[i] == '"')
    1858           encoded = strcat(encoded, "&quot;");
     1680std::vector<std::string*>*
     1681get_jvm_args()
     1682{
     1683  std::string output;
     1684  std::vector<std::string*>* tokenOutput = NULL;
     1685  bool args_defined = read_deploy_property_value("deployment.plugin.jvm.arguments", output);
     1686  if (!args_defined){
     1687    return new std::vector<std::string*>();
     1688  }
     1689  tokenOutput = IcedTeaPluginUtilities::strSplit(output.c_str(), " \n");
     1690  return tokenOutput;
     1691}
     1692
     1693
     1694/*
     1695 * Escape characters for passing to Java.
     1696 * "\n" for new line, "\\" for "\", "\:" for ";"
     1697 */
     1698std::string
     1699escape_parameter_string(const char* to_encode) {
     1700  std::string encoded;
     1701
     1702  if (to_encode == NULL)
     1703  {
     1704      return encoded;
     1705  }
     1706
     1707  size_t length = strlen(to_encode);
     1708  for (int i = 0; i < length; i++)
     1709  {
     1710      if (to_encode[i] == '\n')
     1711          encoded += "\\n";
     1712      else if (to_encode[i] == '\\')
     1713          encoded += "\\\\";
     1714      else if (to_encode[i] == ';')
     1715          encoded += "\\:";
    18591716      else
    1860       {
    1861            char* orig_char = (char*) calloc(2, sizeof(char));
    1862            orig_char[0] = to_encode[i];
    1863            orig_char[1] = '\0';
    1864 
    1865            strcat(encoded, orig_char);
    1866 
    1867            free(orig_char);
    1868            orig_char = NULL;
    1869       }
     1717          encoded += to_encode[i];
    18701718  }
    18711719
     
    18731721}
    18741722
    1875 // Build up the applet tag string that we'll send to the applet
    1876 // viewer.
    1877 static gchar*
    1878 plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[])
    1879 {
    1880   PLUGIN_DEBUG ("plugin_create_applet_tag\n");
    1881 
    1882   gchar* applet_tag = g_strdup ("<EMBED ");
    1883   gchar* parameters = g_strdup ("");
    1884 
    1885   for (int16_t i = 0; i < argc; i++)
    1886     {
    1887       gchar* argn_escaped = encode_string(argn[i]);
    1888       gchar* argv_escaped = encode_string(argv[i]);
    1889 
    1890       if (!g_ascii_strcasecmp (argn_escaped, "code"))
    1891         {
    1892           gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv_escaped);
    1893           applet_tag = g_strconcat (applet_tag, code, NULL);
    1894           g_free (code);
    1895           code = NULL;
    1896     }
    1897       else if (!g_ascii_strcasecmp (argn_escaped, "java_code"))
    1898     {
    1899           gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv_escaped);
    1900           applet_tag = g_strconcat (applet_tag, java_code, NULL);
    1901           g_free (java_code);
    1902           java_code = NULL;
    1903     }
    1904       else if (!g_ascii_strcasecmp (argn_escaped, "codebase"))
    1905     {
    1906           gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv_escaped);
    1907           applet_tag = g_strconcat (applet_tag, codebase, NULL);
    1908           g_free (codebase);
    1909           codebase = NULL;
    1910     }
    1911       else if (!g_ascii_strcasecmp (argn_escaped, "java_codebase"))
    1912     {
    1913           gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv_escaped);
    1914           applet_tag = g_strconcat (applet_tag, java_codebase, NULL);
    1915           g_free (java_codebase);
    1916           java_codebase = NULL;
    1917     }
    1918       else if (!g_ascii_strcasecmp (argn_escaped, "classid"))
    1919     {
    1920           gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv_escaped);
    1921           applet_tag = g_strconcat (applet_tag, classid, NULL);
    1922           g_free (classid);
    1923           classid = NULL;
    1924     }
    1925       else if (!g_ascii_strcasecmp (argn_escaped, "archive"))
    1926     {
    1927           gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv_escaped);
    1928           applet_tag = g_strconcat (applet_tag, archive, NULL);
    1929           g_free (archive);
    1930           archive = NULL;
    1931     }
    1932       else if (!g_ascii_strcasecmp (argn_escaped, "java_archive"))
    1933     {
    1934           gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv_escaped);
    1935           applet_tag = g_strconcat (applet_tag, java_archive, NULL);
    1936           g_free (java_archive);
    1937           java_archive = NULL;
    1938     }
    1939       else if (!g_ascii_strcasecmp (argn_escaped, "width"))
    1940     {
    1941           gchar* width = g_strdup_printf ("width=\"%s\" ", argv_escaped);
    1942           applet_tag = g_strconcat (applet_tag, width, NULL);
    1943           g_free (width);
    1944           width = NULL;
    1945     }
    1946       else if (!g_ascii_strcasecmp (argn_escaped, "height"))
    1947     {
    1948           gchar* height = g_strdup_printf ("height=\"%s\" ", argv_escaped);
    1949           applet_tag = g_strconcat (applet_tag, height, NULL);
    1950           g_free (height);
    1951           height = NULL;
    1952     }
    1953       else
    1954         {
    1955 
    1956           if (argv_escaped != '\0')
    1957             {
    1958               parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn_escaped,
    1959                                         "\" VALUE=\"", argv_escaped, "\">", NULL);
    1960             }
    1961         }
    1962 
    1963       free(argn_escaped);
    1964       free(argv_escaped);
    1965 
    1966       argn_escaped = NULL;
    1967       argv_escaped = NULL;
    1968     }
    1969 
    1970   applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL);
    1971 
    1972   g_free (parameters);
    1973   parameters = NULL;
    1974 
    1975   PLUGIN_DEBUG ("plugin_create_applet_tag return\n");
    1976 
    1977   return applet_tag;
     1723/*
     1724 * Build a string containing an encoded list of parameters to send to the applet viewer.
     1725 * The parameters are separated as 'key1;value1;key2;value2;'. As well, they are
     1726 * separated and escaped as:
     1727 * "\n" for new line, "\\" for "\", "\:" for ";"
     1728 */
     1729std::string
     1730plugin_parameters_string (int argc, char* argn[], char* argv[])
     1731{
     1732  PLUGIN_DEBUG ("plugin_parameters_string\n");
     1733
     1734  std::string parameters;
     1735
     1736  for (int i = 0; i < argc; i++)
     1737  {
     1738    if (argv[i] != NULL)
     1739    {
     1740        std::string name_escaped = escape_parameter_string(argn[i]);
     1741        std::string value_escaped = escape_parameter_string(argv[i]);
     1742
     1743        //Encode parameters and send as 'key1;value1;key2;value2;' etc
     1744        parameters += name_escaped;
     1745        parameters += ';';
     1746        parameters += value_escaped;
     1747        parameters += ';';
     1748    }
     1749  }
     1750
     1751  PLUGIN_DEBUG ("plugin_parameters_string return\n");
     1752
     1753  return parameters;
    19781754}
    19791755
     
    20031779          if (channel_error)
    20041780            {
    2005               PLUGIN_ERROR_TWO ("Failed to write bytes to output channel",
     1781              PLUGIN_ERROR ("Failed to write bytes to output channel '%s' \n",
    20061782                                channel_error->message);
    20071783              g_error_free (channel_error);
     
    20091785            }
    20101786          else
    2011             PLUGIN_ERROR ("Failed to write bytes to output channel");
     1787            PLUGIN_ERROR ("Failed to write bytes to output channel for %s", newline_message);
    20121788        }
    20131789
     
    20171793          if (channel_error)
    20181794            {
    2019               PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel",
     1795              PLUGIN_ERROR ("Failed to flush bytes to output channel '%s'\n",
    20201796                                channel_error->message);
    20211797              g_error_free (channel_error);
     
    20231799            }
    20241800          else
    2025             PLUGIN_ERROR ("Failed to flush bytes to output channel");
     1801            PLUGIN_ERROR ("Failed to flush bytes to output channel for %s", newline_message);
    20261802        }
    20271803      g_free (newline_message);
    20281804      newline_message = NULL;
    20291805
    2030       PLUGIN_DEBUG ("  PIPE: plugin wrote: %s\n", message);
     1806      PLUGIN_DEBUG ("  PIPE: plugin wrote(?): %s\n", message);
    20311807    }
    20321808
    20331809  PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
     1810}
     1811
     1812// unlike like  plugin_send_message_to_appletviewer
     1813// do not debug
     1814// do not error
     1815// do not have its own line end
     1816// is accesed by only one thread
     1817// have own pipe
     1818// jvm must be up
     1819void
     1820plugin_send_message_to_appletviewer_console (gchar const* newline_message)
     1821{
     1822  gsize bytes_written = 0;
     1823  if (g_io_channel_write_chars (debug_to_appletviewer,
     1824                                newline_message, -1, &bytes_written,
     1825                                &channel_error) != G_IO_STATUS_NORMAL)  {
     1826          if (channel_error) {
     1827              //error must be freed
     1828              g_error_free (channel_error);
     1829              channel_error = NULL;
     1830            }
     1831        }
     1832}
     1833//flush only when its full
     1834void flush_plugin_send_message_to_appletviewer_console (){
     1835  if (g_io_channel_flush (debug_to_appletviewer, &channel_error)
     1836                                                 != G_IO_STATUS_NORMAL) {
     1837          if (channel_error) {
     1838              g_error_free (channel_error);
     1839              channel_error = NULL;
     1840            }
     1841        }
    20341842}
    20351843
     
    20841892              if (channel_error)
    20851893                {
    2086                   PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
    2087                                     " appletviewer", channel_error->message);
     1894                  PLUGIN_ERROR ("Failed to write shutdown message to "
     1895                                    " appletviewer, %s \n", channel_error->message);
    20881896                  g_error_free (channel_error);
    20891897                  channel_error = NULL;
    20901898                }
    20911899              else
    2092                 PLUGIN_ERROR ("Failed to write shutdown message to");
     1900                PLUGIN_ERROR ("Failed to write shutdown message to\n");
    20931901            }
    20941902
     
    20981906              if (channel_error)
    20991907                {
    2100                   PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
    2101                                     " appletviewer", channel_error->message);
     1908                  PLUGIN_ERROR ("Failed to write shutdown message to"
     1909                                    " appletviewer %s \n", channel_error->message);
    21021910                  g_error_free (channel_error);
    21031911                  channel_error = NULL;
    21041912                }
    21051913              else
    2106                 PLUGIN_ERROR ("Failed to write shutdown message to");
     1914                PLUGIN_ERROR ("Failed to write shutdown message to\n");
    21071915            }
    21081916
     
    21131921              if (channel_error)
    21141922                {
    2115                   PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
    2116                                     " output channel", channel_error->message);
     1923                  PLUGIN_ERROR ("Failed to shut down appletviewer"
     1924                                    " output channel %s \n", channel_error->message);
    21171925                  g_error_free (channel_error);
    21181926                  channel_error = NULL;
    21191927                }
    21201928              else
    2121                 PLUGIN_ERROR ("Failed to shut down appletviewer");
     1929                PLUGIN_ERROR ("Failed to shut down appletviewer\n");
    21221930            }
    21231931        }
     
    21311939              if (channel_error)
    21321940                {
    2133                   PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
    2134                                     " input channel", channel_error->message);
     1941                  PLUGIN_ERROR ("Failed to shut down appletviewer"
     1942                                    " input channel %s \n", channel_error->message);
    21351943                  g_error_free (channel_error);
    21361944                  channel_error = NULL;
    21371945                }
    21381946              else
    2139                 PLUGIN_ERROR ("Failed to shut down appletviewer");
     1947                PLUGIN_ERROR ("Failed to shut down appletviewer\n");
    21401948            }
    21411949        }
     
    21561964}
    21571965
    2158 static void
     1966void
    21591967plugin_data_destroy (NPP instance)
    21601968{
     
    21731981    }
    21741982
    2175   tofree->window_handle = NULL;
    2176   tofree->window_height = 0;
    2177   tofree->window_width = 0;
    2178 
    2179   // cleanup_appletviewer_mutex:
    2180   g_mutex_free (tofree->appletviewer_mutex);
    2181   tofree->appletviewer_mutex = NULL;
    2182 
    2183   // cleanup_instance_string:
    2184   g_free (tofree->instance_id);
    2185   tofree->instance_id = NULL;
    2186 
    2187   // cleanup applet tag
    2188   g_free (tofree->applet_tag);
    2189   tofree->applet_tag = NULL;
    2190 
    2191   g_free(tofree->source);
    2192   tofree->source = NULL;
    2193 
    2194   // cleanup_data:
    2195   // Eliminate back-pointer to plugin instance.
    2196   tofree->owner = NULL;
     1983  /* Explicitly call destructor */
     1984  tofree->~ITNPPluginData();
     1985
    21971986  (*browser_functions.memfree) (tofree);
    2198   tofree = NULL;
    21991987
    22001988  PLUGIN_DEBUG ("plugin_data_destroy return\n");
     
    22041992initialize_browser_functions(const NPNetscapeFuncs* browserTable)
    22051993{
    2206 #if MOZILLA_VERSION_COLLAPSED < 1090100
    2207 #define NPNETSCAPEFUNCS_LAST_FIELD_USED (browserTable->pluginthreadasynccall)
    2208 #else
    22091994#define NPNETSCAPEFUNCS_LAST_FIELD_USED (browserTable->setvalueforurl)
    2210 #endif
    22111995
    22121996  //Determine the size in bytes, as a difference of the address past the last used field
     
    22502034  pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
    22512035  pluginTable->size = sizeof (NPPluginFuncs);
    2252 
    2253 #if MOZILLA_VERSION_COLLAPSED < 1090100
    2254   pluginTable->newp = NewNPP_NewProc (ITNP_New);
    2255   pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
    2256   pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
    2257   pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
    2258   pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
    2259   pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
    2260   pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
    2261   pluginTable->write = NewNPP_WriteProc (ITNP_Write);
    2262   pluginTable->print = NewNPP_PrintProc (ITNP_Print);
    2263   pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
    2264   pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
    2265 #else
    22662036  pluginTable->newp = NPP_NewProcPtr (ITNP_New);
    22672037  pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
     
    22752045  pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
    22762046  pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
    2277 #endif
    22782047
    22792048  return true;
     2049}
     2050
     2051// Make sure the plugin data directory exists, creating it if necessary.
     2052NPError
     2053initialize_data_directory()
     2054{
     2055
     2056  data_directory = IcedTeaPluginUtilities::getRuntimePath() + "/icedteaplugin-";
     2057  if (getenv("USER") != NULL) {
     2058    data_directory = data_directory + getenv("USER") + "-";
     2059  }
     2060  data_directory += "XXXXXX";
     2061  // Now create a icedteaplugin subdir
     2062  char fileNameX[data_directory.length()+1];
     2063  std::strcpy (fileNameX, data_directory.c_str());
     2064  char * fileName = mkdtemp(fileNameX);
     2065  if (fileName == NULL) {
     2066    PLUGIN_ERROR ("Failed to create data directory %s, %s\n",
     2067                        data_directory.c_str(),
     2068                        strerror (errno));
     2069    return NPERR_GENERIC_ERROR;
     2070  }
     2071  data_directory = std::string(fileName);
     2072
     2073  //open uniques icedteaplugin subdir for one single run 
     2074  data_directory_descriptor = opendir(data_directory.c_str());
     2075  if (data_directory_descriptor == NULL) {
     2076      PLUGIN_ERROR ("Failed to open data directory %s %s\n",
     2077                      data_directory.c_str(), strerror (errno));
     2078      return NPERR_GENERIC_ERROR;
     2079  }
     2080
     2081  return NPERR_NO_ERROR;
    22802082}
    22812083
     
    22912093// been called. There is no need to call this function more than once and
    22922094// this workaround avoids any duplicate calls.
     2095__attribute__ ((visibility ("default")))
    22932096NPError
    22942097#if defined(_WIN32) || defined (__OS2__)
     
    23102113  if ((browserTable == NULL) || (pluginTable == NULL))
    23112114  {
    2312     PLUGIN_ERROR ("Browser or plugin function table is NULL.");
     2115    PLUGIN_ERROR ("Browser or plugin function table is NULL.\n");
    23132116
    23142117    return NPERR_INVALID_FUNCTABLE_ERROR;
     
    23212124  if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
    23222125    {
    2323       PLUGIN_ERROR ("Incompatible version.");
     2126      PLUGIN_ERROR ("Incompatible version.\n");
    23242127
    23252128      return NPERR_INCOMPATIBLE_VERSION_ERROR;
     
    23342137  if ( !browser_functions_supported )
    23352138  {
    2336         PLUGIN_ERROR ("Invalid browser function table.");
     2139        PLUGIN_ERROR ("Invalid browser function table.\n");
    23372140
    23382141        return NPERR_INVALID_FUNCTABLE_ERROR;
     
    23482151  if ( !plugin_functions_supported )
    23492152  {
    2350     PLUGIN_ERROR ("Invalid plugin function table.");
     2153    PLUGIN_ERROR ("Invalid plugin function table.\n");
    23512154
    23522155    return NPERR_INVALID_FUNCTABLE_ERROR;
     
    23712174  NPError np_error = NPERR_NO_ERROR;
    23722175#ifndef __OS2__
    2373   // Make sure the plugin data directory exists, creating it if
    2374   // necessary.
    2375   data_directory = g_strconcat (P_tmpdir, NULL);
    2376   if (!data_directory)
    2377     {
    2378       PLUGIN_ERROR ("Failed to create data directory name.");
    2379       return NPERR_OUT_OF_MEMORY_ERROR;
    2380     }
    2381 
    2382   // If P_tmpdir does not exist, try /tmp directly
    2383 
    2384   if (!g_file_test (data_directory,
    2385                     (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
    2386     {
    2387       int file_error = 0;
    2388 
    2389       data_directory = g_strconcat ("/tmp", NULL);
    2390         if (!data_directory)
    2391           {
    2392             PLUGIN_ERROR ("Failed to create data directory name.");
    2393             return NPERR_OUT_OF_MEMORY_ERROR;
    2394           }
    2395 
    2396     }
    2397 
    2398   data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
    2399 
    2400   if (!data_directory)
    2401   {
    2402       PLUGIN_ERROR ("Failed to create data directory name.");
    2403       return NPERR_OUT_OF_MEMORY_ERROR;
    2404   }
    2405 
    2406   // Now create a icedteaplugin subdir
    2407   if (!g_file_test (data_directory,
    2408                     (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
    2409     {
    2410       int file_error = 0;
    2411 
    2412       file_error = g_mkdir (data_directory, 0700);
    2413       if (file_error != 0)
    2414         {
    2415           PLUGIN_ERROR_THREE ("Failed to create data directory",
    2416                           data_directory,
    2417                           strerror (errno));
    2418           np_error = NPERR_GENERIC_ERROR;
    2419           goto cleanup_data_directory;
    2420         }
    2421     }
    2422 
    2423 
    2424   // If data directory doesn't exit by this point, bail
    2425   if (!g_file_test (data_directory,
    2426                     (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
    2427     {
    2428       PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
    2429                           data_directory,
    2430                           strerror (errno));
    2431 
    2432       np_error = NPERR_GENERIC_ERROR;
    2433             goto cleanup_data_directory;
    2434 
     2176  // create directory for pipes
     2177  np_error =  initialize_data_directory();
     2178  if (np_error != NPERR_NO_ERROR)
     2179    {
     2180      PLUGIN_ERROR("Unable to create data directory %s\n", data_directory.c_str());
     2181      return np_error;
    24352182    }
    24362183#endif
    24372184
    24382185  // Set appletviewer_executable.
    2439   gchar* filename = g_strdup(ICEDTEA_WEB_JRE);
    2440   appletviewer_executable = g_strdup_printf ("%s/bin/java",
    2441                                              filename);
    2442   PLUGIN_DEBUG("Executing java at %s\n", appletviewer_executable);
    2443   if (!appletviewer_executable)
    2444     {
    2445       PLUGIN_ERROR ("Failed to create appletviewer executable name.");
    2446       np_error = NPERR_OUT_OF_MEMORY_ERROR;
    2447       goto cleanup_filename;
    2448     }
    2449 
     2186  PLUGIN_DEBUG("Executing java at %s\n", get_plugin_executable().c_str());
    24502187  np_error = plugin_test_appletviewer ();
    24512188  if (np_error != NPERR_NO_ERROR)
    24522189    {
    2453       plugin_display_failure_dialog ();
    2454       goto cleanup_appletviewer_executable;
    2455     }
    2456   g_free (filename);
     2190      PLUGIN_ERROR("Unable to find java executable %s\n", get_plugin_executable().c_str());
     2191      return np_error;
     2192    }
    24572193
    24582194  // Initialize threads (needed for mutexes).
     
    24642200  {
    24652201    PLUGIN_DEBUG ("Failed to integrate with PM");
    2466     np_error = NPERR_GENERIC_ERROR;
    2467     goto cleanup_appletviewer_executable;
     2202    return NPERR_GENERIC_ERROR;
    24682203  }
    24692204#endif
     
    24712206  plugin_instance_mutex = g_mutex_new ();
    24722207
    2473   PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
     2208  PLUGIN_DEBUG ("NP_Initialize: using %s\n", get_plugin_executable().c_str());
    24742209
    24752210  plugin_req_proc = new PluginRequestProcessor();
     
    25082243
    25092244  return NPERR_NO_ERROR;
    2510 
    2511  cleanup_appletviewer_executable:
    2512   if (appletviewer_executable)
    2513     {
    2514       g_free (appletviewer_executable);
    2515       appletviewer_executable = NULL;
    2516     }
    2517 
    2518  cleanup_filename:
    2519   if (filename)
    2520     {
    2521       g_free (filename);
    2522       filename = NULL;
    2523     }
    2524 
    2525  cleanup_data_directory:
    2526   if (data_directory)
    2527     {
    2528       g_free (data_directory);
    2529       data_directory = NULL;
    2530     }
    2531 
    2532 
    2533   return np_error;
    25342245}
    25352246
     
    25662277// Returns a string describing the MIME type that this plugin
    25672278// handles.
     2279__attribute__ ((visibility ("default")))
    25682280#ifdef LEGACY_XULRUNNERAPI
    25692281  char*
     
    25732285OSCALL NP_GetMIMEDescription ()
    25742286{
     2287  //this function is called severaltimes between lunches
    25752288  PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
    25762289
     
    25822295// Returns a value relevant to the plugin as a whole.  The browser
    25832296// calls this function to obtain information about the plugin.
     2297__attribute__ ((visibility ("default")))
    25842298NPError
    25852299OSCALL NP_GetValue (void* future, NPPVariable variable, void* value)
     
    26032317
    26042318    default:
    2605       PLUGIN_ERROR ("Unknown plugin value requested.");
     2319      PLUGIN_ERROR ("Unknown plugin value requested.\n");
    26062320      result = NPERR_GENERIC_ERROR;
    26072321      break;
     
    26152329// Shuts down the plugin.  Called after the last plugin instance is
    26162330// destroyed.
     2331__attribute__ ((visibility ("default")))
    26172332NPError
    26182333OSCALL NP_Shutdown (void)
     
    26292344      g_mutex_free (plugin_instance_mutex);
    26302345      plugin_instance_mutex = NULL;
    2631     }
    2632 
    2633   if (data_directory)
    2634     {
    2635       g_free (data_directory);
    2636       data_directory = NULL;
    2637     }
    2638 
    2639   if (appletviewer_executable)
    2640     {
    2641       g_free (appletviewer_executable);
    2642       appletviewer_executable = NULL;
    26432346    }
    26442347
     
    26992402#endif
    27002403
     2404  if (plugin_debug_to_console){
     2405    //jvm_up is now false
     2406    if (g_io_channel_shutdown (debug_to_appletviewer,
     2407                                     TRUE, &channel_error)
     2408              != G_IO_STATUS_NORMAL)
     2409            {
     2410              if (channel_error)
     2411                {
     2412                  PLUGIN_ERROR ("Failed to shut down appletviewer"
     2413                                    " debug channel\n", channel_error->message);
     2414                  g_error_free (channel_error);
     2415                  channel_error = NULL;
     2416                }
     2417              else
     2418                PLUGIN_ERROR ("Failed to shut down debug to appletviewer\n");
     2419            }
     2420    // cleanup_out_to_appletviewer:
     2421    if (debug_to_appletviewer)
     2422     g_io_channel_unref (debug_to_appletviewer);
     2423    out_to_appletviewer = NULL;
     2424    // cleanup_debug_pipe:
     2425    // Delete debug pipe.
     2426    PLUGIN_DEBUG ("NP_Shutdown: deleting debug fifo: %s\n", debug_pipe_name);
     2427    unlink (debug_pipe_name);
     2428    PLUGIN_DEBUG ("NP_Shutdown: deleted debug fifo: %s\n", debug_pipe_name);
     2429    // cleanup_out_pipe_name:
     2430    g_free (debug_pipe_name);
     2431    debug_pipe_name = NULL;
     2432  }
     2433 
    27012434  // Destroy the call queue mutex
    27022435  pthread_mutex_destroy(&pluginAsyncCallMutex);
     
    27362469  //delete internal_bus;
    27372470
     2471  cleanUpDir();
     2472 
    27382473  PLUGIN_DEBUG ("NP_Shutdown return\n");
     2474 
     2475  if (plugin_debug_to_file){
     2476    fflush (plugin_file_log);
     2477    //fclose (plugin_file_log);
     2478    //keep writing untill possible!
     2479  } 
    27392480
    27402481  return NPERR_NO_ERROR;
     
    27622503        if (!data->window_handle)
    27632504        {
    2764             plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag);
     2505            plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->parameters_string);
    27652506        }
    27662507
     
    27712512        if (java_result->error_occurred)
    27722513        {
    2773             printf("Error: Unable to fetch applet instance id from Java side.\n");
     2514            PLUGIN_ERROR("Error: Unable to fetch applet instance id from Java side.\n");
    27742515            return NULL;
    27752516        }
     
    27812522        if (java_result->error_occurred)
    27822523        {
    2783             printf("Error: Unable to fetch applet instance id from Java side.\n");
     2524            PLUGIN_ERROR("Error: Unable to fetch applet instance id from Java side.\n");
    27842525            return NULL;
    27852526        }
     
    27872528        applet_class_id.append(*(java_result->return_string));
    27882529
    2789         obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
     2530        obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
    27902531
    27912532    } else
    27922533    {
    2793         obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
     2534        obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(instance, "");
    27942535    }
    27952536
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaNPPlugin.h

    r369 r429  
    4040#define __ICEDTEANPPLUGIN_H__
    4141
    42 #if MOZILLA_VERSION_COLLAPSED < 1090100
    43 #include <nsThreadUtils.h>
    44 #else
    4542#include <npapi.h>
    4643#include <npruntime.h>
    4744#include <npfunctions.h>
    48 #endif
    4945
    5046// GLib includes.
    5147#include <glib.h>
    5248#include <glib/gstdio.h>
    53 
    54 #ifndef __OS2__
    55 // GTK includes.
    56 #include <gtk/gtk.h>
    57 #endif
    5849
    5950#include "IcedTeaPluginUtils.h"
     
    6960  // A unique identifier for this plugin window.
    7061  gchar* instance_id;
    71   // The applet tag sent to Java side
    72   gchar* applet_tag;
     62  // The parameter list string sent to Java side
     63  gchar* parameters_string;
    7364  // Mutex to protect appletviewer_alive.
    7465  GMutex* appletviewer_mutex;
     
    8475  guint32 window_height;
    8576  // The source location for this instance
    86   gchar* source;
     77  std::string source;
    8778  // If this is an actual applet instance, or a dummy instance for static calls
    8879  bool is_applet_instance;
     80
     81  ITNPPluginData() {
     82      instance_id = NULL;
     83      parameters_string = NULL;
     84      appletviewer_mutex = NULL;
     85      owner = (NPP)NULL;
     86      window_handle = NULL;
     87      window_width = 0;
     88      window_height = 0;
     89      is_applet_instance = false;
     90  }
     91  ~ITNPPluginData() {
     92      if (appletviewer_mutex) {
     93        g_mutex_free (appletviewer_mutex);
     94      }
     95      // cleanup_instance_string:
     96      g_free (instance_id);
     97      // cleanup applet tag
     98      g_free (parameters_string);
     99  }
    89100};
    90101
    91 // Queue processing threads
    92 static pthread_t plugin_request_processor_thread1;
    93 static pthread_t plugin_request_processor_thread2;
    94 static pthread_t plugin_request_processor_thread3;
     102// Have the browser allocate a new ITNPPluginData structure.
     103ITNPPluginData* plugin_data_new ();
     104void plugin_data_destroy (NPP instance);
    95105
    96 #ifdef __OS2__
    97 struct QueueProcessorData
    98 {
    99     PluginRequestProcessor *processor;
    100     bool stopRequested;
    101 };
    102 
    103 static QueueProcessorData queue_processor_data1 = { NULL, false };
    104 static QueueProcessorData queue_processor_data2 = { NULL, false };
    105 static QueueProcessorData queue_processor_data3 = { NULL, false };
    106 #endif
    107 
    108 // Condition on which the queue processor waits
    109 extern pthread_cond_t cond_message_available;
     106NPError initialize_data_directory();
     107NPError start_jvm_if_needed();
    110108
    111109// ID of plug-in thread
     
    115113extern pthread_mutex_t pluginAsyncCallMutex;
    116114
    117 // debug switch
     115/*to sync pipe to apletviewer console*/
     116extern pthread_mutex_t debug_pipe_lock;
     117
     118// debug switches
     119extern bool debug_initiated;
    118120extern int plugin_debug;
     121extern bool plugin_debug_headers;
     122extern bool plugin_debug_to_file;
     123extern bool plugin_debug_to_streams;
     124extern bool plugin_debug_to_system;
     125extern bool plugin_debug_to_console;
     126extern FILE * plugin_file_log;
     127extern std::string plugin_file_log_name;
     128extern gchar* debug_pipe_name;
     129
     130extern gboolean jvm_up;
    119131
    120132// Browser function table.
     
    144156/* Sends a message to the appletviewer */
    145157void plugin_send_message_to_appletviewer(gchar const* message);
     158/*this method is not logging, do not add \n and is using different pipe*/
     159void plugin_send_message_to_appletviewer_console(gchar const* message);
     160void flush_plugin_send_message_to_appletviewer_console();
    146161
    147162/* Returns an appropriate (package/object) scriptable npobject */
     
    151166NPObject* allocate_scriptable_object(NPP npp, NPClass *aClass);
    152167
     168NPError plugin_start_appletviewer (ITNPPluginData* data);
     169
    153170#endif  /* __ICEDTEANPPLUGIN_H__ */
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc

    r418 r429  
    4848 */
    4949
    50 // Initialize static members used by the queue processing framework
    51 pthread_mutex_t message_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
    52 pthread_mutex_t syn_write_mutex = PTHREAD_MUTEX_INITIALIZER;
    53 std::vector< std::vector<std::string*>* >* message_queue = new std::vector< std::vector<std::string*>* >();
    54 
    5550/**
    5651 * PluginRequestProcessor constructor.
     
    6156PluginRequestProcessor::PluginRequestProcessor()
    6257{
    63     this->pendingRequests = new std::map<pthread_t, uintmax_t>();
     58    this->message_queue = new std::vector< std::vector<std::string*>* >();
    6459
    6560    internal_req_ref_counter = 0;
    6661
    67     pthread_mutex_init(&message_queue_mutex, NULL);
    68     pthread_mutex_init(&syn_write_mutex, NULL);
    69 
    70     pthread_cond_init(&cond_message_available, NULL);
     62    pthread_mutex_init(&this->message_queue_mutex, NULL);
     63    pthread_mutex_init(&this->syn_write_mutex, NULL);
     64    pthread_cond_init(&this->cond_message_available, NULL);
    7165}
    7266
     
    8175    PLUGIN_DEBUG("PluginRequestProcessor::~PluginRequestProcessor\n");
    8276
    83     if (pendingRequests)
    84         delete pendingRequests;
     77    if (message_queue)
     78        delete message_queue;
    8579
    8680    pthread_mutex_destroy(&message_queue_mutex);
    8781    pthread_mutex_destroy(&syn_write_mutex);
    88 
    8982    pthread_cond_destroy(&cond_message_available);
    9083}
     
    143136            pthread_mutex_lock(&message_queue_mutex);
    144137            message_queue->push_back(message_parts);
     138            pthread_cond_signal(&cond_message_available);
    145139            pthread_mutex_unlock(&message_queue_mutex);
    146140
    147             // Broadcast that a message is now available
    148             pthread_cond_broadcast(&cond_message_available);
    149141
    150142            return true;
     
    414406    propertyNameID = *(message_parts->at(6));
    415407
    416     if (*(message_parts->at(7)) == "literalreturn")
     408    if (*(message_parts->at(7)) == "literalreturn" || *(message_parts->at(7)) == "jsobject" )
    417409    {
    418410        value.append(*(message_parts->at(7)));
     
    441433        if (java_result->error_occurred)
    442434        {
    443             printf("Unable to get member name for setMember. Error occurred: %s\n", java_result->error_msg->c_str());
     435            PLUGIN_ERROR("Unable to get member name for setMember. Error occurred: %s\n", java_result->error_msg->c_str());
    444436            //goto cleanup;
    445437        }
     
    472464 * This is a static function, called in another thread. Since certain data
    473465 * can only be requested from the main thread in Mozilla, this function
    474  * does whatever it can seperately, and then makes an internal request that
     466 * does whatever it can separately, and then makes an internal request that
    475467 * causes _getMember to do the rest of the work.
    476468 *
     
    522514        if (java_result->error_occurred)
    523515        {
    524             printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg->c_str());
     516            PLUGIN_ERROR("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg->c_str());
    525517            //goto cleanup;
    526518        }
     
    636628queue_cleanup(void* data)
    637629{
    638 
    639     pthread_mutex_destroy((pthread_mutex_t*) data);
    640 
    641630    PLUGIN_DEBUG("Queue processing stopped.\n");
     631}
     632
     633static void
     634queue_wait_cleanup(void* data)
     635{
     636    pthread_mutex_unlock((pthread_mutex_t*) data);
    642637}
    643638
     
    651646    PluginRequestProcessor* processor = (PluginRequestProcessor*) data;
    652647#endif
     648    processor->queueProcessorThread();
     649    return NULL;
     650}
     651
     652void
     653PluginRequestProcessor::queueProcessorThread()
     654{
    653655    std::vector<std::string*>* message_parts = NULL;
    654656    std::string command;
    655     pthread_mutex_t wait_mutex = PTHREAD_MUTEX_INITIALIZER;
    656657
    657658    PLUGIN_DEBUG("Queue processor initialized. Queue = %p\n", message_queue);
    658 
    659     pthread_mutex_init(&wait_mutex, NULL);
    660659
    661660#ifdef __OS2__
    662661    queue_processor_data->stopRequested = false;
    663662#else
    664     pthread_cleanup_push(queue_cleanup, (void*) &wait_mutex);
     663    pthread_cleanup_push(queue_cleanup, NULL);
    665664#endif
    666665
     
    681680            if (command == "GetMember")
    682681            {
    683                 processor->sendMember(message_parts);
     682                sendMember(message_parts);
    684683            } else if (command == "ToString")
    685684            {
    686                 processor->sendString(message_parts);
     685                sendString(message_parts);
    687686            } else if (command == "SetMember")
    688687            {
    689688                // write methods are synchronized
    690689                pthread_mutex_lock(&syn_write_mutex);
    691                 processor->setMember(message_parts);
     690                setMember(message_parts);
    692691                pthread_mutex_unlock(&syn_write_mutex);
    693692            } else if (command == "Call")
     
    695694                // write methods are synchronized
    696695                pthread_mutex_lock(&syn_write_mutex);
    697                 processor->call(message_parts);
     696                call(message_parts);
    698697                pthread_mutex_unlock(&syn_write_mutex);
    699698            } else if (command == "Eval")
     
    701700                // write methods are synchronized
    702701                pthread_mutex_lock(&syn_write_mutex);
    703                 processor->eval(message_parts);
     702                eval(message_parts);
    704703                pthread_mutex_unlock(&syn_write_mutex);
    705704            } else if (command == "GetSlot")
     
    707706                // write methods are synchronized
    708707                pthread_mutex_lock(&syn_write_mutex);
    709                 processor->sendMember(message_parts);
     708                sendMember(message_parts);
    710709                pthread_mutex_unlock(&syn_write_mutex);
    711710            } else if (command == "SetSlot")
     
    713712                // write methods are synchronized
    714713                pthread_mutex_lock(&syn_write_mutex);
    715                 processor->setMember(message_parts);
     714                setMember(message_parts);
    716715                pthread_mutex_unlock(&syn_write_mutex);
    717716            } else if (command == "LoadURL") // For instance X url <url> <target>
     
    719718                // write methods are synchronized
    720719                pthread_mutex_lock(&syn_write_mutex);
    721                 processor->loadURL(message_parts);
     720                loadURL(message_parts);
    722721                pthread_mutex_unlock(&syn_write_mutex);
    723722            } else
     
    732731        } else
    733732        {
    734             pthread_mutex_lock(&wait_mutex);
    735             pthread_cond_wait(&cond_message_available, &wait_mutex);
    736             pthread_mutex_unlock(&wait_mutex);
     733            pthread_mutex_lock(&message_queue_mutex);
     734            if (message_queue->size() == 0)
     735            {
     736#ifndef __OS2__           
     737                pthread_cleanup_push(queue_wait_cleanup, &message_queue_mutex);
     738#endif
     739                pthread_cond_wait(&cond_message_available, &message_queue_mutex);
     740#ifndef __OS2__
     741                pthread_cleanup_pop(0);
     742#endif
     743            }
     744            pthread_mutex_unlock(&message_queue_mutex);
    737745        }
    738746
     
    748756
    749757#ifdef __OS2__
    750     queue_cleanup((void*) &wait_mutex);
     758    queue_cleanup(NULL);
     759    queue_wait_cleanup(&message_queue_mutex);
    751760#else
    752761    pthread_cleanup_pop(1);
     
    781790        property_identifier = browser_functions.getstringidentifier(property_id->c_str());
    782791
    783     PLUGIN_DEBUG("Setting %s on instance %p, object %p to value %s\n", browser_functions.utf8fromidentifier(property_identifier), instance, member, value->c_str());
     792    PLUGIN_DEBUG("Setting %s on instance %p, object %p to value %s\n", IcedTeaPluginUtilities::NPIdentifierAsString(property_identifier).c_str(), instance, member, value->c_str());
    784793
    785794    IcedTeaPluginUtilities::javaResultToNPVariant(instance, value, &value_variant);
     
    801810
    802811    instance = (NPP) parameters.at(0);
     812
    803813    parent_ptr = (NPObject*) parameters.at(1);
    804814    std::string*  member_id = (std::string*) parameters.at(2);
     
    813823
    814824    // Get the NPVariant corresponding to this member
    815     PLUGIN_DEBUG("Looking for %p %p %p (%s)\n", instance, parent_ptr, member_identifier, browser_functions.utf8fromidentifier(member_identifier));
     825    PLUGIN_DEBUG("Looking for %p %p %p (%s)\n", instance, parent_ptr, member_identifier, IcedTeaPluginUtilities::NPIdentifierAsString(member_identifier).c_str());
    816826
    817827    if (!browser_functions.hasproperty(instance, parent_ptr, member_identifier))
    818828    {
    819         printf("%s not found!\n", browser_functions.utf8fromidentifier(member_identifier));
     829        PLUGIN_ERROR("%s not found!\n", IcedTeaPluginUtilities::NPIdentifierAsString(member_identifier).c_str());
    820830    }
    821831    ((AsyncCallThreadData*) data)->call_successful = browser_functions.getproperty(instance, parent_ptr, member_identifier, member_ptr);
     
    827837        createJavaObjectFromVariant(instance, *member_ptr, &member_ptr_str);
    828838        ((AsyncCallThreadData*) data)->result.append(member_ptr_str);
    829 
     839    } else
     840    {
     841        ((AsyncCallThreadData*) data)->result.append("null");
    830842    }
    831843    ((AsyncCallThreadData*) data)->result_ready = true;
     
    856868    script_str = (std::string*) call_data->at(2);
    857869
    858 #if MOZILLA_VERSION_COLLAPSED < 1090200
    859     script.utf8characters = script_str->c_str();
    860     script.utf8length = script_str->size();
    861 
    862     PLUGIN_DEBUG("Evaluating: %s\n", script_str->c_str());
    863 #else
    864870    script.UTF8Characters = script_str->c_str();
    865871    script.UTF8Length = script_str->size();
    866872
    867873    PLUGIN_DEBUG("Evaluating: %s\n", script_str->c_str());
    868 #endif
    869874
    870875    ((AsyncCallThreadData*) data)->call_successful = browser_functions.evaluate(instance, window_ptr, &script, eval_variant);
     
    980985    {
    981986        createJavaObjectFromVariant(instance, tostring_result, &(((AsyncCallThreadData*) data)->result));
     987    } else
     988    {
     989        ((AsyncCallThreadData*) data)->result.append("null");
    982990    }
    983991    ((AsyncCallThreadData*) data)->result_ready = true;
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginRequestProcessor.h

    r348 r429  
    4747
    4848#include <npapi.h>
    49 
    50 #if MOZILLA_VERSION_COLLAPSED < 1090100
    51 #include <npupp.h>
    52 #else
    53 #include <npapi.h>
    5449#include <npruntime.h>
    55 #endif
    5650
    5751#include "IcedTeaPluginUtils.h"
     
    7670void* queue_processor(void* data);
    7771
    78 /* Mutex to ensure that the request queue is accessed synchronously */
    79 extern pthread_mutex_t message_queue_mutex;
    80 
    81 /* Mutex to ensure synchronized writes */
    82 extern pthread_mutex_t syn_write_mutex;
    83 
    84 /* Queue for holding messages that get processed in a separate thread */
    85 extern std::vector< std::vector<std::string*>* >* message_queue;
    86 
    8772/**
    8873 * Processes requests made TO the plugin (by java or anyone else)
     
    9277    private:
    9378
    94         /* Requests that are still pending */
    95         std::map<pthread_t, uintmax_t>* pendingRequests;
     79        /* Mutex to ensure that the request queue is accessed synchronously */
     80        pthread_mutex_t message_queue_mutex;
     81
     82        /* Condition on which the queue processor waits */
     83        pthread_cond_t cond_message_available;
     84
     85        /* Queue for holding messages that get processed in a separate thread */
     86        std::vector< std::vector<std::string*>* >* message_queue;
     87
     88        /* Mutex to ensure synchronized writes */
     89        pthread_mutex_t syn_write_mutex;
    9690
    9791        /* Dispatch request processing to a new thread for asynch. processing */
     
    10397        /* Stores the variant on java side */
    10498        void storeVariantInJava(NPVariant variant, std::string* result);
    105 
    106     public:
    107         PluginRequestProcessor(); /* Constructor */
    108         ~PluginRequestProcessor(); /* Destructor */
    109 
    110         /* Process new requests (if applicable) */
    111         virtual bool newMessageOnBus(const char* message);
    11299
    113100        /* Send member ID to Java */
     
    131118        /* Loads a URL into the specified target */
    132119        void loadURL(std::vector<std::string*>* message_parts);
     120
     121    public:
     122        PluginRequestProcessor(); /* Constructor */
     123        ~PluginRequestProcessor(); /* Destructor */
     124
     125        /* Process new requests (if applicable) */
     126        virtual bool newMessageOnBus(const char* message);
     127
     128        /* Thread run method for processing queued messages */
     129        void queueProcessorThread();
    133130};
    134131
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginUtils.cc

    r418 r429  
    4444#include "IcedTeaScriptablePluginObject.h"
    4545#include "IcedTeaPluginUtils.h"
     46#include <fstream>
    4647
    4748/**
     
    5859std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
    5960std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
     61std::queue<std::string> pre_jvm_message;
    6062
    6163/* Plugin async call queue */
    6264static std::vector< PluginThreadCall* >* pendingPluginThreadRequests = new std::vector< PluginThreadCall* >();
     65
     66void *flush_pre_init_messages(void* data) {
     67  while (true){
     68    struct timespec ts;
     69    ts.tv_sec = 1;
     70    ts.tv_nsec = 0;
     71    nanosleep(&ts ,0);
     72    if (jvm_up) {
     73      while (!pre_jvm_message.empty()) {
     74        pthread_mutex_lock(&debug_pipe_lock);
     75        std::string message = pre_jvm_message.front();
     76        pre_jvm_message.pop();
     77        pthread_mutex_unlock(&debug_pipe_lock);
     78        plugin_send_message_to_appletviewer_console(message.c_str());
     79      }
     80      flush_plugin_send_message_to_appletviewer_console();
     81    }
     82  }
     83  return NULL;
     84}
     85
     86void push_pre_init_messages(char * ldm){
     87  pthread_mutex_lock(&debug_pipe_lock);
     88  pre_jvm_message.push(std::string(ldm));
     89  pthread_mutex_unlock(&debug_pipe_lock);
     90}
     91
     92void reset_pre_init_messages(){
     93    pre_jvm_message = std::queue<std::string>();
     94  }
    6395
    6496/**
     
    403435        wchar_t c;
    404436
    405         if (plugin_debug) printf("Converted UTF-16LE string: ");
     437        PLUGIN_DEBUG("Converted UTF-16LE string: \n");
    406438
    407439        result_unicode_str->clear();
     
    417449                (c >= '0' && c <= '9'))
    418450        {
    419                 if (plugin_debug) printf("%c", c);
     451                PLUGIN_DEBUG("%c\n", c);
    420452        }
    421453
     
    424456
    425457        // not routing via debug print macros due to wide-string issues
    426         if (plugin_debug) printf(". Length=%d\n", result_unicode_str->length());
     458        PLUGIN_DEBUG(". Length=%d\n", result_unicode_str->length());
    427459}
    428460
     
    502534}
    503535
     536/* Clear instance_map. Useful for tests. */
     537void
     538IcedTeaPluginUtilities::clearInstanceIDs()
     539{
     540    delete instance_map;
     541    instance_map = new std::map<void*, NPP>();
     542}
     543
    504544/**
    505545 * Removes all mappings to a given instance, and all associated objects
     
    605645    PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
    606646    object_map->erase(key);
     647}
     648
     649/* Clear object_map. Useful for tests. */
     650void
     651IcedTeaPluginUtilities::clearObjectMapping()
     652{
     653    std::map<std::string, NPObject*>::iterator iter = object_map->begin();
     654    for (; iter != object_map->end(); ++iter) {
     655        browser_functions.releaseobject(iter->second);
     656    }
     657    delete object_map;
     658    object_map = new std::map<std::string, NPObject*>();
    607659}
    608660
     
    720772}
    721773
     774/**
     775 * Convert either a void, boolean, or a number
     776 */
     777static void
     778javaPrimitiveResultToNPVariant(const std::string& value, NPVariant* variant)
     779{
     780    if (value == "void")
     781    {
     782        PLUGIN_DEBUG("Method call returned void\n");
     783        VOID_TO_NPVARIANT(*variant);
     784    } else if (value == "null")
     785    {
     786        PLUGIN_DEBUG("Method call returned null\n");
     787        NULL_TO_NPVARIANT(*variant);
     788    } else if (value == "true")
     789    {
     790        PLUGIN_DEBUG("Method call returned a boolean (true)\n");
     791        BOOLEAN_TO_NPVARIANT(true, *variant);
     792    } else if (value == "false")
     793    {
     794        PLUGIN_DEBUG("Method call returned a boolean (false)\n");
     795        BOOLEAN_TO_NPVARIANT(false, *variant);
     796    } else
     797    {
     798        double d = strtod(value.c_str(), NULL);
     799
     800        // See if it is convertible to int
     801        if (value.find(".") != std::string::npos || d < -(0x7fffffffL - 1L) || d > 0x7fffffffL)
     802        {
     803            PLUGIN_DEBUG("Method call returned a double %f\n", d);
     804            DOUBLE_TO_NPVARIANT(d, *variant);
     805        } else
     806        {
     807            int32_t i = (int32_t) d;
     808            PLUGIN_DEBUG("Method call returned an int %d\n", i);
     809            INT32_TO_NPVARIANT(i, *variant);
     810        }
     811    }
     812}
     813
     814static bool
     815javaStringResultToNPVariant(const std::string& jobject_id, NPVariant* variant)
     816{
     817    JavaRequestProcessor jrequest_processor;
     818    JavaResultData* jstring_result = jrequest_processor.getString(jobject_id);
     819
     820    if (jstring_result->error_occurred)
     821    {
     822        return false;
     823    }
     824
     825    std::string str = *jstring_result->return_string;
     826
     827    PLUGIN_DEBUG( "Method call returned a string:\"%s\"\n", str.c_str());
     828
     829    *variant = IcedTeaPluginUtilities::NPVariantStringCopy(str);
     830
     831    return true;
     832}
     833
     834static bool
     835javaJSObjectResultToNPVariant(const std::string& js_id, NPVariant* variant)
     836{
     837    NPVariant* result_variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(js_id);
     838    *variant = *result_variant;
     839    return true;
     840}
     841
     842static bool
     843javaObjectResultToNPVariant(NPP instance, const std::string& jobject_id, NPVariant* variant)
     844{
     845    // Reference the class object so we can construct an NPObject with it and the instance
     846
     847    JavaRequestProcessor jrequest_processor;
     848    JavaResultData* jclass_result = jrequest_processor.getClassID(jobject_id);
     849
     850    if (jclass_result->error_occurred)
     851    {
     852        return false;
     853    }
     854
     855    std::string jclass_id = *jclass_result->return_string;
     856
     857    NPObject* obj;
     858    if (jclass_id.at(0) == '[') // array
     859    {
     860        obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
     861                jobject_id, true);
     862    } else
     863    {
     864        obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
     865                jobject_id, false);
     866    }
     867
     868    OBJECT_TO_NPVARIANT(obj, *variant);
     869
     870    return true;
     871}
     872
    722873bool
    723874IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
    724                                               std::string* java_value,
    725                                               NPVariant* variant)
    726 {
    727     JavaRequestProcessor java_request = JavaRequestProcessor();
    728     JavaResultData* java_result;
    729 
    730     if (java_value->find("literalreturn") == 0)
    731     {
    732         // 'literalreturn ' == 14 to skip
    733         std::string value = java_value->substr(14);
    734 
    735         // VOID/BOOLEAN/NUMBER
    736 
    737         if (value == "void")
    738         {
    739             PLUGIN_DEBUG("Method call returned void\n");
    740             VOID_TO_NPVARIANT(*variant);
    741         } else if (value == "null")
    742         {
    743             PLUGIN_DEBUG("Method call returned null\n");
    744             NULL_TO_NPVARIANT(*variant);
    745         }else if (value == "true")
    746         {
    747             PLUGIN_DEBUG("Method call returned a boolean (true)\n");
    748             BOOLEAN_TO_NPVARIANT(true, *variant);
    749         } else if (value == "false")
    750         {
    751             PLUGIN_DEBUG("Method call returned a boolean (false)\n");
    752             BOOLEAN_TO_NPVARIANT(false, *variant);
    753         } else
    754         {
    755             double d = strtod(value.c_str(), NULL);
    756 
    757             // See if it is convertible to int
    758             if (value.find(".") != std::string::npos ||
    759                 d < -(0x7fffffffL - 1L) ||
    760                 d > 0x7fffffffL)
    761             {
    762                 PLUGIN_DEBUG("Method call returned a double %f\n", d);
    763                 DOUBLE_TO_NPVARIANT(d, *variant);
    764             } else
    765             {
    766                 int32_t i = (int32_t) d;
    767                 PLUGIN_DEBUG("Method call returned an int %d\n", i);
    768                 INT32_TO_NPVARIANT(i, *variant);
    769             }
    770         }
    771     } else {
    772         // Else this is a complex java object
    773 
    774         // To keep code a little bit cleaner, we create variables with proper descriptive names
    775         std::string return_obj_instance_id = std::string();
    776         std::string return_obj_class_id = std::string();
    777         std::string return_obj_class_name = std::string();
    778         return_obj_instance_id.append(*java_value);
    779 
    780         // Find out the class name first, because string is a special case
    781         java_result = java_request.getClassName(return_obj_instance_id);
    782 
    783         if (java_result->error_occurred)
     875        std::string* java_value, NPVariant* variant)
     876{
     877    int literal_n = sizeof("literalreturn"); // Accounts for one space char
     878    int jsobject_n = sizeof("jsobject"); // Accounts for one space char
     879
     880    if (strncmp("literalreturn ", java_value->c_str(), literal_n) == 0)
     881    {
     882        javaPrimitiveResultToNPVariant(java_value->substr(literal_n), variant);
     883    } else if (strncmp("jsobject ", java_value->c_str(), jsobject_n) == 0)
     884    {
     885        javaJSObjectResultToNPVariant(java_value->substr(jsobject_n), variant);
     886    } else
     887    {
     888        std::string jobject_id = *java_value;
     889
     890        JavaRequestProcessor jrequest_processor;
     891        JavaResultData* jclassname_result = jrequest_processor.getClassName(jobject_id);
     892
     893        if (jclassname_result->error_occurred)
    784894        {
    785895            return false;
    786896        }
    787897
    788         return_obj_class_name.append(*(java_result->return_string));
    789 
    790         if (return_obj_class_name == "java.lang.String")
    791         {
    792             // String is a special case as NPVariant can handle it directly
    793             java_result = java_request.getString(return_obj_instance_id);
    794 
    795             if (java_result->error_occurred)
    796             {
    797                 return false;
    798             }
    799 
    800             // needs to be on the heap
    801             NPUTF8* return_str = (NPUTF8*) malloc(sizeof(NPUTF8)*java_result->return_string->size() + 1);
    802             strcpy(return_str, java_result->return_string->c_str());
    803 
    804             PLUGIN_DEBUG("Method call returned a string: \"%s\"\n", return_str);
    805             STRINGZ_TO_NPVARIANT(return_str, *variant);
    806 
    807         } else {
    808 
    809             // Else this is a regular class. Reference the class object so
    810             // we can construct an NPObject with it and the instance
    811             java_result = java_request.getClassID(return_obj_instance_id);
    812 
    813             if (java_result->error_occurred)
    814             {
    815                 return false;
    816             }
    817 
    818             return_obj_class_id.append(*(java_result->return_string));
    819 
    820             NPObject* obj;
    821 
    822             if (return_obj_class_name.find('[') == 0) // array
    823                 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
    824                                 instance,
    825                                 return_obj_class_id, return_obj_instance_id, true);
    826             else
    827                 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
    828                                                 instance,
    829                                                 return_obj_class_id, return_obj_instance_id, false);
    830 
    831             OBJECT_TO_NPVARIANT(obj, *variant);
     898        // Special-case for NPString if string
     899        if (*jclassname_result->return_string == "java.lang.String")
     900        {
     901            return javaStringResultToNPVariant(jobject_id, variant);
     902        } else // Else this needs a java object wrapper
     903        {
     904            return javaObjectResultToNPVariant(instance, jobject_id, variant);
    832905        }
    833906    }
     
    903976IcedTeaPluginUtilities::NPVariantAsString(NPVariant variant)
    904977{
    905 #if MOZILLA_VERSION_COLLAPSED < 1090200
    906   return std::string(
    907     NPVARIANT_TO_STRING(variant).utf8characters,
    908     NPVARIANT_TO_STRING(variant).utf8length);
    909 #else
    910978  return std::string(
    911979    NPVARIANT_TO_STRING(variant).UTF8Characters,
    912980    NPVARIANT_TO_STRING(variant).UTF8Length);
    913 #endif
    914981}
    915982
     
    921988 * @param data Arguments to *func
    922989 */
     990NPString IcedTeaPluginUtilities::NPStringCopy(const std::string& result) {
     991    char* utf8 = (char*)browser_functions.memalloc(result.size() + 1);
     992    strncpy(utf8, result.c_str(), result.size() + 1);
     993
     994    NPString npstr = {utf8, result.size()};
     995    return npstr;
     996}
     997
     998NPVariant IcedTeaPluginUtilities::NPVariantStringCopy(const std::string& result) {
     999    NPString npstr = NPStringCopy(result);
     1000    NPVariant npvar;
     1001    STRINGN_TO_NPVARIANT(npstr.UTF8Characters, npstr.UTF8Length, npvar);
     1002    return npvar;
     1003}
     1004
    9231005void
    9241006IcedTeaPluginUtilities::callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data)
     
    9931075
    9941076/**
     1077 * Returns a vector of gchar* pointing to the elements of the vector string passed in.
     1078 * @param stringVec The vector of strings reference.
     1079 */
     1080std::vector<gchar*>
     1081IcedTeaPluginUtilities::vectorStringToVectorGchar(const std::vector<std::string>* stringVec)
     1082{
     1083  std::vector<gchar*> charVec;
     1084
     1085  for (int i = 0; i < stringVec->size(); i++)
     1086  {
     1087    gchar* element = (gchar*) stringVec->at(i).c_str(); //cast from const char
     1088    charVec.push_back(element);
     1089  }
     1090  charVec.push_back(NULL);
     1091  return charVec;
     1092}
     1093
     1094/**
    9951095 * Runs through the async call wait queue and executes all calls
    9961096 *
     
    10251125}
    10261126
     1127void IcedTeaPluginUtilities::trim(std::string& str) {
     1128        size_t start = str.find_first_not_of(" \t\n"), end = str.find_last_not_of(" \t\n");
     1129        if (start == std::string::npos) {
     1130                return;
     1131        }
     1132        str = str.substr(start, end - start + 1);
     1133}
     1134
     1135std::string IcedTeaPluginUtilities::NPIdentifierAsString(NPIdentifier id) {
     1136    NPUTF8* cstr = browser_functions.utf8fromidentifier(id);
     1137    if (cstr == NULL) {
     1138        /* Treat not-existing strings as empty. To tell if it was a valid string,
     1139         * use browser_functions.identifierisstring. */
     1140        return std::string();
     1141    }
     1142    std::string str = cstr;
     1143    browser_functions.memfree(cstr);
     1144    return str;
     1145}
     1146
     1147bool IcedTeaPluginUtilities::file_exists(std::string filename)
     1148{
     1149    std::ifstream infile(filename.c_str());
     1150    return infile.good();
     1151}
     1152
     1153void IcedTeaPluginUtilities::initFileLog(){
     1154    if (plugin_file_log != NULL ) {
     1155        //reusing
     1156        return;
     1157    }
     1158    plugin_file_log_name = get_log_dir() + "/" + IcedTeaPluginUtilities::generateLogFileName();
     1159    int plugin_file_log_fd = open(plugin_file_log_name.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600);
     1160    if (plugin_file_log_fd <=0 ) {
     1161        plugin_debug_to_file = false;
     1162    } else {
     1163        plugin_file_log = fdopen(plugin_file_log_fd, "w");
     1164    }
     1165    if (plugin_file_log == NULL ) {
     1166        plugin_debug_to_file = false;
     1167    }
     1168}
     1169
     1170
     1171
     1172std::string IcedTeaPluginUtilities::generateLogFileName(){
     1173    char times[96];
     1174    char result[100];
     1175    time_t t = time(NULL);
     1176    struct tm  p;
     1177    localtime_r(&t, &p);
     1178    struct timeval current_time;   \
     1179    gettimeofday (&current_time, NULL);\
     1180    strftime(times, 96, "%Y-%m-%d_%H:%M:%S", &p);
     1181    snprintf(result, 100, "%s.%i",times, current_time.tv_usec/1000);
     1182    return "itw-cplugin-"+std::string(result)+".log";
     1183}
     1184
     1185void IcedTeaPluginUtilities::printDebugStatus(){
     1186      if (plugin_debug){
     1187        PLUGIN_DEBUG("plugin_debug: true, initialised\n");
     1188        if (plugin_debug_headers){
     1189          PLUGIN_DEBUG("plugin_debug_headers: true\n");
     1190        } else {
     1191          PLUGIN_DEBUG("plugin_debug_headers: false\n");
     1192        }
     1193        if (plugin_debug_to_file){
     1194          PLUGIN_DEBUG("plugin_debug_to_file: true, using %s\n", plugin_file_log_name.c_str());
     1195        } else {
     1196          PLUGIN_DEBUG("plugin_debug_to_file: false\n");
     1197        }
     1198        if (plugin_debug_to_streams){
     1199          PLUGIN_DEBUG("plugin_debug_to_streams: true\n");
     1200        } else {
     1201          PLUGIN_DEBUG("plugin_debug_to_streams: false\n");
     1202        }
     1203        if (plugin_debug_to_system){
     1204          PLUGIN_DEBUG("plugin_debug_to_system: true\n");
     1205        } else {
     1206          PLUGIN_DEBUG("plugin_debug_to_system: false\n");
     1207        }
     1208        if (plugin_debug_to_console){
     1209          if (debug_pipe_name){
     1210            PLUGIN_DEBUG("plugin_debug_to_console: true, pipe %s\n", debug_pipe_name);
     1211          } else {
     1212            PLUGIN_DEBUG("plugin_debug_to_console: true, pipe not yet known or broken\n");
     1213          }
     1214        } else {
     1215          PLUGIN_DEBUG("plugin_debug_to_console: false\n");
     1216        }
     1217      }
     1218    }
     1219
     1220
     1221std::string IcedTeaPluginUtilities::getTmpPath(){
     1222  const char* tmpdir_env = getenv("TMPDIR");
     1223  if (tmpdir_env != NULL && g_file_test (tmpdir_env,
     1224                    (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
     1225  {
     1226    return std::string(tmpdir_env);
     1227  }
     1228  else if (g_file_test (P_tmpdir,
     1229                    (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
     1230  {
     1231    return std::string(P_tmpdir);
     1232  }
     1233  else
     1234  {
     1235    // If TMPDIR and P_tmpdir do not exist, try /tmp directly
     1236    return "/tmp";
     1237  }
     1238}
     1239
     1240std::string IcedTeaPluginUtilities::getRuntimePath(){
     1241 const char* rntdir_env = getenv("XDG_RUNTIME_DIR");
     1242  if (rntdir_env != NULL && g_file_test (rntdir_env,
     1243                    (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
     1244  {
     1245    return std::string(rntdir_env);
     1246  }
     1247  return IcedTeaPluginUtilities::getTmpPath();
     1248}
     1249
     1250
    10271251/******************************************
    10281252 * Begin JavaMessageSender implementation *
     
    11601384    PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
    11611385}
     1386
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaPluginUtils.h

    r418 r429  
    4646#include <pthread.h>
    4747#include <stdio.h>
    48 
     48#include <stdlib.h>
     49#include <time.h>
     50#include <syslog.h>
     51#include <sys/time.h>
     52
     53#include <fcntl.h>
    4954#include <cstring>
    5055#include <iostream>
     
    5560#include <string>
    5661#include <vector>
     62#include <queue>
    5763
    5864#include <npapi.h>
    59 
    60 #if MOZILLA_VERSION_COLLAPSED < 1090100
    61 #include <npupp.h>
    62 #else
    63 #include <npapi.h>
     65#include <glib.h>
    6466#include <npruntime.h>
    65 #endif
    66 
    67 extern int plugin_debug; // defined in IcedTeaNPPlugin.cc
    68 
    69 #define PLUGIN_DEBUG(...) \
    70   do                                                          \
    71   {                                                           \
    72     if (plugin_debug)                                         \
    73     {                                                         \
    74       fprintf (stderr, "ITNPP Thread# %ld: ", pthread_self()); \
    75       fprintf (stderr, __VA_ARGS__);                          \
    76     }                                                         \
     67
     68#include "IcedTeaParseProperties.h"
     69
     70void *flush_pre_init_messages(void* data);
     71void push_pre_init_messages(char * ldm);
     72void reset_pre_init_messages();
     73
     74// debugging macro.
     75#define initialize_debug()                                                    \
     76  do                                                                          \
     77  {                                                                           \
     78    if (!debug_initiated) {                                                   \
     79      debug_initiated = true;                                                 \
     80      plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL || is_debug_on(); \
     81      plugin_debug_headers = is_debug_header_on();                            \
     82      plugin_debug_to_file = is_logging_to_file();                            \
     83      plugin_debug_to_streams = is_logging_to_stds();                         \
     84      plugin_debug_to_system = is_logging_to_system();                        \
     85      plugin_debug_to_console = is_java_console_enabled();                    \
     86      if (plugin_debug_to_file) {                                             \
     87           IcedTeaPluginUtilities::initFileLog();                             \
     88      }                                                                       \
     89      if (plugin_debug_to_console) {                                          \
     90          /*initialisation done during jvm startup*/                          \
     91      }                                                                       \
     92      IcedTeaPluginUtilities::printDebugStatus();                             \
     93    }                                                                         \
     94  } while (0)
     95
     96
     97#define  HEADER_SIZE  500
     98#define  BODY_SIZE  500
     99#define  MESSAGE_SIZE  HEADER_SIZE + BODY_SIZE
     100#define  LDEBUG_MESSAGE_SIZE MESSAGE_SIZE+50
     101
     102//header is destination char array
     103#define CREATE_HEADER(ldebug_header)                   \
     104  do                                                   \
     105  {                                                    \
     106    char times[100];                                   \
     107    time_t t = time(NULL);                             \
     108    struct tm  p;                                      \
     109    localtime_r(&t, &p);                               \
     110    strftime(times, 100, "%a %b %d %H:%M:%S %Z %Y", &p);\
     111    const char *userNameforDebug = (getenv("USERNAME") == NULL) ? "unknown user" : getenv("USERNAME");  \
     112    /*this message is parsed in JavaConsole*/          \
     113    snprintf(ldebug_header, HEADER_SIZE, "[%s][ITW-C-PLUGIN][MESSAGE_DEBUG][%s][%s:%d] ITNPP Thread# %ld, gthread %p: ",        \
     114    userNameforDebug, times, __FILE__, __LINE__,  pthread_self(), g_thread_self ());                        \
    77115  } while (0)
     116 
     117
     118#define PLUGIN_DEBUG(...)              \
     119  do                                   \
     120  {                                    \
     121    initialize_debug();                \
     122    if (plugin_debug)  {               \
     123      char ldebug_header[HEADER_SIZE]; \
     124      char ldebug_body[BODY_SIZE];     \
     125      char ldebug_message[MESSAGE_SIZE];\
     126      if (plugin_debug_headers) {      \
     127        CREATE_HEADER(ldebug_header);  \
     128      } else {                         \
     129        sprintf(ldebug_header,"");     \
     130      }                                \
     131      snprintf(ldebug_body, BODY_SIZE,  __VA_ARGS__);                               \
     132      if (plugin_debug_to_streams) {   \
     133        snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
     134        fprintf  (stdout, "%s", ldebug_message);\
     135      }                                \
     136      if (plugin_debug_to_file) {      \
     137        snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body);   \
     138        fprintf (plugin_file_log, "%s", ldebug_message);   \
     139        fflush(plugin_file_log);       \
     140      }                                \
     141      if (plugin_debug_to_console) {   \
     142        /*headers are always going to console*/            \
     143        if (!plugin_debug_headers){      \
     144          CREATE_HEADER(ldebug_header);  \
     145        }                                \
     146        snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
     147        char ldebug_channel_message[LDEBUG_MESSAGE_SIZE];                               \
     148        struct timeval current_time;   \
     149        gettimeofday (&current_time, NULL);\
     150        if (jvm_up) {                  \
     151          snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "plugindebug", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message);   \
     152          push_pre_init_messages(ldebug_channel_message);                           \
     153        } else {                       \
     154          snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "preinit_plugindebug", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message);   \
     155          push_pre_init_messages(ldebug_channel_message);                            \
     156        }                              \
     157      }                                \
     158     if (plugin_debug_to_system){      \
     159     /*no debug messages to systemlog*/\
     160     }                                 \
     161    }                                  \
     162  } while (0)
     163
     164
     165#define PLUGIN_ERROR(...)              \
     166  do                                   \
     167  {                                    \
     168    initialize_debug();                \
     169    char ldebug_header[HEADER_SIZE];   \
     170    char ldebug_body[BODY_SIZE];       \
     171    char ldebug_message[MESSAGE_SIZE]; \
     172    if (plugin_debug_headers) {        \
     173      CREATE_HEADER(ldebug_header);    \
     174    } else {                           \
     175      sprintf(ldebug_header,"");       \
     176    }                                  \
     177    snprintf(ldebug_body, BODY_SIZE,  __VA_ARGS__);   \
     178    if (plugin_debug_to_streams) {     \
     179      snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
     180      fprintf  (stderr, "%s", ldebug_message);                                    \
     181    }                                  \
     182    if (plugin_debug_to_file) {        \
     183      snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
     184      fprintf (plugin_file_log, "%s", ldebug_message);   \
     185      fflush(plugin_file_log);         \
     186    }                                  \
     187    if (plugin_debug_to_console) {     \
     188      /*headers are always going to console*/            \
     189      if (!plugin_debug_headers){            \
     190        CREATE_HEADER(ldebug_header);  \
     191      }                                \
     192      snprintf(ldebug_message, MESSAGE_SIZE, "%s%s", ldebug_header, ldebug_body); \
     193      char ldebug_channel_message[LDEBUG_MESSAGE_SIZE];                               \
     194      struct timeval current_time;     \
     195      gettimeofday (&current_time, NULL);\
     196        if (jvm_up) {                  \
     197          snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "pluginerror", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message);   \
     198          push_pre_init_messages(ldebug_channel_message);                         \
     199        } else {                       \
     200          snprintf(ldebug_channel_message, LDEBUG_MESSAGE_SIZE, "%s %ld %s", "preinit_pluginerror", current_time.tv_sec*1000000L+current_time.tv_usec, ldebug_message);   \
     201          push_pre_init_messages(ldebug_channel_message);                         \
     202        }                              \
     203    }                                  \
     204    if (plugin_debug_to_system){      \
     205      /*java can not have prefix*/    \
     206      openlog("", LOG_NDELAY, LOG_USER);\
     207      syslog(LOG_ERR, "%s", "IcedTea-Web c-plugin - for more info see itweb-settings debug options or console. See http://icedtea.classpath.org/wiki/IcedTea-Web#Filing_bugs for help.");\
     208      syslog(LOG_ERR, "%s", "IcedTea-Web c-plugin error manual log:");\
     209      /*no headers to syslog*/        \
     210      syslog(LOG_ERR, "%s", ldebug_body);   \
     211      closelog();                     \
     212    }                                 \
     213   } while (0)
     214
    78215
    79216#define CHECK_JAVA_RESULT(result_data)                               \
     
    81218    if (((JavaResultData*) result_data)->error_occurred)             \
    82219    {                                                                \
    83         printf("Error: Error occurred on Java side: %s.\n",          \
     220        PLUGIN_ERROR("Error: Error occurred on Java side: %s.\n",    \
    84221               ((JavaResultData*) result_data)->error_msg->c_str()); \
    85222        return;                                                      \
     
    213350        static std::string NPVariantAsString(NPVariant variant);
    214351
     352        /* This must be freed with browserfunctions.memfree */
     353        static NPString NPStringCopy(const std::string& result);
     354
     355        /* This must be freed with browserfunctions.releasevariantvalue */
     356        static NPVariant NPVariantStringCopy(const std::string& result);
     357
     358        /* Returns an std::string represented by the given identifier. */
     359        static std::string NPIdentifierAsString(NPIdentifier id);
     360
    215361        /* Frees the given vector and the strings that its contents point to */
    216362        static void freeStringPtrVector(std::vector<std::string*>* v);
     
    244390        static void printNPVariant(NPVariant variant);
    245391
    246         static void NPVariantToString(NPVariant variant, std::string* result);
     392        static void NPVariantToString(NPVariant variant, std::string* result);
    247393
    248394        static bool javaResultToNPVariant(NPP instance,
     
    254400        static void storeInstanceID(void* member_ptr, NPP instance);
    255401
    256         static void     removeInstanceID(void* member_ptr);
    257 
    258         static NPP getInstanceFromMemberPtr(void* member_ptr);
     402        static void removeInstanceID(void* member_ptr);
     403
     404        /* Clear object_map. Useful for tests. */
     405        static void clearInstanceIDs();
     406
     407        static NPP getInstanceFromMemberPtr(void* member_ptr);
    259408
    260409        static NPObject* getNPObjectFromJavaKey(std::string key);
     
    264413        static void removeObjectMapping(std::string key);
    265414
     415        /* Clear object_map. Useful for tests. */
     416        static void clearObjectMapping();
     417
    266418        static void invalidateInstance(NPP instance);
    267419
     
    269421
    270422        static void decodeURL(const char* url, char** decoded_url);
     423
     424        /* Returns a vector of gchar* pointing to the elements of the vector string passed in*/
     425        static std::vector<gchar*> vectorStringToVectorGchar(const std::vector<std::string>* stringVec);
    271426
    272427        /* Posts call in async queue and waits till execution completes */
    273428        static void callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data);
     429
     430        /*cutting whitespaces from end and start of string*/
     431        static void trim(std::string& str);
     432        static bool file_exists(std::string filename);
     433        //file-loggers helpers
     434        static std::string generateLogFileName();
     435        static void initFileLog();
     436        static void printDebugStatus();
     437        static std::string getTmpPath();
     438        static std::string getRuntimePath();
    274439};
    275440
     
    338503};
    339504
     505
     506
    340507#endif // __ICEDTEAPLUGINUTILS_H__
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaScriptablePluginObject.cc

    r348 r429  
    5050IcedTeaScriptablePluginObject::deAllocate(NPObject *npobj)
    5151{
    52         printf ("** Unimplemented: IcedTeaScriptablePluginObject::deAllocate %p\n", npobj);
     52        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::deAllocate %p\n", npobj);
    5353}
    5454
     
    5656IcedTeaScriptablePluginObject::invalidate(NPObject *npobj)
    5757{
    58         printf ("** Unimplemented: IcedTeaScriptablePluginObject::invalidate %p\n", npobj);
    59 }
    60 
    61 bool
    62 IcedTeaScriptablePluginObject::hasMethod(NPObject *npobj, NPIdentifier name)
    63 {
    64         printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasMethod %p\n", npobj);
    65         return false;
    66 }
    67 
    68 bool
    69 IcedTeaScriptablePluginObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
     58        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::invalidate %p\n", npobj);
     59}
     60
     61bool
     62IcedTeaScriptablePluginObject::hasMethod(NPObject *npobj, NPIdentifier name_id)
     63{
     64        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::hasMethod %p\n", npobj);
     65        return false;
     66}
     67
     68bool
     69IcedTeaScriptablePluginObject::invoke(NPObject *npobj, NPIdentifier name_id, const NPVariant *args,
    7070                        uint32_t argCount,NPVariant *result)
    7171{
    72         printf ("** Unimplemented: IcedTeaScriptablePluginObject::invoke %p\n", npobj);
     72        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::invoke %p\n", npobj);
    7373        return false;
    7474}
     
    7878                               uint32_t argCount, NPVariant *result)
    7979{
    80         printf ("** Unimplemented: IcedTeaScriptablePluginObject::invokeDefault %p\n", npobj);
    81         return false;
    82 }
    83 
    84 bool
    85 IcedTeaScriptablePluginObject::hasProperty(NPObject *npobj, NPIdentifier name)
    86 {
    87         printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasProperty %p\n", npobj);
    88         return false;
    89 }
    90 
    91 bool
    92 IcedTeaScriptablePluginObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
     80        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::invokeDefault %p\n", npobj);
     81        return false;
     82}
     83
     84bool
     85IcedTeaScriptablePluginObject::hasProperty(NPObject *npobj, NPIdentifier name_id)
     86{
     87        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::hasProperty %p\n", npobj);
     88        return false;
     89}
     90
     91bool
     92IcedTeaScriptablePluginObject::getProperty(NPObject *npobj, NPIdentifier name_id, NPVariant *result)
    9393{
    9494        // Package request?
    95         if (!strcmp(browser_functions.utf8fromidentifier(name), "java"))
     95        if (IcedTeaPluginUtilities::NPIdentifierAsString(name_id) == "java")
    9696        {
    97                 //NPObject* obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(getInstanceFromMemberPtr(npobj), name);
     97                //NPObject* obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(getInstanceFromMemberPtr(npobj), name);
    9898                //OBJECT_TO_NPVARIANT(obj, *result);
    9999
    100                 //printf ("Filling variant %p with object %p\n", result);
     100                //PLUGIN_ERROR ("Filling variant %p with object %p\n", result);
    101101        }
    102102
     
    105105
    106106bool
    107 IcedTeaScriptablePluginObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
    108 {
    109         printf ("** Unimplemented: IcedTeaScriptablePluginObject::setProperty %p\n", npobj);
    110         return false;
    111 }
    112 
    113 bool
    114 IcedTeaScriptablePluginObject::removeProperty(NPObject *npobj, NPIdentifier name)
    115 {
    116         printf ("** Unimplemented: IcedTeaScriptablePluginObject::removeProperty %p\n", npobj);
     107IcedTeaScriptablePluginObject::setProperty(NPObject *npobj, NPIdentifier name_id, const NPVariant *value)
     108{
     109        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::setProperty %p\n", npobj);
     110        return false;
     111}
     112
     113bool
     114IcedTeaScriptablePluginObject::removeProperty(NPObject *npobj, NPIdentifier name_id)
     115{
     116        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::removeProperty %p\n", npobj);
    117117        return false;
    118118}
     
    121121IcedTeaScriptablePluginObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
    122122{
    123         printf ("** Unimplemented: IcedTeaScriptablePluginObject::enumerate %p\n", npobj);
     123        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::enumerate %p\n", npobj);
    124124        return false;
    125125}
     
    129129                   NPVariant *result)
    130130{
    131         printf ("** Unimplemented: IcedTeaScriptablePluginObject::construct %p\n", npobj);
     131        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptablePluginObject::construct %p\n", npobj);
    132132        return false;
    133133}
     
    140140}
    141141
     142static NPClass
     143scriptable_plugin_object_class() {
     144    NPClass np_class;
     145    np_class.structVersion = NP_CLASS_STRUCT_VERSION;
     146    np_class.allocate = allocate_scriptable_jp_object;
     147    np_class.deallocate = IcedTeaScriptableJavaPackageObject::deAllocate;
     148    np_class.invalidate = IcedTeaScriptableJavaPackageObject::invalidate;
     149    np_class.hasMethod = IcedTeaScriptableJavaPackageObject::hasMethod;
     150    np_class.invoke = IcedTeaScriptableJavaPackageObject::invoke;
     151    np_class.invokeDefault = IcedTeaScriptableJavaPackageObject::invokeDefault;
     152    np_class.hasProperty = IcedTeaScriptableJavaPackageObject::hasProperty;
     153    np_class.getProperty = IcedTeaScriptableJavaPackageObject::getProperty;
     154    np_class.setProperty = IcedTeaScriptableJavaPackageObject::setProperty;
     155    np_class.removeProperty = IcedTeaScriptableJavaPackageObject::removeProperty;
     156    np_class.enumerate = IcedTeaScriptableJavaPackageObject::enumerate;
     157    np_class.construct = IcedTeaScriptableJavaPackageObject::construct;
     158    return np_class;
     159}
     160
    142161NPObject*
    143 IcedTeaScriptablePluginObject::get_scriptable_java_package_object(NPP instance, const NPUTF8* name)
    144 {
    145 
    146         NPObject* scriptable_object;
    147 
    148         NPClass* np_class = new NPClass();
    149         np_class->structVersion = NP_CLASS_STRUCT_VERSION;
    150         np_class->allocate = allocate_scriptable_jp_object;
    151         np_class->deallocate = IcedTeaScriptableJavaPackageObject::deAllocate;
    152         np_class->invalidate = IcedTeaScriptableJavaPackageObject::invalidate;
    153         np_class->hasMethod = IcedTeaScriptableJavaPackageObject::hasMethod;
    154         np_class->invoke = IcedTeaScriptableJavaPackageObject::invoke;
    155         np_class->invokeDefault = IcedTeaScriptableJavaPackageObject::invokeDefault;
    156         np_class->hasProperty = IcedTeaScriptableJavaPackageObject::hasProperty;
    157         np_class->getProperty = IcedTeaScriptableJavaPackageObject::getProperty;
    158         np_class->setProperty = IcedTeaScriptableJavaPackageObject::setProperty;
    159         np_class->removeProperty = IcedTeaScriptableJavaPackageObject::removeProperty;
    160         np_class->enumerate = IcedTeaScriptableJavaPackageObject::enumerate;
    161         np_class->construct = IcedTeaScriptableJavaPackageObject::construct;
    162 
    163         scriptable_object = browser_functions.createobject(instance, np_class);
    164         PLUGIN_DEBUG("Returning new scriptable package class: %p from instance %p with name %s\n", scriptable_object, instance, name);
     162IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(NPP instance, const NPUTF8* name)
     163{
     164    /* Shared NPClass instance for IcedTeaScriptablePluginObject */
     165    static NPClass np_class = scriptable_plugin_object_class();
     166
     167    NPObject* scriptable_object = browser_functions.createobject(instance, &np_class);
     168    PLUGIN_DEBUG("Returning new scriptable package class: %p from instance %p with name %s\n", scriptable_object, instance, name);
    165169
    166170    ((IcedTeaScriptableJavaPackageObject*) scriptable_object)->setPackageName(name);
     
    168172    IcedTeaPluginUtilities::storeInstanceID(scriptable_object, instance);
    169173
    170         return scriptable_object;
     174    return scriptable_object;
    171175}
    172176
     
    186190IcedTeaScriptableJavaPackageObject::setPackageName(const NPUTF8* name)
    187191{
    188     this->package_name->append(name);
     192    this->package_name->assign(name);
    189193}
    190194
     
    192196IcedTeaScriptableJavaPackageObject::getPackageName()
    193197{
    194     return this->package_name->c_str();
     198    return *this->package_name;
    195199}
    196200
     
    198202IcedTeaScriptableJavaPackageObject::deAllocate(NPObject *npobj)
    199203{
    200     browser_functions.releaseobject(npobj);
     204    delete (IcedTeaScriptableJavaPackageObject*)npobj;
    201205}
    202206
     
    208212
    209213bool
    210 IcedTeaScriptableJavaPackageObject::hasMethod(NPObject *npobj, NPIdentifier name)
     214IcedTeaScriptableJavaPackageObject::hasMethod(NPObject *npobj, NPIdentifier name_id)
    211215{
    212216    // Silly caller. Methods are for objects!
     
    215219
    216220bool
    217 IcedTeaScriptableJavaPackageObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
     221IcedTeaScriptableJavaPackageObject::invoke(NPObject *npobj, NPIdentifier name_id, const NPVariant *args,
    218222                        uint32_t argCount,NPVariant *result)
    219223{
    220         printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invoke %p\n", npobj);
     224        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invoke %p\n", npobj);
    221225        return false;
    222226}
     
    226230                               uint32_t argCount, NPVariant *result)
    227231{
    228         printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invokeDefault %p\n", npobj);
    229         return false;
    230 }
    231 
    232 bool
    233 IcedTeaScriptableJavaPackageObject::hasProperty(NPObject *npobj, NPIdentifier name)
    234 {
    235         PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::hasProperty %s\n", browser_functions.utf8fromidentifier(name));
     232        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invokeDefault %p\n", npobj);
     233        return false;
     234}
     235
     236bool
     237IcedTeaScriptableJavaPackageObject::hasProperty(NPObject *npobj, NPIdentifier name_id)
     238{
     239        std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     240
     241        PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::hasProperty %s\n", name.c_str());
    236242
    237243        bool hasProperty = false;
     
    240246    NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
    241247    int plugin_instance_id = get_id_from_instance(instance);
    242 
    243         PLUGIN_DEBUG("Object package name: \"%s\"\n", ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().c_str());
     248        IcedTeaScriptableJavaPackageObject* scriptable_obj = (IcedTeaScriptableJavaPackageObject*)npobj;
     249
     250        PLUGIN_DEBUG("Object package name: \"%s\"\n", scriptable_obj->getPackageName().c_str());
    244251
    245252        // "^java" is always a package
    246         if (((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().length() == 0 &&
    247             (  !strcmp(browser_functions.utf8fromidentifier(name), "java") ||
    248                !strcmp(browser_functions.utf8fromidentifier(name), "javax")))
     253        if (scriptable_obj->getPackageName().empty() && (name == "java" || name == "javax"))
    249254        {
    250255            return true;
    251256        }
    252257
    253         std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
    254         if (property_name.length() > 0)
     258        std::string property_name = scriptable_obj->getPackageName();
     259        if (!property_name.empty())
    255260            property_name += ".";
    256         property_name += browser_functions.utf8fromidentifier(name);
     261        property_name += name;
    257262
    258263        PLUGIN_DEBUG("Looking for name \"%s\"\n", property_name.c_str());
     
    276281
    277282bool
    278 IcedTeaScriptableJavaPackageObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
    279 {
    280 
    281         PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::getProperty %s\n", browser_functions.utf8fromidentifier(name));
    282 
    283         if (!browser_functions.utf8fromidentifier(name))
     283IcedTeaScriptableJavaPackageObject::getProperty(NPObject *npobj, NPIdentifier name_id, NPVariant *result)
     284{
     285    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     286
     287        PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::getProperty %s\n", name.c_str());
     288
     289        if (!browser_functions.identifierisstring(name_id))
    284290            return false;
    285291
     
    289295    NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
    290296    int plugin_instance_id = get_id_from_instance(instance);
    291 
    292         std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
    293         if (property_name.length() > 0)
    294             property_name += ".";
    295         property_name += browser_functions.utf8fromidentifier(name);
     297    IcedTeaScriptableJavaPackageObject* scriptable_obj = (IcedTeaScriptableJavaPackageObject*)npobj;
     298
     299    std::string property_name = scriptable_obj->getPackageName();
     300    if (!property_name.empty())
     301        property_name += ".";
     302    property_name += name;
    296303
    297304        java_result = java_request.findClass(plugin_instance_id, property_name);
     
    305312        {
    306313                PLUGIN_DEBUG("Returning package object\n");
    307                 obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(
     314                obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(
    308315                                  IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
    309316                                  property_name.c_str());
     
    312319        {
    313320                PLUGIN_DEBUG("Returning Java object\n");
    314                 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
     321                obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(
    315322                                IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
    316323                                *(java_result->return_string), "0", false);
     
    323330
    324331bool
    325 IcedTeaScriptableJavaPackageObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
     332IcedTeaScriptableJavaPackageObject::setProperty(NPObject *npobj, NPIdentifier name_id, const NPVariant *value)
    326333{
    327334        // Can't be going around setting properties on namespaces.. that's madness!
     
    330337
    331338bool
    332 IcedTeaScriptableJavaPackageObject::removeProperty(NPObject *npobj, NPIdentifier name)
    333 {
    334         printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::removeProperty %p\n", npobj);
     339IcedTeaScriptableJavaPackageObject::removeProperty(NPObject *npobj, NPIdentifier name_id)
     340{
     341        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaPackageObject::removeProperty %p\n", npobj);
    335342        return false;
    336343}
     
    339346IcedTeaScriptableJavaPackageObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
    340347{
    341         printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::enumerate %p\n", npobj);
     348        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaPackageObject::enumerate %p\n", npobj);
    342349        return false;
    343350}
     
    347354                   NPVariant *result)
    348355{
    349         printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::construct %p\n", npobj);
     356        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaPackageObject::construct %p\n", npobj);
    350357        return false;
    351358}
     
    358365}
    359366
     367
     368static NPClass
     369scriptable_java_package_object_class() {
     370    NPClass np_class;
     371    np_class.structVersion = NP_CLASS_STRUCT_VERSION;
     372    np_class.allocate = allocate_scriptable_java_object;
     373    np_class.deallocate = IcedTeaScriptableJavaObject::deAllocate;
     374    np_class.invalidate = IcedTeaScriptableJavaObject::invalidate;
     375    np_class.hasMethod = IcedTeaScriptableJavaObject::hasMethod;
     376    np_class.invoke = IcedTeaScriptableJavaObject::invoke;
     377    np_class.invokeDefault = IcedTeaScriptableJavaObject::invokeDefault;
     378    np_class.hasProperty = IcedTeaScriptableJavaObject::hasProperty;
     379    np_class.getProperty = IcedTeaScriptableJavaObject::getProperty;
     380    np_class.setProperty = IcedTeaScriptableJavaObject::setProperty;
     381    np_class.removeProperty = IcedTeaScriptableJavaObject::removeProperty;
     382    np_class.enumerate = IcedTeaScriptableJavaObject::enumerate;
     383    np_class.construct = IcedTeaScriptableJavaObject::construct;
     384    return np_class;
     385}
     386
    360387NPObject*
    361 IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(NPP instance,
     388IcedTeaScriptableJavaObject::get_scriptable_java_object(NPP instance,
    362389                                    std::string class_id,
    363390                                    std::string instance_id,
    364391                                    bool isArray)
    365392{
    366     NPObject* scriptable_object;
    367 
    368     std::string obj_key = std::string();
    369     obj_key += class_id;
    370     obj_key += ":";
    371     obj_key += instance_id;
     393    /* Shared NPClass instance for IcedTeaScriptablePluginObject */
     394    static NPClass np_class = scriptable_java_package_object_class();
     395
     396    std::string obj_key = class_id + ":" + instance_id;
    372397
    373398    PLUGIN_DEBUG("get_scriptable_java_object searching for %s...\n", obj_key.c_str());
    374     scriptable_object = IcedTeaPluginUtilities::getNPObjectFromJavaKey(obj_key);
     399    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*) IcedTeaPluginUtilities::getNPObjectFromJavaKey(obj_key);
    375400
    376401    if (scriptable_object != NULL)
     
    381406    }
    382407
    383 
    384         NPClass* np_class = new NPClass();
    385         np_class->structVersion = NP_CLASS_STRUCT_VERSION;
    386         np_class->allocate = allocate_scriptable_java_object;
    387         np_class->deallocate = IcedTeaScriptableJavaObject::deAllocate;
    388         np_class->invalidate = IcedTeaScriptableJavaObject::invalidate;
    389         np_class->hasMethod = IcedTeaScriptableJavaObject::hasMethod;
    390         np_class->invoke = IcedTeaScriptableJavaObject::invoke;
    391         np_class->invokeDefault = IcedTeaScriptableJavaObject::invokeDefault;
    392         np_class->hasProperty = IcedTeaScriptableJavaObject::hasProperty;
    393         np_class->getProperty = IcedTeaScriptableJavaObject::getProperty;
    394         np_class->setProperty = IcedTeaScriptableJavaObject::setProperty;
    395         np_class->removeProperty = IcedTeaScriptableJavaObject::removeProperty;
    396         np_class->enumerate = IcedTeaScriptableJavaObject::enumerate;
    397         np_class->construct = IcedTeaScriptableJavaObject::construct;
    398 
    399         // try to create normally
    400     scriptable_object =  browser_functions.createobject(instance, np_class);
     408    // try to create normally
     409    scriptable_object = (IcedTeaScriptableJavaObject*)browser_functions.createobject(instance, &np_class);
    401410
    402411    // didn't work? try creating asynch
     
    409418
    410419        thread_data.parameters.push_back(instance);
    411         thread_data.parameters.push_back(np_class);
     420        thread_data.parameters.push_back(&np_class);
    412421        thread_data.parameters.push_back(&scriptable_object);
    413422
     
    421430    PLUGIN_DEBUG("Constructed new Java Object with classid=%s, instanceid=%s, isArray=%d and scriptable_object=%p\n", class_id.c_str(), instance_id.c_str(), isArray, scriptable_object);
    422431
    423         ((IcedTeaScriptableJavaObject*) scriptable_object)->setClassIdentifier(class_id);
    424     ((IcedTeaScriptableJavaObject*) scriptable_object)->setIsArray(isArray);
     432    scriptable_object->class_id = class_id;
     433    scriptable_object->is_object_array = isArray;
    425434
    426435        if (instance_id != "0")
    427             ((IcedTeaScriptableJavaObject*) scriptable_object)->setInstanceIdentifier(instance_id);
     436            scriptable_object->instance_id = instance_id;
    428437
    429438        IcedTeaPluginUtilities::storeInstanceID(scriptable_object, instance);
     
    456465}
    457466
    458 IcedTeaScriptableJavaObject::IcedTeaScriptableJavaObject(NPP instance)
    459 {
    460         this->instance = instance;
    461         this->class_id = new std::string();
    462         this->instance_id = new std::string();
    463 }
    464 
    465 IcedTeaScriptableJavaObject::~IcedTeaScriptableJavaObject()
    466 {
    467         delete this->class_id;
    468         delete this->instance_id;
    469 }
    470 
    471 void
    472 IcedTeaScriptableJavaObject::setClassIdentifier(std::string class_id)
    473 {
    474         this->class_id->append(class_id);
    475 }
    476 
    477 void
    478 IcedTeaScriptableJavaObject::setInstanceIdentifier(std::string instance_id)
    479 {
    480         this->instance_id->append(instance_id);
    481 }
    482 
    483 void
    484 IcedTeaScriptableJavaObject::setIsArray(bool isArray)
    485 {
    486     this->isObjectArray = isArray;
    487 }
    488 
    489 void
    490 IcedTeaScriptableJavaObject::deAllocate(NPObject *npobj)
    491 {
    492         browser_functions.releaseobject(npobj);
    493 }
    494 
    495 void
    496 IcedTeaScriptableJavaObject::invalidate(NPObject *npobj)
    497 {
    498         IcedTeaPluginUtilities::removeInstanceID(npobj);
    499 
    500         std::string obj_key = std::string();
    501         obj_key += ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
    502         obj_key += ":";
    503         obj_key += ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
    504 
    505         IcedTeaPluginUtilities::removeObjectMapping(obj_key);
    506 }
    507 
    508 bool
    509 IcedTeaScriptableJavaObject::hasMethod(NPObject *npobj, NPIdentifier name)
    510 {
    511     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasMethod %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
     467bool
     468IcedTeaScriptableJavaObject::hasMethod(NPObject *npobj, NPIdentifier name_id)
     469{
     470    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     471    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*) npobj;
     472
     473    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasMethod %s (ival=%d)\n", name.c_str(), browser_functions.intfromidentifier(name_id));
    512474    bool hasMethod = false;
    513475
    514476    // If object is an array and requested "method" may be a number, check for it first
    515     if ( !((IcedTeaScriptableJavaObject*) npobj)->isArray()  ||
    516          (browser_functions.intfromidentifier(name) < 0))
    517     {
    518 
    519         if (!browser_functions.utf8fromidentifier(name))
     477    if ( !scriptable_object->is_object_array  ||
     478         (browser_functions.intfromidentifier(name_id) < 0))
     479    {
     480
     481        if (!browser_functions.identifierisstring(name_id))
    520482            return false;
    521483
     
    523485        JavaRequestProcessor java_request = JavaRequestProcessor();
    524486
    525         std::string classId = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
    526         std::string methodName = browser_functions.utf8fromidentifier(name);
    527 
    528         java_result = java_request.hasMethod(classId, methodName);
     487        java_result = java_request.hasMethod(scriptable_object->class_id, name);
    529488        hasMethod = java_result->return_identifier != 0;
    530489    }
     
    535494
    536495bool
    537 IcedTeaScriptableJavaObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
     496IcedTeaScriptableJavaObject::invoke(NPObject *npobj, NPIdentifier name_id, const NPVariant *args,
    538497                        uint32_t argCount, NPVariant *result)
    539498{
    540     NPUTF8* method_name = browser_functions.utf8fromidentifier(name);
     499    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
    541500
    542501    // Extract arg type array
    543     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::invoke %s. Args follow.\n", method_name);
     502    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::invoke %s. Args follow.\n", name.c_str());
    544503    for (int i=0; i < argCount; i++)
    545504    {
     
    550509    JavaRequestProcessor java_request = JavaRequestProcessor();
    551510
    552     NPObject* obj;
    553     std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
    554     std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
    555     std::string callee;
    556     std::string source;
     511    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*)npobj;
     512
     513    std::string instance_id = scriptable_object->instance_id;
     514    std::string class_id = scriptable_object->class_id;
    557515
    558516    NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
     
    567525        if (id == "-1")
    568526        {
    569             printf("Unable to create arguments on Java side\n");
     527            PLUGIN_ERROR("Unable to create arguments on Java side\n");
    570528            return false;
    571529        }
     
    577535    {
    578536        PLUGIN_DEBUG("Calling static method\n");
    579         callee = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
    580537        java_result = java_request.callStaticMethod(
    581538                        IcedTeaPluginUtilities::getSourceFromInstance(instance),
    582                         callee, browser_functions.utf8fromidentifier(name), arg_ids);
     539                        scriptable_object->class_id, name, arg_ids);
    583540    } else
    584541    {
    585542        PLUGIN_DEBUG("Calling method normally\n");
    586         callee = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
    587543        java_result = java_request.callMethod(
    588544                        IcedTeaPluginUtilities::getSourceFromInstance(instance),
    589                         callee, browser_functions.utf8fromidentifier(name), arg_ids);
     545                        scriptable_object->instance_id, name, arg_ids);
    590546    }
    591547
    592548    if (java_result->error_occurred)
    593549    {
    594         // error message must be allocated on heap
    595         char* error_msg = (char*) malloc(java_result->error_msg->length()*sizeof(char));
    596         strcpy(error_msg, java_result->error_msg->c_str());
    597         browser_functions.setexception(npobj, error_msg);
     550        browser_functions.setexception(npobj, java_result->error_msg->c_str());
    598551        return false;
    599552    }
     
    604557
    605558bool
    606 IcedTeaScriptableJavaObject::invokeDefault(NPObject *npobj, const NPVariant *args,
    607                                uint32_t argCount, NPVariant *result)
    608 {
    609         printf ("** Unimplemented: IcedTeaScriptableJavaObject::invokeDefault %p\n", npobj);
    610         return false;
    611 }
    612 
    613 bool
    614 IcedTeaScriptableJavaObject::hasProperty(NPObject *npobj, NPIdentifier name)
    615 {
    616     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasProperty %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
     559IcedTeaScriptableJavaObject::hasProperty(NPObject *npobj, NPIdentifier name_id)
     560{
     561    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     562
     563    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasProperty %s (ival=%d)\n", name.c_str(), browser_functions.intfromidentifier(name_id));
    617564    bool hasProperty = false;
    618565
     566    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*)npobj;
    619567    // If it is an array, only length and indexes are valid
    620     if (((IcedTeaScriptableJavaObject*) npobj)->isArray())
    621     {
    622         if (browser_functions.intfromidentifier(name) >= 0 ||
    623             !strcmp(browser_functions.utf8fromidentifier(name), "length"))
     568    if (scriptable_object->is_object_array)
     569    {
     570        if (browser_functions.intfromidentifier(name_id) >= 0 || name == "length")
    624571            hasProperty = true;
    625572
    626573    } else
    627574    {
    628 
    629         if (!browser_functions.utf8fromidentifier(name))
     575        if (!browser_functions.identifierisstring(name_id))
    630576            return false;
    631577
    632         if (!strcmp(browser_functions.utf8fromidentifier(name), "Packages"))
     578        if (name == "Packages")
    633579        {
    634580            hasProperty = true;
     
    638584            JavaRequestProcessor java_request = JavaRequestProcessor();
    639585
    640             std::string class_id = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
    641             std::string fieldName = browser_functions.utf8fromidentifier(name);
    642 
    643             java_result = java_request.hasField(class_id, fieldName);
     586            java_result = java_request.hasField(scriptable_object->class_id, name);
    644587
    645588            hasProperty = java_result->return_identifier != 0;
     
    652595
    653596bool
    654 IcedTeaScriptableJavaObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
    655 {
    656     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::getProperty %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
    657 
    658     bool isPropertyClass = false;
     597IcedTeaScriptableJavaObject::getProperty(NPObject *npobj, NPIdentifier name_id, NPVariant *result)
     598{
     599    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     600    bool is_string_id = browser_functions.identifierisstring(name_id);
     601    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::getProperty %s (ival=%d)\n", name.c_str(), browser_functions.intfromidentifier(name_id));
     602
    659603    JavaResultData* java_result;
    660604    JavaRequestProcessor java_request = JavaRequestProcessor();
    661605
    662     NPObject* obj;
    663     std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
    664     std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
    665     NPP instance = ((IcedTeaScriptableJavaObject*) npobj)->getInstance();
     606    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*)npobj;
     607
     608    std::string instance_id = scriptable_object->getInstanceID();
     609    std::string class_id = scriptable_object->getClassID();
     610    NPP instance = scriptable_object->instance;
    666611
    667612    if (instance_id.length() > 0) // Could be an array or a simple object
    668613    {
    669614        // If array and requesting length
    670         if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
    671              browser_functions.utf8fromidentifier(name) &&
    672              !strcmp(browser_functions.utf8fromidentifier(name), "length"))
     615        if ( scriptable_object->is_object_array && name == "length")
    673616        {
    674617            java_result = java_request.getArrayLength(instance_id);
    675         } else if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
    676                     browser_functions.intfromidentifier(name) >= 0) // else if array and requesting index
     618        } else if ( scriptable_object->is_object_array &&
     619                    browser_functions.intfromidentifier(name_id) >= 0) // else if array and requesting index
    677620        {
    678621
     
    680623            if (java_result->error_occurred)
    681624            {
    682                 printf("ERROR: Couldn't fetch array length\n");
     625                PLUGIN_ERROR("ERROR: Couldn't fetch array length\n");
    683626                return false;
    684627            }
     
    687630
    688631            // Access beyond size?
    689             if (browser_functions.intfromidentifier(name) >= length)
     632            if (browser_functions.intfromidentifier(name_id) >= length)
    690633            {
    691634                VOID_TO_NPVARIANT(*result);
     
    694637
    695638            std::string index = std::string();
    696             IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name), &index);
     639            IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name_id), &index);
    697640            java_result = java_request.getSlot(instance_id, index);
    698641
    699642        } else // Everything else
    700643        {
    701             if (!browser_functions.utf8fromidentifier(name))
     644            if (!is_string_id) {
    702645                return false;
    703 
    704             if (!strcmp(browser_functions.utf8fromidentifier(name), "Packages"))
     646            }
     647
     648            if (name == "Packages")
    705649            {
    706                 NPObject* pkgObject = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
     650                NPObject* pkgObject = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(instance, "");
    707651                OBJECT_TO_NPVARIANT(pkgObject, *result);
    708652                return true;
     
    711655            java_result = java_request.getField(
    712656                        IcedTeaPluginUtilities::getSourceFromInstance(instance),
    713                         class_id, instance_id, browser_functions.utf8fromidentifier(name));
     657                        class_id, instance_id, name);
    714658        }
    715659    }
    716660    else
    717661    {
    718         if (!browser_functions.utf8fromidentifier(name))
    719             return true;
     662        if (!is_string_id) {
     663            return false;
     664        }
    720665
    721666        java_result = java_request.getStaticField(
    722667                                IcedTeaPluginUtilities::getSourceFromInstance(instance),
    723                                 class_id, browser_functions.utf8fromidentifier(name));
     668                                class_id, name);
    724669    }
    725670
     
    734679
    735680bool
    736 IcedTeaScriptableJavaObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
    737 {
    738     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::setProperty %s (ival=%d) to:\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
     681IcedTeaScriptableJavaObject::setProperty(NPObject *npobj, NPIdentifier name_id, const NPVariant *value)
     682{
     683    std::string name = IcedTeaPluginUtilities::NPIdentifierAsString(name_id);
     684    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::setProperty %s (ival=%d) to:\n", name.c_str(), browser_functions.intfromidentifier(name_id));
    739685    IcedTeaPluginUtilities::printNPVariant(*value);
    740686
    741     bool isPropertyClass = false;
    742687    JavaResultData* java_result;
    743688    JavaRequestProcessor java_request = JavaRequestProcessor();
    744 
    745     NPObject* obj;
    746     std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
    747     std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
     689    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*)npobj;
     690
     691    std::string instance_id = scriptable_object->getInstanceID();
     692    std::string class_id = scriptable_object->getClassID();
    748693
    749694    NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
     
    752697    {
    753698        // If array
    754         if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
    755              browser_functions.utf8fromidentifier(name) &&
    756              !strcmp(browser_functions.utf8fromidentifier(name), "length"))
     699        if (scriptable_object->is_object_array && name == "length")
    757700        {
    758             printf("ERROR: Array length is not a modifiable property\n");
     701            PLUGIN_ERROR("ERROR: Array length is not a modifiable property\n");
    759702            return false;
    760         } else if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
    761                     browser_functions.intfromidentifier(name) >= 0) // else if array and requesting index
     703        } else if ( scriptable_object->is_object_array &&
     704                    browser_functions.intfromidentifier(name_id) >= 0) // else if array and requesting index
    762705        {
    763706
     
    765708            if (java_result->error_occurred)
    766709            {
    767                 printf("ERROR: Couldn't fetch array length\n");
     710                PLUGIN_ERROR("ERROR: Couldn't fetch array length\n");
    768711                return false;
    769712            }
     
    772715
    773716            // Access beyond size?
    774             if (browser_functions.intfromidentifier(name) >= length)
     717            if (browser_functions.intfromidentifier(name_id) >= length)
    775718            {
    776719                return true;
     
    778721
    779722            std::string index = std::string();
    780             IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name), &index);
     723            IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name_id), &index);
    781724
    782725            std::string value_id = std::string();
     
    792735            java_result = java_request.setField(
    793736                        IcedTeaPluginUtilities::getSourceFromInstance(instance),
    794                         class_id, instance_id, browser_functions.utf8fromidentifier(name), value_id);
     737                        class_id, instance_id, name, value_id);
    795738        }
    796739    }
     
    802745        java_result = java_request.setStaticField(
    803746                                IcedTeaPluginUtilities::getSourceFromInstance(instance),
    804                                 class_id, browser_functions.utf8fromidentifier(name), value_id);
     747                                class_id, name, value_id);
    805748    }
    806749
     
    815758
    816759bool
    817 IcedTeaScriptableJavaObject::removeProperty(NPObject *npobj, NPIdentifier name)
    818 {
    819         printf ("** Unimplemented: IcedTeaScriptableJavaObject::removeProperty %p\n", npobj);
    820         return false;
    821 }
    822 
    823 bool
    824 IcedTeaScriptableJavaObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
    825 {
    826         printf ("** Unimplemented: IcedTeaScriptableJavaObject::enumerate %p\n", npobj);
    827         return false;
    828 }
    829 
    830 bool
    831760IcedTeaScriptableJavaObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
    832761                   NPVariant *result)
    833762{
     763    IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*)npobj;
    834764    // Extract arg type array
    835     PLUGIN_DEBUG("IcedTeaScriptableJavaObject::construct %s. Args follow.\n", ((IcedTeaScriptableJavaObject*) npobj)->getClassID().c_str());
     765    PLUGIN_DEBUG("IcedTeaScriptableJavaObject::construct %s. Args follow.\n", scriptable_object->getClassID().c_str());
    836766    for (int i=0; i < argCount; i++)
    837767    {
     
    842772    JavaRequestProcessor java_request = JavaRequestProcessor();
    843773
    844     NPObject* obj;
    845     std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
    846774    NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
    847775
     
    854782        if (id == "0")
    855783        {
    856             // error message must be allocated on heap
    857             char* error_msg = (char*) malloc(1024*sizeof(char));
    858             strcpy(error_msg, "Unable to create argument on Java side");
    859 
    860             browser_functions.setexception(npobj, error_msg);
     784            browser_functions.setexception(npobj, "Unable to create argument on Java side");
    861785            return false;
    862786        }
     
    867791    java_result = java_request.newObject(
    868792                            IcedTeaPluginUtilities::getSourceFromInstance(instance),
    869                             class_id,
     793                            scriptable_object->class_id,
    870794                            arg_ids);
    871795
    872796    if (java_result->error_occurred)
    873797    {
    874         // error message must be allocated on heap
    875         int length = java_result->error_msg->length();
    876         char* error_msg = (char*) malloc((length+1)*sizeof(char));
    877         strcpy(error_msg, java_result->error_msg->c_str());
    878 
    879         browser_functions.setexception(npobj, error_msg);
     798        browser_functions.setexception(npobj, java_result->error_msg->c_str());
    880799        return false;
    881800    }
    882801
    883     std::string return_obj_instance_id = std::string();
    884     std::string return_obj_class_id = class_id;
    885     return_obj_instance_id.append(*(java_result->return_string));
    886 
    887     obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
     802    std::string return_obj_instance_id = *java_result->return_string;
     803    std::string return_obj_class_id = scriptable_object->class_id;
     804
     805    NPObject* obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(
    888806                                IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
    889807                                return_obj_class_id, return_obj_instance_id, false);
  • trunk/icedtea-web/plugin/icedteanp/IcedTeaScriptablePluginObject.h

    r348 r429  
    4040#define __ICEDTEASCRIPTABLEPLUGINOBJECT_H_
    4141
    42 #if MOZILLA_VERSION_COLLAPSED < 1090100
    43 #include "npupp.h"
    44 #else
    4542#include <npapi.h>
    4643#include <npruntime.h>
    47 #endif
    4844
    4945#include "IcedTeaJavaRequestProcessor.h"
     
    6864        static void invalidate(NPObject *npobj);
    6965
    70         static bool hasMethod(NPObject *npobj, NPIdentifier name);
    71 
    72         static bool invoke(NPObject *npobj, NPIdentifier name,
     66        static bool hasMethod(NPObject *npobj, NPIdentifier name_id);
     67
     68        static bool invoke(NPObject *npobj, NPIdentifier name_id,
    7369                const NPVariant *args, uint32_t argCount, NPVariant *result);
    7470
     
    7672                uint32_t argCount, NPVariant *result);
    7773
    78         static bool hasProperty(NPObject *npobj, NPIdentifier name);
    79 
    80         static bool getProperty(NPObject *npobj, NPIdentifier name,
     74        static bool hasProperty(NPObject *npobj, NPIdentifier name_id);
     75
     76        static bool getProperty(NPObject *npobj, NPIdentifier name_id,
    8177                NPVariant *result);
    8278
    83         static bool setProperty(NPObject *npobj, NPIdentifier name,
     79        static bool setProperty(NPObject *npobj, NPIdentifier name_id,
    8480                const NPVariant *value);
    8581
    86         static bool removeProperty(NPObject *npobj, NPIdentifier name);
     82        static bool removeProperty(NPObject *npobj, NPIdentifier name_id);
    8783
    8884        static bool enumerate(NPObject *npobj, NPIdentifier **value,
     
    9288                uint32_t argCount, NPVariant *result);
    9389
    94         static NPObject* get_scriptable_java_package_object(NPP instance, const NPUTF8* name);
    9590};
    9691
     
    117112        static void invalidate(NPObject *npobj);
    118113
    119         static bool hasMethod(NPObject *npobj, NPIdentifier name);
    120 
    121         static bool invoke(NPObject *npobj, NPIdentifier name,
     114        static bool hasMethod(NPObject *npobj, NPIdentifier name_id);
     115
     116        static bool invoke(NPObject *npobj, NPIdentifier name_id,
    122117                const NPVariant *args, uint32_t argCount, NPVariant *result);
    123118
     
    125120                uint32_t argCount, NPVariant *result);
    126121
    127         static bool hasProperty(NPObject *npobj, NPIdentifier name);
    128 
    129         static bool getProperty(NPObject *npobj, NPIdentifier name,
     122        static bool hasProperty(NPObject *npobj, NPIdentifier name_id);
     123
     124        static bool getProperty(NPObject *npobj, NPIdentifier name_id,
    130125                NPVariant *result);
    131126
    132         static bool setProperty(NPObject *npobj, NPIdentifier name,
     127        static bool setProperty(NPObject *npobj, NPIdentifier name_id,
    133128                const NPVariant *value);
    134129
    135         static bool removeProperty(NPObject *npobj, NPIdentifier name);
     130        static bool removeProperty(NPObject *npobj, NPIdentifier name_id);
    136131
    137132        static bool enumerate(NPObject *npobj, NPIdentifier **value,
     
    141136                uint32_t argCount, NPVariant *result);
    142137
    143         static NPObject* get_scriptable_java_object(NPP instance,
    144                                                     std::string class_id,
    145                                                     std::string instance_id,
    146                                                     bool isArray);
     138        static NPObject* get_scriptable_java_package_object(NPP instance, const NPUTF8* name);
    147139
    148140        static bool is_valid_java_object(NPObject* object_ptr);
     
    151143class IcedTeaScriptableJavaObject: public NPObject
    152144{
    153 
    154     private:
    155         NPP instance;
    156         bool isObjectArray;
    157         std::string* class_id;
    158         std::string* instance_id;
    159 
    160     public:
    161         IcedTeaScriptableJavaObject(NPP instance);
    162 
    163         ~IcedTeaScriptableJavaObject();
    164 
    165         void setClassIdentifier(std::string class_id);
    166 
    167         void setInstanceIdentifier(std::string instance_id);
    168 
    169         void setIsArray(bool isArray);
    170 
    171         std::string getClassID() { return *class_id; }
    172 
    173         std::string getInstanceID() { return *instance_id; }
    174 
    175         NPP getInstance() { return instance; }
    176 
    177         bool isArray() { return isObjectArray; }
    178 
    179         static void deAllocate(NPObject *npobj);
    180 
    181         static void invalidate(NPObject *npobj);
    182 
    183         static bool hasMethod(NPObject *npobj, NPIdentifier name);
    184 
    185         static bool invoke(NPObject *npobj, NPIdentifier name,
    186                 const NPVariant *args, uint32_t argCount, NPVariant *result);
    187 
    188         static bool invokeDefault(NPObject *npobj, const NPVariant *args,
    189                 uint32_t argCount, NPVariant *result);
    190 
    191         static bool hasProperty(NPObject *npobj, NPIdentifier name);
    192 
    193         static bool getProperty(NPObject *npobj, NPIdentifier name,
    194                 NPVariant *result);
    195 
    196         static bool setProperty(NPObject *npobj, NPIdentifier name,
    197                 const NPVariant *value);
    198 
    199         static bool removeProperty(NPObject *npobj, NPIdentifier name);
    200 
    201         static bool enumerate(NPObject *npobj, NPIdentifier **value,
    202                 uint32_t *count);
    203 
    204         static bool construct(NPObject *npobj, const NPVariant *args,
    205                 uint32_t argCount, NPVariant *result);
     145private:
     146    NPP instance;
     147    bool is_object_array;
     148    /* These may be empty if 'is_applet_instance' is true
     149     * and the object has not yet been used */
     150    std::string class_id, instance_id;
     151public:
     152    IcedTeaScriptableJavaObject(NPP instance) {
     153        this->instance = instance;
     154        is_object_array = false;
     155    }
     156    static void deAllocate(NPObject *npobj) {
     157        delete (IcedTeaScriptableJavaObject*)npobj;
     158    }
     159    std::string getInstanceID() {
     160        return instance_id;
     161    }
     162    std::string getClassID() {
     163        return class_id;
     164    }
     165    std::string objectKey() {
     166        return getClassID() + ":" + getInstanceID();
     167    }
     168    static void invalidate(NPObject *npobj) {
     169        IcedTeaPluginUtilities::removeInstanceID(npobj);
     170        IcedTeaScriptableJavaObject* scriptable_object = (IcedTeaScriptableJavaObject*) npobj;
     171        IcedTeaPluginUtilities::removeObjectMapping(scriptable_object->objectKey());
     172    }
     173    static bool hasMethod(NPObject *npobj, NPIdentifier name_id);
     174    static bool invoke(NPObject *npobj, NPIdentifier name_id,
     175            const NPVariant *args, uint32_t argCount, NPVariant *result);
     176    static bool invokeDefault(NPObject *npobj, const NPVariant *args,
     177            uint32_t argCount, NPVariant *result) {
     178        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaObject::invokeDefault %p\n", npobj);
     179        return false;
     180    }
     181    static bool hasProperty(NPObject *npobj, NPIdentifier name_id);
     182    static bool getProperty(NPObject *npobj, NPIdentifier name_id,
     183            NPVariant *result);
     184    static bool setProperty(NPObject *npobj, NPIdentifier name_id,
     185            const NPVariant *value);
     186
     187    static bool removeProperty(NPObject *npobj, NPIdentifier name_id) {
     188        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaObject::removeProperty %p\n", npobj);
     189        return false;
     190    }
     191    static bool enumerate(NPObject *npobj, NPIdentifier **value,
     192            uint32_t *count) {
     193        PLUGIN_ERROR ("** Unimplemented: IcedTeaScriptableJavaObject::enumerate %p\n", npobj);
     194        return false;
     195    }
     196    static bool construct(NPObject *npobj, const NPVariant *args,
     197            uint32_t argCount, NPVariant *result);
     198     /* Creates and retains a scriptable java object (intended to be called asynch.) */
     199    static NPObject* get_scriptable_java_object(NPP instance,
     200                                                std::string class_id,
     201                                                std::string instance_id,
     202                                                bool isArray);
    206203};
    207204
  • trunk/icedtea-web/plugin/icedteanp/java/netscape/javascript/JSObject.java

    r418 r429  
    101101
    102102    /**
     103     * Package-private method used through JSUtil#getJSObjectInternalReference.
     104     * We make this package-private to avoid polluting the public interface.
     105     * @return the internal identifier
     106     */
     107    long getInternalReference() {
     108        AccessController.getContext().checkPermission(new JSObjectUnboxPermission());
     109        return internal;
     110    }
     111
     112    /**
    103113     * it is illegal to construct a JSObject manually
    104114     */
  • trunk/icedtea-web/plugin/icedteanp/java/netscape/javascript/JSRunnable.java

    r348 r429  
    4040package netscape.javascript;
    4141
     42import net.sourceforge.jnlp.util.logging.OutputController;
    4243import sun.applet.PluginDebug;
    4344
     
    6768        } catch (Throwable t) {
    6869            PluginDebug.debug(t.toString());
    69             t.printStackTrace(System.err);
     70            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,t);
    7071        }
    7172    }
  • trunk/icedtea-web/plugin/icedteanp/java/netscape/javascript/JSUtil.java

    r348 r429  
    5858        return captureStream.toString();
    5959    }
     60
     61    /**
     62     * Uses package-private method JSObject.getInternalReference.
     63     * This is package-private to avoid polluting the public interface.
     64     * @param js JSObject to unbox
     65     * @return the internal reference stored by the JSObject
     66     */
     67    public static long getJSObjectInternalReference(JSObject js) {
     68        // NB: permission is checked in JSObject
     69        return js.getInternalReference();
     70    }
     71
    6072}
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java

    r348 r429  
    4242import java.lang.reflect.Method;
    4343import java.util.ArrayList;
     44import java.util.Arrays;
     45import java.util.List;
    4446
    4547/*
    4648 * This class resolved overloaded methods in Java objects using a cost
    47  * based-approach as described here:
     49 * based-approach described here:
    4850 *
    49  * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
     51 * http://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
    5052 */
    5153
    5254public class MethodOverloadResolver {
    53 
    54     private static boolean debugging = false;
    55 
    56     public static void main(String[] args) {
    57         testMethodResolver();
    58     }
    59 
    60     public static void testMethodResolver() {
    61         debugging = true;
    62 
    63         ArrayList<Object[]> list = new ArrayList<Object[]>(20);
    64         FooClass fc = new FooClass();
    65 
    66         // Numeric to java primitive
    67         // foo_i has Integer and int params
    68         String s1 = "foo_string_int(S,I)";
    69         String s1a = "foo_string_int(S,S)";
    70         Object[] o1 = { fc.getClass(), "foo_string_int", "blah", 42 };
    71         list.add(o1);
    72         Object[] o1a = { fc.getClass(), "foo_string_int", "blah", "42.42" };
    73         list.add(o1a);
    74 
    75         // Null to non-primitive type
    76         // foo_i is overloaded with Integer and int
    77         String s2 = "foo_string_int(N)";
    78         Object[] o2 = { fc.getClass(), "foo_string_int", "blah", null };
    79         list.add(o2);
    80 
    81         // foo_jsobj is overloaded with JSObject and String params
    82         String s3 = "foo_jsobj(LLowCostSignatureComputer/JSObject;)";
    83         Object[] o3 = { fc.getClass(), "foo_jsobj", new JSObject() };
    84         list.add(o3);
    85 
    86         // foo_classtype is overloaded with Number and Integer
    87         String s4 = "foo_classtype(Ljava/lang/Integer;)";
    88         Object[] o4 = { fc.getClass(), "foo_classtype", 42 };
    89         list.add(o4);
    90 
    91         // foo_multiprim is overloaded with int, long and float types
    92         String s5 = "foo_multiprim(I)";
    93         String s6 = "foo_multiprim(F)";
    94         String s6a = "foo_multiprim(D)";
    95 
    96         Object[] o5 = { fc.getClass(), "foo_multiprim", new Integer(42) };
    97         Object[] o6 = { fc.getClass(), "foo_multiprim", new Float(42.42) };
    98         Object[] o6a = { fc.getClass(), "foo_multiprim", new Double(42.42) };
    99         list.add(o5);
    100         list.add(o6);
    101         list.add(o6a);
    102 
    103         // foo_float has float, String and JSObject type
    104         String s7 = "foo_float(I)";
    105         Object[] o7 = { fc.getClass(), "foo_float", new Integer(42) };
    106         list.add(o7);
    107 
    108         // foo_multiprim(float) is what this should convert
    109         String s8 = "foo_float(S)";
    110         Object[] o8 = { fc.getClass(), "foo_float", "42" };
    111         list.add(o8);
    112 
    113         // foo_class is overloaded with BarClass 2 and 3
    114         String s9 = "foo_class(LLowCostSignatureComputer/BarClass3;)";
    115         Object[] o9 = { fc.getClass(), "foo_class", new BarClass3() };
    116         list.add(o9);
    117 
    118         // foo_strandbyteonly takes string and byte
    119         String s10 = "foo_strandbyteonly(I)";
    120         Object[] o10 = { fc.getClass(), "foo_strandbyteonly", 42 };
    121         list.add(o10);
    122 
    123         // JSOBject to string
    124         String s11 = "foo_strandbyteonly(LLowCostSignatureComputer/JSObject;)";
    125         Object[] o11 = { fc.getClass(), "foo_strandbyteonly", new JSObject() };
    126         list.add(o11);
    127 
    128         // jsobject to string and int to float
    129         String s12 = "foo_str_and_float(S,I)";
    130         Object[] o12 = { fc.getClass(), "foo_str_and_float", new JSObject(), new Integer(42) };
    131         list.add(o12);
    132 
    133         // call for which no match will be found
    134         String s13 = "foo_int_only(JSObject)";
    135         Object[] o13 = { fc.getClass(), "foo_int_only", new JSObject() };
    136         list.add(o13);
    137 
    138         // method with no args
    139         String s14 = "foo_noargs()";
    140         Object[] o14 = { fc.getClass(), "foo_noargs" };
    141         list.add(o14);
    142 
    143         // method which takes a primitive bool, given a Boolean
    144         String s15 = "foo_boolonly()";
    145         Object[] o15 = { fc.getClass(), "foo_boolonly", new Boolean(true) };
    146         list.add(o15);
    147 
    148         for (Object[] o : list) {
    149             Object[] methodAndArgs = getMatchingMethod(o);
    150             if (debugging)
    151                 if (methodAndArgs != null)
    152                     System.out.println("Best match: " + methodAndArgs[0] + "\n");
    153                 else
    154                     System.out.println("No match found.\n");
    155 
    156         }
    157 
     55    static final int NUMERIC_SAME_COST = 1;
     56    static final int NULL_TO_OBJECT_COST = 2;
     57    static final int CLASS_SAME_COST = 3;
     58    static final int NUMERIC_CAST_COST = 4;
     59    static final int NUMERIC_BOOLEAN_COST = 5;
     60
     61    static final int STRING_NUMERIC_CAST_COST = 5;
     62
     63    static final int CLASS_SUPERCLASS_COST = 6;
     64
     65    static final int CLASS_STRING_COST = 7;
     66    static final int ARRAY_CAST_COST = 8;
     67
     68    /* A method signature with its casted parameters
     69     * We pretend a Constructor is a normal 'method' for ease of code reuse */
     70    static class ResolvedMethod {
     71
     72        private java.lang.reflect.AccessibleObject method;
     73        private Object[] castedParameters;
     74        private int cost;
     75
     76        public ResolvedMethod(int cost, java.lang.reflect.AccessibleObject method, Object[] castedParameters) {
     77            this.cost = cost;
     78            this.method = method;
     79            this.castedParameters = castedParameters;
     80        }
     81
     82        java.lang.reflect.AccessibleObject getAccessibleObject() {
     83            return method;
     84        }
     85
     86        public Method getMethod() {
     87            return (Method)method;
     88        }
     89
     90        public Constructor<?> getConstructor() {
     91            return (Constructor<?>)method;
     92        }
     93
     94        public Object[] getCastedParameters() {
     95            return castedParameters;
     96        }
     97
     98        public int getCost() {
     99            return cost;
     100        }
     101    }
     102
     103    /* A cast with an associated 'cost', used for picking method overloads */
     104    static class WeightedCast {
     105
     106        private int cost;
     107        private Object castedObject;
     108
     109        public WeightedCast(int cost, Object castedObject) {
     110            this.cost = cost;
     111            this.castedObject = castedObject;
     112        }
     113
     114        public Object getCastedObject() {
     115            return castedObject;
     116        }
     117
     118        public int getCost() {
     119            return cost;
     120        }
     121    }
     122
     123
     124    public static ResolvedMethod getBestMatchMethod(Class<?> c, String methodName, Object[] args) {
     125        Method[] matchingMethods = getMatchingMethods(c, methodName, args.length);
     126
     127        if (PluginDebug.DEBUG) { /* avoid toString if not needed */
     128            PluginDebug.debug("getMatchingMethod called with: "
     129                    + Arrays.toString(args));
     130        }
     131
     132        return getBestOverloadMatch(c, args, matchingMethods);
     133    }
     134
     135    public static ResolvedMethod getBestMatchConstructor(Class<?> c, Object[] args) {
     136        Constructor<?>[] matchingConstructors = getMatchingConstructors(c, args.length);
     137
     138        if (PluginDebug.DEBUG) { /* avoid toString if not needed */
     139            PluginDebug.debug("getMatchingConstructor called with: "
     140                    + Arrays.toString(args));
     141        }
     142
     143        return getBestOverloadMatch(c, args, matchingConstructors);
    158144    }
    159145
    160146    /*
    161      * Cost based overload resolution algorithm based on cost rules specified here:
    162      *
    163      * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
     147     * Get best-matching method based on a cost based overload resolution
     148     * algorithm is used, described here:
     149     *
     150     * http://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
     151     *
     152     * Note that we consider Constructor's to be 'methods' for convenience. We
     153     * use the common parent class of Method/Constructor, 'AccessibleObject'
     154     *
     155     * NB: Although the spec specifies that ambiguous method calls (ie, same
     156     * cost) should throw errors, we simply pick the first overload for
     157     * simplicity. Method overrides should not be doing wildly different things
     158     * anyway.
    164159     */
    165 
    166     public static Object[] getMatchingMethod(Object[] callList) {
    167         Object[] ret = null;
    168         Class<?> c = (Class<?>) callList[0];
    169         String methodName = (String) callList[1];
    170 
    171         Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
    172 
    173         if (debugging)
    174             System.out.println("getMatchingMethod called with: " + printList(callList));
     160    static ResolvedMethod getBestOverloadMatch(Class<?> c, Object[] args,
     161            java.lang.reflect.AccessibleObject[] candidates) {
    175162
    176163        int lowestCost = Integer.MAX_VALUE;
    177 
    178         for (Method matchingMethod : matchingMethods) {
    179 
     164        java.lang.reflect.AccessibleObject cheapestMethod = null;
     165        Object[] cheapestArgs = null;
     166        boolean ambiguous = false;
     167
     168        methodLoop:
     169        for (java.lang.reflect.AccessibleObject candidate : candidates) {
    180170            int methodCost = 0;
    181             Class[] paramTypes = matchingMethod.getParameterTypes();
    182             Object[] methodAndArgs = new Object[paramTypes.length + 1];
    183             methodAndArgs[0] = matchingMethod;
     171
     172            Class<?>[] paramTypes = getParameterTypesFor(candidate);
     173            Object[] castedArgs = new Object[paramTypes.length];
    184174
    185175            // Figure out which of the matched methods best represents what we
     
    187177            for (int i = 0; i < paramTypes.length; i++) {
    188178                Class<?> paramTypeClass = paramTypes[i];
    189                 Object suppliedParam = callList[i + 2];
     179                Object suppliedParam = args[i];
    190180                Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam
    191                         .getClass()
    192                         : null;
    193 
    194                 Object[] costAndCastedObj = getCostAndCastedObject(
     181                        .getClass() : null;
     182
     183                WeightedCast weightedCast = getCostAndCastedObject(
    195184                        suppliedParam, paramTypeClass);
    196                 methodCost += (Integer) costAndCastedObj[0];
    197 
    198                 if ((Integer) costAndCastedObj[0] < 0)
    199                     break;
    200 
    201                 Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
    202                         : paramTypeClass.cast(costAndCastedObj[1]);
    203                 methodAndArgs[i + 1] = castedObj;
    204 
    205                 Class<?> castedObjClass = castedObj == null ? null : castedObj
    206                         .getClass();
    207                 Boolean castedObjIsPrim = castedObj == null ? null : castedObj
    208                         .getClass().isPrimitive();
    209 
    210                 if (debugging)
    211                     System.out.println("Param " + i + " of method "
    212                             + matchingMethod + " has cost "
    213                             + (Integer) costAndCastedObj[0]
     185
     186                if (weightedCast == null) {
     187                    continue methodLoop; // Cannot call this constructor!
     188                }
     189
     190                methodCost += weightedCast.getCost();
     191
     192                Object castedObj = paramTypeClass.isPrimitive() ?
     193                            weightedCast.getCastedObject()
     194                          : paramTypeClass.cast(weightedCast.getCastedObject());
     195
     196                castedArgs[i] = castedObj;
     197
     198                if (PluginDebug.DEBUG) { /* avoid toString if not needed */
     199                    Class<?> castedObjClass = castedObj == null ? null : castedObj.getClass();
     200                    boolean castedObjIsPrim = castedObj == null ? false : castedObj.getClass().isPrimitive();
     201
     202                    PluginDebug.debug("Param " + i + " of method " + candidate
     203                            + " has cost " + weightedCast.getCost()
    214204                            + " original param type " + suppliedParamClass
    215205                            + " casted to " + castedObjClass + " isPrimitive="
    216206                            + castedObjIsPrim + " value " + castedObj);
    217             }
    218 
    219             if ((methodCost > 0 && methodCost < lowestCost) ||
    220                     paramTypes.length == 0) {
    221                 ret = methodAndArgs;
    222                 lowestCost = methodCost;
    223             }
    224 
    225         }
    226 
    227         return ret;
    228     }
    229 
    230     public static Object[] getMatchingConstructor(Object[] callList) {
    231         Object[] ret = null;
    232         Class<?> c = (Class<?>) callList[0];
    233 
    234         Constructor[] matchingConstructors = getMatchingConstructors(c, callList.length - 1);
    235 
    236         if (debugging)
    237             System.out.println("getMatchingConstructor called with: " + printList(callList));
    238 
    239         int lowestCost = Integer.MAX_VALUE;
    240 
    241         for (Constructor matchingConstructor : matchingConstructors) {
    242 
    243             int constructorCost = 0;
    244             Class<?>[] paramTypes = matchingConstructor.getParameterTypes();
    245             Object[] constructorAndArgs = new Object[paramTypes.length + 1];
    246             constructorAndArgs[0] = matchingConstructor;
    247 
    248             // Figure out which of the matched methods best represents what we
    249             // want
    250             for (int i = 0; i < paramTypes.length; i++) {
    251                 Class<?> paramTypeClass = paramTypes[i];
    252                 Object suppliedParam = callList[i + 1];
    253                 Class suppliedParamClass = suppliedParam != null ? suppliedParam
    254                         .getClass()
    255                         : null;
    256 
    257                 Object[] costAndCastedObj = getCostAndCastedObject(
    258                         suppliedParam, paramTypeClass);
    259                 constructorCost += (Integer) costAndCastedObj[0];
    260 
    261                 if ((Integer) costAndCastedObj[0] < 0)
    262                     break;
    263 
    264                 Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
    265                         : paramTypeClass.cast(costAndCastedObj[1]);
    266                 constructorAndArgs[i + 1] = castedObj;
    267 
    268                 Class<?> castedObjClass = castedObj == null ? null : castedObj
    269                         .getClass();
    270                 Boolean castedObjIsPrim = castedObj == null ? null : castedObj
    271                         .getClass().isPrimitive();
    272 
    273                 if (debugging)
    274                     System.out.println("Param " + i + " of constructor "
    275                             + matchingConstructor + " has cost "
    276                             + (Integer) costAndCastedObj[0]
    277                             + " original param type " + suppliedParamClass
    278                             + " casted to " + castedObjClass + " isPrimitive="
    279                             + castedObjIsPrim + " value " + castedObj);
    280             }
    281 
    282             if ((constructorCost > 0 && constructorCost < lowestCost) ||
    283                     paramTypes.length == 0) {
    284                 ret = constructorAndArgs;
    285                 lowestCost = constructorCost;
    286             }
    287         }
    288 
    289         return ret;
    290     }
    291 
    292     public static Object[] getCostAndCastedObject(Object suppliedParam, Class<?> paramTypeClass) {
    293 
    294         Object[] ret = new Object[2];
    295         Integer cost = new Integer(0);
    296         Object castedObj;
    297 
    298         Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null;
    299 
    300         // Either both are an array, or neither are
    301         boolean suppliedParamIsArray = suppliedParamClass != null && suppliedParamClass.isArray();
    302         if (paramTypeClass.isArray() != suppliedParamIsArray &&
    303                 !paramTypeClass.equals(Object.class) &&
    304                 !paramTypeClass.equals(String.class)) {
    305             ret[0] = Integer.MIN_VALUE; // Not allowed
    306             ret[1] = suppliedParam;
    307             return ret;
    308         }
    309 
    310         // If param type is an array, supplied obj must be an array, Object or String (guaranteed by checks above)
    311         // If it is an array, we need to copy/cast as we scan the array
    312         // If it an object, we return "as is" [Everything can be narrowed to an object, cost=6]
    313         // If it is a string, we need to convert according to the JS engine rules
    314 
    315         if (paramTypeClass.isArray()) {
    316 
    317             Object newArray = Array.newInstance(paramTypeClass.getComponentType(), Array.getLength(suppliedParam));
    318             for (int i = 0; i < Array.getLength(suppliedParam); i++) {
    319                 Object original = Array.get(suppliedParam, i);
    320 
    321                 // When dealing with arrays, we represent empty slots with
    322                 // null. We need to convert this to 0 before recursive
    323                 // calling, since normal transformation does not allow
    324                 // null -> primitive
    325 
    326                 if (original == null && paramTypeClass.getComponentType().isPrimitive())
    327                     original = 0;
    328 
    329                 Object[] costAndCastedObject = getCostAndCastedObject(original, paramTypeClass.getComponentType());
    330 
    331                 if ((Integer) costAndCastedObject[0] < 0) {
    332                     ret[0] = Integer.MIN_VALUE; // Not allowed
    333                     ret[1] = suppliedParam;
    334                     return ret;
    335207                }
    336 
    337                 Array.set(newArray, i, costAndCastedObject[1]);
    338             }
    339 
    340             ret[0] = 9;
    341             ret[1] = newArray;
    342             return ret;
    343         }
    344 
    345         if (suppliedParamIsArray && paramTypeClass.equals(String.class)) {
    346 
    347             ret[0] = 9;
    348             ret[1] = getArrayAsString(suppliedParam);
    349             return ret;
     208            }
     209
     210            if (methodCost <= lowestCost) {
     211                if (methodCost < lowestCost
     212                        || argumentsAreSubclassesOf(castedArgs, cheapestArgs)) {
     213                    lowestCost = methodCost;
     214                    cheapestArgs = castedArgs;
     215                    cheapestMethod = candidate;
     216                    ambiguous = false;
     217                } else {
     218                    ambiguous = true;
     219                }
     220            }
     221
     222        }
     223
     224        // The spec says we should error out if the method call is ambiguous
     225        // Instead we will report it in debug output
     226        if (ambiguous) {
     227            PluginDebug.debug("*** Warning: Ambiguous overload of ", c.getClass(), "#", cheapestMethod, "!");
     228        }
     229
     230        if (cheapestMethod == null) {
     231            return null;
     232        }
     233
     234        return new ResolvedMethod(lowestCost, cheapestMethod, cheapestArgs);
     235    }
     236
     237    public static WeightedCast getCostAndCastedObject(Object suppliedParam,
     238            Class<?> paramTypeClass) {
     239        Class<?> suppliedParamClass = suppliedParam != null ? suppliedParam
     240                .getClass() : null;
     241
     242        boolean suppliedParamIsArray = suppliedParamClass != null
     243                && suppliedParamClass.isArray();
     244
     245        if (suppliedParamIsArray) {
     246            if (paramTypeClass.isArray()) {
     247                return getArrayToArrayCastWeightedCost(suppliedParam,
     248                        paramTypeClass);
     249            }
     250
     251            // Target type must be an array, Object or String
     252            // If it an object, we return "as is" [Everything can be narrowed to an
     253            // object, cost=CLASS_SUPERCLASS_COST]
     254            // If it is a string, we need to convert according to the JS engine
     255            // rules
     256            if (paramTypeClass != String.class
     257                    && paramTypeClass != Object.class) {
     258                return null;
     259            }
     260            if (paramTypeClass.equals(String.class)) {
     261                return new WeightedCast(ARRAY_CAST_COST,
     262                        arrayToJavascriptStyleString(suppliedParam));
     263            }
    350264        }
    351265
    352266        // If this is null, there are only 2 possible cases
    353267        if (suppliedParamClass == null) {
    354             castedObj = null; // if value is null.. well, it is null
    355 
    356268            if (!paramTypeClass.isPrimitive()) {
    357                 cost += 2; // Null to any non-primitive type
     269                return new WeightedCast(NULL_TO_OBJECT_COST, null); // Null to any non-primitive type
     270            }
     271            return null;// Null to primitive not allowed
     272        }
     273
     274        // Numeric type to the analogous Java primitive type
     275        if (paramTypeClass.isPrimitive()
     276                && paramTypeClass == getPrimitiveType(suppliedParam.getClass())) {
     277            return new WeightedCast(NUMERIC_SAME_COST, suppliedParam);
     278
     279        }
     280
     281        // Class type to Class type where the types are the same
     282        if (suppliedParamClass == paramTypeClass) {
     283            return new WeightedCast(CLASS_SAME_COST, suppliedParam);
     284
     285        }
     286
     287        // Numeric type to a different primitive type
     288        boolean wrapsPrimitive = (getPrimitiveType(suppliedParam.getClass()) != null);
     289        if (wrapsPrimitive && paramTypeClass.isPrimitive()) {
     290            double val;
     291
     292            // Coerce booleans
     293            if (suppliedParam.equals(Boolean.TRUE)) {
     294                val = 1.0;
     295            } else if (suppliedParam.equals(Boolean.FALSE)){
     296                val = 0.0;
     297            } else if (suppliedParam instanceof Character) {
     298                val = (double)(Character)suppliedParam;
    358299            } else {
    359                 cost = Integer.MIN_VALUE; // Null to primitive not allowed
    360             }
    361         } else if (paramTypeClass.isPrimitive() && paramTypeClass.equals(getPrimitive(suppliedParam))) {
    362             cost += 1; // Numeric type to the analogous Java primitive type
    363             castedObj = suppliedParam; // Let auto-boxing handle it
    364         } else if (suppliedParamClass.equals(paramTypeClass)) {
    365             cost += 3; // Class type to Class type where the types are equal
    366             castedObj = suppliedParam;
    367         } else if (isNum(suppliedParam) &&
    368                        (paramTypeClass.isPrimitive() ||
    369                                java.lang.Number.class.isAssignableFrom(paramTypeClass) ||
    370                                java.lang.Character.class.isAssignableFrom(paramTypeClass) ||
    371                         java.lang.Byte.class.isAssignableFrom(paramTypeClass)
    372                        )) {
    373             cost += 4; // Numeric type to a different primitive type
    374 
    375             if (suppliedParam.toString().equals("true"))
    376                 suppliedParam = "1";
    377             else if (suppliedParam.toString().equals("false"))
    378                 suppliedParam = "0";
    379 
    380             if (paramTypeClass.equals(Boolean.TYPE))
    381                 castedObj = getNum(suppliedParam.toString(), paramTypeClass).doubleValue() != 0D;
    382             else if (paramTypeClass.equals(Character.TYPE))
    383                 castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
    384             else
    385                 castedObj = getNum(suppliedParam.toString(), paramTypeClass);
    386         } else if (suppliedParam instanceof java.lang.String &&
    387                     isNum(suppliedParam) &&
    388                         (paramTypeClass.isInstance(java.lang.Number.class) ||
    389                                 paramTypeClass.isInstance(java.lang.Character.class) ||
    390                                 paramTypeClass.isInstance(java.lang.Byte.class) ||
    391                          paramTypeClass.isPrimitive())) {
    392             cost += 5; // String to numeric type
    393 
    394             if (suppliedParam.toString().equals("true"))
    395                 suppliedParam = "1";
    396             else if (suppliedParam.toString().equals("false"))
    397                 suppliedParam = "0";
    398 
    399             if (paramTypeClass.equals(Character.TYPE))
    400                 castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
    401             else
    402                 castedObj = getNum(suppliedParam.toString(), paramTypeClass);
    403         } else if (suppliedParam instanceof java.lang.String &&
    404                      (paramTypeClass.equals(java.lang.Boolean.class) ||
    405                       paramTypeClass.equals(java.lang.Boolean.TYPE))) {
    406 
    407             cost += 5; // Same cost as above
    408             castedObj = new Boolean(suppliedParam.toString().length() > 0);
    409         } else if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
    410             cost += 6; // Class type to superclass type;
    411             castedObj = paramTypeClass.cast(suppliedParam);
    412         } else if (paramTypeClass.equals(String.class)) {
    413             cost += 7; // Any Java value to String
    414             castedObj = suppliedParam.toString();
    415         } else if (suppliedParam instanceof JSObject &&
    416                    paramTypeClass.isArray()) {
    417             cost += 8; // JSObject to Java array
    418             castedObj = (JSObject) suppliedParam;
     300                val = ((Number)suppliedParam).doubleValue();
     301            }
     302
     303            int castCost = NUMERIC_CAST_COST;
     304            Object castedObj;
     305            if (paramTypeClass.equals(Boolean.TYPE)) {
     306                castedObj = (val != 0D && !Double.isNaN(val));
     307
     308                if (suppliedParam.getClass() != Boolean.class) {
     309                    castCost = NUMERIC_BOOLEAN_COST;
     310                }
     311            } else {
     312                castedObj = toBoxedPrimitiveType(val, paramTypeClass);
     313            }
     314            return new WeightedCast(castCost, castedObj);
     315        }
     316
     317        // Numeric string to numeric type
     318        if (isNumericString(suppliedParam) && paramTypeClass.isPrimitive()) {
     319            Object castedObj;
     320            if (paramTypeClass.equals(Character.TYPE)) {
     321                castedObj = (char) Short.decode((String)suppliedParam).shortValue();
     322            } else {
     323                castedObj = stringAsPrimitiveType((String)suppliedParam, paramTypeClass);
     324            }
     325            return new WeightedCast(STRING_NUMERIC_CAST_COST, castedObj);
     326        }
     327
     328        // Same cost as above
     329        if (suppliedParam instanceof java.lang.String
     330                && (paramTypeClass == java.lang.Boolean.class || paramTypeClass == java.lang.Boolean.TYPE)) {
     331            return new WeightedCast(STRING_NUMERIC_CAST_COST, !suppliedParam.equals(""));
     332        }
     333
     334        // Class type to superclass type;
     335        if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
     336            return new WeightedCast(CLASS_SUPERCLASS_COST, paramTypeClass.cast(suppliedParam));
     337        }
     338
     339        // Any java value to String
     340        if (paramTypeClass.equals(String.class)) {
     341            return new WeightedCast(CLASS_STRING_COST, suppliedParam.toString());
     342        }
     343
     344        return null;
     345    }
     346
     347    private static WeightedCast getArrayToArrayCastWeightedCost(Object suppliedArray,
     348            Class<?> paramTypeClass) {
     349
     350        int arrLength = Array.getLength(suppliedArray);
     351        Class<?> arrType = paramTypeClass.getComponentType();
     352
     353        // If it is an array, we need to copy/cast as we scan the array
     354        Object newArray = Array.newInstance(arrType, arrLength);
     355
     356        for (int i = 0; i < arrLength; i++) {
     357            Object original = Array.get(suppliedArray, i);
     358
     359            // When dealing with arrays, we represent empty slots with
     360            // null. We need to convert this to 0 before recursive
     361            // calling, since normal transformation does not allow
     362            // null -> primitive
     363
     364            if (original == null && arrType.isPrimitive()) {
     365                original = 0;
     366            }
     367
     368            WeightedCast costAndCastedObject = getCostAndCastedObject(original,
     369                    paramTypeClass.getComponentType());
     370
     371            if (costAndCastedObject == null) {
     372                return null;
     373            }
     374
     375            Array.set(newArray, i, costAndCastedObject.getCastedObject());
     376        }
     377
     378        return new WeightedCast(ARRAY_CAST_COST, newArray);
     379    }
     380
     381    private static Method[] getMatchingMethods(Class<?> c, String name,
     382            int paramCount) {
     383        List<Method> matchingMethods = new ArrayList<Method>();
     384
     385        for (Method m : c.getMethods()) {
     386            if (m.getName().equals(name)) {
     387                if (m.getParameterTypes().length == paramCount) {
     388                    matchingMethods.add(m);
     389                }
     390            }
     391        }
     392
     393        return matchingMethods.toArray(new Method[0]);
     394    }
     395
     396    private static Constructor<?>[] getMatchingConstructors(Class<?> c,
     397            int paramCount) {
     398        List<Constructor<?>> matchingConstructors = new ArrayList<Constructor<?>>();
     399
     400        for (Constructor<?> cs : c.getConstructors()) {
     401            if (cs.getParameterTypes().length == paramCount) {
     402                matchingConstructors.add(cs);
     403            }
     404        }
     405
     406        return matchingConstructors.toArray(new Constructor<?>[0]);
     407    }
     408
     409    private static Class<?> getPrimitiveType(Class<?> c) {
     410        if (c.isPrimitive()) {
     411            return c;
     412        }
     413
     414        if (c == Byte.class) {
     415            return Byte.TYPE;
     416        } else if (c == Character.class) {
     417            return Character.TYPE;
     418        } else if (c == Short.class) {
     419            return Short.TYPE;
     420        } else if (c == Integer.class) {
     421            return Integer.TYPE;
     422        } else if (c == Long.class) {
     423            return Long.TYPE;
     424        } else if (c == Float.class) {
     425            return Float.TYPE;
     426        } else if (c == Double.class) {
     427            return Double.TYPE;
     428        } else if (c == Boolean.class) {
     429            return Boolean.TYPE;
    419430        } else {
    420             cost = Integer.MIN_VALUE; // Not allowed
    421             castedObj = suppliedParam;
    422         }
    423 
    424         ret[0] = cost;
    425         ret[1] = castedObj;
    426 
    427         return ret;
    428 
    429     }
    430 
    431     private static Method[] getMatchingMethods(Class<?> c, String name, int paramCount) {
    432         Method[] allMethods = c.getMethods();
    433         ArrayList<Method> matchingMethods = new ArrayList<Method>(5);
    434 
    435         for (Method m : allMethods) {
    436             if (m.getName().equals(name) && m.getParameterTypes().length == paramCount)
    437                 matchingMethods.add(m);
    438         }
    439 
    440         return matchingMethods.toArray(new Method[0]);
    441     }
    442 
    443     private static Constructor[] getMatchingConstructors(Class<?> c, int paramCount) {
    444         Constructor[] allConstructors = c.getConstructors();
    445         ArrayList<Constructor> matchingConstructors = new ArrayList<Constructor>(5);
    446 
    447         for (Constructor cs : allConstructors) {
    448             if (cs.getParameterTypes().length == paramCount)
    449                 matchingConstructors.add(cs);
    450         }
    451 
    452         return matchingConstructors.toArray(new Constructor[0]);
    453     }
    454 
    455     private static Class getPrimitive(Object o) {
    456 
    457         if (o instanceof java.lang.Byte) {
    458             return java.lang.Byte.TYPE;
    459         } else if (o instanceof java.lang.Character) {
    460             return java.lang.Character.TYPE;
    461         } else if (o instanceof java.lang.Short) {
    462             return java.lang.Short.TYPE;
    463         } else if (o instanceof java.lang.Integer) {
    464             return java.lang.Integer.TYPE;
    465         } else if (o instanceof java.lang.Long) {
    466             return java.lang.Long.TYPE;
    467         } else if (o instanceof java.lang.Float) {
    468             return java.lang.Float.TYPE;
    469         } else if (o instanceof java.lang.Double) {
    470             return java.lang.Double.TYPE;
    471         } else if (o instanceof java.lang.Boolean) {
    472             return java.lang.Boolean.TYPE;
    473         }
    474 
    475         return o.getClass();
    476     }
    477 
    478     private static boolean isNum(Object o) {
    479 
    480         if (o instanceof java.lang.Number)
    481             return true;
    482 
    483         // Boolean is changeable to number as well
    484         if (o instanceof java.lang.Boolean)
    485             return true;
    486 
     431            return null;
     432        }
     433    }
     434
     435    private static boolean isNumericString(Object o) {
    487436        // At this point, it _has_ to be a string else automatically
    488437        // return false
    489         if (!(o instanceof java.lang.String))
     438        if (!(o instanceof java.lang.String)) {
    490439            return false;
     440        }
    491441
    492442        try {
     
    505455    }
    506456
    507     private static Number getNum(String s, Class<?> c) throws NumberFormatException {
    508 
    509         Number n;
    510         if (s.contains("."))
    511             n = new Double(s);
    512         else
    513             n = new Long(s);
     457    private static Object toBoxedPrimitiveType(double val, Class<?> c) {
     458        Class<?> prim = getPrimitiveType(c);
    514459
    515460        // See if we need to collapse first
    516         if (c.equals(java.lang.Integer.class) ||
    517                 c.equals(java.lang.Integer.TYPE)) {
    518             return n.intValue();
    519         }
    520 
    521         if (c.equals(java.lang.Long.class) ||
    522                 c.equals(java.lang.Long.TYPE)) {
    523             return n.longValue();
    524         }
    525 
    526         if (c.equals(java.lang.Short.class) ||
    527                 c.equals(java.lang.Short.TYPE)) {
    528             return n.shortValue();
    529         }
    530 
    531         if (c.equals(java.lang.Float.class) ||
    532                 c.equals(java.lang.Float.TYPE)) {
    533             return n.floatValue();
    534         }
    535 
    536         if (c.equals(java.lang.Double.class) ||
    537                 c.equals(java.lang.Double.TYPE)) {
    538             return n.doubleValue();
    539         }
    540 
    541         if (c.equals(java.lang.Byte.class) ||
    542                 c.equals(java.lang.Byte.TYPE)) {
    543             return n.byteValue();
    544         }
    545 
    546         return n;
    547     }
    548 
    549     private static String printList(Object[] oList) {
    550 
    551         String ret = "";
    552 
    553         ret += "{ ";
    554         for (Object o : oList) {
    555 
    556             String oStr = o != null ? o.toString() + " [" + o.getClass() + "]" : "null";
    557 
    558             ret += oStr;
    559             ret += ", ";
    560         }
    561         ret = ret.substring(0, ret.length() - 2); // remove last ", "
    562         ret += " }";
    563 
    564         return ret;
    565     }
    566 
    567     private static String getArrayAsString(Object array) {
    568         // We are guaranteed that supplied object is a String
    569 
    570         String ret = new String();
    571 
    572         for (int i = 0; i < Array.getLength(array); i++) {
     461        if (prim == Integer.TYPE) {
     462            return (int)val;
     463        } else if (prim == Long.TYPE) {
     464            return (long)val;
     465        } else if (prim == Short.TYPE) {
     466            return (short)val;
     467        } else if (prim == Float.TYPE) {
     468            return (float)val;
     469        } else if (prim == Double.TYPE) {
     470            return val;
     471        } else if (prim == Byte.TYPE) {
     472            return (byte)val;
     473        } else if (prim == Character.TYPE) {
     474            return (char)(short)val;
     475        }
     476        return val;
     477    }
     478
     479    private static Object stringAsPrimitiveType(String s, Class<?> c)
     480            throws NumberFormatException {
     481        double val = Double.parseDouble(s);
     482        return toBoxedPrimitiveType(val, c);
     483
     484    }
     485
     486    // Test whether we can get from 'args' to 'testArgs' only by using widening conversions,
     487    // eg String -> Object
     488    private static boolean argumentsAreSubclassesOf(Object[] args, Object[] testArgs) {
     489        for (int i = 0; i < args.length; i++) {
     490            if (!testArgs[i].getClass().isAssignableFrom(args[i].getClass())) {
     491                return false;
     492            }
     493        }
     494        return true;
     495    }
     496
     497    static Class<?>[] getParameterTypesFor(java.lang.reflect.AccessibleObject method) {
     498        if (method instanceof Method) {
     499            return ((Method)method).getParameterTypes();
     500        } else /*m instanceof Constructor*/ {
     501            return ((Constructor<?>)method).getParameterTypes();
     502        }
     503    }
     504
     505    private static String arrayToJavascriptStyleString(Object array) {
     506        int arrLength = Array.getLength(array);
     507
     508        StringBuilder sb = new StringBuilder();
     509
     510        for (int i = 0; i < arrLength; i++) {
    573511            Object element = Array.get(array, i);
    574512
    575513            if (element != null) {
    576514                if (element.getClass().isArray()) {
    577                     ret += getArrayAsString(element);
     515                    sb.append(arrayToJavascriptStyleString(element));
    578516                } else {
    579                     ret += element;
     517                    sb.append(element);
    580518                }
    581519            }
    582520
    583             ret += ",";
     521            sb.append(',');
    584522        }
    585523
    586524        // Trim the final ","
    587         if (ret.length() > 0) {
    588             ret = ret.substring(0, ret.length() - 1);
    589         }
    590 
    591         return ret;
     525        if (arrLength > 0) {
     526            sb.setLength(sb.length() - 1);
     527        }
     528
     529        return sb.toString();
    592530    }
    593531}
    594 
    595 /** Begin test classes **/
    596 
    597 class FooClass {
    598 
    599     public FooClass() {
    600     }
    601 
    602     public FooClass(Boolean b, int i) {
    603     }
    604 
    605     public FooClass(Boolean b, Integer i) {
    606     }
    607 
    608     public FooClass(Boolean b, short s) {
    609     }
    610 
    611     public FooClass(String s, int i) {
    612     }
    613 
    614     public FooClass(String s, Integer i) {
    615     }
    616 
    617     public FooClass(java.lang.Number num) {
    618     }
    619 
    620     public FooClass(java.lang.Integer integer) {
    621     }
    622 
    623     public FooClass(long l) {
    624     }
    625 
    626     public FooClass(double d) {
    627     }
    628 
    629     public FooClass(float f) {
    630     }
    631 
    632     public FooClass(JSObject j) {
    633     }
    634 
    635     public FooClass(BarClass1 b) {
    636     }
    637 
    638     public FooClass(BarClass2 b) {
    639     }
    640 
    641     public FooClass(String s) {
    642     }
    643 
    644     public FooClass(byte b) {
    645     }
    646 
    647     public FooClass(String s, Float f) {
    648     }
    649 
    650     public FooClass(int i) {
    651     }
    652 
    653     public void FooClass() {
    654     }
    655 
    656     public void FooClass(boolean b) {
    657     }
    658 
    659     public void foo(Boolean b, int i) {
    660     }
    661 
    662     public void foo(Boolean b, Integer i) {
    663     }
    664 
    665     public void foo(Boolean b, short s) {
    666     }
    667 
    668     public void foo_string_int(String s, int i) {
    669     }
    670 
    671     public void foo_string_int(String s, Integer i) {
    672     }
    673 
    674     public void foo_jsobj(JSObject j) {
    675     }
    676 
    677     public void foo_jsobj(String s) {
    678     }
    679 
    680     public void foo_classtype(java.lang.Number num) {
    681     }
    682 
    683     public void foo_classtype(java.lang.Integer integer) {
    684     }
    685 
    686     public void foo_multiprim(int i) {
    687     }
    688 
    689     public void foo_multiprim(long l) {
    690     }
    691 
    692     public void foo_multiprim(float f) {
    693     }
    694 
    695     public void foo_multiprim(double d) {
    696     }
    697 
    698     public void foo_float(float f) {
    699     }
    700 
    701     public void foo_float(String s) {
    702     }
    703 
    704     public void foo_float(JSObject j) {
    705     }
    706 
    707     public void foo_class(BarClass1 b) {
    708     }
    709 
    710     public void foo_class(BarClass2 b) {
    711     }
    712 
    713     public void foo_strandbyteonly(String s) {
    714     }
    715 
    716     public void foo_strandbyteonly(byte b) {
    717     }
    718 
    719     public void foo_str_and_float(String s, Float f) {
    720     }
    721 
    722     public void foo_int_only(int i) {
    723     }
    724 
    725     public void foo_noargs() {
    726     }
    727 
    728     public void foo_boolonly(boolean b) {
    729     }
    730 }
    731 
    732 class BarClass1 {
    733 }
    734 
    735 class BarClass2 extends BarClass1 {
    736 }
    737 
    738 class BarClass3 extends BarClass2 {
    739 }
    740 
    741 class JSObject {
    742 }
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java

    r418 r429  
    5454import java.security.ProtectionDomain;
    5555import java.util.ArrayList;
     56import java.util.Arrays;
    5657import java.util.Hashtable;
    5758import java.util.List;
    5859import java.util.Map;
    5960
     61import net.sourceforge.jnlp.DefaultLaunchHandler;
    6062import net.sourceforge.jnlp.runtime.JNLPRuntime;
    61 import net.sourceforge.jnlp.DefaultLaunchHandler;
     63import net.sourceforge.jnlp.util.logging.OutputController;
     64import netscape.javascript.JSObject;
    6265import netscape.javascript.JSObjectCreatePermission;
     66import netscape.javascript.JSUtil;
    6367
    6468class Signature {
    6569    private String signature;
    6670    private int currentIndex;
    67     private List<Class> typeList;
     71    private List<Class<?>> typeList;
    6872    private static final char ARRAY = '[';
    6973    private static final char OBJECT = 'L';
     
    133137        this.signature = signature;
    134138        currentIndex = 0;
    135         typeList = new ArrayList<Class>(10);
     139        typeList = new ArrayList<Class<?>>(10);
    136140
    137141        String elem;
     
    139143            elem = nextTypeName();
    140144
    141             if (elem == null) // end of signature
     145            if (elem == null) {
    142146                continue;
    143 
    144             Class primitive = primitiveNameToType(elem);
    145             if (primitive != null)
     147            }
     148
     149            Class<?> primitive = primitiveNameToType(elem);
     150            if (primitive != null) {
    146151                typeList.add(primitive);
     152            }
    147153            else {
    148154                int dimsize = 0;
     
    161167                        typeList.add(Array.newInstance(primitive, dims)
    162168                                                                .getClass());
    163                     } else
     169                    } else {
    164170                        typeList.add(Array.newInstance(
    165171                                                                getClass(arrayType, cl), dims).getClass());
     172                    }
    166173                } else {
    167174                    typeList.add(getClass(elem, cl));
     
    175182    }
    176183
    177     public static Class getClass(String name, ClassLoader cl) {
    178 
    179         Class c = null;
     184    public static Class<?> getClass(String name, ClassLoader cl) {
     185
     186        Class<?> c = null;
    180187
    181188        try {
     
    194201    }
    195202
    196     public static Class primitiveNameToType(String name) {
    197         if (name.equals("void"))
     203    public static Class<?> primitiveNameToType(String name) {
     204        if (name.equals("void")) {
    198205            return Void.TYPE;
    199         else if (name.equals("boolean"))
     206        }
     207        else if (name.equals("boolean")) {
    200208            return Boolean.TYPE;
    201         else if (name.equals("byte"))
     209        }
     210        else if (name.equals("byte")) {
    202211            return Byte.TYPE;
    203         else if (name.equals("char"))
     212        }
     213        else if (name.equals("char")) {
    204214            return Character.TYPE;
    205         else if (name.equals("short"))
     215        }
     216        else if (name.equals("short")) {
    206217            return Short.TYPE;
    207         else if (name.equals("int"))
     218        }
     219        else if (name.equals("int")) {
    208220            return Integer.TYPE;
    209         else if (name.equals("long"))
     221        }
     222        else if (name.equals("long")) {
    210223            return Long.TYPE;
    211         else if (name.equals("float"))
     224        }
     225        else if (name.equals("float")) {
    212226            return Float.TYPE;
    213         else if (name.equals("double"))
     227        }
     228        else if (name.equals("double")) {
    214229            return Double.TYPE;
    215         else
     230        }
     231        else {
    216232            return null;
    217     }
    218 
    219     public Class[] getClassArray() {
    220         return typeList.subList(0, typeList.size()).toArray(new Class[] {});
     233        }
     234    }
     235
     236    public Class<?>[] getClassArray() {
     237        return typeList.subList(0, typeList.size()).toArray(new Class<?>[] {});
    221238    }
    222239}
     
    232249    int identifier = 0;
    233250
    234     public static PluginStreamHandler streamhandler;
     251    private static PluginStreamHandler streamhandler;
    235252
    236253    long startTime = 0;
    237254
    238     public PluginAppletSecurityContext(int identifier) {
     255    /* Package-private constructor that allows for bypassing security manager installation.
     256     * This is useful for testing. Note that while the public constructor should be used otherwise,
     257     * the security installation can't be bypassed if it has already occurred.*/
     258    PluginAppletSecurityContext(int identifier, boolean ensureSecurityContext) {
    239259        this.identifier = identifier;
    240260
    241         // We need a security manager.. and since there is a good chance that
    242         // an applet will be loaded at some point, we should make it the SM
    243         // that JNLPRuntime will try to install
    244         if (System.getSecurityManager() == null) {
    245             JNLPRuntime.initialize(/* isApplication */false);
    246             JNLPRuntime.setDefaultLaunchHandler(new DefaultLaunchHandler(System.err));
    247         }
    248 
    249         JNLPRuntime.disableExit();
     261        if (ensureSecurityContext) {
     262            // We need a security manager.. and since there is a good chance that
     263            // an applet will be loaded at some point, we should make it the SM
     264            // that JNLPRuntime will try to install
     265            if (System.getSecurityManager() == null) {
     266                JNLPRuntime.initialize(/* isApplication */false);
     267                JNLPRuntime.setDefaultLaunchHandler(new DefaultLaunchHandler(OutputController.getLogger()));
     268            }
     269
     270            JNLPRuntime.disableExit();
     271        }
    250272
    251273        URL u = null;
     
    253275            u = new URL("file://");
    254276        } catch (Exception e) {
    255             e.printStackTrace();
    256         }
    257 
    258         this.classLoaders.put(liveconnectLoader, u);
     277            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
     278        }
     279
     280        PluginAppletSecurityContext.classLoaders.put(liveconnectLoader, u);
     281    }
     282
     283    public PluginAppletSecurityContext(int identifier) {
     284        this(identifier, true);
    259285    }
    260286
    261287    private static <V> V parseCall(String s, ClassLoader cl, Class<V> c) {
    262         if (c == Integer.class)
     288        if (c == Integer.class) {
    263289            return c.cast(new Integer(s));
    264         else if (c == String.class)
    265             return c.cast(new String(s));
    266         else if (c == Signature.class)
     290        }
     291        else if (c == String.class) {
     292            return c.cast(s);
     293        }
     294        else if (c == Signature.class) {
    267295            return c.cast(new Signature(s, cl));
    268         else
     296        }
     297        else {
    269298            throw new RuntimeException("Unexpected call value.");
    270     }
    271 
    272     private Object parseArgs(String s, Class c) {
    273         if (c == Boolean.TYPE || c == Boolean.class)
    274             return new Boolean(s);
    275         else if (c == Byte.TYPE || c == Byte.class)
     299        }
     300    }
     301
     302    private Object parseArgs(String s, Class<?> c) {
     303        if (c == Boolean.TYPE || c == Boolean.class) {
     304            return Boolean.valueOf(s);
     305        }
     306        else if (c == Byte.TYPE || c == Byte.class) {
    276307            return new Byte(s);
     308        }
    277309        else if (c == Character.TYPE || c == Character.class) {
    278310            String[] bytes = s.split("_");
     
    281313            int full = ((high << 8) & 0x0ff00) | (low & 0x0ff);
    282314            return new Character((char) full);
    283         } else if (c == Short.TYPE || c == Short.class)
     315        } else if (c == Short.TYPE || c == Short.class) {
    284316            return new Short(s);
    285         else if (c == Integer.TYPE || c == Integer.class)
     317        }
     318        else if (c == Integer.TYPE || c == Integer.class) {
    286319            return new Integer(s);
    287         else if (c == Long.TYPE || c == Long.class)
     320        }
     321        else if (c == Long.TYPE || c == Long.class) {
    288322            return new Long(s);
    289         else if (c == Float.TYPE || c == Float.class)
     323        }
     324        else if (c == Float.TYPE || c == Float.class) {
    290325            return new Float(s);
    291         else if (c == Double.TYPE || c == Double.class)
     326        }
     327        else if (c == Double.TYPE || c == Double.class) {
    292328            return new Double(s);
    293         else
     329        }
     330        else {
    294331            return store.getObject(new Integer(s));
     332        }
    295333    }
    296334
    297335    public void associateSrc(ClassLoader cl, URL src) {
    298336        PluginDebug.debug("Associating ", cl, " with ", src);
    299         this.classLoaders.put(cl, src);
     337        PluginAppletSecurityContext.classLoaders.put(cl, src);
    300338    }
    301339
    302340    public void associateInstance(Integer i, ClassLoader cl) {
    303341        PluginDebug.debug("Associating ", cl, " with instance ", i);
    304         this.instanceClassLoaders.put(i, cl);
     342        PluginAppletSecurityContext.instanceClassLoaders.put(i, cl);
    305343    }
    306344
     
    309347    }
    310348
     349    public static PluginStreamHandler getStreamhandler() {
     350        return streamhandler;
     351    }   
     352
    311353    public static Map<String, String> getLoaderInfo() {
    312354        Hashtable<String, String> map = new Hashtable<String, String>();
     
    319361    }
    320362
     363    private static long privilegedJSObjectUnbox(final JSObject js) {
     364        return AccessController.doPrivileged(new PrivilegedAction<Long>() {
     365            @Override
     366            public Long run() { 
     367                return JSUtil.getJSObjectInternalReference(js);
     368            }
     369        });
     370    }
     371
     372    /**
     373     * Create a string that identifies a Java object precisely, for passing to
     374     * Javascript.
     375     *
     376     * For builtin value types, a 'literalreturn' prefix is used and the object
     377     * is passed with a string representation.
     378     *
     379     * For JSObject's, a 'jsobject' prefix is used and the object is passed
     380     * with the JSObject's internal identifier.
     381     *
     382     * For other Java objects, an object store reference is used.
     383     *
     384     * @param obj the object for which to create an identifier
     385     * @param type the type to use for representation decisions
     386     * @param unboxPrimitives whether to treat boxed primitives as value types
     387     * @return an identifier string
     388     */
     389    public String toObjectIDString(Object obj, Class<?> type, boolean unboxPrimitives) {
     390
     391        /* Void (can occur from declared return type), pass special "void" string: */
     392        if (type == Void.TYPE) {
     393            return "literalreturn void";
     394        }
     395
     396        /* Null, pass special "null" string: */
     397        if (obj == null) {
     398            return "literalreturn null";
     399        }
     400
     401        /* Primitive, accurately represented by its toString() form: */
     402        boolean returnAsString = ( type == Boolean.TYPE
     403                                || type == Byte.TYPE
     404                                || type == Short.TYPE
     405                                || type == Integer.TYPE
     406                                || type == Long.TYPE );
     407        if (unboxPrimitives) {
     408            returnAsString = ( returnAsString
     409                            || type == Boolean.class
     410                            || type == Byte.class
     411                            || type == Short.class
     412                            || type == Integer.class
     413                            || type == Long.class);
     414        }
     415        if (returnAsString) {
     416            return "literalreturn " + obj.toString();
     417        }
     418
     419        /* Floating point number, we ensure we give enough precision: */
     420        if ( type == Float.TYPE || type == Double.TYPE ||
     421                ( unboxPrimitives && (type == Float.class || type == Double.class) )) {
     422            return "literalreturn " + String.format("%308.308e", obj);
     423        }
     424
     425        /* Character that should be returned as number: */
     426        if (type == Character.TYPE || (unboxPrimitives && type == Character.class)) {
     427            return "literalreturn " + (int) (Character) obj;
     428        }
     429
     430        /* JSObject, unwrap underlying Javascript reference: */
     431        if (type == netscape.javascript.JSObject.class) {
     432            long reference = privilegedJSObjectUnbox((JSObject)obj);
     433            return "jsobject " + Long.toString(reference);
     434        }
     435
     436        /* Other kind of object, track this object and return our reference: */
     437        store.reference(obj);
     438        return store.getIdentifier(obj).toString();
     439    }
     440
    321441    public void handleMessage(int reference, String src, AccessControlContext callContext, String message) {
    322442
     
    325445        try {
    326446            if (message.startsWith("FindClass")) {
    327                 ClassLoader cl = null;
    328                 Class c = null;
     447                ClassLoader cl;
     448                Class<?> c;
    329449                cl = liveconnectLoader;
    330450                String[] args = message.split(" ");
     
    339459                } catch (ClassNotFoundException cnfe) {
    340460
    341                     cl = this.instanceClassLoaders.get(instance);
     461                    cl = PluginAppletSecurityContext.instanceClassLoaders.get(instance);
    342462                    PluginDebug.debug("Not found. Looking in ", cl);
    343463
     
    367487                if (message.startsWith("GetStaticMethodID") ||
    368488                                    methodName.equals("<init>") ||
    369                                     methodName.equals("<clinit>"))
    370                     c = (Class<?>) store.getObject(classID);
    371                 else
    372                     c = store.getObject(classID).getClass();
    373 
    374                 Method m = null;
    375                 Constructor cs = null;
    376                 Object o = null;
     489                                    methodName.equals("<clinit>")) {
     490                                                c = (Class<?>) store.getObject(classID);
     491                                            }
     492                else {
     493                                                c = store.getObject(classID).getClass();
     494                                            }
     495
     496                Method m;
     497                Constructor<?> cs;
     498                Object o;
    377499                if (methodName.equals("<init>")
    378500                                                || methodName.equals("<clinit>")) {
     
    396518                PluginDebug.debug("GetStaticFieldID/GetFieldID got class=", c.getName());
    397519
    398                 Field f = null;
     520                Field f;
    399521                f = c.getField(fieldName);
    400522
     
    415537
    416538                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     539                    @Override
    417540                    public Object run() {
    418541                        try {
     
    424547                }, acc);
    425548
    426                 if (ret instanceof Throwable)
     549                if (ret instanceof Throwable) {
    427550                    throw (Throwable) ret;
    428 
    429                 if (ret == null) {
    430                     write(reference, "GetStaticField literalreturn null");
    431                 } else if (f.getType() == Boolean.TYPE
    432                         || f.getType() == Byte.TYPE
    433                         || f.getType() == Short.TYPE
    434                         || f.getType() == Integer.TYPE
    435                         || f.getType() == Long.TYPE) {
    436                     write(reference, "GetStaticField literalreturn " + ret);
    437                 } else if (f.getType() == Float.TYPE
    438                                 || f.getType() == Double.TYPE) {
    439                     write(reference, "GetStaticField literalreturn " + String.format("%308.308e", ret));
    440                 } else if (f.getType() == Character.TYPE) {
    441                     write(reference, "GetStaticField literalreturn " + (int) (Character) ret);
    442                 } else {
    443                     // Track returned object.
    444                     store.reference(ret);
    445                     write(reference, "GetStaticField " + store.getIdentifier(ret));
    446                 }
     551                }
     552
     553                String objIDStr = toObjectIDString(ret, f.getType(), false /*do not unbox primitives*/);
     554                write(reference, "GetStaticField " + objIDStr);
    447555            } else if (message.startsWith("GetValue")) {
    448556                String[] args = message.split(" ");
     
    450558
    451559                Object ret = store.getObject(index);
    452 
    453                 if (ret == null) {
    454                     write(reference, "GetValue literalreturn null");
    455                 } else if (ret.getClass() == Boolean.TYPE
    456                         || ret.getClass() == Boolean.class
    457                         || ret.getClass() == Byte.TYPE
    458                         || ret.getClass() == Byte.class
    459                         || ret.getClass() == Short.TYPE
    460                         || ret.getClass() == Short.class
    461                         || ret.getClass() == Integer.TYPE
    462                         || ret.getClass() == Integer.class
    463                         || ret.getClass() == Long.TYPE
    464                         || ret.getClass() == Long.class) {
    465                     write(reference, "GetValue literalreturn " + ret);
    466                 } else if (ret.getClass() == Float.TYPE
    467                         || ret.getClass() == Float.class
    468                         || ret.getClass() == Double.TYPE
    469                         || ret.getClass() == Double.class) {
    470                     write(reference, "GetValue literalreturn " + String.format("%308.308e", ret));
    471                 } else if (ret.getClass() == Character.TYPE
    472                         || ret.getClass() == Character.class) {
    473                     write(reference, "GetValue literalreturn " + (int) (Character) ret);
    474                 } else {
    475                     // Track returned object.
    476                     store.reference(ret);
    477                     write(reference, "GetValue " + store.getIdentifier(ret));
    478                 }
     560                Class<?> retClass = ret != null ? ret.getClass() : null;
     561
     562                String objIDStr = toObjectIDString(ret, retClass, true /*unbox primitives*/);
     563                write(reference, "GetValue " + objIDStr);
    479564            } else if (message.startsWith("SetStaticField") ||
    480565                                   message.startsWith("SetField")) {
     
    487572                final Field f = (Field) store.getObject(fieldID);
    488573
    489                 final Object fValue = MethodOverloadResolver.getCostAndCastedObject(value, f.getType())[1];
     574                final Object fValue = MethodOverloadResolver.getCostAndCastedObject(value, f.getType()).getCastedObject();
    490575
    491576                AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
    492                 checkPermission(src,
    493                                                 message.startsWith("SetStaticField") ? (Class) o : o.getClass(),
    494                                                 acc);
     577                checkPermission(src, message.startsWith("SetStaticField") ? (Class) o : o.getClass(), acc);
    495578
    496579                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     580                    @Override
    497581                    public Object run() {
    498582                        try {
     
    506590                }, acc);
    507591
    508                 if (ret instanceof Throwable)
     592                if (ret instanceof Throwable) {
    509593                    throw (Throwable) ret;
     594                }
    510595
    511596                write(reference, "SetField");
     
    515600                Integer index = parseCall(args[2], null, Integer.class);
    516601
    517                 Object ret = Array.get(store.getObject(arrayID), index);
    518                 Class retClass = store.getObject(arrayID).getClass().getComponentType(); // prevent auto-boxing influence
    519 
    520                 if (ret == null) {
    521                     write(reference, "GetObjectArrayElement literalreturn null");
    522                 } else if (retClass == Boolean.TYPE
    523                         || retClass == Byte.TYPE
    524                         || retClass == Short.TYPE
    525                         || retClass == Integer.TYPE
    526                         || retClass == Long.TYPE) {
    527                     write(reference, "GetObjectArrayElement literalreturn " + ret);
    528                 } else if (retClass == Float.TYPE
    529                                 || retClass == Double.TYPE) {
    530                     write(reference, "GetObjectArrayElement literalreturn " + String.format("%308.308e", ret));
    531                 } else if (retClass == Character.TYPE) {
    532                     write(reference, "GetObjectArrayElement literalreturn " + (int) (Character) ret);
    533                 } else {
    534                     // Track returned object.
    535                     store.reference(ret);
    536                     write(reference, "GetObjectArrayElement " + store.getIdentifier(ret));
    537                 }
     602                Object array = store.getObject(arrayID);
     603                Object ret = Array.get(array, index);
     604                Class<?> retClass = array.getClass().getComponentType(); // prevent auto-boxing influence
     605
     606                String objIDStr = toObjectIDString(ret, retClass, false /*do not unbox primitives*/);
     607                write(reference, "GetObjectArrayElement " + objIDStr);
    538608
    539609            } else if (message.startsWith("SetObjectArrayElement")) {
     
    546616
    547617                // Cast the object to appropriate type before insertion
    548                 value = MethodOverloadResolver.getCostAndCastedObject(value, store.getObject(arrayID).getClass().getComponentType())[1];
     618                value = MethodOverloadResolver.getCostAndCastedObject(value, store.getObject(arrayID).getClass().getComponentType()).getCastedObject();
    549619
    550620                Array.set(store.getObject(arrayID), index, value);
     
    573643
    574644                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     645                    @Override
    575646                    public Object run() {
    576647                        try {
     
    582653                }, acc);
    583654
    584                 if (ret instanceof Throwable)
     655                if (ret instanceof Throwable) {
    585656                    throw (Throwable) ret;
    586 
    587                 if (ret == null) {
    588                     write(reference, "GetField literalreturn null");
    589                 } else if (f.getType() == Boolean.TYPE
    590                         || f.getType() == Byte.TYPE
    591                         || f.getType() == Short.TYPE
    592                         || f.getType() == Integer.TYPE
    593                         || f.getType() == Long.TYPE) {
    594                     write(reference, "GetField literalreturn " + ret);
    595                 } else if (f.getType() == Float.TYPE
    596                                 || f.getType() == Double.TYPE) {
    597                     write(reference, "GetField literalreturn " + String.format("%308.308e", ret));
    598                 } else if (f.getType() == Character.TYPE) {
    599                     write(reference, "GetField literalreturn " + (int) (Character) ret);
    600                 } else {
    601                     // Track returned object.
    602                     store.reference(ret);
    603                     write(reference, "GetField " + store.getIdentifier(ret));
    604                 }
    605 
     657                }
     658
     659                String objIDStr = toObjectIDString(ret, f.getType(), false /*do not unbox primitives*/);
     660                write(reference, "GetField " + objIDStr);
    606661            } else if (message.startsWith("GetObjectClass")) {
    607662                int oid = Integer.parseInt(message.substring("GetObjectClass"
     
    626681                }
    627682
    628                 // length -3 to discard first 3, + 2 for holding object
    629                 // and method name
    630                 Object[] arguments = new Object[args.length - 1];
    631                 arguments[0] = c;
    632                 arguments[1] = methodName;
    633                 for (int i = 0; i < args.length - 3; i++) {
    634                     arguments[i + 2] = store.getObject(parseCall(args[3 + i], null, Integer.class));
    635                     PluginDebug.debug("GOT ARG: ", arguments[i + 2]);
    636                 }
    637 
    638                 Object[] matchingMethodAndArgs = MethodOverloadResolver.getMatchingMethod(arguments);
    639 
    640                 if (matchingMethodAndArgs == null) {
     683                // Discard first 3 parts of message
     684                Object[] arguments = new Object[args.length - 3];
     685                for (int i = 0; i < arguments.length; i++) {
     686                    arguments[i] = store.getObject(parseCall(args[3 + i], null, Integer.class));
     687                    PluginDebug.debug("GOT ARG: ", arguments[i]);
     688                }
     689
     690                MethodOverloadResolver.ResolvedMethod rm =
     691                        MethodOverloadResolver.getBestMatchMethod(c, methodName, arguments);
     692
     693                if (rm == null) {
    641694                    write(reference, "Error: No suitable method named " + methodName + " with matching args found");
    642695                    return;
    643696                }
    644697
    645                 final Method m = (Method) matchingMethodAndArgs[0];
    646                 Object[] castedArgs = new Object[matchingMethodAndArgs.length - 1];
    647                 for (int i = 0; i < castedArgs.length; i++) {
    648                     castedArgs[i] = matchingMethodAndArgs[i + 1];
    649                 }
    650 
    651                 String collapsedArgs = "";
    652                 for (Object arg : castedArgs) {
    653                     collapsedArgs += " " + arg;
    654                 }
     698                final Method m = rm.getMethod();
     699                final Object[] castedArgs = rm.getCastedParameters();
    655700
    656701                PluginDebug.debug("Calling method ", m, " on object ", o
    657                                                 , " (", c, ") with ", collapsedArgs);
     702                                                , " (", c, ") with ", Arrays.toString(castedArgs));
    658703
    659704                AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
     
    666711                m.setAccessible(true);
    667712                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     713                    @Override
    668714                    public Object run() {
    669715                        try {
     
    675721                }, acc);
    676722
    677                 if (ret instanceof Throwable)
     723                if (ret instanceof Throwable) {
    678724                    throw (Throwable) ret;
     725                 }
    679726
    680727                String retO;
     
    685732                }
    686733
    687                 PluginDebug.debug("Calling ", m, " on ", o, " with "
    688                                                 , collapsedArgs, " and that returned: ", ret
    689                                                 , " of type ", retO);
    690 
    691                 if (m.getReturnType().equals(java.lang.Void.class) ||
    692                                     m.getReturnType().equals(java.lang.Void.TYPE)) {
    693                     write(reference, "CallMethod literalreturn void");
    694                 } else if (ret == null) {
    695                     write(reference, "CallMethod literalreturn null");
    696                 } else if (m.getReturnType() == Boolean.TYPE
    697                                                 || m.getReturnType() == Byte.TYPE
    698                                                 || m.getReturnType() == Short.TYPE
    699                                                 || m.getReturnType() == Integer.TYPE
    700                                                 || m.getReturnType() == Long.TYPE) {
    701                     write(reference, "CallMethod literalreturn " + ret);
    702                 } else if (m.getReturnType() == Float.TYPE
    703                                 || m.getReturnType() == Double.TYPE) {
    704                     write(reference, "CallMethod literalreturn " + String.format("%308.308e", ret));
    705                 } else if (m.getReturnType() == Character.TYPE) {
    706                     write(reference, "CallMethod literalreturn " + (int) (Character) ret);
    707                 } else {
    708                     // Track returned object.
    709                     store.reference(ret);
    710                     write(reference, "CallMethod " + store.getIdentifier(ret));
    711                 }
     734                PluginDebug.debug("Calling ", m, " on ", o, " with ",
     735                        Arrays.toString(castedArgs), " and that returned: ", ret,
     736                        " of type ", retO);
     737
     738                String objIDStr = toObjectIDString(ret, m.getReturnType(), false /*do not unbox primitives*/);
     739                write(reference, "CallMethod " + objIDStr);
    712740            } else if (message.startsWith("GetSuperclass")) {
    713741                String[] args = message.split(" ");
    714742                Integer classID = parseCall(args[1], null, Integer.class);
    715                 Class<?> c = null;
    716                 Class<?> ret = null;
     743                Class<?> c;
     744                Class<?> ret;
    717745
    718746                c = (Class) store.getObject(classID);
     
    749777                Integer stringID = parseCall(args[1], null, Integer.class);
    750778
    751                 String o = null;
     779                String o;
    752780                byte[] b = null;
    753781                o = (String) store.getObject(stringID);
     
    759787                Integer stringID = parseCall(args[1], null, Integer.class);
    760788
    761                 String o = null;
     789                String o;
    762790                byte[] b = null;
    763791                o = (String) store.getObject(stringID);
     
    769797                Integer stringID = parseCall(args[1], null, Integer.class);
    770798
    771                 String o = null;
     799                String o;
    772800                byte[] b = null;
    773801                StringBuffer buf = null;
     
    776804                buf = new StringBuffer(b.length * 2);
    777805                buf.append(b.length);
    778                 for (int i = 0; i < b.length; i++)
    779                     buf
    780                                                         .append(" "
    781                                                                         + Integer
    782                                                                                         .toString(((int) b[i]) & 0x0ff, 16));
     806                for (int i = 0; i < b.length; i++) {
     807                    buf.append(" " + Integer.toString(((int) b[i]) & 0x0ff, 16));
     808                }
    783809
    784810                write(reference, "GetStringUTFChars " + buf);
     
    787813                Integer stringID = parseCall(args[1], null, Integer.class);
    788814
    789                 String o = null;
     815                String o;
    790816                byte[] b = null;
    791817                StringBuffer buf = null;
     
    795821                buf = new StringBuffer(b.length * 2);
    796822                buf.append(b.length);
    797                 for (int i = 0; i < b.length; i++)
    798                     buf
    799                                                         .append(" "
    800                                                                         + Integer
    801                                                                                         .toString(((int) b[i]) & 0x0ff, 16));
     823                for (int i = 0; i < b.length; i++) {
     824                    buf.append(" " + Integer.toString(((int) b[i]) & 0x0ff, 16));
     825                }
    802826
    803827                PluginDebug.debug("Java: GetStringChars: ", o);
     
    808832                Integer objectID = parseCall(args[1], null, Integer.class);
    809833
    810                 String o = null;
     834                String o;
    811835                byte[] b = null;
    812836                StringBuffer buf = null;
     
    815839                buf = new StringBuffer(b.length * 2);
    816840                buf.append(b.length);
    817                 for (int i = 0; i < b.length; i++)
    818                     buf
    819                             .append(" "
    820                                     + Integer
    821                                             .toString(((int) b[i]) & 0x0ff, 16));
     841                for (int i = 0; i < b.length; i++) {
     842                    buf.append(" " + Integer.toString(((int) b[i]) & 0x0ff, 16));
     843                }
    822844
    823845                write(reference, "GetToStringValue " + buf);
     
    827849                Integer length = parseCall(args[2], null, Integer.class);
    828850
    829                 Object newArray = null;
    830 
    831                 Class c;
     851                Object newArray;
     852
     853                Class<?> c;
    832854                if (type.equals("bool")) {
    833855                    c = Boolean.class;
     
    844866                }
    845867
    846                 if (args.length > 3)
     868                if (args.length > 3) {
    847869                    newArray = Array.newInstance(c, new int[] { length, parseCall(args[3], null, Integer.class) });
    848                 else
     870                }
     871                else {
    849872                    newArray = Array.newInstance(c, length);
     873                }
    850874
    851875                store.reference(newArray);
     
    856880                Integer methodNameID = parseCall(args[2], null, Integer.class);
    857881
    858                 Class c = (Class<?>) store.getObject(classNameID);
     882                Class<?> c = (Class<?>) store.getObject(classNameID);
    859883                String methodName = (String) store.getObject(methodNameID);
    860884
     
    887911                Integer fieldNameID = parseCall(args[2], null, Integer.class);
    888912
    889                 Class c = (Class) store.getObject(classNameID);
     913                Class<?> c = (Class<?>) store.getObject(classNameID);
    890914                String fieldName = (String) store.getObject(fieldNameID);
    891915
     
    908932                Integer objectID = parseCall(args[3], null, Integer.class);
    909933
    910                 Object newArray = null;
     934                Object newArray;
    911935                newArray = Array.newInstance((Class) store.getObject(classID),
    912936                                                length);
    913937
    914938                Object[] array = (Object[]) newArray;
    915                 for (int i = 0; i < array.length; i++)
     939                for (int i = 0; i < array.length; i++) {
    916940                    array[i] = store.getObject(objectID);
     941                }
    917942                store.reference(newArray);
    918943                write(reference, "NewObjectArray "
     
    924949                Integer methodID = parseCall(args[2], null, Integer.class);
    925950
    926                 final Constructor m = (Constructor) store.getObject(methodID);
     951                final Constructor<?> m = (Constructor<?>) store.getObject(methodID);
    927952                Class[] argTypes = m.getParameterTypes();
    928953
     
    935960                AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
    936961
    937                 Class c = (Class) store.getObject(classID);
     962                Class<?> c = (Class<?>) store.getObject(classID);
    938963                checkPermission(src, c, acc);
    939964
    940965                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     966                    @Override
    941967                    public Object run() {
    942968                        try {
     
    948974                }, acc);
    949975
    950                 if (ret instanceof Throwable)
     976                if (ret instanceof Throwable) {
    951977                    throw (Throwable) ret;
     978                }
    952979
    953980                store.reference(ret);
     
    958985                String[] args = message.split(" ");
    959986                Integer classID = parseCall(args[1], null, Integer.class);
    960                 Class c = (Class) store.getObject(classID);
    961                 final Constructor cons;
    962                 final Object[] fArguments;
    963 
    964                 Object[] arguments = new Object[args.length - 1];
    965                 arguments[0] = c;
    966                 for (int i = 0; i < args.length - 2; i++) {
    967                     arguments[i + 1] = store.getObject(parseCall(args[2 + i],
     987                Class<?> c = (Class<?>) store.getObject(classID);
     988
     989                // Discard first 2 parts of message
     990                Object[] arguments = new Object[args.length - 2];
     991                for (int i = 0; i < arguments.length; i++) {
     992                    arguments[i] = store.getObject(parseCall(args[2 + i],
    968993                            null, Integer.class));
    969                     PluginDebug.debug("GOT ARG: ", arguments[i + 1]);
    970                 }
    971 
    972                 Object[] matchingConstructorAndArgs = MethodOverloadResolver
    973                         .getMatchingConstructor(arguments);
    974 
    975                 if (matchingConstructorAndArgs == null) {
     994                    PluginDebug.debug("GOT ARG: ", arguments[i]);
     995                }
     996
     997                MethodOverloadResolver.ResolvedMethod resolvedConstructor =
     998                        MethodOverloadResolver.getBestMatchConstructor(c, arguments);
     999
     1000                if (resolvedConstructor == null) {
    9761001                    write(reference,
    9771002                            "Error: No suitable constructor with matching args found");
     
    9791004                }
    9801005
    981                 Object[] castedArgs = new Object[matchingConstructorAndArgs.length - 1];
    982                 for (int i = 0; i < castedArgs.length; i++) {
    983                     castedArgs[i] = matchingConstructorAndArgs[i + 1];
    984                 }
    985 
    986                 cons = (Constructor) matchingConstructorAndArgs[0];
    987                 fArguments = castedArgs;
    988 
    989                 String collapsedArgs = "";
    990                 for (Object arg : fArguments) {
    991                     collapsedArgs += " " + arg.toString();
    992                 }
     1006                final Constructor<?> cons = resolvedConstructor.getConstructor();
     1007                final Object[] castedArgs = resolvedConstructor.getCastedParameters();
    9931008
    9941009                PluginDebug.debug("Calling constructor on class ", c,
    995                                    " with ", collapsedArgs);
     1010                                   " with ", Arrays.toString(castedArgs));
    9961011
    9971012                AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
     
    9991014
    10001015                Object ret = AccessController.doPrivileged(new PrivilegedAction<Object>() {
     1016                    @Override
    10011017                    public Object run() {
    10021018                        try {
    1003                             return cons.newInstance(fArguments);
     1019                            return cons.newInstance(castedArgs);
    10041020                        } catch (Throwable t) {
    10051021                            return t;
     
    10081024                }, acc);
    10091025
    1010                 if (ret instanceof Throwable)
     1026                if (ret instanceof Throwable) {
    10111027                    throw (Throwable) ret;
     1028                }
    10121029
    10131030                store.reference(ret);
     
    10401057                int bytelength = 2 * strlength;
    10411058                byte[] byteArray = new byte[bytelength];
    1042                 String ret = null;
     1059                String ret;
    10431060                for (int i = 0; i < strlength; i++) {
    10441061                    int c = parseCall(args[2 + i], null, Integer.class);
     
    10571074            } else if (message.startsWith("ExceptionOccurred")) {
    10581075                PluginDebug.debug("EXCEPTION: ", throwable);
    1059                 if (throwable != null)
     1076                if (throwable != null) {
    10601077                    store.reference(throwable);
     1078                }
    10611079                write(reference, "ExceptionOccurred "
    10621080                                                + store.getIdentifier(throwable));
    10631081            } else if (message.startsWith("ExceptionClear")) {
    1064                 if (throwable != null && store.contains(throwable))
     1082                if (throwable != null && store.contains(throwable)) {
    10651083                    store.unreference(store.getIdentifier(throwable));
     1084                }
    10661085                throwable = null;
    10671086                write(reference, "ExceptionClear");
     
    10931112            }
    10941113        } catch (Throwable t) {
    1095             t.printStackTrace();
     1114            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,t);
    10961115            String msg = t.getCause() != null ? t.getCause().getMessage() : t.getMessage();
    10971116
     
    11131132            // the exception we get here will always be an
    11141133            // "InvocationTargetException" due to the use of reflection above
    1115             if (message.startsWith("CallMethod") || message.startsWith("CallStaticMethod"))
     1134            if (message.startsWith("CallMethod") || message.startsWith("CallStaticMethod")) {
    11161135                throwable = t.getCause();
     1136            }
    11171137        }
    11181138
     
    11271147     * @throws AccessControlException If the script has insufficient permissions
    11281148     */
    1129     public void checkPermission(String jsSrc, Class target, AccessControlContext acc) throws AccessControlException {
     1149    public void checkPermission(String jsSrc, Class<?> target, AccessControlContext acc) throws AccessControlException {
    11301150        // NPRuntime does not allow cross-site calling. We therefore always
    11311151        // allow this, for the time being
     
    12101230        name = name.replace('/', '.');
    12111231        ClassLoader cl = liveconnectLoader;
    1212         Class c = null;
     1232        Class<?> c = null;
    12131233
    12141234        try {
     
    12171237        } catch (ClassNotFoundException cnfe) {
    12181238            // do nothing ... this should never happen
    1219             cnfe.printStackTrace();
     1239            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,cnfe);
    12201240        }
    12211241
     
    12291249        Class<?> c = (Class<?>) store.getObject(classID);
    12301250        Method m = null;
    1231         Constructor cs = null;
     1251        Constructor<?> cs = null;
    12321252
    12331253        try {
     
    12421262        } catch (NoSuchMethodException e) {
    12431263            // should never happen
    1244             e.printStackTrace();
     1264            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    12451265        }
    12461266
     
    12561276        } catch (SecurityException e) {
    12571277            // should never happen
    1258             e.printStackTrace();
     1278            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    12591279        } catch (NoSuchFieldException e) {
    12601280            // should never happen
    1261             e.printStackTrace();
     1281            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    12621282        }
    12631283
     
    13151335            }
    13161336
    1317             if (src.equals("[System]"))
     1337            if (src.equals("[System]")) {
    13181338                grantedPermissions.add(new JSObjectCreatePermission());
     1339            }
    13191340
    13201341        } else {
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java

    r418 r429  
    6363package sun.applet;
    6464
     65import static net.sourceforge.jnlp.runtime.Translator.R;
     66
    6567import java.applet.Applet;
    6668import java.applet.AppletContext;
    6769import java.applet.AudioClip;
     70import java.awt.BorderLayout;
     71import java.awt.Component;
    6872import java.awt.Dimension;
    6973import java.awt.Frame;
     
    7175import java.awt.Image;
    7276import java.awt.Insets;
    73 import java.awt.Toolkit;
    7477import java.awt.event.WindowAdapter;
    7578import java.awt.event.WindowEvent;
     
    7982import java.io.IOException;
    8083import java.io.InputStream;
    81 import java.io.PrintStream;
    82 import java.io.Reader;
    83 import java.io.StringReader;
    8484import java.io.UnsupportedEncodingException;
    85 import java.lang.reflect.InvocationTargetException;
    8685import java.net.SocketPermission;
    8786import java.net.URI;
    8887import java.net.URL;
     88import java.net.URLConnection;
    8989import java.security.AccessController;
    9090import java.security.AllPermission;
    9191import java.security.PrivilegedAction;
    92 import java.security.PrivilegedActionException;
    93 import java.security.PrivilegedExceptionAction;
    9492import java.util.Enumeration;
    9593import java.util.HashMap;
     
    9896import java.util.Map;
    9997import java.util.Vector;
    100 
    10198import java.util.concurrent.ConcurrentHashMap;
    10299import java.util.concurrent.ConcurrentMap;
    103100import java.util.concurrent.TimeUnit;
    104 
    105101import java.util.concurrent.locks.Condition;
    106102import java.util.concurrent.locks.ReentrantLock;
     
    108104import javax.swing.SwingUtilities;
    109105
     106import net.sourceforge.jnlp.LaunchException;
    110107import net.sourceforge.jnlp.NetxPanel;
     108import net.sourceforge.jnlp.PluginParameters;
    111109import net.sourceforge.jnlp.runtime.JNLPClassLoader;
     110import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel;
     111import net.sourceforge.jnlp.security.appletextendedsecurity.AppletStartupSecuritySettings;
     112import net.sourceforge.jnlp.splashscreen.SplashController;
     113import net.sourceforge.jnlp.splashscreen.SplashPanel;
     114import net.sourceforge.jnlp.splashscreen.SplashUtils;
    112115import sun.awt.AppContext;
    113116import sun.awt.SunToolkit;
     
    115118
    116119import com.sun.jndi.toolkit.url.UrlUtil;
    117 
    118 /**
    119  * Lets us construct one using unix-style one shot behaviors
    120  */
    121 
    122 class PluginAppletPanelFactory {
    123 
    124     public AppletPanel createPanel(PluginStreamHandler streamhandler,
    125                                    final int identifier,
    126                                    final long handle, int x, int y,
    127                                    final URL doc,
    128                                    final Hashtable<String, String> atts) {
    129         final NetxPanel panel = AccessController.doPrivileged(new PrivilegedAction<NetxPanel>() {
    130             public NetxPanel run() {
    131                 NetxPanel panel = new NetxPanel(doc, atts, false);
    132                 NetxPanel.debug("Using NetX panel");
    133                 PluginDebug.debug(atts.toString());
    134                 return panel;
    135             }
    136         });
    137 
    138         // Framing the panel needs to happen in a thread whose thread group
    139         // is the same as the threadgroup of the applet thread. If this
    140         // isn't the case, the awt eventqueue thread's context classloader
    141         // won't be set to a JNLPClassLoader, and when an applet class needs
    142         // to be loaded from the awt eventqueue, it won't be found.
    143         Thread panelInit = new Thread(panel.getThreadGroup(), new Runnable() {
    144             @Override public void run() {
    145                 panel.createNewAppContext();
    146                 // create the frame.
    147                 PluginAppletViewer.framePanel(identifier, handle, panel);
    148                 panel.init();
    149                 // Start the applet
    150                 initEventQueue(panel);
    151             }
    152         }, "NetXPanel initializer");
    153 
    154         panelInit.start();
    155         while(panelInit.isAlive()) {
    156             try {
    157                 panelInit.join();
    158             } catch (InterruptedException e) {
    159             }
    160         }
    161 
    162         // Wait for the panel to initialize
    163         PluginAppletViewer.waitForAppletInit(panel);
    164 
    165         Applet a = panel.getApplet();
    166 
    167         // Still null?
    168         if (a == null) {
    169             streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError: " + "Initialization timed out");
    170             return null;
    171         }
    172 
    173         PluginDebug.debug("Applet ", a.getClass(), " initialized");
    174         streamhandler.write("instance " + identifier + " reference 0 initialized");
    175 
    176         /* AppletViewerPanel sometimes doesn't set size right initially. This
    177          * causes the parent frame to be the default (10x10) size.
    178          * 
    179          * Normally it goes unnoticed since browsers like Firefox make a resize
    180          * call after init. However some browsers (e.g. Midori) don't.
    181          *
    182          * We therefore manually set the parent to the right size.
    183          */
    184         try {
    185             SwingUtilities.invokeAndWait(new Runnable() {
    186                 public void run() {
    187                     panel.getParent().setSize(Integer.valueOf(atts.get("width")), Integer.valueOf(atts.get("height")));
    188                 }
    189             });
    190         } catch (InvocationTargetException ite) {
    191             // Not being able to resize is non-fatal
    192             PluginDebug.debug("Unable to resize panel: ");
    193             ite.printStackTrace();
    194         } catch (InterruptedException ie) {
    195             // Not being able to resize is non-fatal
    196             PluginDebug.debug("Unable to resize panel: ");
    197             ie.printStackTrace();
    198         }
    199 
    200         AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc);
    201         AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader());
    202 
    203         return panel;
    204     }
    205 
    206     public boolean isStandalone() {
    207         return false;
    208     }
    209 
    210     /**
    211      * Send the initial set of events to the appletviewer event queue.
    212      * On start-up the current behaviour is to load the applet and call
    213      * Applet.init() and Applet.start().
    214      */
    215     private void initEventQueue(AppletPanel panel) {
    216         // appletviewer.send.event is an undocumented and unsupported system
    217         // property which is used exclusively for testing purposes.
    218         PrivilegedAction<String> pa = new PrivilegedAction<String>() {
    219             public String run() {
    220                 return System.getProperty("appletviewer.send.event");
    221             }
    222         };
    223         String eventList = AccessController.doPrivileged(pa);
    224 
    225         if (eventList == null) {
    226             // Add the standard events onto the event queue.
    227             panel.sendEvent(AppletPanel.APPLET_LOAD);
    228             panel.sendEvent(AppletPanel.APPLET_INIT);
    229             panel.sendEvent(AppletPanel.APPLET_START);
    230         } else {
    231             // We're testing AppletViewer.  Force the specified set of events
    232             // onto the event queue, wait for the events to be processed, and
    233             // exit.
    234 
    235             // The list of events that will be executed is provided as a
    236             // ","-separated list.  No error-checking will be done on the list.
    237             String[] events = eventList.split(",");
    238 
    239             for (String event : events) {
    240                 PluginDebug.debug("Adding event to queue: ", event);
    241                 if ("dispose".equals(event))
    242                     panel.sendEvent(AppletPanel.APPLET_DISPOSE);
    243                 else if ("load".equals(event))
    244                     panel.sendEvent(AppletPanel.APPLET_LOAD);
    245                 else if ("init".equals(event))
    246                     panel.sendEvent(AppletPanel.APPLET_INIT);
    247                 else if ("start".equals(event))
    248                     panel.sendEvent(AppletPanel.APPLET_START);
    249                 else if ("stop".equals(event))
    250                     panel.sendEvent(AppletPanel.APPLET_STOP);
    251                 else if ("destroy".equals(event))
    252                     panel.sendEvent(AppletPanel.APPLET_DESTROY);
    253                 else if ("quit".equals(event))
    254                     panel.sendEvent(AppletPanel.APPLET_QUIT);
    255                 else if ("error".equals(event))
    256                     panel.sendEvent(AppletPanel.APPLET_ERROR);
    257                 else
    258                     // non-fatal error if we get an unrecognized event
    259                     PluginDebug.debug("Unrecognized event name: ", event);
    260             }
    261 
    262             while (!panel.emptyEventQueue())
    263                 ;
    264         }
    265     }
    266 }
     120import net.sourceforge.jnlp.runtime.JNLPRuntime;
     121import net.sourceforge.jnlp.util.logging.OutputController;
    267122
    268123/*
     
    271126@SuppressWarnings("serial")
    272127public class PluginAppletViewer extends PluginAppletViewerBase
    273         implements AppletContext, Printable {
     128        implements AppletContext, Printable, SplashController {
    274129
    275130    /**
     
    323178    private Graphics bufFrameImgGraphics;
    324179
     180
     181    private SplashPanel splashPanel;
     182   
     183    private static long REQUEST_TIMEOUT=60000;//60s
     184
     185    private static void waitForRequestCompletion(PluginCallRequest request) {
     186        try {
     187            if (!request.isDone()) {
     188                request.wait(REQUEST_TIMEOUT);
     189            }
     190            if (!request.isDone()) {
     191                // Do not wait indefinitely to avoid the potential of deadlock
     192                throw new RuntimeException("Possible deadlock, releasing");
     193            }
     194        } catch (InterruptedException ex) {
     195            throw new RuntimeException("Interrupted waiting for call request.", ex);
     196        }
     197    }
     198
    325199    /**
    326200     * Null constructor to allow instantiation via newInstance()
     
    329203    }
    330204
    331     public static void framePanel(int identifier, long handle, NetxPanel panel) {
     205    public static PluginAppletViewer framePanel(int identifier, long handle, int width, int height, NetxPanel panel) {
    332206
    333207        PluginDebug.debug("Framing ", panel);
    334 
    335         // SecurityManager MUST be set, and only privileged code may call reFrame()
     208 
     209        // SecurityManager MUST be set, and only privileged code may call framePanel()
    336210        System.getSecurityManager().checkPermission(new AllPermission());
    337211
    338212        PluginAppletViewer appletFrame = new PluginAppletViewer(handle, identifier, panel);
    339 
    340         appletFrame.add("Center", panel);
    341         appletFrame.pack();
    342 
     213        appletFrame.setSize(width, height);
     214       
    343215        appletFrame.appletEventListener = new AppletEventListener(appletFrame, appletFrame);
    344216        panel.addAppletListener(appletFrame.appletEventListener);
     217         // Clear references, if any
     218        if (applets.containsKey(identifier)) {
     219            PluginAppletViewer oldFrame = applets.get(identifier);           
     220            oldFrame.remove(panel);
     221            panel.removeAppletListener(oldFrame.appletEventListener);
     222        }
    345223
    346224        appletsLock.lock();
     
    350228
    351229        PluginDebug.debug(panel, " framed");
     230        return appletFrame;
    352231    }
    353232
     
    369248        windowEventListener = new WindowAdapter() {
    370249
     250            @Override
    371251            public void windowClosing(WindowEvent evt) {
    372252                destroyApplet(identifier);
    373253            }
    374254
     255            @Override
    375256            public void windowIconified(WindowEvent evt) {
    376257                appletStop();
    377258            }
    378259
     260            @Override
    379261            public void windowDeiconified(WindowEvent evt) {
    380262                appletStart();
     
    383265
    384266        addWindowListener(windowEventListener);
    385 
     267        final AppletPanel fPanel = panel;
     268        try {
     269            SwingUtilities.invokeAndWait(new SplashCreator(fPanel));
     270        } catch (Exception e) {
     271            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); // Not much we can do other than  print
     272        }
     273
     274    }
     275
     276    @Override
     277    public void replaceSplash(final SplashPanel newSplash) {
     278        if (splashPanel == null) {
     279            return;
     280        }
     281        if (newSplash == null) {
     282            removeSplash();
     283            return;
     284        }
     285        try {
     286            SwingUtilities.invokeAndWait(new Runnable() {
     287
     288                @Override
     289                public void run() {
     290                    splashPanel.getSplashComponent().setVisible(false);
     291                    splashPanel.stopAnimation();
     292                    remove(splashPanel.getSplashComponent());
     293                    newSplash.setPercentage(splashPanel.getPercentage());
     294                    newSplash.setSplashWidth(splashPanel.getSplashWidth());
     295                    newSplash.setSplashHeight(splashPanel.getSplashHeight());
     296                    newSplash.adjustForSize();
     297                    splashPanel = newSplash;
     298                    add("Center", splashPanel.getSplashComponent());
     299                    pack();
     300                }
     301            });
     302        } catch (Exception e) {
     303            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); // Not much we can do other than print
     304        }
     305    }
     306
     307    @Override
     308    public void removeSplash() {
     309        if (splashPanel == null) {
     310            return;
     311        }
     312        try {
     313            SwingUtilities.invokeAndWait(new Runnable() {
     314
     315                @Override
     316                public void run() {
     317                    splashPanel.getSplashComponent().setVisible(false);
     318                    splashPanel.stopAnimation();
     319                    removeAll();
     320                    setLayout(new BorderLayout());
     321                    //remove(splashPanel.getSplashComponent());
     322                    splashPanel = null;
     323                    //remove(panel);
     324                    // Re-add the applet to notify container
     325                    add(panel);
     326                    panel.setVisible(true);
     327                    pack();
     328                }
     329            });
     330        } catch (Exception e) {
     331            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e); // Not much we can do other than print
     332        }
     333    }
     334
     335    @Override
     336    public int getSplashWidth() {
     337        if (splashPanel != null) {
     338            return splashPanel.getSplashWidth();
     339        } else {
     340            return -1;
     341        }
     342    }
     343
     344    @Override
     345    public int getSplashHeigth() {
     346        if (splashPanel != null) {
     347            return splashPanel.getSplashHeight();
     348        } else {
     349            return -1;
     350        }
    386351    }
    387352
     
    395360        }
    396361
     362        @Override
    397363        public void appletStateChanged(AppletEvent evt) {
    398364            AppletPanel src = (AppletPanel) evt.getSource();
     
    401367            panelLive.signalAll();
    402368            panelLock.unlock();
    403 
    404369            switch (evt.getID()) {
    405370                case AppletPanel.APPLET_RESIZE: {
     
    427392                    // so we will have to rearrange it as well.
    428393                    //
    429                     if (a != null)
     394                    if (a != null) {
    430395                        AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
    431                     else
     396                    }
     397                    else {
    432398                        AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
     399                    }
    433400
    434401                    updateStatus(appletViewer.identifier, PAV_INIT_STATUS.INIT_COMPLETE);
    435402
     403                    break;
     404                }
     405                case AppletPanel.APPLET_START: {
     406                    if (src.status != AppletPanel.APPLET_INIT && src.status != AppletPanel.APPLET_STOP) {
     407                        String s="Applet started, but but reached invalid state";
     408                        PluginDebug.debug(s);
     409                        SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s));
     410                        appletViewer.replaceSplash(sp);
     411                    }
     412
     413                    break;
     414                }
     415                case AppletPanel.APPLET_ERROR: {
     416                    String s="Undefined error causing applet not to staart appeared";
     417                    PluginDebug.debug(s);
     418                        SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s));
     419                        appletViewer.replaceSplash(sp);
    436420                    break;
    437421                }
     
    448432    }
    449433
     434    private static void handleInitializationMessage(int identifier, String message) throws IOException, LaunchException {
     435
     436        /* The user has specified via a global setting that applets should not be run.*/
     437        if (AppletStartupSecuritySettings.getInstance().getSecurityLevel() == AppletSecurityLevel.DENY_ALL) {
     438            throw new LaunchException(null, null, R("LSFatal"), R("LCClient"), R("LUnsignedApplet"), R("LUnsignedAppletPolicyDenied"));
     439        }
     440
     441        // If there is a key for this status, it means it
     442        // was either initialized before, or destroy has been
     443        // processed. Stop moving further.
     444        if (updateStatus(identifier, PAV_INIT_STATUS.PRE_INIT) != null) {
     445            return;
     446        }
     447
     448        // Extract the information from the message
     449        String[] msgParts = new String[4];
     450        for (int i = 0; i < 3; i++) {
     451            int spaceLocation = message.indexOf(' ');
     452            int nextSpaceLocation = message.indexOf(' ', spaceLocation + 1);
     453            msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation);
     454            message = message.substring(nextSpaceLocation + 1);
     455        }
     456
     457        long handle = Long.parseLong(msgParts[0]);
     458        String width = msgParts[1];
     459        String height = msgParts[2];
     460
     461        int spaceLocation = message.indexOf(' ', "tag".length() + 1);
     462        String documentBase = message.substring("tag".length() + 1, spaceLocation);
     463        String paramString = message.substring(spaceLocation + 1);
     464
     465        PluginDebug.debug("Handle = ", handle, "\n",
     466                            "Width = ", width, "\n",
     467                            "Height = ", height, "\n",
     468                            "DocumentBase = ", documentBase, "\n",
     469                            "Params = ", paramString);
     470        JNLPRuntime.saveHistory(documentBase);
     471
     472        PluginAppletPanelFactory factory = new PluginAppletPanelFactory();
     473        AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
     474        URL url = new URL(documentBase);
     475        URLConnection conn = url.openConnection();
     476        /* The original URL may have been redirected - this
     477         * sets it to whatever URL/codebase we ended up getting
     478         */
     479        url = conn.getURL();
     480
     481        PluginParameters params = new PluginParameterParser().parse(width, height, paramString);
     482
     483        // Let user know we are starting up
     484        streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start"));
     485        factory.createPanel(streamhandler, identifier, handle, url, params);
     486
     487        long maxTimeToSleep = APPLET_TIMEOUT;
     488        appletsLock.lock();
     489        try {
     490            while (!applets.containsKey(identifier) &&
     491                    maxTimeToSleep > 0) { // Map is populated only by reFrame
     492                maxTimeToSleep -= waitTillTimeout(appletsLock, appletAdded,
     493                                                  maxTimeToSleep);
     494            }
     495        }
     496        finally {
     497            appletsLock.unlock();
     498        }
     499
     500        // If wait exceeded maxWait, we timed out. Throw an exception
     501        if (maxTimeToSleep <= 0)  {
     502            // Caught in handleMessage
     503            throw new RuntimeException("Applet initialization timeout");
     504        }
     505
     506        // We should not try to destroy an applet during
     507        // initialization. It may cause an inconsistent state,
     508        // which would bad if it's a trusted applet that
     509        // read/writes to files
     510        waitForAppletInit(applets.get(identifier).panel);
     511
     512        // Should we proceed with reframing?
     513         PluginDebug.debug("Init complete");
     514
     515        if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) {
     516            destroyApplet(identifier);
     517            return;
     518        }
     519    }
     520
    450521    /**
    451522     * Handle an incoming message from the plugin.
     
    457528        try {
    458529            if (message.startsWith("handle")) {
    459 
    460                 // If there is a key for this status, it means it
    461                 // was either initialized before, or destroy has been
    462                 // processed. Stop moving further.
    463                 if (updateStatus(identifier, PAV_INIT_STATUS.PRE_INIT) != null)
    464                     return;
    465 
    466                 // Extract the information from the message
    467                 String[] msgParts = new String[4];
    468                 for (int i = 0; i < 3; i++) {
    469                     int spaceLocation = message.indexOf(' ');
    470                     int nextSpaceLocation = message.indexOf(' ', spaceLocation + 1);
    471                     msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation);
    472                     message = message.substring(nextSpaceLocation + 1);
    473                 }
    474 
    475                 long handle = Long.parseLong(msgParts[0]);
    476                 String width = msgParts[1];
    477                 String height = msgParts[2];
    478 
    479                 int spaceLocation = message.indexOf(' ', "tag".length() + 1);
    480                 String documentBase =
    481                         UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation));
    482                 String tag = message.substring(spaceLocation + 1);
    483 
    484                 PluginDebug.debug("Handle = ", handle, "\n",
    485                                     "Width = ", width, "\n",
    486                                     "Height = ", height, "\n",
    487                                     "DocumentBase = ", documentBase, "\n",
    488                                     "Tag = ", tag);
    489 
    490                 PluginAppletViewer.parse
    491                                         (identifier, handle, width, height,
    492                                                 new StringReader(tag),
    493                                                 new URL(documentBase));
    494 
    495                 long maxTimeToSleep = APPLET_TIMEOUT;
    496                 appletsLock.lock();
    497                 try {
    498                     while (!applets.containsKey(identifier) &&
    499                             maxTimeToSleep > 0) { // Map is populated only by reFrame
    500                         maxTimeToSleep -= waitTillTimeout(appletsLock, appletAdded,
    501                                                           maxTimeToSleep);
    502                     }
    503                 }
    504                 finally {
    505                     appletsLock.unlock();
    506                 }
    507 
    508                 // If wait exceeded maxWait, we timed out. Throw an exception
    509                 if (maxTimeToSleep <= 0)
    510                     throw new Exception("Applet initialization timeout");
    511 
    512                 // We should not try to destroy an applet during
    513                 // initialization. It may cause an inconsistent state,
    514                 // which would bad if it's a trusted applet that
    515                 // read/writes to files
    516                 waitForAppletInit(applets.get(identifier).panel);
    517 
    518                 // Should we proceed with reframing?
    519                 if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) {
    520                     destroyApplet(identifier);
    521                     return;
    522                 }
    523 
     530                handleInitializationMessage(identifier, message);
    524531            } else if (message.startsWith("destroy")) {
    525532
     
    545552
    546553                // don't bother processing further for inactive applets
    547                 if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE))
     554                if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE)) {
    548555                    return;
     556                }
    549557
    550558                applets.get(identifier).handleMessage(reference, message);
     
    552560        } catch (Exception e) {
    553561
    554             e.printStackTrace();
     562            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    555563
    556564            // If an exception happened during pre-init, we need to update status
     
    612620    private static synchronized void destroyApplet(int identifier) {
    613621
     622        // We should not try to destroy an applet during
     623        // initialization. It may cause an inconsistent state.
     624        waitForAppletInit( applets.get(identifier).panel );
     625
    614626        PluginDebug.debug("DestroyApplet called for ", identifier);
    615627
     
    630642
    631643            // If panel is already disposed, return
    632             if (pav.panel.applet == null) {
     644            if (pav.panel.getApplet() == null) {
    633645                PluginDebug.debug(identifier, " panel inactive. Returning.");
    634646                return;
     
    638650
    639651            SwingUtilities.invokeLater(new Runnable() {
     652                @Override
    640653                public void run() {
    641654                    pav.appletClose();
     
    656669    public static void waitForAppletInit(NetxPanel panel) {
    657670
     671        PluginDebug.debug("Waiting for applet init");
     672
    658673        // Wait till initialization finishes
    659674        long maxTimeToSleep = APPLET_TIMEOUT;
     
    661676        panelLock.lock();
    662677        try {
    663             while (panel.getApplet() == null &&
    664                     panel.isAlive() &&
     678            while (!panel.isInitialized() &&
    665679                    maxTimeToSleep > 0) {
    666680                PluginDebug.debug("Waiting for applet panel ", panel, " to initialize...");
     
    675689    }
    676690
     691    /* Resizes an applet panel, waiting for the applet to initialze.
     692     * Should be done asynchronously to avoid the chance of deadlock. */
     693    private void resizeAppletPanel(final int width, final int height) {
     694        // Wait for panel to come alive
     695        waitForAppletInit(panel);
     696
     697        SwingUtilities.invokeLater(new Runnable() {
     698            @Override
     699            public void run() {
     700                panel.updateSizeInAtts(height, width);
     701
     702                setSize(width, height);
     703
     704                // There is a rather odd drawing bug whereby resizing
     705                // the panel makes no difference on initial call
     706                // because the panel thinks that it is already the
     707                // right size. Validation has no effect there either.
     708                // So we work around by setting size to 1, validating,
     709                // and then setting to the right size and validating
     710                // again. This is not very efficient, and there is
     711                // probably a better way -- but resizing happens
     712                // quite infrequently, so for now this is how we do it
     713
     714                panel.setSize(1, 1);
     715                panel.validate();
     716
     717                panel.setSize(width, height);
     718                panel.validate();
     719
     720                panel.getApplet().resize(width, height);
     721                panel.getApplet().validate();
     722            }
     723        });
     724    }
     725
    677726    public void handleMessage(int reference, String message) {
    678727        if (message.startsWith("width")) {
    679728
    680             // Wait for panel to come alive
    681             long maxTimeToSleep = APPLET_TIMEOUT;
    682             statusLock.lock();
    683             try {
    684                 while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) &&
    685                         maxTimeToSleep > 0) {
    686                     maxTimeToSleep -= waitTillTimeout(statusLock, initComplete,
    687                                                       maxTimeToSleep);
    688                 }
    689             }
    690             finally {
    691                 statusLock.unlock();
    692             }
    693 
    694729            // 0 => width, 1=> width_value, 2 => height, 3=> height_value
    695730            String[] dimMsg = message.split(" ");
    696731
     732            final int width = Integer.parseInt(dimMsg[1]);
    697733            final int height = Integer.parseInt(dimMsg[3]);
    698             final int width = Integer.parseInt(dimMsg[1]);
    699 
    700             panel.updateSizeInAtts(height, width);
    701 
    702             try {
    703                 SwingUtilities.invokeAndWait(new Runnable() {
    704                     public void run() {
    705 
    706                         setSize(width, height);
    707 
    708                         // There is a rather odd drawing bug whereby resizing
    709                         // the panel makes no difference on initial call
    710                         // because the panel thinks that it is already the
    711                         // right size. Validation has no effect there either.
    712                         // So we work around by setting size to 1, validating,
    713                         // and then setting to the right size and validating
    714                         // again. This is not very efficient, and there is
    715                         // probably a better way -- but resizing happens
    716                         // quite infrequently, so for now this is how we do it
    717 
    718                         panel.setSize(1, 1);
    719                         panel.validate();
    720 
    721                         panel.setSize(width, height);
    722                         panel.validate();
    723 
    724                         panel.applet.resize(width, height);
    725                         panel.applet.validate();
    726                     }
    727                 });
    728             } catch (InterruptedException e) {
    729                 // do nothing
    730                 e.printStackTrace();
    731             } catch (InvocationTargetException e) {
    732                 // do nothing
    733                 e.printStackTrace();
    734             }
     734
     735            /* Resize the applet asynchronously, to avoid the chance of
     736             * deadlock while waiting for the applet to initialize.
     737             *
     738             * In general, worker threads should spawn new threads for any blocking operations. */
     739            Thread resizeAppletThread = new Thread("resizeAppletThread") {
     740                @Override
     741                public void run() {
     742                    resizeAppletPanel(width, height);
     743                }
     744            };
     745
     746            /* Let it eventually complete */
     747            resizeAppletThread.start();
    735748
    736749        } else if (message.startsWith("GetJavaObject")) {
     
    740753            Object o;
    741754
    742             // First, wait for panel to instantiate
    743             // Next, wait for panel to come alive
    744             long maxTimeToSleep = APPLET_TIMEOUT;
    745             panelLock.lock();
    746             try {
    747                 while (panel == null || !panel.isAlive())
    748                     maxTimeToSleep -= waitTillTimeout(panelLock, panelLive,
    749                                                       maxTimeToSleep);
    750             }
    751             finally {
    752                 panelLock.unlock();
    753             }
    754 
    755755            // Wait for the panel to initialize
    756756            // (happens in a separate thread)
    757757            waitForAppletInit(panel);
    758758
    759             PluginDebug.debug(panel, " -- ", panel.getApplet(), " -- ", panel.isAlive());
     759            PluginDebug.debug(panel, " -- ", panel.getApplet(), " -- initialized: ", panel.isInitialized());
    760760
    761761            // Still null?
    762762            if (panel.getApplet() == null) {
    763                 streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError: " + "Initialization timed out");
     763                streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError: " + "Initialization failed");
     764                streamhandler.write("context 0 reference " + reference + " Error");
    764765                return;
    765766            }
     
    785786     * Get an audio clip.
    786787     */
     788    @Override
    787789    public AudioClip getAudioClip(URL url) {
    788790        checkConnect(url);
     
    801803     * Get an image.
    802804     */
     805    @Override
    803806    public Image getImage(URL url) {
    804807        return getCachedImage(url);
     
    826829
    827830                String resourceName = originalURL.substring(codeBase.length());
    828                 JNLPClassLoader loader = (JNLPClassLoader) panel.getAppletClassLoader();
    829 
    830                 URL localURL = null;
    831                 if (loader.resourceAvailableLocally(resourceName))
    832                     url = loader.getResource(resourceName);
    833 
    834                 url = localURL != null ? localURL : url;
     831                if (panel.getAppletClassLoader() instanceof JNLPClassLoader) {
     832                    JNLPClassLoader loader = (JNLPClassLoader) panel.getAppletClassLoader();
     833
     834                    URL localURL = null;
     835                    if (loader.resourceAvailableLocally(resourceName)) {
     836                        url = loader.getResource(resourceName);
     837                    }
     838
     839                    url = localURL != null ? localURL : url;
     840                }
    835841            }
    836842
     
    846852            }
    847853        } catch (Exception e) {
    848             System.err.println("Error occurred when trying to fetch image:");
    849             e.printStackTrace();
     854            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Error occurred when trying to fetch image:");
     855            OutputController.getLogger().log(e);
    850856            return null;
    851857        }
     
    864870     * Get an applet by name.
    865871     */
     872    @Override
    866873    public Applet getApplet(String name) {
    867874        name = name.toLowerCase();
     
    894901     * applets on this page.
    895902     */
     903    @Override
    896904    public Enumeration<Applet> getApplets() {
    897905        Vector<Applet> v = new Vector<Applet>();
     
    915923    }
    916924
    917     /**
    918      * Ignore.
    919      */
     925    @Override
    920926    public void showDocument(URL url) {
    921927        PluginDebug.debug("Showing document...");
     
    923929    }
    924930
    925     /**
    926      * Ignore.
    927      */
     931    @Override
    928932    public void showDocument(URL url, String target) {
     933        // If it is a javascript document, eval on current page.
     934        if ("javascript".equals(url.getProtocol())) {
     935            // Snip protocol off string
     936            String evalString = url.toString().substring("javascript:".length());
     937            eval(getWindow(), evalString);
     938            return;
     939        }
    929940        try {
    930941            Long reference = getRequestIdentifier();
     
    940951     * Show status.
    941952     */
     953    @Override
    942954    public void showStatus(String status) {
    943955        try {
     
    10281040
    10291041    public static void setMember(long internal, String name, Object value) {
    1030         System.err.println("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive());
    1031         AppletSecurityContextManager.getSecurityContext(0).store(name);
    1032         int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
     1042        PluginDebug.debug("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive());
     1043        PluginAppletSecurityContext securityContext = AppletSecurityContextManager.getSecurityContext(0);
     1044        securityContext.store(name);
     1045        int nameID = securityContext.getIdentifier(name);
    10331046        Long reference = getRequestIdentifier();
    10341047
    10351048        // work on a copy of value, as we don't want to be manipulating
    10361049        // complex objects
    1037         String valueToSetTo;
    1038         if (value instanceof java.lang.Byte ||
    1039                 value instanceof java.lang.Character ||
    1040                 value instanceof java.lang.Short ||
    1041                 value instanceof java.lang.Integer ||
    1042                 value instanceof java.lang.Long ||
    1043                 value instanceof java.lang.Float ||
    1044                 value instanceof java.lang.Double ||
    1045                 value instanceof java.lang.Boolean) {
    1046 
    1047             valueToSetTo = "literalreturn " + value.toString();
    1048 
    1049             // Character -> Str results in str value.. we need int value as
    1050             // per specs.
    1051             if (value instanceof java.lang.Character) {
    1052                 valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
    1053             } else if (value instanceof Float ||
    1054                         value instanceof Double) {
    1055                 valueToSetTo = "literalreturn " + String.format("%308.308e", value);
    1056             }
    1057 
    1058         } else {
    1059             AppletSecurityContextManager.getSecurityContext(0).store(value);
    1060             valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
    1061         }
     1050        String objIDStr = securityContext.toObjectIDString(value,
     1051                value.getClass(), true /* unbox primitives */);
    10621052
    10631053        // Prefix with dummy instance for convenience.
    10641054        PluginCallRequest request = requestFactory.getPluginCallRequest("void",
    10651055                "instance " + 0 + " reference " + reference + " SetMember " +
    1066                         internal + " " + nameID + " " + valueToSetTo, reference);
     1056                        internal + " " + nameID + " " + objIDStr, reference);
    10671057
    10681058        streamhandler.postCallRequest(request);
     
    10861076    // FIXME: handle long index as well.
    10871077    public static void setSlot(long internal, int index, Object value) {
    1088         AppletSecurityContextManager.getSecurityContext(0).store(value);
     1078        PluginAppletSecurityContext securityContext = AppletSecurityContextManager.getSecurityContext(0);
     1079        securityContext.store(value);
    10891080        Long reference = getRequestIdentifier();
    10901081
    1091         // work on a copy of value, as we don't want to be manipulating
    1092         // complex objects
    1093         String valueToSetTo;
    1094         if (value instanceof java.lang.Byte ||
    1095                 value instanceof java.lang.Character ||
    1096                 value instanceof java.lang.Short ||
    1097                 value instanceof java.lang.Integer ||
    1098                 value instanceof java.lang.Long ||
    1099                 value instanceof java.lang.Float ||
    1100                 value instanceof java.lang.Double ||
    1101                 value instanceof java.lang.Boolean) {
    1102 
    1103             valueToSetTo = "literalreturn " + value.toString();
    1104 
    1105             // Character -> Str results in str value.. we need int value as
    1106             // per specs.
    1107             if (value instanceof java.lang.Character) {
    1108                 valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
    1109             } else if (value instanceof Float ||
    1110                         value instanceof Double) {
    1111                 valueToSetTo = "literalreturn " + String.format("%308.308e", value);
    1112             }
    1113 
    1114         } else {
    1115             AppletSecurityContextManager.getSecurityContext(0).store(value);
    1116             valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
    1117         }
     1082        String objIDStr = securityContext.toObjectIDString(value,
     1083                value.getClass(), true /* unbox primitives */);
    11181084
    11191085        // Prefix with dummy instance for convenience.
    11201086        PluginCallRequest request = requestFactory.getPluginCallRequest("void",
    11211087                "instance " + 0 + " reference " + reference + " SetSlot " +
    1122                         internal + " " + index + " " + valueToSetTo, reference);
     1088                        internal + " " + index + " " + objIDStr, reference);
    11231089
    11241090        streamhandler.postCallRequest(request);
     
    11801146            synchronized (request) {
    11811147                PluginDebug.debug("wait eval request 2");
    1182                 while (request.isDone() == false)
     1148                while (request.isDone() == false) {
    11831149                    request.wait();
     1150                }
    11841151                PluginDebug.debug("wait eval request 3");
    11851152            }
     
    12451212            synchronized (request) {
    12461213                PluginDebug.debug("wait call request 2");
    1247                 while (request.isDone() == false)
     1214                while (request.isDone() == false) {
    12481215                    request.wait();
     1216                }
    12491217                PluginDebug.debug("wait call request 3");
    12501218            }
     
    12691237
    12701238        } catch (UnsupportedEncodingException e) {
    1271             e.printStackTrace();
     1239            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    12721240            return null;
    12731241        }
     
    12801248            synchronized (request) {
    12811249                PluginDebug.debug("wait cookieinfo request 2");
    1282                 while (request.isDone() == false)
     1250                while (request.isDone() == false) {
    12831251                    request.wait();
     1252                }
    12841253                PluginDebug.debug("wait cookieinfo request 3");
    12851254            }
     
    12921261    }
    12931262
    1294     public static Object requestPluginProxyInfo(URI uri) {
    1295 
    1296         String requestURI = null;
     1263    /**
     1264     * Obtain information about the proxy from the browser.
     1265     *
     1266     * @param uri a String in url-encoded form
     1267     * @return a {@link URI} that indicates a proxy.
     1268     */
     1269    public static Object requestPluginProxyInfo(String uri) {
    12971270        Long reference = getRequestIdentifier();
    1298 
    1299         try {
    1300 
    1301             // there is no easy way to get SOCKS proxy info. So, we tell mozilla that we want proxy for
    1302             // an HTTP uri in case of non http/ftp protocols. If we get back a SOCKS proxy, we can
    1303             // use that, if we get back an http proxy, we fallback to DIRECT connect
    1304 
    1305             String scheme = uri.getScheme();
    1306             String port = uri.getPort() != -1 ? ":" + uri.getPort() : "";
    1307             if (!uri.getScheme().startsWith("http") && !uri.getScheme().equals("ftp"))
    1308                 scheme = "http";
    1309 
    1310             requestURI = UrlUtil.encode(scheme + "://" + uri.getHost() + port + "/" + uri.getPath(), "UTF-8");
    1311         } catch (Exception e) {
    1312             PluginDebug.debug("Cannot construct URL from ", uri.toString(), " ... falling back to DIRECT proxy");
    1313             e.printStackTrace();
    1314             return null;
    1315         }
    13161271
    13171272        PluginCallRequest request = requestFactory.getPluginCallRequest("proxyinfo",
    13181273                "plugin PluginProxyInfo reference " + reference + " " +
    1319                         requestURI, reference);
     1274                        uri, reference);
    13201275
    13211276        PluginMessageConsumer.registerPriorityWait(reference);
     
    13261281            synchronized (request) {
    13271282                PluginDebug.debug("wait call request 2");
    1328                 while (request.isDone() == false)
     1283                while (request.isDone() == false) {
    13291284                    request.wait();
     1285                }
    13301286                PluginDebug.debug("wait call request 3");
    13311287            }
     
    13521308            synchronized (request) {
    13531309                PluginDebug.debug("wait finalize request 2");
    1354                 while (request.isDone() == false)
     1310                while (request.isDone() == false) {
    13551311                    request.wait();
     1312                }
    13561313                PluginDebug.debug("wait finalize request 3");
    13571314            }
     
    13731330        streamhandler.postCallRequest(request);
    13741331        streamhandler.write(request.getMessage());
    1375         try {
    1376             PluginDebug.debug("wait ToString request 1");
    1377             synchronized (request) {
    1378                 PluginDebug.debug("wait ToString request 2");
    1379                 while (request.isDone() == false)
    1380                     request.wait();
    1381                 PluginDebug.debug("wait ToString request 3");
    1382             }
    1383         } catch (InterruptedException e) {
    1384             throw new RuntimeException("Interrupted waiting for call request.",
    1385                                         e);
    1386         }
     1332        PluginDebug.debug("wait ToString request 1");
     1333        synchronized (request) {
     1334            PluginDebug.debug("wait ToString request 2");
     1335            waitForRequestCompletion(request);
     1336            PluginDebug.debug("wait ToString request 3");
     1337        }
     1338
    13871339        PluginDebug.debug(" ToString DONE");
    13881340        return (String) request.getObject();
     
    13971349    }
    13981350
     1351    @Override
    13991352    public void setStream(String key, InputStream stream) throws IOException {
    14001353        // We do nothing.
     
    14111364        // We do nothing.
    14121365        return null;
    1413     }
    1414 
    1415     /**
    1416      * Decodes the string (converts html escapes into proper characters)
    1417      *
    1418      * @param toDecode The string to decode
    1419      * @return The decoded string
    1420      */
    1421     public static String decodeString(String toDecode) {
    1422 
    1423         toDecode = toDecode.replace("&gt;", ">");
    1424         toDecode = toDecode.replace("&lt;", "<");
    1425         toDecode = toDecode.replace("&amp;", "&");
    1426         toDecode = toDecode.replace("&#10;", "\n");
    1427         toDecode = toDecode.replace("&#13;", "\r");
    1428         toDecode = toDecode.replace("&quot;", "\"");
    1429 
    1430         return toDecode;
    14311366    }
    14321367
     
    14481383
    14491384    /**
    1450      * Print the HTML tag.
    1451      */
    1452     public static void printTag(PrintStream out, Hashtable<String, String> atts) {
    1453         out.print("<applet");
    1454 
    1455         String v = atts.get("codebase");
    1456         if (v != null) {
    1457             out.print(" codebase=\"" + v + "\"");
    1458         }
    1459 
    1460         v = atts.get("code");
    1461         if (v == null) {
    1462             v = "applet.class";
    1463         }
    1464         out.print(" code=\"" + v + "\"");
    1465         v = atts.get("width");
    1466         if (v == null) {
    1467             v = "150";
    1468         }
    1469         out.print(" width=" + v);
    1470 
    1471         v = atts.get("height");
    1472         if (v == null) {
    1473             v = "100";
    1474         }
    1475         out.print(" height=" + v);
    1476 
    1477         v = atts.get("name");
    1478         if (v != null) {
    1479             out.print(" name=\"" + v + "\"");
    1480         }
    1481         out.println(">");
    1482 
    1483         // A very slow sorting algorithm
    1484         int len = atts.size();
    1485         String params[] = new String[len];
    1486         len = 0;
    1487         for (Enumeration<String> e = atts.keys(); e.hasMoreElements();) {
    1488             String param = e.nextElement();
    1489             int i = 0;
    1490             for (; i < len; i++) {
    1491                 if (params[i].compareTo(param) >= 0) {
    1492                     break;
    1493                 }
    1494             }
    1495             System.arraycopy(params, i, params, i + 1, len - i);
    1496             params[i] = param;
    1497             len++;
    1498         }
    1499 
    1500         for (int i = 0; i < len; i++) {
    1501             String param = params[i];
    1502             if (systemParam.get(param) == null) {
    1503                 out.println("<param name=" + param +
    1504                         " value=\"" + atts.get(param) + "\">");
    1505             }
    1506         }
    1507         out.println("</applet>");
    1508     }
    1509 
    1510     /**
    15111385     * Make sure the atrributes are uptodate.
    15121386     */
     
    15141388        Dimension d = panel.getSize();
    15151389        Insets in = panel.getInsets();
    1516         panel.atts.put("width",
    1517                        Integer.valueOf(d.width - (in.left + in.right)).toString());
    1518         panel.atts.put("height",
    1519                        Integer.valueOf(d.height - (in.top + in.bottom)).toString());
     1390        int width = d.width - (in.left + in.right);
     1391        int height = d.height - (in.top + in.bottom);
     1392        panel.updateSizeInAtts(height, width);
    15201393    }
    15211394
     
    15501423         */
    15511424        try {
    1552             ((AppletViewerPanel)panel).joinAppletThread();
    1553             ((AppletViewerPanel)panel).release();
     1425            ((AppletViewerPanelAccess)panel).joinAppletThread();
     1426            ((AppletViewerPanelAccess)panel).release();
    15541427        } catch (InterruptedException e) {
    15551428            return; // abort the reload
     
    15571430
    15581431        AccessController.doPrivileged(new PrivilegedAction<Void>() {
     1432            @Override
    15591433            public Void run() {
    1560                 ((AppletViewerPanel)panel).createAppletThread();
     1434                ((AppletViewerPanelAccess)panel).createAppletThread();
    15611435                return null;
    15621436            }
     
    15681442    }
    15691443
     1444    @Override
    15701445    public int print(Graphics graphics, PageFormat pf, int pageIndex) {
    15711446        return Printable.NO_SUCH_PAGE;
     
    16131488        new Thread(new Runnable() {
    16141489            @SuppressWarnings("deprecation")
     1490            @Override
    16151491            public void run() {
    16161492                ClassLoader cl = p.applet.getClass().getClassLoader();
     
    16181494                // Since we want to deal with JNLPClassLoader, extract it if this
    16191495                // is a codebase loader
    1620                 if (cl instanceof JNLPClassLoader.CodeBaseClassLoader)
     1496                if (cl instanceof JNLPClassLoader.CodeBaseClassLoader) {
    16211497                    cl = ((JNLPClassLoader.CodeBaseClassLoader) cl).getParentJNLPClassLoader();
    1622 
    1623                 ThreadGroup tg = ((JNLPClassLoader) cl).getApplication().getThreadGroup();
     1498                }
    16241499
    16251500                appletShutdown(p);
     
    16271502               
    16281503                // Mark classloader unusable
    1629                 ((JNLPClassLoader) cl).decrementLoaderUseCount();
     1504                if (cl instanceof JNLPClassLoader) {
     1505                    ((JNLPClassLoader) cl).decrementLoaderUseCount();
     1506                }
    16301507
    16311508                try {
    16321509                    SwingUtilities.invokeAndWait(new Runnable() {
     1510                        @Override
    16331511                        public void run() {
    16341512                            dispose();
     
    16641542    }
    16651543
    1666     /**
    1667      * Scan spaces.
    1668      */
    1669     public static void skipSpace(int[] c, Reader in) throws IOException {
    1670         while ((c[0] >= 0) &&
    1671                 ((c[0] == ' ') || (c[0] == '\t') || (c[0] == '\n') || (c[0] == '\r'))) {
    1672             c[0] = in.read();
    1673         }
    1674     }
    1675 
    1676     /**
    1677      * Scan identifier
    1678      */
    1679     public static String scanIdentifier(int[] c, Reader in) throws IOException {
    1680         StringBuilder buf = new StringBuilder();
    1681 
    1682         if (c[0] == '!') {
    1683             // Technically, we should be scanning for '!--' but we are reading
    1684             // from a stream, and there is no way to peek ahead. That said,
    1685             // a ! at this point can only mean comment here afaik, so we
    1686             // should be okay
    1687             skipComment(c, in);
    1688             return "";
    1689         }
    1690 
    1691         while (true) {
    1692             if (((c[0] >= 'a') && (c[0] <= 'z')) ||
    1693                     ((c[0] >= 'A') && (c[0] <= 'Z')) ||
    1694                     ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) {
    1695                 buf.append((char) c[0]);
    1696                 c[0] = in.read();
    1697             } else {
    1698                 return buf.toString();
    1699             }
    1700         }
    1701     }
    1702 
    1703     public static void skipComment(int[] c, Reader in) throws IOException {
    1704         StringBuilder buf = new StringBuilder();
    1705         boolean commentHeaderPassed = false;
    1706         c[0] = in.read();
    1707         buf.append((char) c[0]);
    1708 
    1709         while (true) {
    1710             if (c[0] == '-' && (c[0] = in.read()) == '-') {
    1711                 buf.append((char) c[0]);
    1712                 if (commentHeaderPassed) {
    1713                     // -- encountered ... is > next?
    1714                     if ((c[0] = in.read()) == '>') {
    1715                         buf.append((char) c[0]);
    1716 
    1717                         PluginDebug.debug("Comment skipped: ", buf.toString());
    1718 
    1719                         // comment skipped.
    1720                         return;
    1721                     }
    1722                 } else {
    1723                     // first -- is part of <!-- ... , just mark that we have passed it
    1724                     commentHeaderPassed = true;
    1725                 }
    1726 
    1727             } else if (commentHeaderPassed == false) {
    1728                 buf.append((char) c[0]);
    1729                 PluginDebug.debug("Warning: Attempted to skip comment, but this tag does not appear to be a comment: ", buf.toString());
    1730                 return;
    1731             }
    1732 
    1733             c[0] = in.read();
    1734             buf.append((char) c[0]);
    1735         }
    1736     }
    1737 
    1738     /**
    1739      * Scan tag
    1740      */
    1741     public static Hashtable<String, String> scanTag(int[] c, Reader in) throws IOException {
    1742         Hashtable<String, String> atts = new Hashtable<String, String>();
    1743         skipSpace(c, in);
    1744         while (c[0] >= 0 && c[0] != '>') {
    1745             String att = decodeString(scanIdentifier(c, in));
    1746             String val = "";
    1747             skipSpace(c, in);
    1748             if (c[0] == '=') {
    1749                 int quote = -1;
    1750                 c[0] = in.read();
    1751                 skipSpace(c, in);
    1752                 if ((c[0] == '\'') || (c[0] == '\"')) {
    1753                     quote = c[0];
    1754                     c[0] = in.read();
    1755                 }
    1756                 StringBuilder buf = new StringBuilder();
    1757                 while ((c[0] > 0) &&
    1758                         (((quote < 0) && (c[0] != ' ') && (c[0] != '\t') &&
    1759                                 (c[0] != '\n') && (c[0] != '\r') && (c[0] != '>'))
    1760                          || ((quote >= 0) && (c[0] != quote)))) {
    1761                     buf.append((char) c[0]);
    1762                     c[0] = in.read();
    1763                 }
    1764                 if (c[0] == quote) {
    1765                     c[0] = in.read();
    1766                 }
    1767                 skipSpace(c, in);
    1768                 val = decodeString(buf.toString());
    1769             }
    1770 
    1771             PluginDebug.debug("PUT ", att, " = '", val, "'");
    1772             atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
    1773 
    1774             while (true) {
    1775                 if ((c[0] == '>') || (c[0] < 0) ||
    1776                         ((c[0] >= 'a') && (c[0] <= 'z')) ||
    1777                         ((c[0] >= 'A') && (c[0] <= 'Z')) ||
    1778                         ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_'))
    1779                     break;
    1780                 c[0] = in.read();
    1781             }
    1782             //skipSpace(in);
    1783         }
    1784         return atts;
    1785     }
    1786 
    1787     // private static final == inline
    1788     private static final boolean isInt(Object o) {
    1789         boolean isInt = false;
    1790         try {
    1791             Integer.parseInt((String) o);
    1792             isInt = true;
    1793         } catch (Exception e) {
    1794             // don't care
    1795         }
    1796 
    1797         return isInt;
    1798     }
    1799 
    1800     /* values used for placement of AppletViewer's frames */
    1801     private static int x = 0;
    1802     private static int y = 0;
    1803     private static final int XDELTA = 30;
    1804     private static final int YDELTA = XDELTA;
    1805 
    1806     static String encoding = null;
    1807 
    1808     /**
    1809      * Scan an html file for <applet> tags
    1810      */
    1811     public static void parse(int identifier, long handle, String width, String height, Reader in, URL url, String enc)
    1812             throws IOException {
    1813         encoding = enc;
    1814         parse(identifier, handle, width, height, in, url, System.out, new PluginAppletPanelFactory());
    1815     }
    1816 
    1817     public static void parse(int identifier, long handle, String width, String height, Reader in, URL url)
    1818             throws PrivilegedActionException {
    1819 
    1820         final int fIdentifier = identifier;
    1821         final long fHandle = handle;
    1822         final String fWidth = width;
    1823         final String fHeight = height;
    1824         final Reader fIn = in;
    1825         final URL fUrl = url;
    1826         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
    1827             public Void run() throws IOException {
    1828                 parse(fIdentifier, fHandle, fWidth, fHeight, fIn, fUrl,
    1829                         System.out, new PluginAppletPanelFactory());
    1830                 return null;
    1831             }
    1832         });
    1833     }
    1834 
    1835     @SuppressWarnings("unused")
    1836     public static void parse(int identifier, long handle, String width,
    1837                  String height, Reader in, URL url,
    1838                               PrintStream statusMsgStream,
    1839                               PluginAppletPanelFactory factory)
    1840             throws IOException {
    1841         boolean isObjectTag = false;
    1842         boolean objectTagAlreadyParsed = false;
    1843 
    1844         // The current character
    1845         // FIXME: This is an evil hack to force pass-by-reference.. the
    1846         // parsing code needs to be rewritten from scratch to prevent such
    1847         //a need
    1848         int[] c = new int[1];
    1849 
    1850         // warning messages
    1851         String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
    1852         String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
    1853         String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
    1854         String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
    1855         String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
    1856         String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
    1857         String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
    1858         String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
    1859         String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
    1860         String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
    1861         String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
    1862         String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
    1863 
    1864         java.net.URLConnection conn = url.openConnection();
    1865         /* The original URL may have been redirected - this
    1866          * sets it to whatever URL/codebase we ended up getting
    1867          */
    1868         url = conn.getURL();
    1869 
    1870         int ydisp = 1;
    1871         Hashtable<String, String> atts = null;
    1872 
    1873         while (true) {
    1874             c[0] = in.read();
    1875             if (c[0] == -1)
    1876                 break;
    1877 
    1878             if (c[0] == '<') {
    1879                 c[0] = in.read();
    1880                 if (c[0] == '/') {
    1881                     c[0] = in.read();
    1882                     String nm = scanIdentifier(c, in);
    1883                     if (nm.equalsIgnoreCase("applet") ||
    1884                              nm.equalsIgnoreCase("object") ||
    1885                              nm.equalsIgnoreCase("embed")) {
    1886 
    1887                         // We can't test for a code tag until </OBJECT>
    1888                         // because it is a parameter, not an attribute.
    1889                         if (isObjectTag) {
    1890                             if (atts.get("code") == null && atts.get("object") == null) {
    1891                                 statusMsgStream.println(objectRequiresCodeWarning);
    1892                                 atts = null;
    1893                             }
    1894                         }
    1895 
    1896                         if (atts != null) {
    1897                             // XXX 5/18 In general this code just simply
    1898                             // shouldn't be part of parsing.  It's presence
    1899                             // causes things to be a little too much of a
    1900                             // hack.
    1901 
    1902                             // Let user know we are starting up
    1903                             streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start"));
    1904                             factory.createPanel(streamhandler, identifier, handle, x, y, url, atts);
    1905 
    1906                             x += XDELTA;
    1907                             y += YDELTA;
    1908                             // make sure we don't go too far!
    1909                             Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    1910                             if ((x > d.width - 300) || (y > d.height - 300)) {
    1911                                 x = 0;
    1912                                 y = 2 * ydisp * YDELTA;
    1913                                 ydisp++;
    1914                             }
    1915                         }
    1916                         atts = null;
    1917                         isObjectTag = false;
    1918                     }
    1919                 } else {
    1920                     String nm = scanIdentifier(c, in);
    1921                     if (nm.equalsIgnoreCase("param")) {
    1922                         Hashtable<String, String> t = scanTag(c, in);
    1923                         String att = t.get("name");
    1924 
    1925                         if (att == null) {
    1926                             statusMsgStream.println(requiresNameWarning);
    1927                         } else {
    1928                             String val = t.get("value");
    1929                             if (val == null) {
    1930                                 statusMsgStream.println(requiresNameWarning);
    1931                             } else {
    1932                                 PluginDebug.debug("PUT ", att, " = ", val);
    1933                                 atts.put(att.toLowerCase(), val);
    1934                             }
    1935                         }
    1936                     } else if (nm.equalsIgnoreCase("applet")) {
    1937                         atts = scanTag(c, in);
    1938 
    1939                         // If there is a classid and no code tag present, transform it to code tag
    1940                         if (atts.get("code") == null && atts.get("classid") != null
    1941                                 && !(atts.get("classid")).startsWith("clsid:")) {
    1942                             atts.put("code", atts.get("classid"));
    1943                         }
    1944 
    1945                         // remove java: from code tag
    1946                         if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) {
    1947                             atts.put("code", (atts.get("code")).substring(5));
    1948                         }
    1949 
    1950                         if (atts.get("code") == null && atts.get("object") == null) {
    1951                             statusMsgStream.println(appletRequiresCodeWarning);
    1952                             atts = null;
    1953                         }
    1954 
    1955                         if (atts.get("width") == null || !isInt(atts.get("width"))) {
    1956                             atts.put("width", width);
    1957                         }
    1958 
    1959                         if (atts.get("height") == null || !isInt(atts.get("height"))) {
    1960                             atts.put("height", height);
    1961                         }
    1962                     } else if (nm.equalsIgnoreCase("object")) {
    1963                         isObjectTag = true;
    1964 
    1965                         // Once code is set, additional nested objects are ignored
    1966                         if (!objectTagAlreadyParsed) {
    1967                             objectTagAlreadyParsed = true;
    1968                             atts = scanTag(c, in);
    1969                         }
    1970 
    1971                         // If there is a classid and no code tag present, transform it to code tag
    1972                         if (atts.get("code") == null && atts.get("classid") != null
    1973                                 && !(atts.get("classid")).startsWith("clsid:")) {
    1974                             atts.put("code", atts.get("classid"));
    1975                         }
    1976 
    1977                         // remove java: from code tag
    1978                         if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) {
    1979                             atts.put("code", (atts.get("code")).substring(5));
    1980                         }
    1981 
    1982                         // java_* aliases override older names:
    1983                         // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-ie
    1984                         if (atts.get("java_code") != null) {
    1985                             atts.put("code", (atts.get("java_code")));
    1986                         }
    1987 
    1988                         if (atts.containsKey("code")) {
    1989                             objectTagAlreadyParsed = true;
    1990                         }
    1991 
    1992                         if (atts.get("java_codebase") != null) {
    1993                             atts.put("codebase", (atts.get("java_codebase")));
    1994                         }
    1995 
    1996                         if (atts.get("java_archive") != null) {
    1997                             atts.put("archive", (atts.get("java_archive")));
    1998                         }
    1999 
    2000                         if (atts.get("java_object") != null) {
    2001                             atts.put("object", (atts.get("java_object")));
    2002                         }
    2003 
    2004                         if (atts.get("java_type") != null) {
    2005                             atts.put("type", (atts.get("java_type")));
    2006                         }
    2007 
    2008                         if (atts.get("width") == null || !isInt(atts.get("width"))) {
    2009                             atts.put("width", width);
    2010                         }
    2011 
    2012                         if (atts.get("height") == null || !isInt(atts.get("height"))) {
    2013                             atts.put("height", height);
    2014                         }
    2015                     } else if (nm.equalsIgnoreCase("embed")) {
    2016                         atts = scanTag(c, in);
    2017 
    2018                         // If there is a classid and no code tag present, transform it to code tag
    2019                         if (atts.get("code") == null && atts.get("classid") != null
    2020                                 && !(atts.get("classid")).startsWith("clsid:")) {
    2021                             atts.put("code", atts.get("classid"));
    2022                         }
    2023 
    2024                         // remove java: from code tag
    2025                         if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) {
    2026                             atts.put("code", (atts.get("code")).substring(5));
    2027                         }
    2028 
    2029                         // java_* aliases override older names:
    2030                         // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav
    2031                         if (atts.get("java_code") != null) {
    2032                             atts.put("code", (atts.get("java_code")));
    2033                         }
    2034 
    2035                         if (atts.get("java_codebase") != null) {
    2036                             atts.put("codebase", (atts.get("java_codebase")));
    2037                         }
    2038 
    2039                         if (atts.get("java_archive") != null) {
    2040                             atts.put("archive", (atts.get("java_archive")));
    2041                         }
    2042 
    2043                         if (atts.get("java_object") != null) {
    2044                             atts.put("object", (atts.get("java_object")));
    2045                         }
    2046 
    2047                         if (atts.get("java_type") != null) {
    2048                             atts.put("type", (atts.get("java_type")));
    2049                         }
    2050 
    2051                         if (atts.get("code") == null && atts.get("object") == null) {
    2052                             statusMsgStream.println(embedRequiresCodeWarning);
    2053                             atts = null;
    2054                         }
    2055 
    2056                         if (atts.get("width") == null || !isInt(atts.get("width"))) {
    2057                             atts.put("width", width);
    2058                         }
    2059 
    2060                         if (atts.get("height") == null || !isInt(atts.get("height"))) {
    2061                             atts.put("height", height);
    2062                         }
    2063 
    2064                     }
    2065                 }
    2066             }
    2067         }
    2068         in.close();
    2069     }
    2070 
    2071     private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
    20721544
    20731545    private static void checkConnect(URL url) {
     
    20771549                java.security.Permission perm =
    20781550                        url.openConnection().getPermission();
    2079                 if (perm != null)
     1551                if (perm != null) {
    20801552                    security.checkPermission(perm);
    2081                 else
     1553                }
     1554                else {
    20821555                    security.checkConnect(url.getHost(), url.getPort());
     1556                }
    20831557            } catch (java.io.IOException ioe) {
    20841558                security.checkConnect(url.getHost(), url.getPort());
     
    20941568     * which are accounted for) and then calls paint anyway.
    20951569     */
    2096     public void update(Graphics g) {
     1570    @Override
     1571    public void paint(Graphics g) {
    20971572
    20981573        // If the image or the graphics don't exist, create new ones
    20991574        if (bufFrameImg == null || bufFrameImgGraphics == null) {
    2100             bufFrameImg = createImage(getWidth(), getHeight());
     1575            // although invisible applets do not have right to paint
     1576            // we rather paint to 1x1 to be sure all callbacks  will be completed
     1577            bufFrameImg = createImage(Math.max(1, getWidth()), Math.max(1, getHeight()));
    21011578            bufFrameImgGraphics = bufFrameImg.getGraphics();
    21021579        }
    21031580
    21041581        // Paint off-screen
    2105         paint(bufFrameImgGraphics);
     1582        for (Component c: this.getComponents()) {
     1583                c.paint(bufFrameImgGraphics);
     1584        }
    21061585
    21071586        // Draw the painted image
    21081587        g.drawImage(bufFrameImg, 0, 0, this);
    21091588    }
    2110 
     1589   
     1590   
     1591    @Override
     1592    public void update(Graphics g) {
     1593        paint(g);
     1594    }
     1595 
    21111596    /**
    21121597     * Waits on a given condition queue until timeout.
     
    21261611
    21271612        // Can't wait on null. Return 0 indicating no wait happened.
    2128         if (lock == null)
    2129             return 0;
     1613        if (lock == null) {
     1614                                               return 0;
     1615                                           }
    21301616
    21311617        assert lock.isHeldByCurrentThread();
     
    21421628        return System.nanoTime() - sleepStart;
    21431629    }
     1630
     1631    private class SplashCreator implements Runnable {
     1632
     1633        private final AppletPanel fPanel;
     1634
     1635        public SplashCreator(AppletPanel fPanel) {
     1636            this.fPanel = fPanel;
     1637        }
     1638
     1639        @Override
     1640        public void run() {
     1641            add("Center", fPanel);
     1642            fPanel.setVisible(false);
     1643            splashPanel = SplashUtils.getSplashScreen(fPanel.getWidth(), fPanel.getHeight());
     1644            if (splashPanel != null) {
     1645                splashPanel.startAnimation();
     1646                PluginDebug.debug("Added splash " + splashPanel);
     1647                add("Center", splashPanel.getSplashComponent());
     1648            }
     1649            pack();
     1650        }
     1651    }
    21441652}
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginDebug.java

    r348 r429  
    3838package sun.applet;
    3939
     40import net.sourceforge.jnlp.runtime.JNLPRuntime;
     41import net.sourceforge.jnlp.util.logging.OutputController;
     42
    4043public class PluginDebug {
    4144
    42     static final boolean DEBUG = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
     45    static final boolean DEBUG = JNLPRuntime.isDebug();
    4346
    4447    public static void debug(Object... messageChunks) {
     
    5154                b.append(chunk);
    5255            }
    53             System.err.println(b.toString());
     56            OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, b.toString());
    5457        }
    5558    }
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginException.java

    r418 r429  
    3838package sun.applet;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
     41
    4042public class PluginException extends Exception {
    4143
    4244    public PluginException(PluginStreamHandler sh, int instance, int reference, Throwable t) {
    43         t.printStackTrace();
     45        OutputController.getLogger().log(OutputController.Level.ERROR_ALL,t);
    4446        this.setStackTrace(t.getStackTrace());
    4547
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginMain.java

    r418 r429  
    6464
    6565import java.io.IOException;
     66import java.lang.reflect.Field;
    6667import java.net.Authenticator;
    6768import java.net.CookieHandler;
    6869import java.net.CookieManager;
    6970import java.net.ProxySelector;
     71import java.net.URL;
     72import java.net.URLStreamHandler;
    7073import java.util.Enumeration;
     74import java.util.Hashtable;
     75import java.util.Map;
    7176import java.util.Properties;
     77import sun.awt.AppContext;
     78import sun.awt.SunToolkit;
    7279
    7380import net.sourceforge.jnlp.config.DeploymentConfiguration;
    7481import net.sourceforge.jnlp.runtime.JNLPRuntime;
    7582import net.sourceforge.jnlp.security.JNLPAuthenticator;
     83import net.sourceforge.jnlp.util.logging.JavaConsole;
     84import net.sourceforge.jnlp.util.logging.LogConfig;
     85import net.sourceforge.jnlp.util.logging.OutputController;
    7686
    7787/**
     
    7989 */
    8090public class PluginMain extends PluginMainBase {
    81     // the files where stdout/stderr are sent to
    82     public static final String PLUGIN_STDERR_FILE = "java.stderr";
    83     public static final String PLUGIN_STDOUT_FILE = "java.stdout";
    8491
    8592    // This is used in init().  Getting rid of this is desirable but depends
    8693    // on whether the property that uses it is necessary/standard.
    8794    private static final String theVersion = System.getProperty("java.version");
     95
     96    /* Install a handler directly using reflection. This ensures that java doesn't error-out
     97     * when javascript is used in a URL. We can then handle these URLs correctly in eg PluginAppletViewer.showDocument().
     98     */
     99    static private void installDummyJavascriptProtocolHandler() {
     100        try {
     101            Field handlersField = URL.class.getDeclaredField("handlers");
     102            handlersField.setAccessible(true);
     103
     104            @SuppressWarnings("unchecked")
     105            Hashtable<String, URLStreamHandler> handlers = (Hashtable<String,URLStreamHandler>)handlersField.get(null);
     106
     107            // Place an arbitrary handler, we only need the URL construction to not error-out
     108            handlers.put("javascript", new sun.net.www.protocol.http.Handler());
     109        } catch (Exception e) {
     110            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to install 'javascript:' URL protocol handler!");
     111            OutputController.getLogger().log(e);
     112        }
     113    }
    88114
    89115    /**
     
    92118    public static void main(String args[])
    93119            throws IOException {
     120        //we are polite, we reprint start arguments
     121        OutputController.getLogger().log("startup arguments: ");
     122        for (int i = 0; i < args.length; i++) {
     123            String string = args[i];
     124            OutputController.getLogger().log(i + ": "+string);
     125           
     126        }
     127        if (AppContext.getAppContext() == null) {
     128            SunToolkit.createNewAppContext();
     129        }
     130        installDummyJavascriptProtocolHandler();
     131
    94132        if (!checkArgs(args)) {
    95             System.exit(1);
    96         }
    97 
     133            JNLPRuntime.exit(1);
     134        }
     135        DeploymentConfiguration.move14AndOlderFilesTo15StructureCatched();
     136        if (JavaConsole.isEnabled()) {
     137            if ((args.length < 3) || !new File(args[2]).exists()) {
     138                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Warning, although console is on, plugin debug connection do not exists. No plugin information will be displayed in console (only java ones).");
     139            } else {
     140                JavaConsole.getConsole().createPluginReader(new File(args[2]));
     141            }
     142        }
    98143        try {
    99144            PluginStreamHandler streamHandler = connect(args);
    100             boolean redirectStreams = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
    101 
    102             // must be called before JNLPRuntime.initialize()
    103             JNLPRuntime.setRedirectStreams(redirectStreams);
    104145
    105146            PluginAppletSecurityContext sc = new PluginAppletSecurityContext(0);
     
    117158
    118159            setCookieHandler(streamHandler);
     160            JavaConsole.getConsole().setClassLoaderInfoProvider(new JavaConsole.ClassLoaderInfoProvider() {
     161
     162                @Override
     163                public Map<String, String> getLoaderInfo() {
     164                    return PluginAppletSecurityContext.getLoaderInfo();
     165                }
     166            });
    119167
    120168        } catch (Exception e) {
    121             e.printStackTrace();
    122             System.err.println("Something very bad happened. I don't know what to do, so I am going to exit :(");
    123             System.exit(1);
     169            OutputController.getLogger().log(e);
     170            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Something very bad happened. I don't know what to do, so I am going to exit :(");
     171            JNLPRuntime.exit(1);
    124172        }
    125173    }
     
    187235        }
    188236        // override the proxy selector set by JNLPRuntime
    189         ProxySelector.setDefault(new PluginProxySelector());
     237        ProxySelector.setDefault(new PluginProxySelector(JNLPRuntime.getConfiguration()));
    190238    }
    191239
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java

    r348 r429  
    1 /* VoidPluginCallRequest -- represent Java-to-JavaScript requests
     1/*
    22   Copyright (C) 2008  Red Hat
    33
     
    4040import java.util.ArrayList;
    4141import java.util.LinkedList;
     42import net.sourceforge.jnlp.util.logging.OutputController;
    4243
    4344class PluginMessageConsumer {
     
    117118    }
    118119
    119     public void notifyWorkerIsFree(PluginMessageHandlerWorker worker) {
    120         consumerThread.interrupt();
    121     }
    122 
    123120    public void queue(String message) {
    124121        synchronized (readQueue) {
     
    127124
    128125        // Wake that lazy consumer thread
    129         consumerThread.interrupt();
     126        consumerThread.notifyHasWork();
    130127    }
    131128
    132129    protected class ConsumerThread extends Thread {
     130
     131        public ConsumerThread() {
     132            super("PluginMessageConsumer.ConsumerThread");
     133        }
     134
     135        // Notify that either work is ready to do, or a worker is available
     136        public synchronized void notifyHasWork() {
     137            notifyAll();
     138        }
     139
     140        // Wait a bit until either work is ready to do, or a worker is available
     141        public synchronized void waitForWork() {
     142            try {
     143                // Do not wait indefinitely to avoid the potential of deadlock
     144                wait(1000);
     145            } catch (InterruptedException e) {
     146                // Should not typically occur
     147               OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
     148            }
     149        }
    133150
    134151        /**
     
    191208
    192209                    worker.setmessage(message);
    193                     worker.interrupt();
     210                    worker.notifyHasWork();
    194211
    195212                } else {
    196                     try {
    197                         Thread.sleep(1000);
    198                     } catch (InterruptedException ie) {
    199                     }
     213                    waitForWork();
    200214                }
    201215            }
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java

    r418 r429  
    3838package sun.applet;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
     41
    4042class PluginMessageHandlerWorker extends Thread {
    4143
     
    4345    private final boolean isPriorityWorker;
    4446    private final int id;
    45     private String message;
     47    private volatile String message;
    4648    private PluginStreamHandler streamHandler;
    4749    private PluginMessageConsumer consumer;
     50
     51    public synchronized void notifyHasWork() {
     52        notifyAll();
     53    }
     54
     55    public synchronized void waitForWork() {
     56        try {
     57            // Do not wait indefinitely to avoid the potential of deadlock
     58            wait(1000);
     59        } catch (InterruptedException e) {
     60            // Should not typically occur
     61           OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
     62        }
     63    }
    4864
    4965    public PluginMessageHandlerWorker(
     
    5167                PluginStreamHandler streamHandler, int id,
    5268                boolean isPriorityWorker) {
     69        super("PluginMessageHandlerWorker" + id);
    5370
    5471        this.id = id;
     
    93110
    94111            } else {
     112                waitForWork();
    95113
    96                 // Sleep when there is nothing to do
    97                 try {
    98                     Thread.sleep(Integer.MAX_VALUE);
    99                     PluginDebug.debug("Consumer thread ", id, " sleeping...");
    100                 } catch (InterruptedException ie) {
    101                     PluginDebug.debug("Consumer thread ", id, " woken...");
    102                     // nothing.. someone woke us up, see if there
    103                     // is work to do
    104                 }
     114                // Someone woke us up, see if there is work to do
     115                // PluginDebug.debug("Consumer thread ", id, " woken...");
    105116            }
    106117        }
     
    120131        synchronized (this) {
    121132            this.free = true;
    122 
    123             // Signal the consumer that we are done in case it was waiting
    124             consumer.notifyWorkerIsFree(this);
    125133        }
    126134    }
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginObjectStore.java

    r348 r429  
    4646    INSTANCE;
    4747
    48     private HashMap<Integer, Object> objects = new HashMap<Integer, Object>();
    49     private HashMap<Integer, Integer> counts = new HashMap<Integer, Integer>();
    50     private HashMap<Object, Integer> identifiers = new HashMap<Object, Integer>();
     48    private final Map<Integer, Object> objects = new HashMap<Integer, Object>();
     49    private final Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
     50    private final Map<Object, Integer> identifiers = new HashMap<Object, Integer>();
    5151    private final Object lock = new Object();
    5252
     
    6565
    6666    public Integer getIdentifier(Object object) {
     67        if (object == null)
     68            return 0;
     69
    6770        synchronized(lock) {
    68             if (object == null)
    69                 return 0;
    7071            return identifiers.get(object);
    7172        }
     
    7374
    7475    public boolean contains(Object object) {
    75         synchronized(lock) {
    76             if (object == null)
     76        if (object != null) {
     77            synchronized(lock) {
    7778                return identifiers.containsKey(object);
     79            }
     80        }
     81        return false;
    7882
    79             return false;
    80         }
    8183    }
    8284
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java

    r348 r429  
    3939
    4040import java.net.URI;
     41import net.sourceforge.jnlp.util.logging.OutputController;
    4142
    4243/**
     
    6970            // Nothing.. this is expected if there is no proxy
    7071        } catch (Exception e) {
    71             e.printStackTrace();
     72            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    7273        }
    7374
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginProxySelector.java

    r348 r429  
    3838package sun.applet;
    3939
     40import java.io.UnsupportedEncodingException;
    4041import java.net.InetSocketAddress;
    4142import java.net.Proxy;
    4243import java.net.URI;
     44import java.net.URISyntaxException;
    4345import java.util.ArrayList;
    4446import java.util.List;
    4547
     48import com.sun.jndi.toolkit.url.UrlUtil;
     49
     50import net.sourceforge.jnlp.config.DeploymentConfiguration;
    4651import net.sourceforge.jnlp.runtime.JNLPProxySelector;
     52import net.sourceforge.jnlp.util.logging.OutputController;
    4753import net.sourceforge.jnlp.util.TimedHashMap;
    4854
     
    5965
    6066    private TimedHashMap<String, Proxy> proxyCache = new TimedHashMap<String, Proxy>();
     67
     68    public PluginProxySelector(DeploymentConfiguration config) {
     69        super(config);
     70    }
    6171
    6272    /**
     
    7989
    8090        // Nothing usable in cache. Fetch info from browser
     91
     92        String requestURI;
     93        try {
     94            requestURI = convertUriSchemeForProxyQuery(uri);
     95        } catch (Exception e) {
     96            PluginDebug.debug("Cannot construct URL from ", uri.toString(), " ... falling back to DIRECT proxy");
     97            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
     98            proxyList.add(Proxy.NO_PROXY);
     99            return proxyList;
     100        }
     101
    81102        Proxy proxy = Proxy.NO_PROXY;
    82         Object o = PluginAppletViewer.requestPluginProxyInfo(uri);
     103        Object o = getProxyFromRemoteCallToBrowser(requestURI);
    83104
    84105        // If the browser returned anything, try to parse it. If anything in the try block fails, the fallback is direct connection
     
    96117                    proxy = new Proxy(type, socketAddr);
    97118
    98                     String uriKey = uri.getScheme() + "://" + uri.getHost();
     119                    String uriKey = computeKey(uri);
    99120                    proxyCache.put(uriKey, proxy);
    100121                } else {
     
    103124            }
    104125        } catch (Exception e) {
    105             e.printStackTrace();
     126            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    106127        }
    107128
     
    113134    }
    114135
     136    /** For tests to override */
     137    protected Object getProxyFromRemoteCallToBrowser(String uri) {
     138        return PluginAppletViewer.requestPluginProxyInfo(uri);
     139    }
     140
    115141    /**
    116142     * Checks to see if proxy information is already cached.
     
    120146     */
    121147    private Proxy checkCache(URI uri) {
    122 
    123         String uriKey = uri.getScheme() + "://" + uri.getHost();
     148        String uriKey = computeKey(uri);
    124149        if (proxyCache.get(uriKey) != null) {
    125150            return proxyCache.get(uriKey);
     
    129154    }
    130155
     156    /** Compute a key to use for the proxy cache */
     157    private String computeKey(URI uri) {
     158        return uri.getScheme() + "://" + uri.getHost();
     159    }
     160
     161    public static String convertUriSchemeForProxyQuery(URI uri) throws URISyntaxException, UnsupportedEncodingException {
     162        // there is no easy way to get SOCKS proxy info. So, we tell mozilla that we want proxy for
     163        // an HTTP uri in case of non http/ftp protocols. If we get back a SOCKS proxy, we can
     164        // use that, if we get back an http proxy, we fallback to DIRECT connect
     165
     166        String scheme = uri.getScheme();
     167        if (!scheme.startsWith("http") && !scheme.equals("ftp")) {
     168            scheme = "http";
     169        }
     170
     171        URI result = new URI(scheme, uri.getUserInfo(), uri.getHost(), uri.getPort(),
     172                uri.getPath(), uri.getQuery(), uri.getFragment());
     173        return UrlUtil.encode(result.toString(), "UTF-8");
     174    }
    131175}
  • trunk/icedtea-web/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java

    r418 r429  
    1 /* VoidPluginCallRequest -- represent Java-to-JavaScript requests
     1/*
    22   Copyright (C) 2008  Red Hat
    33
     
    4545import java.io.OutputStream;
    4646import java.io.OutputStreamWriter;
    47 import java.net.MalformedURLException;
    4847import java.nio.charset.Charset;
    4948
    5049import javax.swing.SwingUtilities;
     50import net.sourceforge.jnlp.runtime.JNLPRuntime;
     51import net.sourceforge.jnlp.runtime.Translator;
     52import net.sourceforge.jnlp.util.logging.JavaConsole;
     53import net.sourceforge.jnlp.util.logging.OutputController;
    5154
    5255public class PluginStreamHandler {
     
    5760    private RequestQueue queue = new RequestQueue();
    5861
    59     private JavaConsole console = new JavaConsole();
    6062
    6163    private PluginMessageConsumer consumer;
     
    6365
    6466
    65     public PluginStreamHandler(InputStream inputstream, OutputStream outputstream)
    66             throws MalformedURLException, IOException {
     67    public PluginStreamHandler(InputStream inputstream, OutputStream outputstream) {
    6768
    6869        PluginDebug.debug("Current context CL=", Thread.currentThread().getContextClassLoader());
     
    8283    public void startProcessing() {
    8384
    84         Thread listenerThread = new Thread() {
     85        Thread listenerThread = new Thread("PluginStreamHandlerListenerThread") {
    8586
    8687            public void run() {
     
    105106                        AppletSecurityContextManager.dumpStore(0);
    106107                        PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
    107                         System.exit(0);
     108                        JNLPRuntime.exit(0);
    108109                    }
    109110                }
     
    242243    private void handlePluginMessage(String message) {
    243244        if (message.equals("plugin showconsole")) {
    244             showConsole();
     245            if (JavaConsole.isEnabled()){
     246                JavaConsole.getConsole().showConsoleLater();
     247            } else {
     248                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, Translator.R("DPJavaConsoleDisabledHint"));
     249            }
    245250        } else if (message.equals("plugin hideconsole")) {
    246             hideConsole();
     251            if (JavaConsole.isEnabled()){
     252                JavaConsole.getConsole().hideConsoleLater();
     253            } else {
     254                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, Translator.R("DPJavaConsoleDisabledHint"));
     255            }
    247256        } else {
    248257            // else this is something that was specifically requested
     
    312321     *
    313322     * @return the read string
    314      *
    315      * @exception IOException if an error occurs
    316323     */
    317324    private String read() {
     
    334341                AppletSecurityContextManager.dumpStore(0);
    335342                PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
    336                 System.exit(0);
     343                JNLPRuntime.exit(0);
    337344            }
    338345        } catch (IOException e) {
    339             e.printStackTrace();
     346            OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    340347        }
    341348
     
    347354     *
    348355     * @param message the message to write
    349      *
    350      * @exception IOException if an error occurs
    351356     */
    352357    public void write(String message) {
     
    362367                // pipe may have closed
    363368                if (!shuttingDown) {
    364                     e.printStackTrace();
     369                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL,e);
    365370                }
    366371
     
    368373                // we can do anymore. Don't hang around.
    369374                PluginDebug.debug("Unable to write to PIPE. APPLETVIEWER exiting");
    370                 System.exit(1);
     375                JNLPRuntime.exit(1);
    371376            }
    372377        }
     
    374379        return;
    375380    }
    376 
    377     private void showConsole() {
    378         SwingUtilities.invokeLater(new Runnable() {
    379             public void run() {
    380                 console.showConsole();
    381             }
    382         });
    383     }
    384 
    385     private void hideConsole() {
    386         SwingUtilities.invokeLater(new Runnable() {
    387             public void run() {
    388                 console.hideConsole();
    389             }
    390         });
    391     }
    392381}
Note: See TracChangeset for help on using the changeset viewer.