<commit_before>/*
 * Copyright 2009-2011 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "condor_common.h"
#include "condor_config.h"

#include "SchedulerObject.h"

#include "ArgsSchedulerSubmitJob.h"
#include "ArgsSchedulerSetJobAttribute.h"
#include "ArgsSchedulerHoldJob.h"
#include "ArgsSchedulerReleaseJob.h"
#include "ArgsSchedulerRemoveJob.h"

#ifndef WIN32
	#include "stdint.h"
#endif

#include "PoolUtils.h"
#include "JobUtils.h"
#include "Utils.h"

#include "condor_attributes.h"

#include "condor_debug.h"

#include "condor_qmgr.h"

#include "MgmtConversionMacros.h"

#ifndef READ_ONLY_SCHEDULER_OBJECT
// Global Scheduler object, used for needReschedule
#include "../condor_schedd.V6/scheduler.h"
extern Scheduler scheduler;
extern char * Name;
extern bool qmgmt_all_users_trusted;
#endif

using namespace com::redhat::grid;
using namespace qmf::com::redhat::grid;
using namespace qpid::management;
using namespace qpid::types;

SchedulerObject::SchedulerObject(qpid::management::ManagementAgent *agent,
					const char* _name)
{
	mgmtObject = new qmf::com::redhat::grid::Scheduler(agent, this);

	// By default the scheduler will be persistent.
	bool _lifetime = param_boolean("QMF_IS_PERSISTENT", true);
	agent->addObject(mgmtObject, _name, _lifetime);
}

SchedulerObject::~SchedulerObject()
{
	if (mgmtObject) {
		mgmtObject->resourceDestroy();
	}
}

void
SchedulerObject::update(const ClassAd &ad)
{
	MGMT_DECLARATIONS;

	mgmtObject->set_Pool(GetPoolName());

	STRING(CondorPlatform);
	STRING(CondorVersion);
	TIME_INTEGER(DaemonStartTime);
	TIME_INTEGER(JobQueueBirthdate);
	STRING(Machine);
	INTEGER(MaxJobsRunning);
	INTEGER(MonitorSelfAge);
	DOUBLE(MonitorSelfCPUUsage);
	DOUBLE(MonitorSelfImageSize);
	INTEGER(MonitorSelfRegisteredSocketCount);
	INTEGER(MonitorSelfResidentSetSize);
	TIME_INTEGER(MonitorSelfTime);
	STRING(MyAddress);
		//TIME_INTEGER(MyCurrentTime);
	STRING(Name);
	INTEGER(NumUsers);
	STRING(MyAddress);
	INTEGER(TotalHeldJobs);
	INTEGER(TotalIdleJobs);
	INTEGER(TotalJobAds);
	INTEGER(TotalRemovedJobs);
	INTEGER(TotalRunningJobs);

	mgmtObject->set_System(mgmtObject->get_Machine());

	// debug
	if (DebugFlags & D_FULLDEBUG) {
		const_cast<ClassAd*>(&ad)->dPrint(D_FULLDEBUG|D_NOHEADER);
	}
}

#ifndef READ_ONLY_SCHEDULER_OBJECT
Manageable::status_t
SchedulerObject::Submit(Variant::Map &jobAdMap, std::string &id, std::string &text)
{
	int cluster;
	int proc;

	// our mandatory set of attributes for a submit
	const char* required[] = {
				ATTR_JOB_CMD,
				ATTR_REQUIREMENTS,
				ATTR_OWNER,
				ATTR_JOB_IWD,
				NULL
				};

		// 1. Create transaction
	BeginTransaction();

		// 2. Create cluster
	if (-1 == (cluster = NewCluster())) {
		AbortTransaction();
		text = "Failed to create new cluster";
		return STATUS_USER + 1;
	}

		// 3. Create proc
	if (-1 == (proc = NewProc(cluster))) {
		AbortTransaction();
		text = "Failed to create new proc";
		return STATUS_USER + 2;
	}

		// 4. Submit job ad

		// Schema: (vanilla job)
		// Schedd demands - Owner, JobUniverse
		// To run - JobStatus, Requirements

		// Schedd excepts if no Owner
		// Schedd prunes on startup if no Owner or JobUniverse
		// Schedd won't run job without JobStatus
		// Job cannot match without Requirements
		// Shadow rejects jobs without an Iwd
		// Shadow: Job has no CondorVersion, assuming pre version 6.3.3
		// Shadow: Unix Vanilla job is pre version 6.3.3, setting 'TransferFiles = "NEVER"'
		// Starter won't run job without Cmd
		// Starter needs a valid Owner (local account name) if not using nobody
		// condor_q requires ClusterId (int), ProcId (int), QDate (int), RemoteUserCpu (float), JobStatus (int), JobPrio (int), ImageSize (int), Owner (str) and Cmd (str)

		// Schema: (vm job)

	ClassAd ad;
	int universe;

    // ShouldTransferFiles - unset by default, must be set
    // shadow will try to setup local transfer sandbox otherwise
    // without good priv
    ad.Assign(ATTR_SHOULD_TRANSFER_FILES, "NO");

	if (!PopulateAdFromVariantMap(jobAdMap, ad, text)) {
		AbortTransaction();
		return STATUS_USER + 3;
	}

	std::string missing;
	if (!CheckRequiredAttrs(ad, required, missing)) {
		AbortTransaction();
		text = "Job ad is missing required attributes: " + missing;
		return STATUS_USER + 4;
	}

		// EARLY SET: These attribute are set early so the incoming ad
		// has a change to override them.
	::SetAttribute(cluster, proc, ATTR_JOB_STATUS, "1"); // 1 = idle

		// Junk that condor_q wants, but really shouldn't be necessary
	::SetAttribute(cluster, proc, ATTR_JOB_REMOTE_USER_CPU, "0.0"); // float
	::SetAttribute(cluster, proc, ATTR_JOB_PRIO, "0");              // int
	::SetAttribute(cluster, proc, ATTR_IMAGE_SIZE, "0");            // int

	if (!ad.LookupInteger(ATTR_JOB_UNIVERSE, universe)) {
		char* uni_str = param("DEFAULT_UNIVERSE");
		if (!uni_str) {
			universe = CONDOR_UNIVERSE_VANILLA;
		}
		else {
			universe = CondorUniverseNumber(uni_str);
		}
		::SetAttributeInt(cluster, proc, ATTR_JOB_UNIVERSE, universe );
	}
	// more stuff - without these our idle stats are whack
	if ( universe != CONDOR_UNIVERSE_MPI && universe != CONDOR_UNIVERSE_PVM ) {
		::SetAttribute(cluster, proc, ATTR_MAX_HOSTS, "1");              // int
		::SetAttribute(cluster, proc, ATTR_MIN_HOSTS, "1");            // int
	}
	::SetAttribute(cluster, proc, ATTR_CURRENT_HOSTS, "0"); // int

	ExprTree *expr;
	const char *name;
	std::string value;
	ad.ResetExpr();
	while (ad.NextExpr(name,expr)) {

			// All these extra lookups are horrible. They have to
			// be there because the ClassAd may have multiple
			// copies of the same attribute name! This means that
			// the last attribute with a given name will set the
			// value, but the last attribute tends to be the
			// attribute with the oldest (wrong) value. How
			// annoying is that!
		if (!(expr = ad.Lookup(name))) {
			dprintf(D_ALWAYS, "Failed to lookup %s\n", name);

			AbortTransaction();
			text = "Failed to parse job ad attribute";
			return STATUS_USER + 6;
		}

        value = ExprTreeToString(expr);
        ::SetAttribute(cluster, proc, name, value.c_str());
	}

		// LATE SET: These attributes are set late, after the incoming
		// ad, so they override whatever the incoming ad set.
	char buf[22]; // 22 is max size for an id, 2^32 + . + 2^32 + \0
	snprintf(buf, 22, "%d", cluster);
	::SetAttribute(cluster, proc, ATTR_CLUSTER_ID, buf);
	snprintf(buf, 22, "%d", proc);
	::SetAttribute(cluster, proc, ATTR_PROC_ID, buf);
	snprintf(buf, 22, "%d", time(NULL));
	::SetAttribute(cluster, proc, ATTR_Q_DATE, buf);

		// Could check for some invalid attributes, e.g
		//  JobUniverse <= CONDOR_UNIVERSE_MIN or >= CONDOR_UNIVERSE_MAX

		// 5. Commit transaction
	CommitTransaction();

		// 6. Reschedule
	scheduler.needReschedule();

		// 7. Return identifier
		// TODO: dag ids?
	MyString tmp;
	tmp.sprintf("%s#%d.%d", Name, cluster, proc);
	id = tmp.Value();

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::SetAttribute(std::string key,
							  std::string name,
							  std::string value,
							  std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "SetAttribute: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (IsSubmissionChange(name.c_str())) {
		text = "Changes to submission name not allowed";
		return STATUS_USER + 1;
	}

	if (IsKeyword(name.c_str())) {
		text = "Attribute name is reserved: " + name;
		return STATUS_USER + 2;
	}

	if (!IsValidAttributeName(name,text)) {
		return STATUS_USER + 3;
	}

		// All values are strings in the eyes of
		// ::SetAttribute. Their type is inferred when read from
		// the ClassAd log. It is important that the incoming
		// value is properly quoted to differentiate between EXPR
		// and STRING.
	if (::SetAttribute(id.cluster,
					   id.proc,
					   name.c_str(),
					   value.c_str())) {
		text = "Failed to set attribute " + name + " to " + value;
		return STATUS_USER + 4;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Hold(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Hold: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!holdJob(id.cluster,
				 id.proc,
				 reason.c_str(),
				 true, // Always perform this action within a transaction
				 true, // Always notify the shadow of the hold
				 false, // Do not email the user about this action
				 false, // Do not email admin about this action
				 false // This is not a system related (internal) hold
				 )) {
		text = "Failed to hold job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Release(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Release: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!releaseJob(id.cluster,
					id.proc,
					reason.c_str(),
					true, // Always perform this action within a transaction
					false, // Do not email the user about this action
					false // Do not email admin about this action
					)) {
		text = "Failed to release job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Remove(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Remove: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!abortJob(id.cluster,
				  id.proc,
				  reason.c_str(),
				  true // Always perform within a transaction
				  )) {
		text = "Failed to remove job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}
#endif

qpid::management::ManagementObject *
SchedulerObject::GetManagementObject(void) const
{
	return mgmtObject;
}

Manageable::status_t
SchedulerObject::ManagementMethod(uint32_t methodId,
								  Args &args,
								  std::string &text)
{
#ifndef READ_ONLY_SCHEDULER_OBJECT
	Manageable::status_t result = STATUS_OK;
	bool orig_qaut = qmgmt_all_users_trusted;
	qmgmt_all_users_trusted = true;

	switch (methodId) {
	case qmf::com::redhat::grid::Scheduler::METHOD_ECHO:
		if (!param_boolean("QMF_MANAGEMENT_METHOD_ECHO", false)) return STATUS_NOT_IMPLEMENTED;

		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_SUBMITJOB:
		result = Submit(((ArgsSchedulerSubmitJob &) args).i_Ad,
					  ((ArgsSchedulerSubmitJob &) args).o_Id,
					  text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_SETJOBATTRIBUTE:
		result = SetAttribute(((ArgsSchedulerSetJobAttribute &) args).i_Id,
							((ArgsSchedulerSetJobAttribute &) args).i_Name,
							((ArgsSchedulerSetJobAttribute &) args).i_Value,
							text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_HOLDJOB:
		result = Hold(((ArgsSchedulerHoldJob &) args).i_Id,
					((ArgsSchedulerHoldJob &) args).i_Reason,
					text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_RELEASEJOB:
		result = Release(((ArgsSchedulerReleaseJob &) args).i_Id,
					   ((ArgsSchedulerReleaseJob &) args).i_Reason,
					   text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_REMOVEJOB:
		result = Remove(((ArgsSchedulerRemoveJob &) args).i_Id,
					  ((ArgsSchedulerRemoveJob &) args).i_Reason,
					  text);
		break;
	default:
		result = STATUS_NOT_IMPLEMENTED;
	}

	qmgmt_all_users_trusted = orig_qaut;
	return result;
#else
	return STATUS_NOT_IMPLEMENTED;
#endif
}

bool
SchedulerObject::AuthorizeMethod(uint32_t methodId, Args& args, const std::string& userId) {
	dprintf(D_FULLDEBUG, "AuthorizeMethod: checking '%s'\n", userId.c_str());
	if (0 == userId.compare("cumin")) {
		return true;
	}
	return false;
}
<commit_msg>Reset qmgmt_all_users_trusted at all exit points<commit_after>/*
 * Copyright 2009-2011 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "condor_common.h"
#include "condor_config.h"

#include "SchedulerObject.h"

#include "ArgsSchedulerSubmitJob.h"
#include "ArgsSchedulerSetJobAttribute.h"
#include "ArgsSchedulerHoldJob.h"
#include "ArgsSchedulerReleaseJob.h"
#include "ArgsSchedulerRemoveJob.h"

#ifndef WIN32
	#include "stdint.h"
#endif

#include "PoolUtils.h"
#include "JobUtils.h"
#include "Utils.h"

#include "condor_attributes.h"

#include "condor_debug.h"

#include "condor_qmgr.h"

#include "MgmtConversionMacros.h"

#ifndef READ_ONLY_SCHEDULER_OBJECT
// Global Scheduler object, used for needReschedule
#include "../condor_schedd.V6/scheduler.h"
extern Scheduler scheduler;
extern char * Name;
extern bool qmgmt_all_users_trusted;
#endif

using namespace com::redhat::grid;
using namespace qmf::com::redhat::grid;
using namespace qpid::management;
using namespace qpid::types;

SchedulerObject::SchedulerObject(qpid::management::ManagementAgent *agent,
					const char* _name)
{
	mgmtObject = new qmf::com::redhat::grid::Scheduler(agent, this);

	// By default the scheduler will be persistent.
	bool _lifetime = param_boolean("QMF_IS_PERSISTENT", true);
	agent->addObject(mgmtObject, _name, _lifetime);
}

SchedulerObject::~SchedulerObject()
{
	if (mgmtObject) {
		mgmtObject->resourceDestroy();
	}
}

void
SchedulerObject::update(const ClassAd &ad)
{
	MGMT_DECLARATIONS;

	mgmtObject->set_Pool(GetPoolName());

	STRING(CondorPlatform);
	STRING(CondorVersion);
	TIME_INTEGER(DaemonStartTime);
	TIME_INTEGER(JobQueueBirthdate);
	STRING(Machine);
	INTEGER(MaxJobsRunning);
	INTEGER(MonitorSelfAge);
	DOUBLE(MonitorSelfCPUUsage);
	DOUBLE(MonitorSelfImageSize);
	INTEGER(MonitorSelfRegisteredSocketCount);
	INTEGER(MonitorSelfResidentSetSize);
	TIME_INTEGER(MonitorSelfTime);
	STRING(MyAddress);
		//TIME_INTEGER(MyCurrentTime);
	STRING(Name);
	INTEGER(NumUsers);
	STRING(MyAddress);
	INTEGER(TotalHeldJobs);
	INTEGER(TotalIdleJobs);
	INTEGER(TotalJobAds);
	INTEGER(TotalRemovedJobs);
	INTEGER(TotalRunningJobs);

	mgmtObject->set_System(mgmtObject->get_Machine());

	// debug
	if (DebugFlags & D_FULLDEBUG) {
		const_cast<ClassAd*>(&ad)->dPrint(D_FULLDEBUG|D_NOHEADER);
	}
}

#ifndef READ_ONLY_SCHEDULER_OBJECT
Manageable::status_t
SchedulerObject::Submit(Variant::Map &jobAdMap, std::string &id, std::string &text)
{
	int cluster;
	int proc;

	// our mandatory set of attributes for a submit
	const char* required[] = {
				ATTR_JOB_CMD,
				ATTR_REQUIREMENTS,
				ATTR_OWNER,
				ATTR_JOB_IWD,
				NULL
				};

		// 1. Create transaction
	BeginTransaction();

		// 2. Create cluster
	if (-1 == (cluster = NewCluster())) {
		AbortTransaction();
		text = "Failed to create new cluster";
		return STATUS_USER + 1;
	}

		// 3. Create proc
	if (-1 == (proc = NewProc(cluster))) {
		AbortTransaction();
		text = "Failed to create new proc";
		return STATUS_USER + 2;
	}

		// 4. Submit job ad

		// Schema: (vanilla job)
		// Schedd demands - Owner, JobUniverse
		// To run - JobStatus, Requirements

		// Schedd excepts if no Owner
		// Schedd prunes on startup if no Owner or JobUniverse
		// Schedd won't run job without JobStatus
		// Job cannot match without Requirements
		// Shadow rejects jobs without an Iwd
		// Shadow: Job has no CondorVersion, assuming pre version 6.3.3
		// Shadow: Unix Vanilla job is pre version 6.3.3, setting 'TransferFiles = "NEVER"'
		// Starter won't run job without Cmd
		// Starter needs a valid Owner (local account name) if not using nobody
		// condor_q requires ClusterId (int), ProcId (int), QDate (int), RemoteUserCpu (float), JobStatus (int), JobPrio (int), ImageSize (int), Owner (str) and Cmd (str)

		// Schema: (vm job)

	ClassAd ad;
	int universe;

    // ShouldTransferFiles - unset by default, must be set
    // shadow will try to setup local transfer sandbox otherwise
    // without good priv
    ad.Assign(ATTR_SHOULD_TRANSFER_FILES, "NO");

	if (!PopulateAdFromVariantMap(jobAdMap, ad, text)) {
		AbortTransaction();
		return STATUS_USER + 3;
	}

	std::string missing;
	if (!CheckRequiredAttrs(ad, required, missing)) {
		AbortTransaction();
		text = "Job ad is missing required attributes: " + missing;
		return STATUS_USER + 4;
	}

		// EARLY SET: These attribute are set early so the incoming ad
		// has a change to override them.
	::SetAttribute(cluster, proc, ATTR_JOB_STATUS, "1"); // 1 = idle

		// Junk that condor_q wants, but really shouldn't be necessary
	::SetAttribute(cluster, proc, ATTR_JOB_REMOTE_USER_CPU, "0.0"); // float
	::SetAttribute(cluster, proc, ATTR_JOB_PRIO, "0");              // int
	::SetAttribute(cluster, proc, ATTR_IMAGE_SIZE, "0");            // int

	if (!ad.LookupInteger(ATTR_JOB_UNIVERSE, universe)) {
		char* uni_str = param("DEFAULT_UNIVERSE");
		if (!uni_str) {
			universe = CONDOR_UNIVERSE_VANILLA;
		}
		else {
			universe = CondorUniverseNumber(uni_str);
		}
		::SetAttributeInt(cluster, proc, ATTR_JOB_UNIVERSE, universe );
	}
	// more stuff - without these our idle stats are whack
	if ( universe != CONDOR_UNIVERSE_MPI && universe != CONDOR_UNIVERSE_PVM ) {
		::SetAttribute(cluster, proc, ATTR_MAX_HOSTS, "1");              // int
		::SetAttribute(cluster, proc, ATTR_MIN_HOSTS, "1");            // int
	}
	::SetAttribute(cluster, proc, ATTR_CURRENT_HOSTS, "0"); // int

	ExprTree *expr;
	const char *name;
	std::string value;
	ad.ResetExpr();
	while (ad.NextExpr(name,expr)) {

			// All these extra lookups are horrible. They have to
			// be there because the ClassAd may have multiple
			// copies of the same attribute name! This means that
			// the last attribute with a given name will set the
			// value, but the last attribute tends to be the
			// attribute with the oldest (wrong) value. How
			// annoying is that!
		if (!(expr = ad.Lookup(name))) {
			dprintf(D_ALWAYS, "Failed to lookup %s\n", name);

			AbortTransaction();
			text = "Failed to parse job ad attribute";
			return STATUS_USER + 6;
		}

        value = ExprTreeToString(expr);
        ::SetAttribute(cluster, proc, name, value.c_str());
	}

		// LATE SET: These attributes are set late, after the incoming
		// ad, so they override whatever the incoming ad set.
	char buf[22]; // 22 is max size for an id, 2^32 + . + 2^32 + \0
	snprintf(buf, 22, "%d", cluster);
	::SetAttribute(cluster, proc, ATTR_CLUSTER_ID, buf);
	snprintf(buf, 22, "%d", proc);
	::SetAttribute(cluster, proc, ATTR_PROC_ID, buf);
	snprintf(buf, 22, "%d", time(NULL));
	::SetAttribute(cluster, proc, ATTR_Q_DATE, buf);

		// Could check for some invalid attributes, e.g
		//  JobUniverse <= CONDOR_UNIVERSE_MIN or >= CONDOR_UNIVERSE_MAX

		// 5. Commit transaction
	CommitTransaction();

		// 6. Reschedule
	scheduler.needReschedule();

		// 7. Return identifier
		// TODO: dag ids?
	MyString tmp;
	tmp.sprintf("%s#%d.%d", Name, cluster, proc);
	id = tmp.Value();

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::SetAttribute(std::string key,
							  std::string name,
							  std::string value,
							  std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "SetAttribute: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (IsSubmissionChange(name.c_str())) {
		text = "Changes to submission name not allowed";
		return STATUS_USER + 1;
	}

	if (IsKeyword(name.c_str())) {
		text = "Attribute name is reserved: " + name;
		return STATUS_USER + 2;
	}

	if (!IsValidAttributeName(name,text)) {
		return STATUS_USER + 3;
	}

		// All values are strings in the eyes of
		// ::SetAttribute. Their type is inferred when read from
		// the ClassAd log. It is important that the incoming
		// value is properly quoted to differentiate between EXPR
		// and STRING.
	if (::SetAttribute(id.cluster,
					   id.proc,
					   name.c_str(),
					   value.c_str())) {
		text = "Failed to set attribute " + name + " to " + value;
		return STATUS_USER + 4;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Hold(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Hold: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!holdJob(id.cluster,
				 id.proc,
				 reason.c_str(),
				 true, // Always perform this action within a transaction
				 true, // Always notify the shadow of the hold
				 false, // Do not email the user about this action
				 false, // Do not email admin about this action
				 false // This is not a system related (internal) hold
				 )) {
		text = "Failed to hold job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Release(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Release: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!releaseJob(id.cluster,
					id.proc,
					reason.c_str(),
					true, // Always perform this action within a transaction
					false, // Do not email the user about this action
					false // Do not email admin about this action
					)) {
		text = "Failed to release job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}

Manageable::status_t
SchedulerObject::Remove(std::string key, std::string &reason, std::string &text)
{
	PROC_ID id = getProcByString(key.c_str());
	if (id.cluster < 0 || id.proc < 0) {
		dprintf(D_FULLDEBUG, "Remove: Failed to parse id: %s\n", key.c_str());
		text = "Invalid Id";
		return STATUS_USER + 0;
	}

	if (!abortJob(id.cluster,
				  id.proc,
				  reason.c_str(),
				  true // Always perform within a transaction
				  )) {
		text = "Failed to remove job";
		return STATUS_USER + 1;
	}

	return STATUS_OK;
}
#endif

qpid::management::ManagementObject *
SchedulerObject::GetManagementObject(void) const
{
	return mgmtObject;
}

Manageable::status_t
SchedulerObject::ManagementMethod(uint32_t methodId,
								  Args &args,
								  std::string &text)
{
#ifndef READ_ONLY_SCHEDULER_OBJECT
	Manageable::status_t result = STATUS_OK;
	bool orig_qaut = qmgmt_all_users_trusted;
	qmgmt_all_users_trusted = true;

	switch (methodId) {
	case qmf::com::redhat::grid::Scheduler::METHOD_ECHO:
		if (!param_boolean("QMF_MANAGEMENT_METHOD_ECHO", false)) {
			qmgmt_all_users_trusted = orig_qaut;
			return STATUS_NOT_IMPLEMENTED;
		}
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_SUBMITJOB:
		result = Submit(((ArgsSchedulerSubmitJob &) args).i_Ad,
					  ((ArgsSchedulerSubmitJob &) args).o_Id,
					  text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_SETJOBATTRIBUTE:
		result = SetAttribute(((ArgsSchedulerSetJobAttribute &) args).i_Id,
							((ArgsSchedulerSetJobAttribute &) args).i_Name,
							((ArgsSchedulerSetJobAttribute &) args).i_Value,
							text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_HOLDJOB:
		result = Hold(((ArgsSchedulerHoldJob &) args).i_Id,
					((ArgsSchedulerHoldJob &) args).i_Reason,
					text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_RELEASEJOB:
		result = Release(((ArgsSchedulerReleaseJob &) args).i_Id,
					   ((ArgsSchedulerReleaseJob &) args).i_Reason,
					   text);
		break;
	case qmf::com::redhat::grid::Scheduler::METHOD_REMOVEJOB:
		result = Remove(((ArgsSchedulerRemoveJob &) args).i_Id,
					  ((ArgsSchedulerRemoveJob &) args).i_Reason,
					  text);
		break;
	default:
		result = STATUS_NOT_IMPLEMENTED;
	}

	qmgmt_all_users_trusted = orig_qaut;
	return result;
#else
	return STATUS_NOT_IMPLEMENTED;
#endif
}

bool
SchedulerObject::AuthorizeMethod(uint32_t methodId, Args& args, const std::string& userId) {
	dprintf(D_FULLDEBUG, "AuthorizeMethod: checking '%s'\n", userId.c_str());
	if (0 == userId.compare("cumin")) {
		return true;
	}
	return false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: MultipleItemConverter.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: bm $ $Date: 2003-10-07 17:18:34 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2003 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#include "MultipleItemConverter.hxx"
#include "ItemPropertyMap.hxx"

#include <algorithm>

using namespace ::com::sun::star;

namespace comphelper
{

MultipleItemConverter::MultipleItemConverter( SfxItemPool& rItemPool )
        : ItemConverter( NULL, rItemPool )
{
}
MultipleItemConverter::~MultipleItemConverter()
{
    ::std::for_each( m_aConverters.begin(), m_aConverters.end(),
                     DeleteItemConverterPtr() );
}

void MultipleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const
{
    ::std::vector< ItemConverter* >::const_iterator       aIter = m_aConverters.begin();
    const ::std::vector< ItemConverter* >::const_iterator aEnd  = m_aConverters.end();
    if( aIter != aEnd )
    {
        (*aIter)->FillItemSet( rOutItemSet );
        aIter++;
    }
    for( ; aIter != aEnd; aIter++ )
    {
        SfxItemSet aSet = this->CreateEmptyItemSet();
        (*aIter)->FillItemSet( aSet );
        InvalidateUnequalItems( rOutItemSet, aSet );
    }
    // no own items
}

bool MultipleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet )
{
    bool bResult = false;

    ::std::for_each( m_aConverters.begin(), m_aConverters.end(),
                     ApplyItemSetFunc( rItemSet, bResult ));

    // no own items
    return bResult;
}

bool MultipleItemConverter::GetItemPropertyName( USHORT nWhichId, ::rtl::OUString & rOutName ) const
{
    return false;
}

} //  namespace comphelper
<commit_msg>INTEGRATION: CWS ooo19126 (1.3.110); FILE MERGED 2005/09/05 18:42:40 rt 1.3.110.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: MultipleItemConverter.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 00:30:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include "MultipleItemConverter.hxx"
#include "ItemPropertyMap.hxx"

#include <algorithm>

using namespace ::com::sun::star;

namespace comphelper
{

MultipleItemConverter::MultipleItemConverter( SfxItemPool& rItemPool )
        : ItemConverter( NULL, rItemPool )
{
}
MultipleItemConverter::~MultipleItemConverter()
{
    ::std::for_each( m_aConverters.begin(), m_aConverters.end(),
                     DeleteItemConverterPtr() );
}

void MultipleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const
{
    ::std::vector< ItemConverter* >::const_iterator       aIter = m_aConverters.begin();
    const ::std::vector< ItemConverter* >::const_iterator aEnd  = m_aConverters.end();
    if( aIter != aEnd )
    {
        (*aIter)->FillItemSet( rOutItemSet );
        aIter++;
    }
    for( ; aIter != aEnd; aIter++ )
    {
        SfxItemSet aSet = this->CreateEmptyItemSet();
        (*aIter)->FillItemSet( aSet );
        InvalidateUnequalItems( rOutItemSet, aSet );
    }
    // no own items
}

bool MultipleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet )
{
    bool bResult = false;

    ::std::for_each( m_aConverters.begin(), m_aConverters.end(),
                     ApplyItemSetFunc( rItemSet, bResult ));

    // no own items
    return bResult;
}

bool MultipleItemConverter::GetItemPropertyName( USHORT nWhichId, ::rtl::OUString & rOutName ) const
{
    return false;
}

} //  namespace comphelper
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"

#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media_gallery/media_file_system_registry.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/system_monitor/media_storage_util.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

using extensions::Extension;

namespace chrome {

namespace {

bool IsAttachedDevice(const std::string& device_id) {
  if (!MediaStorageUtil::IsRemovableDevice(device_id))
    return false;

  std::vector<base::SystemMonitor::RemovableStorageInfo> removable_storages =
      base::SystemMonitor::Get()->GetAttachedRemovableStorage();
  for (size_t i = 0; i < removable_storages.size(); ++i) {
    if (removable_storages[i].device_id == device_id)
      return true;
  }
  return false;
}

}  // namespace

MediaGalleriesDialogController::MediaGalleriesDialogController(
    content::WebContents* web_contents,
    const Extension& extension,
    const base::Closure& on_finish)
      : web_contents_(web_contents),
        extension_(&extension),
        on_finish_(on_finish) {
  MediaFileSystemRegistry* registry =
      g_browser_process->media_file_system_registry();
  preferences_ = registry->GetPreferences(
      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
  InitializePermissions();

  dialog_.reset(MediaGalleriesDialog::Create(this));

  base::SystemMonitor* monitor = base::SystemMonitor::Get();
  if (monitor)
    monitor->AddDevicesChangedObserver(this);
}

MediaGalleriesDialogController::MediaGalleriesDialogController()
    : web_contents_(NULL),
      extension_(NULL),
      preferences_(NULL) {}

MediaGalleriesDialogController::~MediaGalleriesDialogController() {
  base::SystemMonitor* monitor = base::SystemMonitor::Get();
  if (monitor)
    monitor->RemoveDevicesChangedObserver(this);

  if (select_folder_dialog_.get())
    select_folder_dialog_->ListenerDestroyed();
}

// static
string16 MediaGalleriesDialogController::GetGalleryDisplayName(
    const MediaGalleryPrefInfo& gallery) {
  string16 name = gallery.display_name;
  if (IsAttachedDevice(gallery.device_id)) {
    name += ASCIIToUTF16(" ");
    name +=
        l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED);
  }
  return name;
}

// static
string16 MediaGalleriesDialogController::GetGalleryTooltip(
    const MediaGalleryPrefInfo& gallery) {
  return gallery.AbsolutePath().LossyDisplayName();
}

string16 MediaGalleriesDialogController::GetHeader() const {
  std::string extension_name(extension_ ? extension_->name() : "");
  return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER,
                                    UTF8ToUTF16(extension_name));
}

string16 MediaGalleriesDialogController::GetSubtext() const {
  std::string extension_name(extension_ ? extension_->name() : "");
  return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT,
                                    UTF8ToUTF16(extension_name));
}

bool MediaGalleriesDialogController::HasPermittedGalleries() const {
  for (KnownGalleryPermissions::const_iterator iter = permissions().begin();
       iter != permissions().end(); ++iter) {
    if (iter->second.allowed)
      return true;
  }
  return false;
}

void MediaGalleriesDialogController::OnAddFolderClicked() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  select_folder_dialog_ =
      ui::SelectFileDialog::Create(this, new ChromeSelectFilePolicy(NULL));
  select_folder_dialog_->SelectFile(
      ui::SelectFileDialog::SELECT_FOLDER,
      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY_TITLE),
      user_data_dir,
      NULL, 0, FILE_PATH_LITERAL(""),
      web_contents_->GetView()->GetTopLevelNativeWindow(),
      NULL);
}

void MediaGalleriesDialogController::DidToggleGallery(
    const MediaGalleryPrefInfo* gallery,
    bool enabled) {
  // Check known galleries.
  KnownGalleryPermissions::iterator iter =
      known_galleries_.find(gallery->pref_id);
  if (iter != known_galleries_.end()) {
    iter->second.allowed = enabled;
    return;
  }

  // Check new galleries.
  for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    if (&iter->pref_info == gallery) {
      iter->allowed = enabled;
      return;
    }
  }

  NOTREACHED();
}

void MediaGalleriesDialogController::DialogFinished(bool accepted) {
  if (accepted)
    SavePermissions();

  on_finish_.Run();
  delete this;
}

const MediaGalleriesDialogController::KnownGalleryPermissions&
MediaGalleriesDialogController::permissions() const {
  return known_galleries_;
}

content::WebContents* MediaGalleriesDialogController::web_contents() {
  return web_contents_;
}

void MediaGalleriesDialogController::FileSelected(const FilePath& path,
                                                  int /*index*/,
                                                  void* /*params*/) {
  // Try to find it in |known_galleries_|.
  MediaGalleryPrefInfo gallery;
  bool gallery_exists = preferences_->LookUpGalleryByPath(path, &gallery);
  if (gallery_exists && gallery.type != MediaGalleryPrefInfo::kBlackListed) {
    KnownGalleryPermissions::const_iterator iter =
        known_galleries_.find(gallery.pref_id);

    if (iter == known_galleries_.end()) {
      // This is rare, but could happen if a gallery was not "known"
      // when the controller first initialized, but has since been added.
      known_galleries_[gallery.pref_id] = GalleryPermission(gallery, true);
      iter = known_galleries_.find(gallery.pref_id);
    }

    dialog_->UpdateGallery(&iter->second.pref_info, true);
    return;
  }

  // Try to find it in |new_galleries_| (user added same folder twice).
  for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    if (iter->pref_info.path == gallery.path &&
        iter->pref_info.device_id == gallery.device_id) {
      iter->allowed = true;
      dialog_->UpdateGallery(&iter->pref_info, true);
      return;
    }
  }

  // Lastly, add it to |new_galleries_|.
  new_galleries_.push_back(GalleryPermission(gallery, true));
  dialog_->UpdateGallery(&new_galleries_.back().pref_info, true);
}

void MediaGalleriesDialogController::OnRemovableStorageAttached(
    const std::string& id,
    const string16& /*name*/,
    const FilePath::StringType& /*location*/) {
  UpdateGalleryOnDeviceEvent(id, true /* attached */);
}

void MediaGalleriesDialogController::OnRemovableStorageDetached(
    const std::string& id) {
  UpdateGalleryOnDeviceEvent(id, false /* detached */);
}

void MediaGalleriesDialogController::InitializePermissions() {
  const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
  const MediaGalleryPrefIdSet permitted_galleries =
      preferences_->GalleriesForExtension(*extension_);

  for (MediaGalleriesPrefInfoMap::const_iterator iter = galleries.begin();
       iter != galleries.end();
       ++iter) {
    const MediaGalleryPrefInfo& gallery = iter->second;
    if (gallery.type == MediaGalleryPrefInfo::kBlackListed)
      continue;

    known_galleries_[iter->first] = GalleryPermission(gallery, false);
  }

  MediaGalleryPrefIdSet permitted =
      preferences_->GalleriesForExtension(*extension_);

  for (MediaGalleryPrefIdSet::iterator iter = permitted.begin();
       iter != permitted.end(); ++iter) {
    known_galleries_[*iter].allowed = true;
  }
}

void MediaGalleriesDialogController::SavePermissions() {
  for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
       iter != known_galleries_.end(); ++iter) {
    preferences_->SetGalleryPermissionForExtension(
        *extension_, iter->first, iter->second.allowed);
  }

  for (NewGalleryPermissions::const_iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    // If the user added a gallery then unchecked it, forget about it.
    if (!iter->allowed)
      continue;

    const MediaGalleryPrefInfo& gallery = iter->pref_info;
    MediaGalleryPrefId id = preferences_->AddGallery(
        gallery.device_id, gallery.display_name, gallery.path, true);
    preferences_->SetGalleryPermissionForExtension(
        *extension_, id, true);
  }
}

void MediaGalleriesDialogController::UpdateGalleryOnDeviceEvent(
    const std::string& device_id, bool attached) {
  GalleryPermission* gallery = NULL;
  for (KnownGalleryPermissions::iterator iter = known_galleries_.begin();
       iter != known_galleries_.end(); ++iter) {
    if (iter->second.pref_info.device_id == device_id) {
      gallery = &iter->second;
      break;
    }
  }

  if (!gallery) {
    for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
         iter != new_galleries_.end(); ++iter) {
      if (iter->pref_info.device_id == device_id) {
        gallery = &(*iter);
        break;
      }
    }
  }

  if (gallery)
    dialog_->UpdateGallery(&gallery->pref_info, gallery->allowed);
}

// MediaGalleries dialog -------------------------------------------------------

MediaGalleriesDialog::~MediaGalleriesDialog() {}

}  // namespace chrome
<commit_msg>[Cleanup] Remove unused local variable from MediaGalleriesDialogController.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"

#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media_gallery/media_file_system_registry.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/system_monitor/media_storage_util.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

using extensions::Extension;

namespace chrome {

namespace {

bool IsAttachedDevice(const std::string& device_id) {
  if (!MediaStorageUtil::IsRemovableDevice(device_id))
    return false;

  std::vector<base::SystemMonitor::RemovableStorageInfo> removable_storages =
      base::SystemMonitor::Get()->GetAttachedRemovableStorage();
  for (size_t i = 0; i < removable_storages.size(); ++i) {
    if (removable_storages[i].device_id == device_id)
      return true;
  }
  return false;
}

}  // namespace

MediaGalleriesDialogController::MediaGalleriesDialogController(
    content::WebContents* web_contents,
    const Extension& extension,
    const base::Closure& on_finish)
      : web_contents_(web_contents),
        extension_(&extension),
        on_finish_(on_finish) {
  MediaFileSystemRegistry* registry =
      g_browser_process->media_file_system_registry();
  preferences_ = registry->GetPreferences(
      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
  InitializePermissions();

  dialog_.reset(MediaGalleriesDialog::Create(this));

  base::SystemMonitor* monitor = base::SystemMonitor::Get();
  if (monitor)
    monitor->AddDevicesChangedObserver(this);
}

MediaGalleriesDialogController::MediaGalleriesDialogController()
    : web_contents_(NULL),
      extension_(NULL),
      preferences_(NULL) {}

MediaGalleriesDialogController::~MediaGalleriesDialogController() {
  base::SystemMonitor* monitor = base::SystemMonitor::Get();
  if (monitor)
    monitor->RemoveDevicesChangedObserver(this);

  if (select_folder_dialog_.get())
    select_folder_dialog_->ListenerDestroyed();
}

// static
string16 MediaGalleriesDialogController::GetGalleryDisplayName(
    const MediaGalleryPrefInfo& gallery) {
  string16 name = gallery.display_name;
  if (IsAttachedDevice(gallery.device_id)) {
    name += ASCIIToUTF16(" ");
    name +=
        l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_DEVICE_ATTACHED);
  }
  return name;
}

// static
string16 MediaGalleriesDialogController::GetGalleryTooltip(
    const MediaGalleryPrefInfo& gallery) {
  return gallery.AbsolutePath().LossyDisplayName();
}

string16 MediaGalleriesDialogController::GetHeader() const {
  std::string extension_name(extension_ ? extension_->name() : "");
  return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER,
                                    UTF8ToUTF16(extension_name));
}

string16 MediaGalleriesDialogController::GetSubtext() const {
  std::string extension_name(extension_ ? extension_->name() : "");
  return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_SUBTEXT,
                                    UTF8ToUTF16(extension_name));
}

bool MediaGalleriesDialogController::HasPermittedGalleries() const {
  for (KnownGalleryPermissions::const_iterator iter = permissions().begin();
       iter != permissions().end(); ++iter) {
    if (iter->second.allowed)
      return true;
  }
  return false;
}

void MediaGalleriesDialogController::OnAddFolderClicked() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  select_folder_dialog_ =
      ui::SelectFileDialog::Create(this, new ChromeSelectFilePolicy(NULL));
  select_folder_dialog_->SelectFile(
      ui::SelectFileDialog::SELECT_FOLDER,
      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY_TITLE),
      user_data_dir,
      NULL, 0, FILE_PATH_LITERAL(""),
      web_contents_->GetView()->GetTopLevelNativeWindow(),
      NULL);
}

void MediaGalleriesDialogController::DidToggleGallery(
    const MediaGalleryPrefInfo* gallery,
    bool enabled) {
  // Check known galleries.
  KnownGalleryPermissions::iterator iter =
      known_galleries_.find(gallery->pref_id);
  if (iter != known_galleries_.end()) {
    iter->second.allowed = enabled;
    return;
  }

  // Check new galleries.
  for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    if (&iter->pref_info == gallery) {
      iter->allowed = enabled;
      return;
    }
  }

  NOTREACHED();
}

void MediaGalleriesDialogController::DialogFinished(bool accepted) {
  if (accepted)
    SavePermissions();

  on_finish_.Run();
  delete this;
}

const MediaGalleriesDialogController::KnownGalleryPermissions&
MediaGalleriesDialogController::permissions() const {
  return known_galleries_;
}

content::WebContents* MediaGalleriesDialogController::web_contents() {
  return web_contents_;
}

void MediaGalleriesDialogController::FileSelected(const FilePath& path,
                                                  int /*index*/,
                                                  void* /*params*/) {
  // Try to find it in |known_galleries_|.
  MediaGalleryPrefInfo gallery;
  bool gallery_exists = preferences_->LookUpGalleryByPath(path, &gallery);
  if (gallery_exists && gallery.type != MediaGalleryPrefInfo::kBlackListed) {
    KnownGalleryPermissions::const_iterator iter =
        known_galleries_.find(gallery.pref_id);

    if (iter == known_galleries_.end()) {
      // This is rare, but could happen if a gallery was not "known"
      // when the controller first initialized, but has since been added.
      known_galleries_[gallery.pref_id] = GalleryPermission(gallery, true);
      iter = known_galleries_.find(gallery.pref_id);
    }

    dialog_->UpdateGallery(&iter->second.pref_info, true);
    return;
  }

  // Try to find it in |new_galleries_| (user added same folder twice).
  for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    if (iter->pref_info.path == gallery.path &&
        iter->pref_info.device_id == gallery.device_id) {
      iter->allowed = true;
      dialog_->UpdateGallery(&iter->pref_info, true);
      return;
    }
  }

  // Lastly, add it to |new_galleries_|.
  new_galleries_.push_back(GalleryPermission(gallery, true));
  dialog_->UpdateGallery(&new_galleries_.back().pref_info, true);
}

void MediaGalleriesDialogController::OnRemovableStorageAttached(
    const std::string& id,
    const string16& /*name*/,
    const FilePath::StringType& /*location*/) {
  UpdateGalleryOnDeviceEvent(id, true /* attached */);
}

void MediaGalleriesDialogController::OnRemovableStorageDetached(
    const std::string& id) {
  UpdateGalleryOnDeviceEvent(id, false /* detached */);
}

void MediaGalleriesDialogController::InitializePermissions() {
  const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
  for (MediaGalleriesPrefInfoMap::const_iterator iter = galleries.begin();
       iter != galleries.end();
       ++iter) {
    const MediaGalleryPrefInfo& gallery = iter->second;
    if (gallery.type == MediaGalleryPrefInfo::kBlackListed)
      continue;

    known_galleries_[iter->first] = GalleryPermission(gallery, false);
  }

  MediaGalleryPrefIdSet permitted =
      preferences_->GalleriesForExtension(*extension_);

  for (MediaGalleryPrefIdSet::iterator iter = permitted.begin();
       iter != permitted.end(); ++iter) {
    known_galleries_[*iter].allowed = true;
  }
}

void MediaGalleriesDialogController::SavePermissions() {
  for (KnownGalleryPermissions::const_iterator iter = known_galleries_.begin();
       iter != known_galleries_.end(); ++iter) {
    preferences_->SetGalleryPermissionForExtension(
        *extension_, iter->first, iter->second.allowed);
  }

  for (NewGalleryPermissions::const_iterator iter = new_galleries_.begin();
       iter != new_galleries_.end(); ++iter) {
    // If the user added a gallery then unchecked it, forget about it.
    if (!iter->allowed)
      continue;

    const MediaGalleryPrefInfo& gallery = iter->pref_info;
    MediaGalleryPrefId id = preferences_->AddGallery(
        gallery.device_id, gallery.display_name, gallery.path, true);
    preferences_->SetGalleryPermissionForExtension(
        *extension_, id, true);
  }
}

void MediaGalleriesDialogController::UpdateGalleryOnDeviceEvent(
    const std::string& device_id, bool attached) {
  GalleryPermission* gallery = NULL;
  for (KnownGalleryPermissions::iterator iter = known_galleries_.begin();
       iter != known_galleries_.end(); ++iter) {
    if (iter->second.pref_info.device_id == device_id) {
      gallery = &iter->second;
      break;
    }
  }

  if (!gallery) {
    for (NewGalleryPermissions::iterator iter = new_galleries_.begin();
         iter != new_galleries_.end(); ++iter) {
      if (iter->pref_info.device_id == device_id) {
        gallery = &(*iter);
        break;
      }
    }
  }

  if (gallery)
    dialog_->UpdateGallery(&gallery->pref_info, gallery->allowed);
}

// MediaGalleries dialog -------------------------------------------------------

MediaGalleriesDialog::~MediaGalleriesDialog() {}

}  // namespace chrome
<|endoftext|>


<commit_before>/*
 * SessionBreakpoints.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "environment/EnvironmentUtils.hpp"

#include <algorithm>

#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/utility.hpp>
#include <boost/foreach.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/Exec.hpp>
#include <core/FilePath.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/RRoutines.hpp>
#include <r/RErrorCategory.hpp>
#include <r/RUtil.hpp>
#include <r/session/RSession.hpp>
#include <r/session/RClientState.hpp>
#include <r/Rinternals.h>

#include <session/SessionModuleContext.hpp>
#include <session/SessionUserSettings.hpp>
#include <session/projects/SessionProjects.hpp>

using namespace core;
using namespace r::sexp;
using namespace r::exec;

namespace session {
namespace modules {
namespace breakpoints {
namespace
{

int s_maxShinyFunctionId = 0;

class ShinyFunction
{
public:
   SEXP expr;
   SEXP function;
   int id;
   ShinyFunction(SEXP exprIn, SEXP functionIn):
      expr(exprIn),
      function(functionIn),
      id(s_maxShinyFunctionId++)
   {}
   bool contains(std::string filename, int line)
   {
      // Extract from the expression its location in the source file and see if
      // the line number given is in range.
      SEXP srcref = r::sexp::getAttrib(function, "srcref");
      if (srcref == NULL || TYPEOF(srcref) == NILSXP)
         return false;

      if (!(line >= INTEGER(srcref)[0] &&
            line <= INTEGER(srcref)[2]))
         return false;

      // Extract from the expression the source file in which it resides and
      // see if it matches the source file given.
      SEXP srcfile = r::sexp::getAttrib(srcref, "srcfile");
      if (srcfile == NULL || TYPEOF(srcfile) == NILSXP)
         return false;

      SEXP file = r::sexp::findVar("filename", srcfile);
      if (file == NULL || TYPEOF(file) == NILSXP)
         return false;

      std::string srcfilename;
      Error error = r::sexp::extract(file, &srcfilename);
      if (error)
         return false;

      return module_context::resolveAliasedPath(srcfilename) ==
             module_context::resolveAliasedPath(filename);
   }
};

// A list of the Shiny functions we know about (see notes in
// rs_registerShinyFunction for an explanation of how this memory is managed)
std::vector<boost::shared_ptr<ShinyFunction> > s_shinyFunctions;

class Breakpoint
{
public:
   int type;
   int lineNumber;
   int id;
   std::string path;
   Breakpoint(int typeIn, int lineNumberIn, int idIn, std::string pathIn):
      type(typeIn),
      lineNumber(lineNumberIn),
      id(idIn),
      path(pathIn)
   {}
};

// A list of the breakpoints we know about. Note that this is a slave list;
// the client maintains the master copy and is responsible for synchronizing
// with this list.
std::vector<boost::shared_ptr<Breakpoint> > s_breakpoints;
bool s_breakpointsInSync = false;

ShinyFunction* findShinyFunction(std::string filename, int line)
{
   BOOST_FOREACH(boost::shared_ptr<ShinyFunction> psf, s_shinyFunctions)
   {
      if (psf->contains(filename, line))
         return psf.get();
   }

   // Didn't find a match
   return NULL;
}

boost::shared_ptr<Breakpoint> breakpointFromJson(json::Object& obj)
{
   return boost::make_shared<Breakpoint>(obj["type"].get_int(),
                                         obj["line_number"].get_int(),
                                         obj["id"].get_int(),
                                         obj["path"].get_str());

}

// Runs a series of pre-flight checks to determine whether we can set a
// breakpoint at the given location, and, if we can, what kind of breakpoint
// we should set.
Error getFunctionState(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   json::Object response;
   std::string functionName, fileName, packageName;
   int lineNumber = 0, shinyFunctionId = 0;
   bool inSync = false, isShinyFunction = false;
   Error error = json::readParams(
            request.params, &functionName, &fileName, &lineNumber);
   if (error)
   {
       return error;
   }

   // check whether the function belongs to an expression in a running
   // Shiny application
   ShinyFunction* psf = findShinyFunction(fileName, lineNumber);
   if (psf)
   {
      isShinyFunction = true;
      shinyFunctionId = psf->id;
   }
   else
   {
      // check whether the function is in a package
      packageName = module_context::packageNameForSourceFile(
                       module_context::resolveAliasedPath(fileName));

      // get the source refs and code for the function
      SEXP srcRefs = NULL;
      Protect protect;
      std::string functionCode;
      error = r::exec::RFunction(".rs.getFunctionSourceRefs",
                                 functionName,
                                 fileName,
                                 packageName)
            .call(&srcRefs, &protect);
      if (!error)
      {
         error = r::exec::RFunction(".rs.getFunctionSourceCode",
                                    functionName,
                                    fileName,
                                    packageName)
               .call(&functionCode);
      }
      // compare with the disk if we were able to get the source code;
      // otherwise, assume it's out of sync
      if (!error)
         inSync = !environment::functionDiffersFromSource(srcRefs, functionCode);
   }

   response["sync_state"] = inSync;
   response["package_name"] = packageName;
   response["is_package_function"] = packageName.length() > 0;
   response["is_shiny_function"] = isShinyFunction;
   response["shiny_function_id"] = shinyFunctionId;
   pResponse->setResult(response);

   return Success();
}

// Sets a breakpoint on a single copy of a function. Invoked several times to
// look for function copies in alternate environemnts. Returns true if a
// breakpoint was set; false otherwise.
bool setBreakpoint(const std::string& functionName,
                   const std::string& fileName,
                   const std::string& packageName,
                   const json::Array& steps)
{
   SEXP env = NULL;
   Protect protect;
   Error error = r::exec::RFunction(".rs.getEnvironmentOfFunction",
                                    functionName,
                                    fileName,
                                    packageName)
                                    .call(&env, &protect);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // if we found a function in the requested environment, set the breakpoint
   if (TYPEOF(env) == ENVSXP)
   {
      error = r::exec::RFunction(".rs.setFunctionBreakpoints",
                                 functionName,
                                 env,
                                 steps).call();
      if (error)
      {
         LOG_ERROR(error);
         return false;
      }
      // successfully set a breakpoint
      return true;
   }

   // did not find the function in the environment
   return false;
}

// Set a breakpoint on a function, potentially on multiple copies:
// 1. The private copy of the function inside the package under development
//    (even if from another package; it may be an imported copy)
// 2. The private copy of the function inside its own package (if from a
//    package)
// 3. The copy of the function on the global search path
//
// Note that this is not guaranteed to find ALL copies of the function in ANY
// environment--at most, three breakpoints are set.
Error setBreakpoints(const json::JsonRpcRequest& request,
                     json::JsonRpcResponse* pResponse)
{
   std::string functionName, fileName, packageName;
   json::Array steps;
   bool set = false;
   Error error = json::readParams(request.params,
            &functionName,
            &fileName,
            &packageName,
            &steps);
   if (error)
      return error;

   // If we're in package development mode, try to set a breakpoint in the
   // package's namespace first.
   const projects::ProjectContext& projectContext = projects::projectContext();
   if (projectContext.config().buildType == r_util::kBuildTypePackage)
   {
      set |= setBreakpoint(
               functionName, fileName,
               projectContext.packageInfo().name(), steps);
   }

   // If a package name was specified, try to set a breakpoint in that package's
   // namespace, too.
   if (packageName.length() > 0)
   {
      set |= setBreakpoint(functionName, fileName, packageName, steps);
   }

   // Always search the global namespace.
   set |= setBreakpoint(functionName, fileName, "", steps);

   // Couldn't find a function to set a breakpoint on--maybe a bad parameter?
   if (!set)
   {
      return Error(json::errc::ParamInvalid, ERROR_LOCATION);
   }

   return Success();
}

Error setBreakpointsDirty(const json::JsonRpcRequest& ,
                          json::JsonRpcResponse* )
{
   s_breakpointsInSync = false;
   return Success();
}

// Called on init and when we need an up-to-date list of breakpoints from the
// client--just slurps information from the client's persisted store of
// breakpoints.
void syncClientBreakpoints()
{
   try
   {
      json::Value breakpointStateValue =
         r::session::clientState().getProjectPersistent("debug-breakpoints",
                                                        "debugBreakpointsState");
      json::Object breakpointState = breakpointStateValue.get_obj();
      json::Array breakpointArray = breakpointState["breakpoints"].get_array();

      s_breakpoints.clear();
      BOOST_FOREACH(json::Value bp, breakpointArray)
      {
         s_breakpoints.push_back(breakpointFromJson(bp.get_obj()));
      }
   }
   catch (...)
   {
      // OK if we fail to get the breakpoints here--the client may have not set
      // any yet
   }
   s_breakpointsInSync = true;
}

Error initBreakpoints()
{
   syncClientBreakpoints();
   return Success();
}

// Called by the R garbage collector when a Shiny function is cleaned up;
// we use this as a trigger to clean up our own references to the function.
void unregisterShinyFunction(SEXP extptr)
{
   // Extract the raw pointer from the EXTPTRSXP
   ShinyFunction* psf =
         static_cast<ShinyFunction*>(r::sexp::getExternalPtrAddr(extptr));
   if (!psf)
      return;

   // Look over each Shiny function we know about; if this was a function
   // we were tracking, release it.
   for (std::vector<boost::shared_ptr<ShinyFunction> >::iterator psfi =
               s_shinyFunctions.begin();
        psfi != s_shinyFunctions.end();
        psfi++)
   {
      if (psfi->get() == psf)
      {
         s_shinyFunctions.erase(psfi);
         break;
      }
   }
   r::sexp::clearExternalPtr(extptr);
}

} // anonymous namespace

void rs_registerShinyFunction(SEXP params)
{
   SEXP expr = r::sexp::findVar("expr", params);
   SEXP fun = r::sexp::findVar("fun", params);

   // The memory allocated here is attached to the SEXP "fun" as an attribute
   // of type EXTPTRSXP. When the function is cleaned up by the garbage
   // collector, R calls the finalizer.
   boost::shared_ptr<ShinyFunction> psf =
            boost::make_shared<ShinyFunction>(expr, fun);
   s_shinyFunctions.push_back(psf);

   // Attach the information we just created to the Shiny function.
   SEXP extptr = r::sexp::makeExternalPtr(psf.get(), unregisterShinyFunction);
   r::sexp::setAttrib(fun, "_rs_shinyDebugInfo", extptr);

   // Look over the list of breakpoints we know about and see if any of them
   // are unbound breakpoints in the region of the file just identified.
   if (!s_breakpointsInSync)
      syncClientBreakpoints();

   std::vector<int> lines;
   BOOST_FOREACH(boost::shared_ptr<Breakpoint> pbp, s_breakpoints)
   {
      if (psf->contains(pbp->path, pbp->lineNumber))
         lines.push_back(pbp->lineNumber);
   }

   // If we found breakpoint lines in this Shiny function, set breakpoints
   // on it.
   if (lines.size() > 0)
   {
      r::exec::RFunction(".rs.setShinyBreakpoints",
                         std::string("fun"),
                         params,
                         lines).call();
   }
}

json::Value debugStateAsJson()
{
   json::Object state;

   // look for the debug state environment created by debugSource; if
   // it exists, emit the pieces the client cares about.
   SEXP debugState = r::sexp::findVar(".rs.topDebugState");
   if (TYPEOF(debugState) == ENVSXP)
   {
      state["top_level_debug"] = true;
      state["debug_step"] =
          r::sexp::asInteger(r::sexp::findVar("currentDebugStep", debugState));
      state["debug_file"] =
          r::sexp::asString(r::sexp::findVar("currentDebugFile", debugState));
      SEXP srcref = r::sexp::findVar("currentDebugSrcref", debugState);
      environment::sourceRefToJson(srcref, &state);
   }
   else
   {
      state["top_level_debug"] = json::Value(false);
   }

   return state;
}

bool haveSrcrefAttribute()
{
   // check whether this is R 2.14 or greater
   bool haveSrcref = false;
   Error error = r::exec::evaluateString("getRversion() >= '2.14.0'", &haveSrcref);
   if (error)
      LOG_ERROR(error);
   return haveSrcref;
}

Error initialize()
{
   using boost::bind;
   using namespace module_context;

   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "get_function_state", getFunctionState))
      (bind(registerRpcMethod, "set_function_breakpoints", setBreakpoints))
      (bind(registerRpcMethod, "set_breakpoints_dirty", setBreakpointsDirty))
      (bind(sourceModuleRFile, "SessionBreakpoints.R"))
      (bind(initBreakpoints));

   return initBlock.execute();
}

} // namepsace breakpoints
} // namespace modules
} // namesapce session

<commit_msg>narrow breakpoint scope to expression; improve encapsulation<commit_after>/*
 * SessionBreakpoints.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "environment/EnvironmentUtils.hpp"

#include <algorithm>

#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/utility.hpp>
#include <boost/foreach.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/Exec.hpp>
#include <core/FilePath.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/RRoutines.hpp>
#include <r/RErrorCategory.hpp>
#include <r/RUtil.hpp>
#include <r/session/RSession.hpp>
#include <r/session/RClientState.hpp>
#include <r/Rinternals.h>

#include <session/SessionModuleContext.hpp>
#include <session/SessionUserSettings.hpp>
#include <session/projects/SessionProjects.hpp>

using namespace core;
using namespace r::sexp;
using namespace r::exec;

namespace session {
namespace modules {
namespace breakpoints {
namespace
{

int s_maxShinyFunctionId = 0;

class ShinyFunction
{
public:
   ShinyFunction(SEXP exprIn, SEXP functionIn):
      expr_(exprIn),
      id_(s_maxShinyFunctionId++),
      firstLine_(0),
      lastLine_(0)
   {
      // If the srcref attribute is present on the expression, use it to
      // compute the first and last lines of the function in the original
      // source file.
      SEXP srcref = r::sexp::getAttrib(expr_, "srcref");
      if (srcref != NULL && TYPEOF(srcref) != NILSXP)
      {
         SEXP firstRef = VECTOR_ELT(srcref, 0);
         firstLine_ = INTEGER(firstRef)[0];
         SEXP lastRef = VECTOR_ELT(srcref, r::sexp::length(srcref) - 1);
         lastLine_ = INTEGER(lastRef)[2];
      }
      // If the srcfile attribute is present, extract it
      SEXP srcfile = r::sexp::getAttrib(expr_, "srcfile");
      if (srcfile != NULL && TYPEOF(srcfile) != NILSXP)
      {
         SEXP file = r::sexp::findVar("filename", srcfile);
         r::sexp::extract(file, &srcfilename_);
      }
   }

   bool contains(std::string filename, int line)
   {
      if (!(line >= firstLine_ && line <= lastLine_))
         return false;

      return module_context::resolveAliasedPath(srcfilename_) ==
             module_context::resolveAliasedPath(filename);
   }

   int getId()
   {
      return id_;
   }

private:
   SEXP expr_;
   int id_;
   int firstLine_;
   int lastLine_;
   std::string srcfilename_;
};

// A list of the Shiny functions we know about (see notes in
// rs_registerShinyFunction for an explanation of how this memory is managed)
std::vector<boost::shared_ptr<ShinyFunction> > s_shinyFunctions;

class Breakpoint
{
public:
   int type;
   int lineNumber;
   int id;
   std::string path;
   Breakpoint(int typeIn, int lineNumberIn, int idIn, std::string pathIn):
      type(typeIn),
      lineNumber(lineNumberIn),
      id(idIn),
      path(pathIn)
   {}
};

// A list of the breakpoints we know about. Note that this is a slave list;
// the client maintains the master copy and is responsible for synchronizing
// with this list.
std::vector<boost::shared_ptr<Breakpoint> > s_breakpoints;
bool s_breakpointsInSync = false;

ShinyFunction* findShinyFunction(std::string filename, int line)
{
   BOOST_FOREACH(boost::shared_ptr<ShinyFunction> psf, s_shinyFunctions)
   {
      if (psf->contains(filename, line))
         return psf.get();
   }

   // Didn't find a match
   return NULL;
}

boost::shared_ptr<Breakpoint> breakpointFromJson(json::Object& obj)
{
   return boost::make_shared<Breakpoint>(obj["type"].get_int(),
                                         obj["line_number"].get_int(),
                                         obj["id"].get_int(),
                                         obj["path"].get_str());

}

// Runs a series of pre-flight checks to determine whether we can set a
// breakpoint at the given location, and, if we can, what kind of breakpoint
// we should set.
Error getFunctionState(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   json::Object response;
   std::string functionName, fileName, packageName;
   int lineNumber = 0, shinyFunctionId = 0;
   bool inSync = false, isShinyFunction = false;
   Error error = json::readParams(
            request.params, &functionName, &fileName, &lineNumber);
   if (error)
   {
       return error;
   }

   // check whether the function belongs to an expression in a running
   // Shiny application
   ShinyFunction* psf = findShinyFunction(fileName, lineNumber);
   if (psf)
   {
      isShinyFunction = true;
      shinyFunctionId = psf->getId();
   }
   else
   {
      // check whether the function is in a package
      packageName = module_context::packageNameForSourceFile(
                       module_context::resolveAliasedPath(fileName));

      // get the source refs and code for the function
      SEXP srcRefs = NULL;
      Protect protect;
      std::string functionCode;
      error = r::exec::RFunction(".rs.getFunctionSourceRefs",
                                 functionName,
                                 fileName,
                                 packageName)
            .call(&srcRefs, &protect);
      if (!error)
      {
         error = r::exec::RFunction(".rs.getFunctionSourceCode",
                                    functionName,
                                    fileName,
                                    packageName)
               .call(&functionCode);
      }
      // compare with the disk if we were able to get the source code;
      // otherwise, assume it's out of sync
      if (!error)
         inSync = !environment::functionDiffersFromSource(srcRefs, functionCode);
   }

   response["sync_state"] = inSync;
   response["package_name"] = packageName;
   response["is_package_function"] = packageName.length() > 0;
   response["is_shiny_function"] = isShinyFunction;
   response["shiny_function_id"] = shinyFunctionId;
   pResponse->setResult(response);

   return Success();
}

// Sets a breakpoint on a single copy of a function. Invoked several times to
// look for function copies in alternate environemnts. Returns true if a
// breakpoint was set; false otherwise.
bool setBreakpoint(const std::string& functionName,
                   const std::string& fileName,
                   const std::string& packageName,
                   const json::Array& steps)
{
   SEXP env = NULL;
   Protect protect;
   Error error = r::exec::RFunction(".rs.getEnvironmentOfFunction",
                                    functionName,
                                    fileName,
                                    packageName)
                                    .call(&env, &protect);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // if we found a function in the requested environment, set the breakpoint
   if (TYPEOF(env) == ENVSXP)
   {
      error = r::exec::RFunction(".rs.setFunctionBreakpoints",
                                 functionName,
                                 env,
                                 steps).call();
      if (error)
      {
         LOG_ERROR(error);
         return false;
      }
      // successfully set a breakpoint
      return true;
   }

   // did not find the function in the environment
   return false;
}

// Set a breakpoint on a function, potentially on multiple copies:
// 1. The private copy of the function inside the package under development
//    (even if from another package; it may be an imported copy)
// 2. The private copy of the function inside its own package (if from a
//    package)
// 3. The copy of the function on the global search path
//
// Note that this is not guaranteed to find ALL copies of the function in ANY
// environment--at most, three breakpoints are set.
Error setBreakpoints(const json::JsonRpcRequest& request,
                     json::JsonRpcResponse* pResponse)
{
   std::string functionName, fileName, packageName;
   json::Array steps;
   bool set = false;
   Error error = json::readParams(request.params,
            &functionName,
            &fileName,
            &packageName,
            &steps);
   if (error)
      return error;

   // If we're in package development mode, try to set a breakpoint in the
   // package's namespace first.
   const projects::ProjectContext& projectContext = projects::projectContext();
   if (projectContext.config().buildType == r_util::kBuildTypePackage)
   {
      set |= setBreakpoint(
               functionName, fileName,
               projectContext.packageInfo().name(), steps);
   }

   // If a package name was specified, try to set a breakpoint in that package's
   // namespace, too.
   if (packageName.length() > 0)
   {
      set |= setBreakpoint(functionName, fileName, packageName, steps);
   }

   // Always search the global namespace.
   set |= setBreakpoint(functionName, fileName, "", steps);

   // Couldn't find a function to set a breakpoint on--maybe a bad parameter?
   if (!set)
   {
      return Error(json::errc::ParamInvalid, ERROR_LOCATION);
   }

   return Success();
}

Error setBreakpointsDirty(const json::JsonRpcRequest& ,
                          json::JsonRpcResponse* )
{
   s_breakpointsInSync = false;
   return Success();
}

// Called on init and when we need an up-to-date list of breakpoints from the
// client--just slurps information from the client's persisted store of
// breakpoints.
void syncClientBreakpoints()
{
   try
   {
      json::Value breakpointStateValue =
         r::session::clientState().getProjectPersistent("debug-breakpoints",
                                                        "debugBreakpointsState");
      json::Object breakpointState = breakpointStateValue.get_obj();
      json::Array breakpointArray = breakpointState["breakpoints"].get_array();

      s_breakpoints.clear();
      BOOST_FOREACH(json::Value bp, breakpointArray)
      {
         s_breakpoints.push_back(breakpointFromJson(bp.get_obj()));
      }
   }
   catch (...)
   {
      // OK if we fail to get the breakpoints here--the client may have not set
      // any yet
   }
   s_breakpointsInSync = true;
}

Error initBreakpoints()
{
   syncClientBreakpoints();
   return Success();
}

// Called by the R garbage collector when a Shiny function is cleaned up;
// we use this as a trigger to clean up our own references to the function.
void unregisterShinyFunction(SEXP extptr)
{
   // Extract the raw pointer from the EXTPTRSXP
   ShinyFunction* psf =
         static_cast<ShinyFunction*>(r::sexp::getExternalPtrAddr(extptr));
   if (!psf)
      return;

   // Look over each Shiny function we know about; if this was a function
   // we were tracking, release it.
   for (std::vector<boost::shared_ptr<ShinyFunction> >::iterator psfi =
               s_shinyFunctions.begin();
        psfi != s_shinyFunctions.end();
        psfi++)
   {
      if (psfi->get() == psf)
      {
         s_shinyFunctions.erase(psfi);
         break;
      }
   }
   r::sexp::clearExternalPtr(extptr);
}

} // anonymous namespace

void rs_registerShinyFunction(SEXP params)
{
   SEXP expr = r::sexp::findVar("expr", params);
   SEXP fun = r::sexp::findVar("fun", params);

   // The memory allocated here is attached to the SEXP "fun" as an attribute
   // of type EXTPTRSXP. When the function is cleaned up by the garbage
   // collector, R calls the finalizer.
   boost::shared_ptr<ShinyFunction> psf =
            boost::make_shared<ShinyFunction>(expr, fun);
   s_shinyFunctions.push_back(psf);

   // Attach the information we just created to the Shiny function.
   SEXP extptr = r::sexp::makeExternalPtr(psf.get(), unregisterShinyFunction);
   r::sexp::setAttrib(fun, "_rs_shinyDebugInfo", extptr);

   // Look over the list of breakpoints we know about and see if any of them
   // are unbound breakpoints in the region of the file just identified.
   if (!s_breakpointsInSync)
      syncClientBreakpoints();

   std::vector<int> lines;
   BOOST_FOREACH(boost::shared_ptr<Breakpoint> pbp, s_breakpoints)
   {
      if (psf->contains(pbp->path, pbp->lineNumber))
         lines.push_back(pbp->lineNumber);
   }

   // If we found breakpoint lines in this Shiny function, set breakpoints
   // on it.
   if (lines.size() > 0)
   {
      r::exec::RFunction(".rs.setShinyBreakpoints",
                         std::string("fun"),
                         params,
                         lines).call();
   }
}

json::Value debugStateAsJson()
{
   json::Object state;

   // look for the debug state environment created by debugSource; if
   // it exists, emit the pieces the client cares about.
   SEXP debugState = r::sexp::findVar(".rs.topDebugState");
   if (TYPEOF(debugState) == ENVSXP)
   {
      state["top_level_debug"] = true;
      state["debug_step"] =
          r::sexp::asInteger(r::sexp::findVar("currentDebugStep", debugState));
      state["debug_file"] =
          r::sexp::asString(r::sexp::findVar("currentDebugFile", debugState));
      SEXP srcref = r::sexp::findVar("currentDebugSrcref", debugState);
      environment::sourceRefToJson(srcref, &state);
   }
   else
   {
      state["top_level_debug"] = json::Value(false);
   }

   return state;
}

bool haveSrcrefAttribute()
{
   // check whether this is R 2.14 or greater
   bool haveSrcref = false;
   Error error = r::exec::evaluateString("getRversion() >= '2.14.0'", &haveSrcref);
   if (error)
      LOG_ERROR(error);
   return haveSrcref;
}

Error initialize()
{
   using boost::bind;
   using namespace module_context;

   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "get_function_state", getFunctionState))
      (bind(registerRpcMethod, "set_function_breakpoints", setBreakpoints))
      (bind(registerRpcMethod, "set_breakpoints_dirty", setBreakpointsDirty))
      (bind(sourceModuleRFile, "SessionBreakpoints.R"))
      (bind(initBreakpoints));

   return initBlock.execute();
}

} // namepsace breakpoints
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>
#include "AddressPool.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Target/TargetLoweringObjectFile.h"

using namespace llvm;

class MCExpr;

unsigned AddressPool::getIndex(const MCSymbol *Sym, bool TLS) {
  auto IterBool =
      Pool.insert(std::make_pair(Sym, AddressPoolEntry(Pool.size(), TLS)));
  return IterBool.first->second.Number;
}

// Emit addresses into the section given.
void AddressPool::emit(AsmPrinter &Asm, const MCSection *AddrSection) {
  if (Pool.empty())
    return;

  // Start the dwarf addr section.
  Asm.OutStreamer.SwitchSection(AddrSection);

  // Order the address pool entries by ID
  SmallVector<const MCExpr *, 64> Entries(Pool.size());

  for (const auto &I : Pool)
    Entries[I.second.Number] =
        I.second.TLS
            ? Asm.getObjFileLowering().getDebugThreadLocalSymbol(I.first)
            : MCSymbolRefExpr::Create(I.first, Asm.OutContext);

  for (const MCExpr *Entry : Entries)
    Asm.OutStreamer.EmitValue(Entry, Asm.getDataLayout().getPointerSize());
}
<commit_msg>Add missing cpp file header<commit_after>//===-- llvm/CodeGen/AddressPool.cpp - Dwarf Debug Framework ---*- C++ -*--===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "AddressPool.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Target/TargetLoweringObjectFile.h"

using namespace llvm;

class MCExpr;

unsigned AddressPool::getIndex(const MCSymbol *Sym, bool TLS) {
  auto IterBool =
      Pool.insert(std::make_pair(Sym, AddressPoolEntry(Pool.size(), TLS)));
  return IterBool.first->second.Number;
}

// Emit addresses into the section given.
void AddressPool::emit(AsmPrinter &Asm, const MCSection *AddrSection) {
  if (Pool.empty())
    return;

  // Start the dwarf addr section.
  Asm.OutStreamer.SwitchSection(AddrSection);

  // Order the address pool entries by ID
  SmallVector<const MCExpr *, 64> Entries(Pool.size());

  for (const auto &I : Pool)
    Entries[I.second.Number] =
        I.second.TLS
            ? Asm.getObjFileLowering().getDebugThreadLocalSymbol(I.first)
            : MCSymbolRefExpr::Create(I.first, Asm.OutContext);

  for (const MCExpr *Entry : Entries)
    Asm.OutStreamer.EmitValue(Entry, Asm.getDataLayout().getPointerSize());
}
<|endoftext|>