Example #1
0
/*
 * There are a few ways to arrive in the initsequencer.
 * 1. From _PG_init (called exactly once when the library is loaded for ANY
 *    reason).
 *    1a. Because of the command LOAD 'libraryname';
 *        This case can be distinguished because _PG_init will have found the
 *        LOAD command and saved the 'libraryname' in pljavaLoadPath.
 *    1b. Because of a CREATE FUNCTION naming this library. pljavaLoadPath will
 *        be NULL.
 *    1c. By the first actual use of a PL/Java function, causing this library
 *        to be loaded. pljavaLoadPath will be NULL. The called function's Oid
 *        will be available to the call handler once we return from _PG_init,
 *        but it isn't (easily) available here.
 * 2. From the call handler, if initialization isn't complete yet. That can only
 *    mean something failed in the earlier call to _PG_init, and whatever it was
 *    is highly likely to fail again. That may lead to the untidyness of
 *    duplicated diagnostic messages, but for now I like the belt-and-suspenders
 *    approach of making sure the init sequence gets as many chances as possible
 *    to succeed.
 * 3. From a GUC assign hook, if the user has updated a setting that might allow
 *    initialization to succeed. It resumes from where it left off.
 *
 * In all cases, the sequence must progress as far as starting the VM and
 * initializing the PL/Java classes. In all cases except 1a, that's enough,
 * assuming the language handlers and schema have all been set up already (or,
 * in case 1b, the user is intent on setting them up explicitly).
 *
 * In case 1a, we can go ahead and test for, and create, the schema, functions,
 * and language entries as needed, using pljavaLoadPath as the library path
 * if creating the language handler functions. One-stop shopping. (The presence
 * of pljavaLoadPath in any of the other cases, such as resumption by an assign
 * hook, indicates it is really a continuation of case 1a.)
 */
static void initsequencer(enum initstage is, bool tolerant)
{
	JVMOptList optList;
	Invocation ctx;
	jint JNIresult;
	char *greeting;

	switch (is)
	{
	case IS_FORMLESS_VOID:
		initstage = IS_GUCS_REGISTERED;

	case IS_GUCS_REGISTERED:
		libjvmlocation = strdup("libjvm.so");

		initstage = IS_PLJAVA_ENABLED;

	case IS_PLJAVA_ENABLED:
		libjvm_handle = pg_dlopen(libjvmlocation);
		if ( NULL == libjvm_handle )
		{
			ereport(ERROR, (
				errmsg("Cannot load libjvm.so library, check that it is available in LD_LIBRARY_PATH"),
				errdetail("%s", (char *)pg_dlerror())));
			goto check_tolerant;
		}
		initstage = IS_CAND_JVMOPENED;

	case IS_CAND_JVMOPENED:
		pljava_createvm =
			(jint (JNICALL *)(JavaVM **, void **, void *))
			pg_dlsym(libjvm_handle, "JNI_CreateJavaVM");
		if ( NULL == pljava_createvm )
		{
			/*
			 * If it hasn't got the symbol, it can't be the right
			 * library, so close/unload it so another can be tried.
			 * Format the dlerror string first: dlclose may clobber it.
			 */
			char *dle = MemoryContextStrdup(ErrorContext, pg_dlerror());
			pg_dlclose(libjvm_handle);
			initstage = IS_CAND_JVMLOCATION;
			ereport(ERROR, (
				errmsg("Cannot start Java VM"),
				errdetail("%s", dle),
				errhint("Check that libjvm.so is available in LD_LIBRARY_PATH")));
			goto check_tolerant;
		}
		initstage = IS_CREATEVM_SYM_FOUND;

	case IS_CREATEVM_SYM_FOUND:
		s_javaLogLevel = INFO;
		checkIntTimeType();
		HashMap_initialize(); /* creates things in TopMemoryContext */
#ifdef PLJAVA_DEBUG
		/* Hard setting for debug. Don't forget to recompile...
		 */
		pljava_debug = 1;
#endif
		initstage = IS_MISC_ONCE_DONE;

	case IS_MISC_ONCE_DONE:
		JVMOptList_init(&optList); /* uses CurrentMemoryContext */
		seenVisualVMName = false;
		addUserJVMOptions(&optList);
		if ( ! seenVisualVMName )
			JVMOptList_addVisualVMName(&optList);
		JVMOptList_add(&optList, "vfprintf", (void*)my_vfprintf, true);
#ifndef GCJ
		JVMOptList_add(&optList, "-Xrs", 0, true);
#endif
		effectiveClassPath = getClassPath("-Djava.class.path=");
		if(effectiveClassPath != 0)
		{
			JVMOptList_add(&optList, effectiveClassPath, 0, true);
		}
		initstage = IS_JAVAVM_OPTLIST;

	case IS_JAVAVM_OPTLIST:
		JNIresult = initializeJavaVM(&optList); /* frees the optList */
		if( JNI_OK != JNIresult )
		{
			initstage = IS_MISC_ONCE_DONE; /* optList has been freed */
			StaticAssertStmt(sizeof(jint) <= sizeof(long int),
				"jint wider than long int?!");
			ereport(WARNING,
				(errmsg("failed to create Java virtual machine"),
				 errdetail("JNI_CreateJavaVM returned an error code: %ld",
					(long int)JNIresult),
				 jvmStartedAtLeastOnce ?
					errhint("Because an earlier attempt during this session "
					"did start a VM before failing, this probably means your "
					"Java runtime environment does not support more than one "
					"VM creation per session.  You may need to exit this "
					"session and start a new one.") : 0));
			goto check_tolerant;
		}
		jvmStartedAtLeastOnce = true;
		elog(DEBUG2, "successfully created Java virtual machine");
		initstage = IS_JAVAVM_STARTED;

	case IS_JAVAVM_STARTED:
#ifdef USE_PLJAVA_SIGHANDLERS
		pqsignal(SIGINT,  pljavaStatementCancelHandler);
		pqsignal(SIGTERM, pljavaDieHandler);
#endif
		/* Register an on_proc_exit handler that destroys the VM
		 */
		on_proc_exit(_destroyJavaVM, 0);
		initstage = IS_SIGHANDLERS;

	case IS_SIGHANDLERS:
		Invocation_pushBootContext(&ctx);
		PG_TRY();
		{
			initPLJavaClasses();
			initJavaSession();
			Invocation_popBootContext();
			initstage = IS_PLJAVA_FOUND;
		}
		PG_CATCH();
		{
			MemoryContextSwitchTo(ctx.upperContext); /* leave ErrorContext */
			Invocation_popBootContext();
			initstage = IS_MISC_ONCE_DONE;
			/* We can't stay here...
			 */
			if ( tolerant )
				reLogWithChangedLevel(WARNING); /* so xact is not aborted */
			else
			{
				EmitErrorReport(); /* no more unwinding, just log it */
				/* Seeing an ERROR emitted to the log, without leaving the
				 * transaction aborted, would violate the principle of least
				 * astonishment. But at check_tolerant below, another ERROR will
				 * be thrown immediately, so the transaction effect will be as
				 * expected and this ERROR will contribute information beyond
				 * what is in the generic one thrown down there.
				 */
				FlushErrorState();
			}
		}
		PG_END_TRY();
		if ( IS_PLJAVA_FOUND != initstage )
		{
			/* JVM initialization failed for some reason. Destroy
			 * the VM if it exists. Perhaps the user will try
			 * fixing the pljava.classpath and make a new attempt.
			 */
			ereport(WARNING, (
				errmsg("failed to load initial PL/Java classes"),
				errhint("The most common reason is that \"pljava_classpath\" "
					"needs to be set, naming the proper \"pljava.jar\" file.")
					));
			_destroyJavaVM(0, 0);
			goto check_tolerant;
		}

	case IS_PLJAVA_FOUND:
		greeting = InstallHelper_hello();
		ereport(NULL != pljavaLoadPath ? NOTICE : DEBUG1, (
				errmsg("PL/Java loaded"),
				errdetail("versions:\n%s", greeting)));
		pfree(greeting);
		if ( NULL != pljavaLoadPath )
			InstallHelper_groundwork(); /* sqlj schema, language handlers, ...*/
		initstage = IS_COMPLETE;

	case IS_COMPLETE:
		pljavaLoadingAsExtension = false;
		if ( alteredSettingsWereNeeded )
		{
			/* Use this StringInfoData to conditionally construct part of the
			 * hint string suggesting ALTER DATABASE ... SET ... FROM CURRENT
			 * provided the server is >= 9.2 where that will actually work.
			 * In 9.3, psprintf appeared, which would make this all simpler,
			 * but if 9.3+ were all that had to be supported, this would all
			 * be moot anyway. Doing the initStringInfo inside the ereport
			 * ensures the string is allocated in ErrorContext and won't leak.
			 * Don't remove the extra parens grouping
			 * (initStringInfo, appendStringInfo, errhint) ... with the parens,
			 * that's a comma expression, which is sequenced; without them, they
			 * are just function parameters with evaluation order unknown.
			 */
			StringInfoData buf;
#if PG_VERSION_NUM >= 90200
#define MOREHINT \
				appendStringInfo(&buf, \
					"using ALTER DATABASE %s SET ... FROM CURRENT or ", \
					pljavaDbName()),
#else
#define MOREHINT
#endif
			ereport(NOTICE, (
				errmsg("PL/Java successfully started after adjusting settings"),
				(initStringInfo(&buf),
				MOREHINT
				errhint("The settings that worked should be saved (%s"
					"in the \"%s\" file). For a reminder of what has been set, "
					"try: SELECT name, setting FROM pg_settings WHERE name LIKE"
					" 'pljava.%%' AND source = 'session'",
					buf.data,
					superuser()
						? PG_GETCONFIGOPTION("config_file")
						: "postgresql.conf"))));
#undef MOREHINT
			if ( loadAsExtensionFailed )
			{
				ereport(NOTICE, (errmsg(
					"PL/Java load successful after failed CREATE EXTENSION"),
					errdetail(
					"PL/Java is now installed, but not as an extension."),
					errhint(
					"To correct that, either COMMIT or ROLLBACK, make sure "
					"the working settings are saved, exit this session, and "
					"in a new session, either: "
					"1. if committed, run "
					"\"CREATE EXTENSION pljava FROM unpackaged\", or 2. "
					"if rolled back, simply \"CREATE EXTENSION pljava\" again."
					)));
			}
		}
		return;

	default:
		ereport(ERROR, (
			errmsg("cannot set up PL/Java"),
			errdetail(
				"An unexpected stage was reached in the startup sequence."),
			errhint(
				"Please report the circumstances to the PL/Java maintainers.")
			));
	}

check_tolerant:
	if ( pljavaLoadingAsExtension )
	{
		tolerant = false;
		loadAsExtensionFailed = true;
		pljavaLoadingAsExtension = false;
	}
	if ( !tolerant )
	{
		ereport(ERROR, (
			errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
			errmsg(
				"cannot use PL/Java before successfully completing its setup"),
			errhint(
				"Check the log for messages closely preceding this one, "
				"detailing what step of setup failed and what will be needed, "
				"probably setting one of the \"pljava.\" configuration "
				"variables, to complete the setup. If there is not enough "
				"help in the log, try again with different settings for "
				"\"log_min_messages\" or \"log_error_verbosity\".")));
	}
}
OSStatus MRJSession::open(const char* consolePath)
{
    // Use vanilla JNI invocation API to fire up a fresh JVM.
    string classPath = getClassPath();
    string pluginHome = getPluginHome();
    JavaVMOption theOptions[] = {
    	{ (char*) classPath.c_str() },
    	{ (char*) pluginHome.c_str() },
#if REDIRECT_VFPRINTF
    	{ "vfprintf", NewMachOFunctionPointer(&java_vfprintf) }
#endif
    };

    JavaVMInitArgs theInitArgs = {
    	JNI_VERSION_1_2,
    	sizeof(theOptions) / sizeof(JavaVMOption),
    	theOptions,
    	JNI_TRUE
    };

    mStatus = ::JNI_CreateJavaVM(&mJavaVM, (void**) &mMainEnv, &theInitArgs);
    
    if (mStatus == noErr) {
       	// create a monitor for the message queue to unblock Java threads.
		mMessageMonitor = new MRJMonitor(this);
    }

    JNIEnv* env = mMainEnv;
    jclass session = env->FindClass("netscape/oji/MRJSession");
    if (session) {
        mSession = (jclass) env->NewGlobalRef(session);
        jmethodID openMethod = env->GetStaticMethodID(session, "open", "(Ljava/lang/String;)V");
        if (openMethod) {
            jstring path = env->NewStringUTF(consolePath);
            if (path) {
                env->CallStaticVoidMethod(session, openMethod, path);
                if (env->ExceptionCheck())
                    env->ExceptionClear();
                env->DeleteLocalRef(path);
            }
        } else {
            env->ExceptionClear();
        }
        env->DeleteLocalRef(session);
    } else {
        env->ExceptionClear();
    }

    if (mStatus == noErr)
        theSession = this;

#if REDIRECT_VFPRINTF
    // XXX test the vfprintf function.
    jclass notThere = env->FindClass("class/not/Found");
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
#endif

    return mStatus;
}
Example #3
0
void JVM::jvmStartup(QString libname)
{
	QLibrary lib (libname);
	cjvm_fn fn = (cjvm_fn) lib.resolve("JNI_CreateJavaVM");

	qDebug() << "libjvm found in" << libname;
	setSettingsValue("extensions/jvm_path", libname);

	if (!fn)
	{
		Logger::global()->enterLogMessage("JPlugin", QObject::tr("Failed to load the correct libjvm: %1").arg(lib.errorString()));
		return;
	}

	jint res;
	JavaVMInitArgs vm_args;
#ifdef DEBUG_BUILD
	JavaVMOption options[9];
#else
	JavaVMOption options[7];
#endif
	
	JNIEnv* env;
	QByteArray classpath = getClassPath().toUtf8();
	int mb = getSettingsValue("java/maxheap").toInt();

	if (!mb)
		mb = 16;

	classpath.prepend("-Djava.class.path=");
	qDebug() << "Java Classpath set to" << classpath;

	options[0].optionString = classpath.data();
	options[1].optionString = static_cast<char*>(alloca(24));

	snprintf(options[1].optionString, 24, "-Xmx%dm", mb);
	options[2].optionString = const_cast<char*>("-Djava.security.manager");
	options[3].optionString = const_cast<char*>("-Djava.security.policy=" DATA_LOCATION "/data/java/extension.policy");
	options[4].optionString = const_cast<char*>("-XX:+UseParNewGC");
	options[5].optionString = const_cast<char*>("-XX:MinHeapFreeRatio=5");
	options[6].optionString = const_cast<char*>("-XX:MaxHeapFreeRatio=10");
#ifdef DEBUG_BUILD
	options[7].optionString = const_cast<char*>("-Xdebug");
	options[8].optionString = const_cast<char*>("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8222");
#endif

	vm_args.version = 0x00010006;
	vm_args.options = options;
	vm_args.nOptions = sizeof(options)/sizeof(options[0]);
	vm_args.ignoreUnrecognized = JNI_TRUE;

	res = fn(&m_jvm, (void**)&env, &vm_args);
	if (res < 0)
	{
		Logger::global()->enterLogMessage("JPlugin", QObject::tr("Failed to create a Java VM"));
		return;
	}
	JNIEnv** penv = new JNIEnv*;
	*penv = env;
	m_env.setLocalData(penv);

	if (!m_instance)
		m_instance = this;

	try
	{
		singleCObjectRegisterNatives();
		JSettings::registerNatives();
		JPlugin::registerNatives();
		JTransferPlugin::registerNatives();
		JDownloadPlugin::registerNatives();
		JBackgroundWorker::registerNatives();
		JAccountStatusPlugin::registerNatives();
	}
	catch (...)
	{
		qDebug() << "Failed to register JNI functions. This usually happens when there is an API discrepancy between the Java and the native code.\nPlease, remove ~/.local/share/fatrat/data/java/libs/fatrat-jplugins-core.jar, and try again";
		abort();
	}
}
bool
ScriptablePluginObject::Invoke(NPIdentifier name, const NPVariant *args,
                               uint32_t argCount, NPVariant *result)
/*
name : method name
args : arguments
argCount : number of arguments
result : return value
*/
{
	NPIdentifier test_id = NPN_GetStringIdentifier("test");
	if (name == test_id) {
		printf("temp = %s\n",getTemporaryPath());
		printf("home = %s\n",getHomePath());
		printf("firefox = %s\n",getFirefoxPath());
		printf("conf = %s\n",getConfPath());
		printf("classpath = %s\n",getClassPath());
		printf("spawn = %s\n",getSpawnPath());
		VOID_TO_NPVARIANT(*result);
		return true;
	}

	NPError err;
	if (!this->HasMethod(name))
		return false;
	VOID_TO_NPVARIANT(*result);

	//login.jsp test
	NPIdentifier doSignature_id = NPN_GetStringIdentifier("doSignature");
	NPIdentifier getPublicKeyContent_id = NPN_GetStringIdentifier("getPublicKeyContent");


	NPObject* sWindowNPObj;

	if ((err = NPN_GetValue(mNpp, NPNVWindowNPObject, &sWindowNPObj)) != NPERR_NO_ERROR) {
		printf("Error in getting NPNVWindowNPObject: %d\n",err);
		return false;
	}

	const char *tmpdir = getTemporaryPath();
	const char *classpath = getClassPath();
	const char *spawnpath = getSpawnPath();

	if (name == doSignature_id) {
		if ((argCount == 2) && (NPVARIANT_IS_STRING(args[0])) && (NPVARIANT_IS_STRING(args[1]))) {
			char *randomStr = NULL;
			char *tpmPass = NULL;
			NPString n_randomStr = NPVARIANT_TO_STRING(args[0]);
			NPString n_tpmPass = NPVARIANT_TO_STRING(args[1]);
			m_strFromNP(&randomStr,n_randomStr);
			m_strFromNP(&tpmPass,n_tpmPass);
			printf("input = %s, %s",randomStr, tpmPass);

			char* ret = NULL;
			char *fname = tempnam(tmpdir,"jni");
			if (fname == NULL)
				fname = "tmp";
			char* margs[12];
			margs[0] = (char*) spawn_file;
			margs[1] = "--file";
			margs[2] = fname;
			margs[3] = "--method";
			margs[4] = "doSignature";
			margs[5] = "--classpath";
			margs[6] = (char*) classpath;
			margs[7] = "--args";
			margs[8] = "2";
			margs[9] = randomStr;
			margs[10] = tpmPass;
			margs[11] = NULL;
			// in windows use registry to find Firefox directory
			// in other OS, use path _spawnvp
			int rval = _spawnv(_P_WAIT,spawnpath,margs);
			if (rval) {
				fprintf(stderr,"error = %d\n",rval);
			}
			else {
				ret = getFileContent(fname);
				if (ret) {
					STRINGZ_TO_NPVARIANT(ret,*result); 
				}
				else {
					fprintf(stderr,"cannot read output file");
				}
				unlink(fname);
			}
			free(fname);
		}
		else {
			NPString str;
			str.UTF8Characters = "alert('usage: doSignature(String, String)');";
			str.UTF8Length = strlen(str.UTF8Characters);
			NPN_Evaluate(this->mNpp, sWindowNPObj, &str, NULL);
		}
	}
	else if (name == getPublicKeyContent_id) {
		if (argCount == 0) {
			char *ret = NULL;
			char *fname = tempnam(tmpdir,"jni");
			if (fname == NULL)
				fname = "tmp";
			char* margs[8];
			margs[0] = (char*) spawn_file;
			margs[1] = "--file";
			margs[2] = fname;
			margs[3] = "--method";
			margs[4] = "getPublicKeyContent";
			margs[5] = "--classpath";
			margs[6] = (char*) classpath;
			margs[7] = NULL;
			int rval = _spawnv(_P_WAIT,spawnpath,margs);
			if (rval) {
				fprintf(stderr,"error = %d\n",rval);
			}
			else {
				ret = getFileContent(fname);
				if (ret) {
					STRINGZ_TO_NPVARIANT(ret,*result); 
				}
				else {
					fprintf(stderr,"cannot read output file");
				}
				unlink(fname);
			}
			free(fname);
		}
		else {
			NPString str;
			str.UTF8Characters = "alert('usage: getPublicKeyContent()');";
			str.UTF8Length = strlen(str.UTF8Characters);
			NPN_Evaluate(this->mNpp, sWindowNPObj, &str, NULL);
		}
	}
	NPN_ReleaseObject(sWindowNPObj);
  return true;
}
Example #5
0
bool SunJVMExe::run(const std::string& mainclass, bool useconsole)
{
  if (!m_version.isValid())
    {
      m_version = guessVersion();
    }
  
  if (!m_version.isValid())
    return false;
  
  std::vector<std::string> execv;

  execv.push_back(StringUtils::requoteForCommandLine(lookUpExecutable(useconsole)));

   if (m_vmParameter != "")
    {
      std::vector<std::string> vmParameter = StringUtils::split(m_vmParameter, " ", " ", false);
      for (std::vector<std::string>::iterator i=vmParameter.begin(); i != vmParameter.end(); i++)
      {
        execv.push_back(*i);
      }
    }
    
   if (m_maxHeap > 0)
    {
      if ((m_version.getMajor()==1)&&(m_version.getMinor()==1))
	execv.push_back("-mx" + StringUtils::toString(m_maxHeap));
      else
	execv.push_back("-Xmx" + StringUtils::toString(m_maxHeap));
    }

  if (m_initialHeap > 0)
    {
      if ((m_version.getMajor()==1)&&(m_version.getMinor()==1))
	execv.push_back("-ms" + StringUtils::toString(m_initialHeap));
      else
	execv.push_back("-Xms" + StringUtils::toString(m_initialHeap));
    }

  for (int i=0; i<m_properties.size(); i++)
    if(m_properties[i].getName()[0]=='-') {
        execv.push_back( StringUtils::requoteForCommandLine(m_properties[i].getName()));
    } else {
    execv.push_back( StringUtils::requoteForCommandLine("-D" + m_properties[i].getName()) + "=" + StringUtils::requoteForCommandLine(m_properties[i].getValue()));
    }

  std::string classpath;
  if ((m_version.getMajor()==1)&&(m_version.getMinor()==1))
    classpath = getClassPath(true);
  else
    classpath = getClassPath(false);
  
  if (classpath.size() > 0)
    execv.push_back("-classpath " + StringUtils::requoteForCommandLine(classpath));

  execv.push_back(mainclass);

  for (int i=0; i<m_arguments.size(); i++)
    {
      execv.push_back( StringUtils::requoteForCommandLine(m_arguments[i]) );
    }

  std::string execmd = StringUtils::join(execv, " ");
  DEBUG("COMMAND: <" + execmd + ">");

  Process proc(execmd, useconsole);
  if (proc.run())
    {
      DEBUG("Started successfully");
      proc.join();
      m_exitCode = proc.getExitCode();
      return true;
    }
  else
    {
      DEBUG("Failed running " + execmd);
    }
  return false;
}