<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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_debug.h"
#include "subsystem_info.h"

//
// Simple class to manage a single lookup item
//
class SubsystemInfoLookup
{
public:
	SubsystemInfoLookup( SubsystemType, SubsystemClass,
						 const char *, const char * );
	~SubsystemInfoLookup( void ) { };

	SubsystemType getType( void ) const { return m_Type; };
	SubsystemClass getClass( void ) const { return m_Class; } ;
	const char * getTypeName( void ) const { return m_TypeName; };
	const char * getTypeSubstr( void ) const { return m_TypeSubstr; };

	bool match( SubsystemType _type ) const { return m_Type == _type; };
	bool match( SubsystemClass _class ) const { return m_Class == _class; };
	bool match( const char *_name ) const;
	bool matchSubstr( const char *_name ) const;
	bool isValid( ) const { return m_Type != SUBSYSTEM_TYPE_INVALID; };

private:
	SubsystemType	 m_Type;
	SubsystemClass	 m_Class;
	const char		*m_TypeName;
	const char		*m_TypeSubstr;
};
SubsystemInfoLookup::SubsystemInfoLookup(
	SubsystemType _type, SubsystemClass _class,
	const char *_type_name, const char *_type_substr = NULL )
{
	m_Type = _type; m_Class = _class;
	m_TypeName = _type_name, m_TypeSubstr = _type_substr;
}
bool
SubsystemInfoLookup::match( const char *_name ) const
{
	return ( strcasecmp(_name, m_TypeName) == 0 );
};
bool
SubsystemInfoLookup::matchSubstr( const char *_name ) const
{
	const char	*substr = m_TypeSubstr ? m_TypeSubstr : m_TypeName;
	return ( strcasestr(_name, substr) != NULL );
};

//
// Simple class to manage the lookup table
//
class SubsystemInfoTable
{
public:
	SubsystemInfoTable( void );
	~SubsystemInfoTable( void ) { };
	const SubsystemInfoLookup *lookup( SubsystemType ) const;
	const SubsystemInfoLookup *lookup( SubsystemClass ) const;
	const SubsystemInfoLookup *lookup( const char * ) const;
	const SubsystemInfoLookup *Invalid( void ) const { return m_Invalid; };

private:
	const SubsystemInfoLookup			*m_Invalid;
	static const SubsystemInfoLookup	 m_Table[];
};

// -----------------------------------------------------------------
// **** README README README README README README README README ****
// -----------------------------------------------------------------
// Make SURE that you read the README at the top of the include file
// subsystem_info.h before editing this file.
//
// SubsystemInfoLookup(
//   <subsystem type>,		 SUBSYSTEM_TYPE_XXXX
//   <subsystem class>,      SUBSYSTEM_CLASS_XXXX
//   <subsystem type name>   Type name string
//   [,<subsystem substr>])  Type substring (passed to strcasestr())
//
// By default, the lookup will use the <subsystem type name> for
// subsystem "fuzzy" matching, otherwise it will use the substr
// that you provide as the type name.
//
// The second to last entry in the table has an empty string so
// that it'll match any name passed in.
// -----------------------------------------------------------------
const SubsystemInfoLookup SubsystemInfoTable::m_Table[] =
{
	SubsystemInfoLookup( SUBSYSTEM_TYPE_MASTER, SUBSYSTEM_CLASS_DAEMON,
						 "MASTER" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_COLLECTOR, SUBSYSTEM_CLASS_DAEMON,
						 "COLLECTOR" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_NEGOTIATOR, SUBSYSTEM_CLASS_DAEMON,
						 "NEGOTIATOR" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SCHEDD, SUBSYSTEM_CLASS_DAEMON,
						 "SCHEDD" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SHADOW, SUBSYSTEM_CLASS_DAEMON,
						 "SHADOW" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_STARTD, SUBSYSTEM_CLASS_DAEMON,
						 "STARTD" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_STARTER, SUBSYSTEM_CLASS_DAEMON,
						 "STARTER" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_GAHP, SUBSYSTEM_CLASS_DAEMON,
						 "GAHP" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_TOOL, SUBSYSTEM_CLASS_CLIENT,
						 "TOOL" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SUBMIT, SUBSYSTEM_CLASS_CLIENT,
						 "SUBMIT" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_JOB, SUBSYSTEM_CLASS_JOB,
						 "JOB" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_DAEMON, SUBSYSTEM_CLASS_DAEMON,
						 "DAEMON", "" /* empty string, match anything */ ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_INVALID, SUBSYSTEM_CLASS_NONE,
						 "INVALID" )
};

SubsystemInfoTable::SubsystemInfoTable(void)
{
	int num = ( sizeof(m_Table) / sizeof(SubsystemInfoLookup) );
	m_Invalid = &m_Table[num - 1];
	ASSERT( m_Invalid != NULL );
	ASSERT( m_Invalid->match(SUBSYSTEM_TYPE_INVALID) );
}

// Internal method to lookup by SubsystemType
const SubsystemInfoLookup *
SubsystemInfoTable::lookup( SubsystemType _type ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_type) ) {
			return cur;
		}
	}
	return m_Invalid;
}

// Internal method to lookup by SubsystemClass
const SubsystemInfoLookup *
SubsystemInfoTable::lookup( SubsystemClass _class ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_class) ) {
			return cur;
		}
	}
	return m_Invalid;
}

const SubsystemInfoLookup *
// Lookup by name
SubsystemInfoTable::lookup( const char *_name ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_name) ) {
			return cur;
		}
	}
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->matchSubstr(_name) ) {
			return cur;
		}
	}

	// Return the invalid entry
	return m_Invalid;
}
static const SubsystemInfoTable *infoTable = new SubsystemInfoTable( );

//
// C++ SubsystemInfo methods
//

SubsystemInfo::SubsystemInfo( const char *_name, SubsystemType _type )
{
	m_Name = NULL;
	m_TempName = NULL;
	m_LocalName = NULL;
	setName( _name );
	if ( _type == SUBSYSTEM_TYPE_AUTO ) {
		setTypeFromName( _name );
	}
	else {
		setType( _type );
	}
}

SubsystemInfo::~SubsystemInfo( void )
{
	if ( m_Name ) {
		free( const_cast<char *>( m_Name ) );
		m_Name = NULL;
	}
}

bool
SubsystemInfo::nameMatch( const char *_name ) const
{
	return ( strcasecmp(_name, m_Name) == 0 );
}

const char *
SubsystemInfo::setName( const char *_name )
{
	if ( _name != NULL ) {
		m_Name = strdup(_name);
		m_NameValid = true ;
	}
	else {
		m_Name = strdup("UNKNOWN");		// Fill in a value so it's not NULL
		m_NameValid = false;
	}
	return m_Name;
}

// Temp name handling
const char *
SubsystemInfo::setTempName( const char *_name )
{
	resetTempName( );
	if ( _name ) {
		m_TempName = strdup( _name );
	}
	return m_TempName;
}

void
SubsystemInfo::resetTempName( void )
{
	if ( m_TempName ) {
		free( const_cast<char*>(m_TempName) );
		m_TempName = NULL;
	}
}

// Public interface to set the type from a name
SubsystemType
SubsystemInfo::setTypeFromName( const char *_type_name )
{
	if ( NULL == _type_name ) {
		_type_name = m_Name;
	}
	if ( NULL == _type_name ) {
		return setType( SUBSYSTEM_TYPE_DAEMON );
	}

	// First, look for an exact match
	const SubsystemInfoLookup	*match = infoTable->lookup( _type_name );
	if ( match ) {
		return setType( match, _type_name );
	}
	return setType( SUBSYSTEM_TYPE_DAEMON, _type_name );
}

// Public set type method
SubsystemType
SubsystemInfo::setType( SubsystemType _type )
{
	return setType( _type, NULL );
}

// Internal set type method
SubsystemType
SubsystemInfo::setType( SubsystemType _type, const char *_type_name )
{
	return setType( infoTable->lookup(_type), _type_name );
}

// Internal set type method
SubsystemType
SubsystemInfo::setType( const SubsystemInfoLookup *info,
						const char *type_name )
{
	m_Type = info->getType();
	setClass( info );
	m_Info = info;
	if ( type_name != NULL ) {
		m_TypeName = type_name;
	}
	else {
		m_TypeName = info->getTypeName();
	}

	return m_Type;
}

// Internal set class method
SubsystemClass
SubsystemInfo::setClass( const SubsystemInfoLookup *info )
{
	static const char *_class_names[] = {
		"None",
		"DAEMON",
		"CLIENT",
		"JOB"
	};
	static int		_num = ( sizeof(_class_names) / sizeof(const char *) );

	m_Class = info->getClass();
	ASSERT ( ( m_Class >= 0 ) && ( m_Class <= _num ) );
	m_ClassName = _class_names[m_Class];
	return m_Class;
}

// Methods to get/set the local name
const char *
SubsystemInfo::getLocalName( const char * _default ) const
{
	if ( m_LocalName ) {
		return m_LocalName;
	}
	else {
		return _default;
	}
}
const char *
SubsystemInfo::setLocalName( const char * _name )
{
	if ( m_LocalName ) {
		free( const_cast<char *>( m_LocalName ) );
		m_LocalName = NULL;
	}
	m_LocalName = strdup(_name);
	return m_LocalName;
}

// Public dprintf / printf methods
void
SubsystemInfo::dprintf( int level ) const
{
	::dprintf( level, "%s\n", getString() );
}
void
SubsystemInfo::printf( void ) const
{
	::printf( "%s\n", getString() );
}
const char *
SubsystemInfo::getString( void ) const
{
	static char	 buf[128];
	const char	*type_name = "UNKNOWN";

	if ( m_Info ) {
		type_name = m_Info->getTypeName();
	}
	snprintf( buf, sizeof(buf),
			  "SubsystemInfo: name=%s type=%s(%d) class=%s(%d)",
			  m_Name, type_name, m_Type, m_ClassName, m_Class );
	return buf;
}

/* Helper function to retrieve the value of mySubSystem global variable
 * from C functions.  This is helpful because mySubSystem is decorated w/ C++
 * linkage.
 */
extern "C" {
	const char* get_mySubSystem(void) { return mySubSystem->getName(); }
	SubsystemType get_mySubsystemType(void)  { return mySubSystem->getType(); }
}

<commit_msg>Fixed a compile problem on a couple of platforms<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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_debug.h"
#include "subsystem_info.h"
#include <string.h>

//
// Simple class to manage a single lookup item
//
class SubsystemInfoLookup
{
public:
	SubsystemInfoLookup( SubsystemType, SubsystemClass,
						 const char *, const char * );
	~SubsystemInfoLookup( void ) { };

	SubsystemType getType( void ) const { return m_Type; };
	SubsystemClass getClass( void ) const { return m_Class; } ;
	const char * getTypeName( void ) const { return m_TypeName; };
	const char * getTypeSubstr( void ) const { return m_TypeSubstr; };

	bool match( SubsystemType _type ) const { return m_Type == _type; };
	bool match( SubsystemClass _class ) const { return m_Class == _class; };
	bool match( const char *_name ) const;
	bool matchSubstr( const char *_name ) const;
	bool isValid( ) const { return m_Type != SUBSYSTEM_TYPE_INVALID; };

private:
	SubsystemType	 m_Type;
	SubsystemClass	 m_Class;
	const char		*m_TypeName;
	const char		*m_TypeSubstr;
};
SubsystemInfoLookup::SubsystemInfoLookup(
	SubsystemType _type, SubsystemClass _class,
	const char *_type_name, const char *_type_substr = NULL )
{
	m_Type = _type; m_Class = _class;
	m_TypeName = _type_name, m_TypeSubstr = _type_substr;
}
bool
SubsystemInfoLookup::match( const char *_name ) const
{
	return ( strcasecmp(_name, m_TypeName) == 0 );
};
bool
SubsystemInfoLookup::matchSubstr( const char *_name ) const
{
	const char	*substr = m_TypeSubstr ? m_TypeSubstr : m_TypeName;
	return ( strcasestr(_name, substr) != NULL );
};

//
// Simple class to manage the lookup table
//
class SubsystemInfoTable
{
public:
	SubsystemInfoTable( void );
	~SubsystemInfoTable( void ) { };
	const SubsystemInfoLookup *lookup( SubsystemType ) const;
	const SubsystemInfoLookup *lookup( SubsystemClass ) const;
	const SubsystemInfoLookup *lookup( const char * ) const;
	const SubsystemInfoLookup *Invalid( void ) const { return m_Invalid; };

private:
	const SubsystemInfoLookup			*m_Invalid;
	static const SubsystemInfoLookup	 m_Table[];
};

// -----------------------------------------------------------------
// **** README README README README README README README README ****
// -----------------------------------------------------------------
// Make SURE that you read the README at the top of the include file
// subsystem_info.h before editing this file.
//
// SubsystemInfoLookup(
//   <subsystem type>,		 SUBSYSTEM_TYPE_XXXX
//   <subsystem class>,      SUBSYSTEM_CLASS_XXXX
//   <subsystem type name>   Type name string
//   [,<subsystem substr>])  Type substring (passed to strcasestr())
//
// By default, the lookup will use the <subsystem type name> for
// subsystem "fuzzy" matching, otherwise it will use the substr
// that you provide as the type name.
//
// The second to last entry in the table has an empty string so
// that it'll match any name passed in.
// -----------------------------------------------------------------
const SubsystemInfoLookup SubsystemInfoTable::m_Table[] =
{
	SubsystemInfoLookup( SUBSYSTEM_TYPE_MASTER, SUBSYSTEM_CLASS_DAEMON,
						 "MASTER" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_COLLECTOR, SUBSYSTEM_CLASS_DAEMON,
						 "COLLECTOR" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_NEGOTIATOR, SUBSYSTEM_CLASS_DAEMON,
						 "NEGOTIATOR" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SCHEDD, SUBSYSTEM_CLASS_DAEMON,
						 "SCHEDD" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SHADOW, SUBSYSTEM_CLASS_DAEMON,
						 "SHADOW" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_STARTD, SUBSYSTEM_CLASS_DAEMON,
						 "STARTD" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_STARTER, SUBSYSTEM_CLASS_DAEMON,
						 "STARTER" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_GAHP, SUBSYSTEM_CLASS_DAEMON,
						 "GAHP" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_TOOL, SUBSYSTEM_CLASS_CLIENT,
						 "TOOL" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_SUBMIT, SUBSYSTEM_CLASS_CLIENT,
						 "SUBMIT" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_JOB, SUBSYSTEM_CLASS_JOB,
						 "JOB" ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_DAEMON, SUBSYSTEM_CLASS_DAEMON,
						 "DAEMON", "" /* empty string, match anything */ ),
	SubsystemInfoLookup( SUBSYSTEM_TYPE_INVALID, SUBSYSTEM_CLASS_NONE,
						 "INVALID" )
};

SubsystemInfoTable::SubsystemInfoTable(void)
{
	int num = ( sizeof(m_Table) / sizeof(SubsystemInfoLookup) );
	m_Invalid = &m_Table[num - 1];
	ASSERT( m_Invalid != NULL );
	ASSERT( m_Invalid->match(SUBSYSTEM_TYPE_INVALID) );
}

// Internal method to lookup by SubsystemType
const SubsystemInfoLookup *
SubsystemInfoTable::lookup( SubsystemType _type ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_type) ) {
			return cur;
		}
	}
	return m_Invalid;
}

// Internal method to lookup by SubsystemClass
const SubsystemInfoLookup *
SubsystemInfoTable::lookup( SubsystemClass _class ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_class) ) {
			return cur;
		}
	}
	return m_Invalid;
}

const SubsystemInfoLookup *
// Lookup by name
SubsystemInfoTable::lookup( const char *_name ) const
{
	const SubsystemInfoLookup *cur;
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->match(_name) ) {
			return cur;
		}
	}
	for ( cur = m_Table;  cur->isValid();  cur++ ) {
		if ( cur->matchSubstr(_name) ) {
			return cur;
		}
	}

	// Return the invalid entry
	return m_Invalid;
}
static const SubsystemInfoTable *infoTable = new SubsystemInfoTable( );

//
// C++ SubsystemInfo methods
//

SubsystemInfo::SubsystemInfo( const char *_name, SubsystemType _type )
{
	m_Name = NULL;
	m_TempName = NULL;
	m_LocalName = NULL;
	setName( _name );
	if ( _type == SUBSYSTEM_TYPE_AUTO ) {
		setTypeFromName( _name );
	}
	else {
		setType( _type );
	}
}

SubsystemInfo::~SubsystemInfo( void )
{
	if ( m_Name ) {
		free( const_cast<char *>( m_Name ) );
		m_Name = NULL;
	}
}

bool
SubsystemInfo::nameMatch( const char *_name ) const
{
	return ( strcasecmp(_name, m_Name) == 0 );
}

const char *
SubsystemInfo::setName( const char *_name )
{
	if ( _name != NULL ) {
		m_Name = strdup(_name);
		m_NameValid = true ;
	}
	else {
		m_Name = strdup("UNKNOWN");		// Fill in a value so it's not NULL
		m_NameValid = false;
	}
	return m_Name;
}

// Temp name handling
const char *
SubsystemInfo::setTempName( const char *_name )
{
	resetTempName( );
	if ( _name ) {
		m_TempName = strdup( _name );
	}
	return m_TempName;
}

void
SubsystemInfo::resetTempName( void )
{
	if ( m_TempName ) {
		free( const_cast<char*>(m_TempName) );
		m_TempName = NULL;
	}
}

// Public interface to set the type from a name
SubsystemType
SubsystemInfo::setTypeFromName( const char *_type_name )
{
	if ( NULL == _type_name ) {
		_type_name = m_Name;
	}
	if ( NULL == _type_name ) {
		return setType( SUBSYSTEM_TYPE_DAEMON );
	}

	// First, look for an exact match
	const SubsystemInfoLookup	*match = infoTable->lookup( _type_name );
	if ( match ) {
		return setType( match, _type_name );
	}
	return setType( SUBSYSTEM_TYPE_DAEMON, _type_name );
}

// Public set type method
SubsystemType
SubsystemInfo::setType( SubsystemType _type )
{
	return setType( _type, NULL );
}

// Internal set type method
SubsystemType
SubsystemInfo::setType( SubsystemType _type, const char *_type_name )
{
	return setType( infoTable->lookup(_type), _type_name );
}

// Internal set type method
SubsystemType
SubsystemInfo::setType( const SubsystemInfoLookup *info,
						const char *type_name )
{
	m_Type = info->getType();
	setClass( info );
	m_Info = info;
	if ( type_name != NULL ) {
		m_TypeName = type_name;
	}
	else {
		m_TypeName = info->getTypeName();
	}

	return m_Type;
}

// Internal set class method
SubsystemClass
SubsystemInfo::setClass( const SubsystemInfoLookup *info )
{
	static const char *_class_names[] = {
		"None",
		"DAEMON",
		"CLIENT",
		"JOB"
	};
	static int		_num = ( sizeof(_class_names) / sizeof(const char *) );

	m_Class = info->getClass();
	ASSERT ( ( m_Class >= 0 ) && ( m_Class <= _num ) );
	m_ClassName = _class_names[m_Class];
	return m_Class;
}

// Methods to get/set the local name
const char *
SubsystemInfo::getLocalName( const char * _default ) const
{
	if ( m_LocalName ) {
		return m_LocalName;
	}
	else {
		return _default;
	}
}
const char *
SubsystemInfo::setLocalName( const char * _name )
{
	if ( m_LocalName ) {
		free( const_cast<char *>( m_LocalName ) );
		m_LocalName = NULL;
	}
	m_LocalName = strdup(_name);
	return m_LocalName;
}

// Public dprintf / printf methods
void
SubsystemInfo::dprintf( int level ) const
{
	::dprintf( level, "%s\n", getString() );
}
void
SubsystemInfo::printf( void ) const
{
	::printf( "%s\n", getString() );
}
const char *
SubsystemInfo::getString( void ) const
{
	static char	 buf[128];
	const char	*type_name = "UNKNOWN";

	if ( m_Info ) {
		type_name = m_Info->getTypeName();
	}
	snprintf( buf, sizeof(buf),
			  "SubsystemInfo: name=%s type=%s(%d) class=%s(%d)",
			  m_Name, type_name, m_Type, m_ClassName, m_Class );
	return buf;
}

/* Helper function to retrieve the value of mySubSystem global variable
 * from C functions.  This is helpful because mySubSystem is decorated w/ C++
 * linkage.
 */
extern "C" {
	const char* get_mySubSystem(void) { return mySubSystem->getName(); }
	SubsystemType get_mySubsystemType(void)  { return mySubSystem->getType(); }
}

<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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_attributes.h"
#include "dagman_classad.h"
#include "dc_schedd.h"
#include "condor_qmgr.h"
#include "debug.h"
#include "dagman_metrics.h"
#include "basename.h"

//---------------------------------------------------------------------------
Qmgr_connection *
ScheddClassad::OpenConnection()
{
		// Open job queue
	CondorError errstack;
	Qmgr_connection *queue = ConnectQ( _schedd->addr(), 0, false,
				&errstack, NULL, _schedd->version() );
	if ( !queue ) {
		debug_printf( DEBUG_QUIET,
					"WARNING: failed to connect to queue manager (%s)\n",
					errstack.getFullText().c_str() );
		check_warning_strictness( DAG_STRICT_3 );
		return NULL;
	}

	return queue;
}

//---------------------------------------------------------------------------
void
ScheddClassad::CloseConnection( Qmgr_connection *queue )
{
	if ( !DisconnectQ( queue ) ) {
		debug_printf( DEBUG_QUIET,
					"WARNING: queue transaction failed.  No attributes were set.\n" );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, int attrVal )
{
	if ( SetAttributeInt( _jobId._cluster, _jobId._proc,
						  attrName, attrVal ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, const MyString &value )
{
	if ( SetAttributeString( _jobId._cluster, _jobId._proc,
						  attrName, value.Value() ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, const ClassAd &ad )
{
	if ( SetAttributeExpr( _jobId._cluster, _jobId._proc,
						  attrName, &ad ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
bool
ScheddClassad::GetAttribute( const char *attrName, MyString &attrVal,
			bool printWarning )
{
	char *val;
	if ( GetAttributeStringNew( _jobId._cluster, _jobId._proc,
				attrName, &val ) == -1 ) {
		if ( printWarning ) {
			debug_printf( DEBUG_QUIET,
					  	"Warning: failed to get attribute %s\n", attrName );
		}
		return false;
	}

	attrVal = val;
	free( val );
	return true;
}

//---------------------------------------------------------------------------
bool
ScheddClassad::GetAttribute( const char *attrName, int &attrVal,
			bool printWarning )
{
	int val;
	if ( GetAttributeInt( _jobId._cluster, _jobId._proc,
				attrName, &val ) == -1 ) {
		if ( printWarning ) {
			debug_printf( DEBUG_QUIET,
				"Warning: failed to get attribute %s\n", attrName );
		}
		return false;
	}

	attrVal = val;
	return true;
}

//---------------------------------------------------------------------------
DagmanClassad::DagmanClassad( const CondorID &DAGManJobId, DCSchedd *schedd ) :
	_valid( false )
{
	CondorID defaultCondorId;
	if ( DAGManJobId == defaultCondorId ) {
		debug_printf( DEBUG_QUIET, "No HTCondor ID available for DAGMan (running on command line?); DAG status will not be reported to ClassAd\n" );
		return;
	}

	_jobId = DAGManJobId;
	_schedd = schedd;
	_valid = true;

	InitializeMetrics();
}

//---------------------------------------------------------------------------
DagmanClassad::~DagmanClassad()
{
	_valid = false;
}

//---------------------------------------------------------------------------
void
DagmanClassad::Initialize( int maxJobs, int maxIdle, int maxPreScripts,
			int maxPostScripts )
{
	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	SetAttribute( ATTR_DAGMAN_MAXJOBS, maxJobs );
	SetAttribute( ATTR_DAGMAN_MAXIDLE, maxIdle );
	SetAttribute( ATTR_DAGMAN_MAXPRESCRIPTS, maxPreScripts );
	SetAttribute( ATTR_DAGMAN_MAXPOSTSCRIPTS, maxPostScripts );

	CloseConnection( queue );
}

//---------------------------------------------------------------------------
void
DagmanClassad::Update( int total, int done, int pre, int submitted,
			int post, int ready, int failed, int unready,
			DagStatus dagStatus, bool recovery, const DagmanStats &stats,
			int &maxJobs, int &maxIdle, int &maxPreScripts, int &maxPostScripts )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd update -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	SetAttribute( ATTR_DAG_NODES_TOTAL, total );
	SetAttribute( ATTR_DAG_NODES_DONE, done );
	SetAttribute( ATTR_DAG_NODES_PRERUN, pre );
	SetAttribute( ATTR_DAG_NODES_QUEUED, submitted );
	SetAttribute( ATTR_DAG_NODES_POSTRUN, post );
	SetAttribute( ATTR_DAG_NODES_READY, ready );
	SetAttribute( ATTR_DAG_NODES_FAILED, failed );
	SetAttribute( ATTR_DAG_NODES_UNREADY, unready );
	SetAttribute( ATTR_DAG_STATUS, (int)dagStatus );
	SetAttribute( ATTR_DAG_IN_RECOVERY, recovery );

	// Publish DAGMan stats to a classad, then update those also
	ClassAd stats_ad;
	stats.Publish( stats_ad );
	SetAttribute( ATTR_DAG_STATS, stats_ad );

	// Certain DAGMan properties (MaxJobs, MaxIdle, etc.) can be changed by
	// users. Start by declaring variables for these properties.
	int jobAdMaxIdle;
	int jobAdMaxJobs;
	int jobAdMaxPreScripts;
	int jobAdMaxPostScripts;

	// Look up the current values of these properties in the condor_dagman job ad.
	GetAttribute( ATTR_DAGMAN_MAXIDLE, jobAdMaxIdle );
	GetAttribute( ATTR_DAGMAN_MAXJOBS, jobAdMaxJobs );
	GetAttribute( ATTR_DAGMAN_MAXPRESCRIPTS, jobAdMaxPreScripts );
	GetAttribute( ATTR_DAGMAN_MAXPOSTSCRIPTS, jobAdMaxPostScripts );

	// Update our internal dag values according to whatever is in the job ad.
	maxIdle = jobAdMaxIdle;
	maxJobs = jobAdMaxJobs;
	maxPreScripts = jobAdMaxPreScripts;
	maxPostScripts = jobAdMaxPostScripts;

	CloseConnection( queue );
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetInfo( MyString &owner, MyString &nodeName )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	if ( !GetAttribute( ATTR_OWNER, owner ) ) {
		check_warning_strictness( DAG_STRICT_1 );
		owner = "undef";
	}

	if ( !GetAttribute( ATTR_DAG_NODE_NAME, nodeName ) ) {
		// We should only get this value if we're a sub-DAG.
		nodeName = "undef";
	}

	CloseConnection( queue );

	return;
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetSetBatchName( const MyString &primaryDagFile,
			MyString &batchName )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	if ( !GetAttribute( ATTR_JOB_BATCH_NAME, batchName, false ) ) {
			// Default batch name is top-level DAG's primary
			// DAG file (base name only).
		batchName = condor_basename( primaryDagFile.Value() );
		batchName += "+";
		batchName += IntToStr( _jobId._cluster );
		SetAttribute( ATTR_JOB_BATCH_NAME, batchName );
	}

	CloseConnection( queue );

	debug_printf( DEBUG_VERBOSE, "Workflow batch-name: <%s>\n",
				batchName.Value() );
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetAcctInfo( MyString &group, MyString &user )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	GetAttribute( ATTR_ACCT_GROUP, group, false );
	debug_printf( DEBUG_VERBOSE, "Workflow accounting_group: <%s>\n",
				group.Value() );

	GetAttribute( ATTR_ACCT_GROUP_USER, user, false );
	debug_printf( DEBUG_VERBOSE, "Workflow accounting_group_user: <%s>\n",
				user.Value() );

	CloseConnection( queue );

	return;
}

//---------------------------------------------------------------------------
void
DagmanClassad::InitializeMetrics()
{

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	int parentDagmanCluster;
	if ( GetAttributeInt( _jobId._cluster, _jobId._proc,
				ATTR_DAGMAN_JOB_ID, &parentDagmanCluster ) != 0 ) {
		debug_printf( DEBUG_DEBUG_1,
					"Can't get parent DAGMan cluster\n" );
		parentDagmanCluster = -1;
	} else {
		debug_printf( DEBUG_DEBUG_1, "Parent DAGMan cluster: %d\n",
					parentDagmanCluster );
	}

	CloseConnection( queue );

	DagmanMetrics::SetDagmanIds( _jobId, parentDagmanCluster );
}

//---------------------------------------------------------------------------
ProvisionerClassad::ProvisionerClassad( const CondorID &JobId, DCSchedd *schedd ) :
	_valid( false )
{
	CondorID defaultCondorId;
	if ( JobId == defaultCondorId ) {
		debug_printf( DEBUG_QUIET, "No HTCondor ID available for this job." );
		return;
	}

	_jobId = JobId;
	_schedd = schedd;
	_valid = true;
}

//---------------------------------------------------------------------------
ProvisionerClassad::~ProvisionerClassad()
{
	_valid = false;
}

//---------------------------------------------------------------------------
MyString
ProvisionerClassad::GetProvisionerState()
{
	MyString state = "";

	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- ProvisionerClassad object is invalid\n" );
		return state;
	}

	Qmgr_connection *queue = OpenConnection();

	if ( !queue ) {
		return state;
	}

	GetAttribute( ATTR_PROVISIONER_STATE, state, false );
	debug_printf( DEBUG_VERBOSE, "Provisioner job state: <%s>\n",
				state.Value() );

	CloseConnection( queue );

	return state;
}
<commit_msg>Readded std::to_string from crooked merge (#7610) (#7737)<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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_attributes.h"
#include "dagman_classad.h"
#include "dc_schedd.h"
#include "condor_qmgr.h"
#include "debug.h"
#include "dagman_metrics.h"
#include "basename.h"

//---------------------------------------------------------------------------
Qmgr_connection *
ScheddClassad::OpenConnection()
{
		// Open job queue
	CondorError errstack;
	Qmgr_connection *queue = ConnectQ( _schedd->addr(), 0, false,
				&errstack, NULL, _schedd->version() );
	if ( !queue ) {
		debug_printf( DEBUG_QUIET,
					"WARNING: failed to connect to queue manager (%s)\n",
					errstack.getFullText().c_str() );
		check_warning_strictness( DAG_STRICT_3 );
		return NULL;
	}

	return queue;
}

//---------------------------------------------------------------------------
void
ScheddClassad::CloseConnection( Qmgr_connection *queue )
{
	if ( !DisconnectQ( queue ) ) {
		debug_printf( DEBUG_QUIET,
					"WARNING: queue transaction failed.  No attributes were set.\n" );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, int attrVal )
{
	if ( SetAttributeInt( _jobId._cluster, _jobId._proc,
						  attrName, attrVal ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, const MyString &value )
{
	if ( SetAttributeString( _jobId._cluster, _jobId._proc,
						  attrName, value.Value() ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
void
ScheddClassad::SetAttribute( const char *attrName, const ClassAd &ad )
{
	if ( SetAttributeExpr( _jobId._cluster, _jobId._proc,
						  attrName, &ad ) != 0 ) {
		debug_printf( DEBUG_QUIET,
					  "WARNING: failed to set attribute %s\n", attrName );
		check_warning_strictness( DAG_STRICT_3 );
	}
}

//---------------------------------------------------------------------------
bool
ScheddClassad::GetAttribute( const char *attrName, MyString &attrVal,
			bool printWarning )
{
	char *val;
	if ( GetAttributeStringNew( _jobId._cluster, _jobId._proc,
				attrName, &val ) == -1 ) {
		if ( printWarning ) {
			debug_printf( DEBUG_QUIET,
					  	"Warning: failed to get attribute %s\n", attrName );
		}
		return false;
	}

	attrVal = val;
	free( val );
	return true;
}

//---------------------------------------------------------------------------
bool
ScheddClassad::GetAttribute( const char *attrName, int &attrVal,
			bool printWarning )
{
	int val;
	if ( GetAttributeInt( _jobId._cluster, _jobId._proc,
				attrName, &val ) == -1 ) {
		if ( printWarning ) {
			debug_printf( DEBUG_QUIET,
				"Warning: failed to get attribute %s\n", attrName );
		}
		return false;
	}

	attrVal = val;
	return true;
}

//---------------------------------------------------------------------------
DagmanClassad::DagmanClassad( const CondorID &DAGManJobId, DCSchedd *schedd ) :
	_valid( false )
{
	CondorID defaultCondorId;
	if ( DAGManJobId == defaultCondorId ) {
		debug_printf( DEBUG_QUIET, "No HTCondor ID available for DAGMan (running on command line?); DAG status will not be reported to ClassAd\n" );
		return;
	}

	_jobId = DAGManJobId;
	_schedd = schedd;
	_valid = true;

	InitializeMetrics();
}

//---------------------------------------------------------------------------
DagmanClassad::~DagmanClassad()
{
	_valid = false;
}

//---------------------------------------------------------------------------
void
DagmanClassad::Initialize( int maxJobs, int maxIdle, int maxPreScripts,
			int maxPostScripts )
{
	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	SetAttribute( ATTR_DAGMAN_MAXJOBS, maxJobs );
	SetAttribute( ATTR_DAGMAN_MAXIDLE, maxIdle );
	SetAttribute( ATTR_DAGMAN_MAXPRESCRIPTS, maxPreScripts );
	SetAttribute( ATTR_DAGMAN_MAXPOSTSCRIPTS, maxPostScripts );

	CloseConnection( queue );
}

//---------------------------------------------------------------------------
void
DagmanClassad::Update( int total, int done, int pre, int submitted,
			int post, int ready, int failed, int unready,
			DagStatus dagStatus, bool recovery, const DagmanStats &stats,
			int &maxJobs, int &maxIdle, int &maxPreScripts, int &maxPostScripts )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd update -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	SetAttribute( ATTR_DAG_NODES_TOTAL, total );
	SetAttribute( ATTR_DAG_NODES_DONE, done );
	SetAttribute( ATTR_DAG_NODES_PRERUN, pre );
	SetAttribute( ATTR_DAG_NODES_QUEUED, submitted );
	SetAttribute( ATTR_DAG_NODES_POSTRUN, post );
	SetAttribute( ATTR_DAG_NODES_READY, ready );
	SetAttribute( ATTR_DAG_NODES_FAILED, failed );
	SetAttribute( ATTR_DAG_NODES_UNREADY, unready );
	SetAttribute( ATTR_DAG_STATUS, (int)dagStatus );
	SetAttribute( ATTR_DAG_IN_RECOVERY, recovery );

	// Publish DAGMan stats to a classad, then update those also
	ClassAd stats_ad;
	stats.Publish( stats_ad );
	SetAttribute( ATTR_DAG_STATS, stats_ad );

	// Certain DAGMan properties (MaxJobs, MaxIdle, etc.) can be changed by
	// users. Start by declaring variables for these properties.
	int jobAdMaxIdle;
	int jobAdMaxJobs;
	int jobAdMaxPreScripts;
	int jobAdMaxPostScripts;

	// Look up the current values of these properties in the condor_dagman job ad.
	GetAttribute( ATTR_DAGMAN_MAXIDLE, jobAdMaxIdle );
	GetAttribute( ATTR_DAGMAN_MAXJOBS, jobAdMaxJobs );
	GetAttribute( ATTR_DAGMAN_MAXPRESCRIPTS, jobAdMaxPreScripts );
	GetAttribute( ATTR_DAGMAN_MAXPOSTSCRIPTS, jobAdMaxPostScripts );

	// Update our internal dag values according to whatever is in the job ad.
	maxIdle = jobAdMaxIdle;
	maxJobs = jobAdMaxJobs;
	maxPreScripts = jobAdMaxPreScripts;
	maxPostScripts = jobAdMaxPostScripts;

	CloseConnection( queue );
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetInfo( MyString &owner, MyString &nodeName )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	if ( !GetAttribute( ATTR_OWNER, owner ) ) {
		check_warning_strictness( DAG_STRICT_1 );
		owner = "undef";
	}

	if ( !GetAttribute( ATTR_DAG_NODE_NAME, nodeName ) ) {
		// We should only get this value if we're a sub-DAG.
		nodeName = "undef";
	}

	CloseConnection( queue );

	return;
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetSetBatchName( const MyString &primaryDagFile,
			MyString &batchName )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	if ( !GetAttribute( ATTR_JOB_BATCH_NAME, batchName, false ) ) {
			// Default batch name is top-level DAG's primary
			// DAG file (base name only).
		batchName = condor_basename( primaryDagFile.Value() );
		batchName += "+";
		batchName += std::to_string( _jobId._cluster );
		SetAttribute( ATTR_JOB_BATCH_NAME, batchName );
	}

	CloseConnection( queue );

	debug_printf( DEBUG_VERBOSE, "Workflow batch-name: <%s>\n",
				batchName.Value() );
}

//---------------------------------------------------------------------------
void
DagmanClassad::GetAcctInfo( MyString &group, MyString &user )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	GetAttribute( ATTR_ACCT_GROUP, group, false );
	debug_printf( DEBUG_VERBOSE, "Workflow accounting_group: <%s>\n",
				group.Value() );

	GetAttribute( ATTR_ACCT_GROUP_USER, user, false );
	debug_printf( DEBUG_VERBOSE, "Workflow accounting_group_user: <%s>\n",
				user.Value() );

	CloseConnection( queue );

	return;
}

//---------------------------------------------------------------------------
void
DagmanClassad::InitializeMetrics()
{

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	int parentDagmanCluster;
	if ( GetAttributeInt( _jobId._cluster, _jobId._proc,
				ATTR_DAGMAN_JOB_ID, &parentDagmanCluster ) != 0 ) {
		debug_printf( DEBUG_DEBUG_1,
					"Can't get parent DAGMan cluster\n" );
		parentDagmanCluster = -1;
	} else {
		debug_printf( DEBUG_DEBUG_1, "Parent DAGMan cluster: %d\n",
					parentDagmanCluster );
	}

	CloseConnection( queue );

	DagmanMetrics::SetDagmanIds( _jobId, parentDagmanCluster );
}

//---------------------------------------------------------------------------
ProvisionerClassad::ProvisionerClassad( const CondorID &JobId, DCSchedd *schedd ) :
	_valid( false )
{
	CondorID defaultCondorId;
	if ( JobId == defaultCondorId ) {
		debug_printf( DEBUG_QUIET, "No HTCondor ID available for this job." );
		return;
	}

	_jobId = JobId;
	_schedd = schedd;
	_valid = true;
}

//---------------------------------------------------------------------------
ProvisionerClassad::~ProvisionerClassad()
{
	_valid = false;
}

//---------------------------------------------------------------------------
MyString
ProvisionerClassad::GetProvisionerState()
{
	MyString state = "";

	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- ProvisionerClassad object is invalid\n" );
		return state;
	}

	Qmgr_connection *queue = OpenConnection();

	if ( !queue ) {
		return state;
	}

	GetAttribute( ATTR_PROVISIONER_STATE, state, false );
	debug_printf( DEBUG_VERBOSE, "Provisioner job state: <%s>\n",
				state.Value() );

	CloseConnection( queue );

	return state;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__
#define __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__

#include <functional>
#include <string>

#include <stout/base64.hpp>
#include <stout/duration.hpp>
#include <stout/hashmap.hpp>
#include <stout/strings.hpp>

#include <process/future.hpp>
#include <process/http.hpp>
#include <process/process.hpp>
#include <process/time.hpp>

namespace mesos {
namespace internal {
namespace slave {
namespace docker {
namespace registry {

/**
 * Encapsulates JSON Web Token.
 *
 * Reference: https://tools.ietf.org/html/rfc7519.
 */
struct Token
{
  /**
   * Factory method for Token object.
   *
   * Parses the raw token string and validates for token's expiration.
   *
   * @returns Token if parsing and validation succeeds.
   *          Error if parsing or validation fails.
   */
  static Try<Token> create(const std::string& rawString);

  /**
   * Compares token's expiration time(expressed in seconds) with current time.
   *
   * @returns True if token's expiration time is greater than current time.
   *          False if token's expiration time is less than or equal to current
   *          time.
   */
  bool isExpired() const;

  /**
   * Validates the token if its "exp" "nbf" values are in range.
   *
   * @returns True if current time is within token's "exp" and "nbf" values.
   *          False if current time is not within token's "exp" and "nbf"
   *          values.
   */
  bool isValid() const;

  const std::string raw;
  const JSON::Object header;
  const JSON::Object claims;
  // TODO(jojy): Add signature information.

private:
  Token(
      const std::string& raw,
      const JSON::Object& headerJson,
      const JSON::Object& claimsJson,
      const Option<process::Time>& expireTime,
      const Option<process::Time>& notBeforeTime);

  static Result<process::Time> getTimeValue(
      const JSON::Object& object,
      const std::string& key);

  const Option<process::Time> expiration;
  const Option<process::Time> notBefore;
};

// Forward declaration.
class TokenManagerProcess;

/**
 *  Acquires and manages docker registry tokens. It keeps the tokens in its
 *  cache to server any future request for the same token.
 *  The cache grows unbounded.
 *  TODO(jojy): The cache can be optimized to prune based on the expiry time of
 *  the token and server's issue time.
 */
class TokenManager
{
public:
  /**
   * Factory method for creating TokenManager object.
   *
   * TokenManager and registry authorization realm has a 1:1 relationship.
   *
   * @param realm URL of the authorization server from where token will be
   *     requested by this TokenManager.
   * @returns Owned<TokenManager> if success.
   *          Error on failure.
   */
  static Try<process::Owned<TokenManager>> create(
      const process::http::URL& realm);

  /**
   * Returns JSON Web Token from cache or from remote server using "Basic
   * authorization".
   *
   * @param service Name of the service that hosts the resource for which
   *     token is being requested.
   * @param scope unique scope returned by the 401 Unauthorized response
   *     from the registry.
   * @param account Name of the account which the client is acting as.
   * @param user base64 encoded userid for basic authorization.
   * @param password base64 encoded password for basic authorization.
   * @returns Token struct that encapsulates JSON Web Token.
   */
  process::Future<Token> getToken(
      const std::string& service,
      const std::string& scope,
      const Option<std::string>& account,
      const std::string& user,
      const Option<std::string>& password);

  /**
   * Returns JSON Web Token from cache or from remote server using "TLS/Cert"
   * based authorization.
   *
   * @param service Name of the service that hosts the resource for which
   *     token is being requested.
   * @param scope unique scope returned by the 401 Unauthorized response
   *     from the registry.
   * @param account Name of the account which the client is acting as.
   * @returns Token struct that encapsulates JSON Web Token.
   */
  process::Future<Token> getToken(
      const std::string& service,
      const std::string& scope,
      const Option<std::string>& account);

  ~TokenManager();

private:
  TokenManager(process::Owned<TokenManagerProcess>& process);

  TokenManager(const TokenManager&) = delete;
  TokenManager& operator=(const TokenManager&) = delete;

  process::Owned<TokenManagerProcess> process_;
};

} // namespace registry {
} // namespace docker {
} // namespace slave {
} // namespace internal {
} // namespace mesos {

#endif // __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__
<commit_msg>Added reference to docker registry bearer token spec.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__
#define __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__

#include <functional>
#include <string>

#include <stout/base64.hpp>
#include <stout/duration.hpp>
#include <stout/hashmap.hpp>
#include <stout/strings.hpp>

#include <process/future.hpp>
#include <process/http.hpp>
#include <process/process.hpp>
#include <process/time.hpp>

namespace mesos {
namespace internal {
namespace slave {
namespace docker {
namespace registry {

/**
 * Encapsulates JSON Web Token used by Docker.
 *
 * References:
 *   https://docs.docker.com/registry/spec/auth/jwt/
 *   https://tools.ietf.org/html/rfc7519.
 */
struct Token
{
  /**
   * Factory method for Token object.
   *
   * Parses the raw token string and validates for token's expiration.
   *
   * @returns Token if parsing and validation succeeds.
   *          Error if parsing or validation fails.
   */
  static Try<Token> create(const std::string& rawString);

  /**
   * Compares token's expiration time(expressed in seconds) with current time.
   *
   * @returns True if token's expiration time is greater than current time.
   *          False if token's expiration time is less than or equal to current
   *          time.
   */
  bool isExpired() const;

  /**
   * Validates the token if its "exp" "nbf" values are in range.
   *
   * @returns True if current time is within token's "exp" and "nbf" values.
   *          False if current time is not within token's "exp" and "nbf"
   *          values.
   */
  bool isValid() const;

  const std::string raw;
  const JSON::Object header;
  const JSON::Object claims;
  // TODO(jojy): Add signature information.

private:
  Token(
      const std::string& raw,
      const JSON::Object& headerJson,
      const JSON::Object& claimsJson,
      const Option<process::Time>& expireTime,
      const Option<process::Time>& notBeforeTime);

  static Result<process::Time> getTimeValue(
      const JSON::Object& object,
      const std::string& key);

  const Option<process::Time> expiration;
  const Option<process::Time> notBefore;
};

// Forward declaration.
class TokenManagerProcess;

/**
 *  Acquires and manages docker registry tokens. It keeps the tokens in its
 *  cache to server any future request for the same token.
 *  The cache grows unbounded.
 *  TODO(jojy): The cache can be optimized to prune based on the expiry time of
 *  the token and server's issue time.
 */
class TokenManager
{
public:
  /**
   * Factory method for creating TokenManager object.
   *
   * TokenManager and registry authorization realm has a 1:1 relationship.
   *
   * @param realm URL of the authorization server from where token will be
   *     requested by this TokenManager.
   * @returns Owned<TokenManager> if success.
   *          Error on failure.
   */
  static Try<process::Owned<TokenManager>> create(
      const process::http::URL& realm);

  /**
   * Returns JSON Web Token from cache or from remote server using "Basic
   * authorization".
   *
   * @param service Name of the service that hosts the resource for which
   *     token is being requested.
   * @param scope unique scope returned by the 401 Unauthorized response
   *     from the registry.
   * @param account Name of the account which the client is acting as.
   * @param user base64 encoded userid for basic authorization.
   * @param password base64 encoded password for basic authorization.
   * @returns Token struct that encapsulates JSON Web Token.
   */
  process::Future<Token> getToken(
      const std::string& service,
      const std::string& scope,
      const Option<std::string>& account,
      const std::string& user,
      const Option<std::string>& password);

  /**
   * Returns JSON Web Token from cache or from remote server using "TLS/Cert"
   * based authorization.
   *
   * @param service Name of the service that hosts the resource for which
   *     token is being requested.
   * @param scope unique scope returned by the 401 Unauthorized response
   *     from the registry.
   * @param account Name of the account which the client is acting as.
   * @returns Token struct that encapsulates JSON Web Token.
   */
  process::Future<Token> getToken(
      const std::string& service,
      const std::string& scope,
      const Option<std::string>& account);

  ~TokenManager();

private:
  TokenManager(process::Owned<TokenManagerProcess>& process);

  TokenManager(const TokenManager&) = delete;
  TokenManager& operator=(const TokenManager&) = delete;

  process::Owned<TokenManagerProcess> process_;
};

} // namespace registry {
} // namespace docker {
} // namespace slave {
} // namespace internal {
} // namespace mesos {

#endif // __PROVISIONER_DOCKER_TOKEN_MANAGER_HPP__
<|endoftext|>


<commit_before>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef piecewise_polygon_creator_test_suite_hpp
#define piecewise_polygon_creator_test_suite_hpp

#include "eli/code_eli.hpp"

#include "eli/constants/math.hpp"
#include "eli/geom/curve/piecewise.hpp"
#include "eli/geom/curve/piecewise_polygon_creator.hpp"

#include <cmath>    // std::pow, std::exp
#include <cassert>  // assert()

#include <typeinfo> // typeid
#include <string>   // std::string
#include <sstream>  // std::stringstream
#include <iomanip>  // std::setw
#include <limits>   // std::numeric_limits

template<typename data__>
class piecewise_polygon_creator_test_suite : public Test::Suite
{
  private:
    typedef eli::geom::curve::piecewise_polygon_creator<data__, 3> polygon_creator_type;
    typedef eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, 3> piecewise_curve_type;
    typedef typename piecewise_curve_type::curve_type curve_type;
    typedef typename piecewise_curve_type::point_type point_type;
    typedef typename piecewise_curve_type::data_type data_type;
    typedef typename piecewise_curve_type::index_type index_type;
    typedef typename piecewise_curve_type::tolerance_type tolerance_type;

    tolerance_type tol;

  protected:
    void AddTests(const float &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<float>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<float>::create_box_test);
    }
    void AddTests(const double &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<double>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<double>::create_box_test);
    }
    void AddTests(const long double &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<long double>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<long double>::create_box_test);
    }
#ifdef ELI_QD_FOUND
    void AddTests(const dd_real &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<dd_real>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<dd_real>::create_box_test);
    }

    void AddTests(const qd_real &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<qd_real>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<qd_real>::create_box_test);
    }
#endif
  public:
    piecewise_polygon_creator_test_suite() : tol()
    {
      AddTests(data__());
    }
    ~piecewise_polygon_creator_test_suite()
    {
    }

  private:
    void octave_print(int figno, const piecewise_curve_type &pc) const
    {
      index_type i, pp, ns;
      data_type tmin, tmax;

      ns=pc.number_segments();
      pc.get_parameter_min(tmin);
      pc.get_parameter_max(tmax);

      std::cout << "figure(" << figno << ");" << std::endl;

      // get control points and print
      std::cout << "cp_x=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).x();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      std::cout << "cp_y=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).y();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      std::cout << "cp_z=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).z();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      // initialize the t parameters
      std::vector<data__> t(129);
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        t[i]=tmin+(tmax-tmin)*static_cast<data__>(i)/(t.size()-1);
      }

      // set the surface points
      std::cout << "surf_x=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).x();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "surf_y=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).y();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "surf_z=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).z();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "setenv('GNUTERM', 'x11');" << std::endl;
      std::cout << "plot3(surf_x, surf_y, surf_z, '-k');" << std::endl;
      std::cout << "hold on;" << std::endl;
      std::cout << "plot3(cp_x', cp_y', cp_z', '-ok', 'MarkerFaceColor', [0 0 0]);" << std::endl;
      std::cout << "hold off;" << std::endl;
    }

    void create_triangle_test()
    {
      // create triangle with specified parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(3);
        data_type dt0(3), dt1(2), dt2(3), t0(-1), dt;
        point_type p0, p1, p2, ptemp;

        // set the corners
        p0 << 1, 2, 3;
        p1 << 2, 1, 1;
        p2 << 1, 1, 3;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);

        // set the times
        poly_creator.set_t0(t0);
        poly_creator.set_edge_dt(dt0, 0);
        poly_creator.set_edge_dt(dt1, 1);
        poly_creator.set_edge_dt(dt2, 2);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==t0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=dt0);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=dt1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=dt2);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));
      }

      // create triangle with default parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(3);
        data_type dt;
        point_type p0, p1, p2, ptemp;

        // set the corners
        p0 << 1, 0, 0;
        p1 << 0, 1, 0;
        p2 << 0, 0, 1;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=1);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));
      }
    }

    void create_box_test()
    {
      // create box with specified parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(4);
        data_type dt0(3), dt1(2), dt2(3), dt3(2), t0(-1), dt;
        point_type p0, p1, p2, p3, ptemp;

        // set the corners
        p0 << 1, 2, 3;
        p1 << 2, 1, 1;
        p2 << 1, 1, 3;
        p3 << 3, 3, 2;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);
        poly_creator.set_corner(p3, 3);

        // set the times
        poly_creator.set_t0(t0);
        poly_creator.set_edge_dt(dt0, 0);
        poly_creator.set_edge_dt(dt1, 1);
        poly_creator.set_edge_dt(dt2, 2);
        poly_creator.set_edge_dt(dt3, 3);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);
        ptemp=poly_creator.get_corner(3);
        TEST_ASSERT(p3==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==t0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=dt0);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=dt1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=dt2);
        dt=poly_creator.get_edge_dt(3);
        TEST_ASSERT(dt=dt3);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));

        if (typeid(data_type)==typeid(double))
          octave_print(0, pc);
      }

      // create box with default parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(4);
        data_type dt;
        point_type p0, p1, p2, p3, ptemp;

        // set the corners
        p0 << 0, 0, 0;
        p1 << 1, 0, 0;
        p2 << 1, 1, 0;
        p3 << 0, 1, 0;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);
        poly_creator.set_corner(p3, 3);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);
        ptemp=poly_creator.get_corner(3);
        TEST_ASSERT(p3==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(3);
        TEST_ASSERT(dt=1);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));

        if (typeid(data_type)==typeid(double))
          octave_print(0, pc);

      }
    }
};

#endif

<commit_msg>commented out debugging print info.<commit_after>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef piecewise_polygon_creator_test_suite_hpp
#define piecewise_polygon_creator_test_suite_hpp

#include "eli/code_eli.hpp"

#include "eli/constants/math.hpp"
#include "eli/geom/curve/piecewise.hpp"
#include "eli/geom/curve/piecewise_polygon_creator.hpp"

#include <cmath>    // std::pow, std::exp
#include <cassert>  // assert()

#include <typeinfo> // typeid
#include <string>   // std::string
#include <sstream>  // std::stringstream
#include <iomanip>  // std::setw
#include <limits>   // std::numeric_limits

template<typename data__>
class piecewise_polygon_creator_test_suite : public Test::Suite
{
  private:
    typedef eli::geom::curve::piecewise_polygon_creator<data__, 3> polygon_creator_type;
    typedef eli::geom::curve::piecewise<eli::geom::curve::bezier, data__, 3> piecewise_curve_type;
    typedef typename piecewise_curve_type::curve_type curve_type;
    typedef typename piecewise_curve_type::point_type point_type;
    typedef typename piecewise_curve_type::data_type data_type;
    typedef typename piecewise_curve_type::index_type index_type;
    typedef typename piecewise_curve_type::tolerance_type tolerance_type;

    tolerance_type tol;

  protected:
    void AddTests(const float &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<float>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<float>::create_box_test);
    }
    void AddTests(const double &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<double>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<double>::create_box_test);
    }
    void AddTests(const long double &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<long double>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<long double>::create_box_test);
    }
#ifdef ELI_QD_FOUND
    void AddTests(const dd_real &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<dd_real>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<dd_real>::create_box_test);
    }

    void AddTests(const qd_real &)
    {
      // add the tests
      TEST_ADD(piecewise_polygon_creator_test_suite<qd_real>::create_triangle_test);
      TEST_ADD(piecewise_polygon_creator_test_suite<qd_real>::create_box_test);
    }
#endif
  public:
    piecewise_polygon_creator_test_suite() : tol()
    {
      AddTests(data__());
    }
    ~piecewise_polygon_creator_test_suite()
    {
    }

  private:
    void octave_print(int figno, const piecewise_curve_type &pc) const
    {
      index_type i, pp, ns;
      data_type tmin, tmax;

      ns=pc.number_segments();
      pc.get_parameter_min(tmin);
      pc.get_parameter_max(tmax);

      std::cout << "figure(" << figno << ");" << std::endl;

      // get control points and print
      std::cout << "cp_x=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).x();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      std::cout << "cp_y=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).y();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      std::cout << "cp_z=[";
      for (pp=0; pp<ns; ++pp)
      {
        curve_type bez;
        pc.get(bez, pp);
        for (i=0; i<=bez.degree(); ++i)
        {
          std::cout << bez.get_control_point(i).z();
          if (i<bez.degree())
            std::cout << ", ";
          else if (pp<ns-1)
            std::cout << "; ";
        }
        std::cout << std::endl;
      }
      std::cout << "];" << std::endl;

      // initialize the t parameters
      std::vector<data__> t(129);
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        t[i]=tmin+(tmax-tmin)*static_cast<data__>(i)/(t.size()-1);
      }

      // set the surface points
      std::cout << "surf_x=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).x();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "surf_y=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).y();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "surf_z=[";
      for (i=0; i<static_cast<index_type>(t.size()); ++i)
      {
        std::cout << pc.f(t[i]).z();
        if (i<static_cast<index_type>(t.size()-1))
          std::cout << ", ";
      }
      std::cout << "];" << std::endl;

      std::cout << "setenv('GNUTERM', 'x11');" << std::endl;
      std::cout << "plot3(surf_x, surf_y, surf_z, '-k');" << std::endl;
      std::cout << "hold on;" << std::endl;
      std::cout << "plot3(cp_x', cp_y', cp_z', '-ok', 'MarkerFaceColor', [0 0 0]);" << std::endl;
      std::cout << "hold off;" << std::endl;
    }

    void create_triangle_test()
    {
      // create triangle with specified parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(3);
        data_type dt0(3), dt1(2), dt2(3), t0(-1), dt;
        point_type p0, p1, p2, ptemp;

        // set the corners
        p0 << 1, 2, 3;
        p1 << 2, 1, 1;
        p2 << 1, 1, 3;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);

        // set the times
        poly_creator.set_t0(t0);
        poly_creator.set_edge_dt(dt0, 0);
        poly_creator.set_edge_dt(dt1, 1);
        poly_creator.set_edge_dt(dt2, 2);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==t0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=dt0);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=dt1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=dt2);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));
      }

      // create triangle with default parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(3);
        data_type dt;
        point_type p0, p1, p2, ptemp;

        // set the corners
        p0 << 1, 0, 0;
        p1 << 0, 1, 0;
        p2 << 0, 0, 1;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=1);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));
      }
    }

    void create_box_test()
    {
      // create box with specified parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(4);
        data_type dt0(3), dt1(2), dt2(3), dt3(2), t0(-1), dt;
        point_type p0, p1, p2, p3, ptemp;

        // set the corners
        p0 << 1, 2, 3;
        p1 << 2, 1, 1;
        p2 << 1, 1, 3;
        p3 << 3, 3, 2;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);
        poly_creator.set_corner(p3, 3);

        // set the times
        poly_creator.set_t0(t0);
        poly_creator.set_edge_dt(dt0, 0);
        poly_creator.set_edge_dt(dt1, 1);
        poly_creator.set_edge_dt(dt2, 2);
        poly_creator.set_edge_dt(dt3, 3);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);
        ptemp=poly_creator.get_corner(3);
        TEST_ASSERT(p3==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==t0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=dt0);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=dt1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=dt2);
        dt=poly_creator.get_edge_dt(3);
        TEST_ASSERT(dt=dt3);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));

//         if (typeid(data_type)==typeid(double))
//           octave_print(0, pc);
      }

      // create box with default parameterization
      {
        piecewise_curve_type pc;
        polygon_creator_type poly_creator(4);
        data_type dt;
        point_type p0, p1, p2, p3, ptemp;

        // set the corners
        p0 << 0, 0, 0;
        p1 << 1, 0, 0;
        p2 << 1, 1, 0;
        p3 << 0, 1, 0;
        poly_creator.set_corner(p0, 0);
        poly_creator.set_corner(p1, 1);
        poly_creator.set_corner(p2, 2);
        poly_creator.set_corner(p3, 3);

        // test corner settings
        ptemp=poly_creator.get_corner(0);
        TEST_ASSERT(p0==ptemp);
        ptemp=poly_creator.get_corner(1);
        TEST_ASSERT(p1==ptemp);
        ptemp=poly_creator.get_corner(2);
        TEST_ASSERT(p2==ptemp);
        ptemp=poly_creator.get_corner(3);
        TEST_ASSERT(p3==ptemp);

        // test time step settings
        TEST_ASSERT(poly_creator.get_t0()==0);
        dt=poly_creator.get_edge_dt(0);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(1);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(2);
        TEST_ASSERT(dt=1);
        dt=poly_creator.get_edge_dt(3);
        TEST_ASSERT(dt=1);

        // create the polygon
        TEST_ASSERT(poly_creator.create(pc));

//         if (typeid(data_type)==typeid(double))
//           octave_print(0, pc);

      }
    }
};

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS  HEADER
#include "bidirectional-support-impl.h"

// INTERNAL INCLUDES
#include <singleton-service-impl.h>

// EXTERNAL INCLUDES
#include <memory.h>
#include <fribidi/fribidi.h>

namespace Dali
{

namespace TextAbstraction
{

namespace Internal
{

struct BidirectionalSupport::Plugin
{
  /**
   * Stores bidirectional info per paragraph.
   */
  struct BidirectionalInfo
  {
    FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
    FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
    FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
  };

  Plugin()
  : mParagraphBidirectionalInfo(),
    mFreeIndices()
  {}

  ~Plugin()
  {
    // free all resources.
    for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
           endIt = mParagraphBidirectionalInfo.End();
         it != endIt;
         ++it )
    {
      BidirectionalInfo* info = *it;

      free( info->embeddedLevels );
      free( info->characterTypes );
      delete info;
    }
  }

  BidiInfoIndex CreateInfo( const Character* const paragraph,
                            Length numberOfCharacters )
  {
    // Reserve memory for the paragraph's bidirectional info.
    BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();

    bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
    bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );

    // Retrieve the type of each character..
    fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );

    // Retrieve the paragraph's direction.
    bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( paragraph, numberOfCharacters );

    // Retrieve the embedding levels.
    fribidi_get_par_embedding_levels( paragraph, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );

    // Store the bidirectional info and return the index.
    BidiInfoIndex index = 0u;
    if( 0u != mFreeIndices.Count() )
    {
      Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;

      index = *it;

      mFreeIndices.Remove( it );

      *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
    }
    else
    {
      index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );

      mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
    }

    return index;
  }

  void DestroyInfo( BidiInfoIndex bidiInfoIndex )
  {
    if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
    {
      return;
    }

    // Retrieve the paragraph's bidirectional info.
    Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
    BidirectionalInfo* bidirectionalInfo = *it;

    if( NULL != bidirectionalInfo )
    {
      // Free resources and destroy the container.
      free( bidirectionalInfo->embeddedLevels );
      free( bidirectionalInfo->characterTypes );
      delete bidirectionalInfo;

      *it = NULL;
    }

    // Add the index to the free indices vector.
    mFreeIndices.PushBack( bidiInfoIndex );
  }

  void Reorder( BidiInfoIndex bidiInfoIndex,
                CharacterIndex firstCharacterIndex,
                Length numberOfCharacters,
                CharacterIndex* visualToLogicalMap )
  {
    const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;

    // Retrieve the paragraph's bidirectional info.
    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );

    // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
    {
      visualToLogicalMap[ index ] = index;
    }

    // Copy embedded levels as fribidi_reorder_line() may change them.
    const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
    FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
    memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );

    // Reorder the line.
    fribidi_reorder_line( flags,
                          bidirectionalInfo->characterTypes + firstCharacterIndex,
                          numberOfCharacters,
                          0u,
                          bidirectionalInfo->paragraphDirection,
                          embeddedLevels,
                          NULL,
                          reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );

    // Free resources.
    free( embeddedLevels );
  }

  Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
  Vector<BidiInfoIndex>      mFreeIndices;                ///< Stores indices of free positions in the bidirectional info vector.
};

BidirectionalSupport::BidirectionalSupport()
: mPlugin( NULL )
{
}

BidirectionalSupport::~BidirectionalSupport()
{
  delete mPlugin;
}

TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
{
  TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;

  SingletonService service( SingletonService::Get() );
  if( service )
  {
    // Check whether the singleton is already created
    BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
    if(handle)
    {
      // If so, downcast the handle
      BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
    }
    else // create and register the object
    {
      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
      service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
    }
  }

  return bidirectionalSupportHandle;
}

BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
                                                Length numberOfCharacters )
{
  CreatePlugin();

  return mPlugin->CreateInfo( paragraph,
                              numberOfCharacters );
}

void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
{
  CreatePlugin();

  mPlugin->DestroyInfo( bidiInfoIndex );
}

void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
                                    CharacterIndex firstCharacterIndex,
                                    Length numberOfCharacters,
                                    CharacterIndex* visualToLogicalMap )
{
  CreatePlugin();

  mPlugin->Reorder( bidiInfoIndex,
                    firstCharacterIndex,
                    numberOfCharacters,
                    visualToLogicalMap );
}

void BidirectionalSupport::CreatePlugin()
{
  if( !mPlugin )
  {
    mPlugin = new Plugin();
  }
}

} // namespace Internal

} // namespace TextAbstraction

} // namespace Dali
<commit_msg>Fix for bidirectional support.   The text unicodes were pased to the fribidi_get_par_embedding_levels()   and the fribidi_get_par_direction() instead of the character's types.<commit_after>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS  HEADER
#include "bidirectional-support-impl.h"

// INTERNAL INCLUDES
#include <singleton-service-impl.h>

// EXTERNAL INCLUDES
#include <memory.h>
#include <fribidi/fribidi.h>

namespace Dali
{

namespace TextAbstraction
{

namespace Internal
{

struct BidirectionalSupport::Plugin
{
  /**
   * Stores bidirectional info per paragraph.
   */
  struct BidirectionalInfo
  {
    FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
    FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
    FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
  };

  Plugin()
  : mParagraphBidirectionalInfo(),
    mFreeIndices()
  {}

  ~Plugin()
  {
    // free all resources.
    for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
           endIt = mParagraphBidirectionalInfo.End();
         it != endIt;
         ++it )
    {
      BidirectionalInfo* info = *it;

      free( info->embeddedLevels );
      free( info->characterTypes );
      delete info;
    }
  }

  BidiInfoIndex CreateInfo( const Character* const paragraph,
                            Length numberOfCharacters )
  {
    // Reserve memory for the paragraph's bidirectional info.
    BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();

    bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
    bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );

    // Retrieve the type of each character..
    fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );

    // Retrieve the paragraph's direction.
    bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters );

    // Retrieve the embedding levels.
    fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );

    // Store the bidirectional info and return the index.
    BidiInfoIndex index = 0u;
    if( 0u != mFreeIndices.Count() )
    {
      Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;

      index = *it;

      mFreeIndices.Remove( it );

      *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
    }
    else
    {
      index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );

      mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
    }

    return index;
  }

  void DestroyInfo( BidiInfoIndex bidiInfoIndex )
  {
    if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
    {
      return;
    }

    // Retrieve the paragraph's bidirectional info.
    Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
    BidirectionalInfo* bidirectionalInfo = *it;

    if( NULL != bidirectionalInfo )
    {
      // Free resources and destroy the container.
      free( bidirectionalInfo->embeddedLevels );
      free( bidirectionalInfo->characterTypes );
      delete bidirectionalInfo;

      *it = NULL;
    }

    // Add the index to the free indices vector.
    mFreeIndices.PushBack( bidiInfoIndex );
  }

  void Reorder( BidiInfoIndex bidiInfoIndex,
                CharacterIndex firstCharacterIndex,
                Length numberOfCharacters,
                CharacterIndex* visualToLogicalMap )
  {
    const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;

    // Retrieve the paragraph's bidirectional info.
    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );

    // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
    {
      visualToLogicalMap[ index ] = index;
    }

    // Copy embedded levels as fribidi_reorder_line() may change them.
    const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
    FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
    memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );

    // Reorder the line.
    fribidi_reorder_line( flags,
                          bidirectionalInfo->characterTypes + firstCharacterIndex,
                          numberOfCharacters,
                          0u,
                          bidirectionalInfo->paragraphDirection,
                          embeddedLevels,
                          NULL,
                          reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );

    // Free resources.
    free( embeddedLevels );
  }

  Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
  Vector<BidiInfoIndex>      mFreeIndices;                ///< Stores indices of free positions in the bidirectional info vector.
};

BidirectionalSupport::BidirectionalSupport()
: mPlugin( NULL )
{
}

BidirectionalSupport::~BidirectionalSupport()
{
  delete mPlugin;
}

TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
{
  TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;

  SingletonService service( SingletonService::Get() );
  if( service )
  {
    // Check whether the singleton is already created
    BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
    if(handle)
    {
      // If so, downcast the handle
      BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
    }
    else // create and register the object
    {
      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
      service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
    }
  }

  return bidirectionalSupportHandle;
}

BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
                                                Length numberOfCharacters )
{
  CreatePlugin();

  return mPlugin->CreateInfo( paragraph,
                              numberOfCharacters );
}

void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
{
  CreatePlugin();

  mPlugin->DestroyInfo( bidiInfoIndex );
}

void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
                                    CharacterIndex firstCharacterIndex,
                                    Length numberOfCharacters,
                                    CharacterIndex* visualToLogicalMap )
{
  CreatePlugin();

  mPlugin->Reorder( bidiInfoIndex,
                    firstCharacterIndex,
                    numberOfCharacters,
                    visualToLogicalMap );
}

void BidirectionalSupport::CreatePlugin()
{
  if( !mPlugin )
  {
    mPlugin = new Plugin();
  }
}

} // namespace Internal

} // namespace TextAbstraction

} // namespace Dali
<|endoftext|>