<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "osl/file.hxx"
#include "osl/mutex.hxx"

#include <rtl/bootstrap.hxx>
#include <rtl/ustring.hxx>
#include <rtl/logfile.hxx>
#include "cppuhelper/compbase3.hxx"

#include "vcl/wrkwin.hxx"
#include "vcl/timer.hxx"

#include <unotools/configmgr.hxx>

#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include "com/sun/star/deployment/XPackage.hpp"
#include "com/sun/star/deployment/ExtensionManager.hpp"
#include <com/sun/star/task/XJob.hpp>
#include <com/sun/star/task/XJobExecutor.hpp>
#include <com/sun/star/task/XInteractionApprove.hpp>
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>

#include "app.hxx"

#include "../deployment/inc/dp_misc.h"

using rtl::OUString;
using namespace desktop;
using namespace com::sun::star;

#define UNISTRING(s) OUString(RTL_CONSTASCII_USTRINGPARAM(s))

namespace
{
//For use with XExtensionManager.synchronize
class SilentCommandEnv
    : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
                                      task::XInteractionHandler,
                                      ucb::XProgressHandler >
{
    Desktop    *mpDesktop;
    sal_Int32   mnLevel;
    sal_Int32   mnProgress;

public:
             SilentCommandEnv( Desktop* pDesktop );
    virtual ~SilentCommandEnv();

    // XCommandEnvironment
    virtual uno::Reference<task::XInteractionHandler > SAL_CALL
    getInteractionHandler() throw (uno::RuntimeException);
    virtual uno::Reference<ucb::XProgressHandler >
    SAL_CALL getProgressHandler() throw (uno::RuntimeException);

    // XInteractionHandler
    virtual void SAL_CALL handle(
        uno::Reference<task::XInteractionRequest > const & xRequest )
        throw (uno::RuntimeException);

    // XProgressHandler
    virtual void SAL_CALL push( uno::Any const & Status )
        throw (uno::RuntimeException);
    virtual void SAL_CALL update( uno::Any const & Status )
        throw (uno::RuntimeException);
    virtual void SAL_CALL pop() throw (uno::RuntimeException);
};

//-----------------------------------------------------------------------------
SilentCommandEnv::SilentCommandEnv( Desktop* pDesktop )
{
    mpDesktop = pDesktop;
    mnLevel = 0;
    mnProgress = 25;
}

//-----------------------------------------------------------------------------
SilentCommandEnv::~SilentCommandEnv()
{
    mpDesktop->SetSplashScreenText( OUString() );
}

//-----------------------------------------------------------------------------
Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
    throw (uno::RuntimeException)
{
    return this;
}

//-----------------------------------------------------------------------------
Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
    throw (uno::RuntimeException)
{
    return this;
}

//-----------------------------------------------------------------------------
// XInteractionHandler
void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
    throw (uno::RuntimeException)
{
    uno::Any request( xRequest->getRequest() );

    // We approve everything here
    uno::Sequence< Reference< task::XInteractionContinuation > > conts(
        xRequest->getContinuations() );
    Reference< task::XInteractionContinuation > const * pConts =
        conts.getConstArray();
    sal_Int32 len = conts.getLength();
    for ( sal_Int32 pos = 0; pos < len; ++pos )
    {

        Reference< task::XInteractionApprove > xInteractionApprove(
            pConts[ pos ], uno::UNO_QUERY );
        if (xInteractionApprove.is()) {
            xInteractionApprove->select();
        }
    }
}

//-----------------------------------------------------------------------------
// XProgressHandler
void SilentCommandEnv::push( uno::Any const & rStatus )
    throw (uno::RuntimeException)
{
    OUString sText;
    mnLevel += 1;

    if ( rStatus.hasValue() && ( rStatus >>= sText) )
    {
        if ( mnLevel <= 2 )
            mpDesktop->SetSplashScreenText( sText );
        else
            mpDesktop->SetSplashScreenProgress( ++mnProgress );
    }
}

//-----------------------------------------------------------------------------
void SilentCommandEnv::update( uno::Any const & rStatus )
    throw (uno::RuntimeException)
{
    OUString sText;
    if ( rStatus.hasValue() && ( rStatus >>= sText) )
    {
        mpDesktop->SetSplashScreenText( sText );
    }
}

//-----------------------------------------------------------------------------
void SilentCommandEnv::pop() throw (uno::RuntimeException)
{
    mnLevel -= 1;
}

} // end namespace

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static const OUString sConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
static const OUString sAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );
//------------------------------------------------------------------------------
static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > &xContext )
{
    rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.UpdateRequiredDialog");
    uno::Reference< uno::XInterface > xService;
    sal_Int16 nRet = 0;

    uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
    if( !xServiceManager.is() )
        throw uno::RuntimeException(
            UNISTRING( "impl_showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () );

    xService = xServiceManager->createInstanceWithContext( sServiceName, xContext );
    uno::Reference< ui::dialogs::XExecutableDialog > xExecuteable( xService, uno::UNO_QUERY );
    if ( xExecuteable.is() )
        nRet = xExecuteable->execute();

    return nRet;
}

//------------------------------------------------------------------------------
// Check dependencies of all packages
//------------------------------------------------------------------------------
static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
{
    uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
    uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );

    if ( !xExtensionManager.is() )
    {
        OSL_ENSURE( 0, "Could not get the Extension Manager!" );
        return true;
    }

    try {
        xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
                                                            uno::Reference< ucb::XCommandEnvironment >() );
    }
    catch ( deployment::DeploymentException & ) { return true; }
    catch ( ucb::CommandFailedException & ) { return true; }
    catch ( ucb::CommandAbortedException & ) { return true; }
    catch ( lang::IllegalArgumentException & e ) {
        throw uno::RuntimeException( e.Message, e.Context );
    }

    sal_Int32 nMax = 2;
#ifdef DEBUG
    nMax = 3;
#endif

    for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
    {
        uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];

        for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
        {
            uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
            if ( xPackage.is() )
            {
                bool bRegistered = false;
                try {
                    beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
                                                                                uno::Reference< ucb::XCommandEnvironment >() ) );
                    if ( option.IsPresent )
                    {
                        ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
                        if ( reg.IsAmbiguous )
                            bRegistered = false;
                        else
                            bRegistered = reg.Value ? true : false;
                    }
                    else
                        bRegistered = false;
                }
                catch ( uno::RuntimeException & ) { throw; }
                catch ( uno::Exception & exc) {
                    (void) exc;
                    OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
                }

                if ( bRegistered )
                {
                    bool bDependenciesValid = false;
                    try {
                        bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
                    }
                    catch ( deployment::DeploymentException & ) {}
                    if ( ! bDependenciesValid )
                    {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}

//------------------------------------------------------------------------------
// resets the 'check needed' flag (needed, if aborted)
//------------------------------------------------------------------------------
static void impl_setNeedsCompatCheck()
{
    try {
        Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
        // get configuration provider
        Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
                xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);

        Sequence< Any > theArgs(1);
        beans::NamedValue v( OUString::createFromAscii("NodePath"),
                      makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
        theArgs[0] <<= v;
        Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
            theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );

        Any value = makeAny( OUString::createFromAscii("never") );

        pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), value );
        Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
    }
    catch (const Exception&) {}
}

//------------------------------------------------------------------------------
static bool impl_check()
{
    uno::Reference< uno::XComponentContext > xContext = comphelper_getProcessComponentContext();

    bool bDependenciesValid = impl_checkDependencies( xContext );

    short nRet = 0;

    if ( !bDependenciesValid )
        nRet = impl_showExtensionDialog( xContext );

    if ( nRet == -1 )
    {
        impl_setNeedsCompatCheck();
        return true;
    }
    else
        return false;
}

//------------------------------------------------------------------------------
// to check if we need checking the dependencies of the extensions again, we compare
// the build id of the office with the one of the last check
//------------------------------------------------------------------------------
static bool impl_needsCompatCheck()
{
    bool bNeedsCheck = false;
    rtl::OUString aLastCheckBuildID;
    rtl::OUString aCurrentBuildID( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
    rtl::Bootstrap::expandMacros( aCurrentBuildID );

    try {
        Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
        // get configuration provider
        Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
                xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);

        Sequence< Any > theArgs(1);
        beans::NamedValue v( OUString::createFromAscii("NodePath"),
                      makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
        theArgs[0] <<= v;
        Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
            theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );

        Any result = pset->getPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID") );

        result >>= aLastCheckBuildID;
        if ( aLastCheckBuildID != aCurrentBuildID )
        {
            bNeedsCheck = true;
            result <<= aCurrentBuildID;
            pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), result );
            Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
        }
#ifdef DEBUG
        bNeedsCheck = true;
#endif
    }
    catch (const Exception&) {}

    return bNeedsCheck;
}

//------------------------------------------------------------------------------
// Do we need to check the dependencies of the extensions?
// When there are unresolved issues, we can't continue with startup
sal_Bool Desktop::CheckExtensionDependencies()
{
    sal_Bool bAbort = false;

    if ( impl_needsCompatCheck() )
        bAbort = impl_check();

    return bAbort;
}

void Desktop::SynchronizeExtensionRepositories()
{
    RTL_LOGFILE_CONTEXT(aLog,"desktop (jl) ::Desktop::SynchronizeExtensionRepositories");
    OUString sDisable;
    ::rtl::Bootstrap::get( UNISTRING( "DISABLE_SYNC_EXTENSIONS" ), sDisable, OUString() );
    if (sDisable.getLength() > 0)
        return;

    dp_misc::syncRepositories( new SilentCommandEnv( this ) );
}
<commit_msg>jl152 #i77196# dp_misc::sycnRepositories cannot be switched off with bootstrap variable, because it is not necessary fro the perfomance test<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "osl/file.hxx"
#include "osl/mutex.hxx"

#include <rtl/bootstrap.hxx>
#include <rtl/ustring.hxx>
#include <rtl/logfile.hxx>
#include "cppuhelper/compbase3.hxx"

#include "vcl/wrkwin.hxx"
#include "vcl/timer.hxx"

#include <unotools/configmgr.hxx>

#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include "com/sun/star/deployment/XPackage.hpp"
#include "com/sun/star/deployment/ExtensionManager.hpp"
#include <com/sun/star/task/XJob.hpp>
#include <com/sun/star/task/XJobExecutor.hpp>
#include <com/sun/star/task/XInteractionApprove.hpp>
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>

#include "app.hxx"

#include "../deployment/inc/dp_misc.h"

using rtl::OUString;
using namespace desktop;
using namespace com::sun::star;

#define UNISTRING(s) OUString(RTL_CONSTASCII_USTRINGPARAM(s))

namespace
{
//For use with XExtensionManager.synchronize
class SilentCommandEnv
    : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
                                      task::XInteractionHandler,
                                      ucb::XProgressHandler >
{
    Desktop    *mpDesktop;
    sal_Int32   mnLevel;
    sal_Int32   mnProgress;

public:
             SilentCommandEnv( Desktop* pDesktop );
    virtual ~SilentCommandEnv();

    // XCommandEnvironment
    virtual uno::Reference<task::XInteractionHandler > SAL_CALL
    getInteractionHandler() throw (uno::RuntimeException);
    virtual uno::Reference<ucb::XProgressHandler >
    SAL_CALL getProgressHandler() throw (uno::RuntimeException);

    // XInteractionHandler
    virtual void SAL_CALL handle(
        uno::Reference<task::XInteractionRequest > const & xRequest )
        throw (uno::RuntimeException);

    // XProgressHandler
    virtual void SAL_CALL push( uno::Any const & Status )
        throw (uno::RuntimeException);
    virtual void SAL_CALL update( uno::Any const & Status )
        throw (uno::RuntimeException);
    virtual void SAL_CALL pop() throw (uno::RuntimeException);
};

//-----------------------------------------------------------------------------
SilentCommandEnv::SilentCommandEnv( Desktop* pDesktop )
{
    mpDesktop = pDesktop;
    mnLevel = 0;
    mnProgress = 25;
}

//-----------------------------------------------------------------------------
SilentCommandEnv::~SilentCommandEnv()
{
    mpDesktop->SetSplashScreenText( OUString() );
}

//-----------------------------------------------------------------------------
Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
    throw (uno::RuntimeException)
{
    return this;
}

//-----------------------------------------------------------------------------
Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
    throw (uno::RuntimeException)
{
    return this;
}

//-----------------------------------------------------------------------------
// XInteractionHandler
void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
    throw (uno::RuntimeException)
{
    uno::Any request( xRequest->getRequest() );

    // We approve everything here
    uno::Sequence< Reference< task::XInteractionContinuation > > conts(
        xRequest->getContinuations() );
    Reference< task::XInteractionContinuation > const * pConts =
        conts.getConstArray();
    sal_Int32 len = conts.getLength();
    for ( sal_Int32 pos = 0; pos < len; ++pos )
    {

        Reference< task::XInteractionApprove > xInteractionApprove(
            pConts[ pos ], uno::UNO_QUERY );
        if (xInteractionApprove.is()) {
            xInteractionApprove->select();
        }
    }
}

//-----------------------------------------------------------------------------
// XProgressHandler
void SilentCommandEnv::push( uno::Any const & rStatus )
    throw (uno::RuntimeException)
{
    OUString sText;
    mnLevel += 1;

    if ( rStatus.hasValue() && ( rStatus >>= sText) )
    {
        if ( mnLevel <= 2 )
            mpDesktop->SetSplashScreenText( sText );
        else
            mpDesktop->SetSplashScreenProgress( ++mnProgress );
    }
}

//-----------------------------------------------------------------------------
void SilentCommandEnv::update( uno::Any const & rStatus )
    throw (uno::RuntimeException)
{
    OUString sText;
    if ( rStatus.hasValue() && ( rStatus >>= sText) )
    {
        mpDesktop->SetSplashScreenText( sText );
    }
}

//-----------------------------------------------------------------------------
void SilentCommandEnv::pop() throw (uno::RuntimeException)
{
    mnLevel -= 1;
}

} // end namespace

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static const OUString sConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
static const OUString sAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );
//------------------------------------------------------------------------------
static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > &xContext )
{
    rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.UpdateRequiredDialog");
    uno::Reference< uno::XInterface > xService;
    sal_Int16 nRet = 0;

    uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
    if( !xServiceManager.is() )
        throw uno::RuntimeException(
            UNISTRING( "impl_showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () );

    xService = xServiceManager->createInstanceWithContext( sServiceName, xContext );
    uno::Reference< ui::dialogs::XExecutableDialog > xExecuteable( xService, uno::UNO_QUERY );
    if ( xExecuteable.is() )
        nRet = xExecuteable->execute();

    return nRet;
}

//------------------------------------------------------------------------------
// Check dependencies of all packages
//------------------------------------------------------------------------------
static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
{
    uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
    uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );

    if ( !xExtensionManager.is() )
    {
        OSL_ENSURE( 0, "Could not get the Extension Manager!" );
        return true;
    }

    try {
        xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
                                                            uno::Reference< ucb::XCommandEnvironment >() );
    }
    catch ( deployment::DeploymentException & ) { return true; }
    catch ( ucb::CommandFailedException & ) { return true; }
    catch ( ucb::CommandAbortedException & ) { return true; }
    catch ( lang::IllegalArgumentException & e ) {
        throw uno::RuntimeException( e.Message, e.Context );
    }

    sal_Int32 nMax = 2;
#ifdef DEBUG
    nMax = 3;
#endif

    for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
    {
        uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];

        for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
        {
            uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
            if ( xPackage.is() )
            {
                bool bRegistered = false;
                try {
                    beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
                                                                                uno::Reference< ucb::XCommandEnvironment >() ) );
                    if ( option.IsPresent )
                    {
                        ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
                        if ( reg.IsAmbiguous )
                            bRegistered = false;
                        else
                            bRegistered = reg.Value ? true : false;
                    }
                    else
                        bRegistered = false;
                }
                catch ( uno::RuntimeException & ) { throw; }
                catch ( uno::Exception & exc) {
                    (void) exc;
                    OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
                }

                if ( bRegistered )
                {
                    bool bDependenciesValid = false;
                    try {
                        bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
                    }
                    catch ( deployment::DeploymentException & ) {}
                    if ( ! bDependenciesValid )
                    {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}

//------------------------------------------------------------------------------
// resets the 'check needed' flag (needed, if aborted)
//------------------------------------------------------------------------------
static void impl_setNeedsCompatCheck()
{
    try {
        Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
        // get configuration provider
        Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
                xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);

        Sequence< Any > theArgs(1);
        beans::NamedValue v( OUString::createFromAscii("NodePath"),
                      makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
        theArgs[0] <<= v;
        Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
            theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );

        Any value = makeAny( OUString::createFromAscii("never") );

        pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), value );
        Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
    }
    catch (const Exception&) {}
}

//------------------------------------------------------------------------------
static bool impl_check()
{
    uno::Reference< uno::XComponentContext > xContext = comphelper_getProcessComponentContext();

    bool bDependenciesValid = impl_checkDependencies( xContext );

    short nRet = 0;

    if ( !bDependenciesValid )
        nRet = impl_showExtensionDialog( xContext );

    if ( nRet == -1 )
    {
        impl_setNeedsCompatCheck();
        return true;
    }
    else
        return false;
}

//------------------------------------------------------------------------------
// to check if we need checking the dependencies of the extensions again, we compare
// the build id of the office with the one of the last check
//------------------------------------------------------------------------------
static bool impl_needsCompatCheck()
{
    bool bNeedsCheck = false;
    rtl::OUString aLastCheckBuildID;
    rtl::OUString aCurrentBuildID( UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" ) );
    rtl::Bootstrap::expandMacros( aCurrentBuildID );

    try {
        Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
        // get configuration provider
        Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >(
                xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW);

        Sequence< Any > theArgs(1);
        beans::NamedValue v( OUString::createFromAscii("NodePath"),
                      makeAny( OUString::createFromAscii("org.openoffice.Setup/Office") ) );
        theArgs[0] <<= v;
        Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
            theConfigProvider->createInstanceWithArguments( sAccessSrvc, theArgs ), UNO_QUERY_THROW );

        Any result = pset->getPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID") );

        result >>= aLastCheckBuildID;
        if ( aLastCheckBuildID != aCurrentBuildID )
        {
            bNeedsCheck = true;
            result <<= aCurrentBuildID;
            pset->setPropertyValue( OUString::createFromAscii("LastCompatibilityCheckID"), result );
            Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
        }
#ifdef DEBUG
        bNeedsCheck = true;
#endif
    }
    catch (const Exception&) {}

    return bNeedsCheck;
}

//------------------------------------------------------------------------------
// Do we need to check the dependencies of the extensions?
// When there are unresolved issues, we can't continue with startup
sal_Bool Desktop::CheckExtensionDependencies()
{
    sal_Bool bAbort = false;

    if ( impl_needsCompatCheck() )
        bAbort = impl_check();

    return bAbort;
}

void Desktop::SynchronizeExtensionRepositories()
{
    RTL_LOGFILE_CONTEXT(aLog,"desktop (jl) ::Desktop::SynchronizeExtensionRepositories");
    dp_misc::syncRepositories( new SilentCommandEnv( this ) );
}
<|endoftext|>


<commit_before>/*
 * SessionRCompletions.cpp
 *
 * Copyright (C) 2014 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 "SessionRCompletions.hpp"

#include <core/Exec.hpp>

#include <boost/range/adaptors.hpp>

#include <r/RSexp.hpp>
#include <r/RInternal.hpp>
#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/RRoutines.hpp>
#include <r/ROptions.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RSessionUtils.hpp>

#include <core/system/FileScanner.hpp>

#include <core/r_util/RProjectFile.hpp>
#include <core/r_util/RSourceIndex.hpp>
#include <core/r_util/RPackageInfo.hpp>
#include <core/r_util/RSourceIndex.hpp>

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

#include "SessionCodeSearch.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace r_completions {

namespace {

char ends(char begins) {
   switch(begins) {
   case '(': return ')';
   case '[': return ']';
   case '{': return '}';
   }
   return '\0';
}

bool isBinaryOp(char character)
{
   return character == '~' ||
         character == '!' ||
         character == '@' ||
         character == '$' ||
         character == '%' ||
         character == '^' ||
         character == '&' ||
         character == '*' ||
         character == '-' ||
         character == '+' ||
         character == '*' ||
         character == '/' ||
         character == '=' ||
         character == '|' ||
         character == '<' ||
         character == '>' ||
         character == '?';

}

} // end anonymous namespace

std::string finishExpression(const std::string& expression)
{
   std::string result = expression;

   // If the last character of the expression is a binary op, then we
   // place a '.' after it
   int n = expression.length();
   if (isBinaryOp(expression[n - 1]))
      result.append(".");

   std::vector<char> terminators;

   char top = '\0';
   terminators.push_back(top);

   bool in_string = false;
   bool in_escape = false;

   for (int i = 0; i < n; i++) {

      char cur = expression[i];

      if (in_string) {

         if (in_escape) {
            in_escape = false;
            continue;
         }

         if (cur == '\\') {
            in_escape = true;
            continue;
         }

         if (cur != top) {
            continue;
         }

         in_string = false;
         terminators.pop_back();
         top = terminators.back();
         continue;

      }

      if (cur == top) {
         terminators.pop_back();
         top = terminators.back();
      } else if (cur == '(' || cur == '{' || cur == '[') {
         char end = ends(cur);
         top = end;
         terminators.push_back(top);
      } else if (cur == '"' || cur == '`' || cur == '\'') {
         top = cur;
         in_string = true;
         terminators.push_back(top);
      }

   }

   // append to the output
   for (std::size_t i = terminators.size() - 1; i > 0; --i)
      result.push_back(terminators[i]);

   return result;
}

namespace {

SEXP rs_finishExpression(SEXP stringSEXP)
{
   r::sexp::Protect rProtect;
   int n = r::sexp::length(stringSEXP);

   std::vector<std::string> output;
   output.reserve(n);
   for (int i = 0; i < n; ++i)
      output.push_back(finishExpression(CHAR(STRING_ELT(stringSEXP, i))));

   return r::sexp::create(output, &rProtect);
}

struct SourceIndexCompletions {
   std::vector<std::string> completions;
   std::vector<bool> isFunction;
   bool moreAvailable;
};

SourceIndexCompletions getSourceIndexCompletions(const std::string& token)
{
   // get functions from the source index
   std::vector<core::r_util::RSourceItem> items;
   bool moreAvailable = false;

   // TODO: wire up 'moreAvailable'
   modules::code_search::searchSource(token,
                                      1E3,
                                      true,
                                      &items,
                                      &moreAvailable);

   SourceIndexCompletions srcCompletions;
   BOOST_FOREACH(const core::r_util::RSourceItem& item, items)
   {
      if (item.braceLevel() == 0)
      {
         srcCompletions.completions.push_back(item.name());
         srcCompletions.isFunction.push_back(item.isFunction() || item.isMethod());
      }
   }

   srcCompletions.moreAvailable = moreAvailable;
   return srcCompletions;
}

SEXP rs_getSourceIndexCompletions(SEXP tokenSEXP)
{
   r::sexp::Protect protect;
   std::string token = r::sexp::asString(tokenSEXP);
   SourceIndexCompletions srcCompletions = getSourceIndexCompletions(token);

   std::vector<std::string> names;
   names.push_back("completions");
   names.push_back("isFunction");
   names.push_back("moreAvailable");

   SEXP resultSEXP = r::sexp::createList(names, &protect);
   r::sexp::setNamedListElement(resultSEXP, "completions", srcCompletions.completions);
   r::sexp::setNamedListElement(resultSEXP, "isFunction", srcCompletions.isFunction);
   r::sexp::setNamedListElement(resultSEXP, "moreAvailable", srcCompletions.moreAvailable);

   return resultSEXP;
}

bool subsequenceFilter(const FileInfo& fileInfo,
                       const std::string& pattern,
                       int parentPathLength,
                       int maxCount,
                       std::vector<std::string>* pPaths,
                       int* pCount,
                       bool* pMoreAvailable)
{
   if (*pCount >= maxCount)
   {
      *pMoreAvailable = true;
      return false;
   }

   bool isSubsequence = string_utils::isSubsequence(
            fileInfo.absolutePath().substr(parentPathLength + 2),
            pattern,
            true);

   if (isSubsequence)
   {
      ++*pCount;
      pPaths->push_back(fileInfo.absolutePath());
   }

   // Always add subdirectories
   if (fileInfo.isDirectory())
   {
      return true;
   }

   return false;
}

SEXP rs_scanFiles(SEXP pathSEXP,
                  SEXP patternSEXP,
                  SEXP maxCountSEXP)
{
   std::string path = r::sexp::asString(pathSEXP);
   std::string pattern = r::sexp::asString(patternSEXP);
   int maxCount = r::sexp::asInteger(maxCountSEXP);

   FilePath filePath(path);
   FileInfo fileInfo(filePath);
   tree<FileInfo> tree;

   core::system::FileScannerOptions options;
   options.recursive = true;
   options.yield = true;

   // Use a subsequence filter, and bail after too many files
   std::vector<std::string> paths;

   int count = 0;
   bool moreAvailable = false;
   options.filter = boost::bind(subsequenceFilter,
                                _1,
                                pattern,
                                path.length(),
                                maxCount,
                                &paths,
                                &count,
                                &moreAvailable);

   Error error = scanFiles(fileInfo, options, &tree);
   if (error)
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder builder(&protect);

   builder.add("paths", paths);
   builder.add("more_available", moreAvailable);

   return r::sexp::create(builder, &protect);
}

SEXP rs_isSubsequence(SEXP stringsSEXP, SEXP querySEXP)
{
   std::vector<std::string> strings;
   if (!r::sexp::fillVectorString(stringsSEXP, &strings))
      return R_NilValue;

   std::string query = r::sexp::asString(querySEXP);

   std::vector<bool> result(strings.size());

   std::transform(strings.begin(),
                  strings.end(),
                  result.begin(),
                  boost::bind(
                     string_utils::isSubsequence,
                     _1,
                     query));

   r::sexp::Protect protect;
   return r::sexp::create(result, &protect);

}

SEXP rs_getActiveFrame(SEXP depthSEXP)
{
   int depth = r::sexp::asInteger(depthSEXP);
   RCNTXT* context = r::getGlobalContext();
   for (int i = 0; i < depth; ++i)
   {
      context = context->nextcontext;
      if (context == NULL)
         return R_NilValue;
   }
   return context->cloenv;
}

SEXP rs_getNAMESPACEImportedSymbols(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   using namespace core::r_util;
   std::vector<std::string> pkgs;

   BOOST_FOREACH(const std::string& pkg, RSourceIndex::getImportedPackages())
   {
      pkgs.push_back(pkg);
   }

   BOOST_FOREACH(const std::string& pkg,
                 RSourceIndex::getImportFromDirectives() | boost::adaptors::map_keys)
   {
      pkgs.push_back(pkg);
   }

   using namespace r::sexp;
   Protect protect;
   r::sexp::ListBuilder builder(&protect);

   BOOST_FOREACH(const std::string& pkg, pkgs)
   {
      const AsyncLibraryCompletions& completions = RSourceIndex::getCompletions(pkg);
      r::sexp::ListBuilder child(&protect);

      // If the inferred package is listed _only_ in the NAMESPACE 'importFrom',
      // then we want to selectively return symbols.
      if ((index && index->getInferredPackages().count(pkg) == 0) &&
          RSourceIndex::getImportedPackages().count(pkg) == 0 &&
          RSourceIndex::getImportFromDirectives().count(pkg) != 0)
      {
         std::vector<std::string> exports;
         std::vector<int> types;

         std::set<std::string>& directives =
               RSourceIndex::getImportFromDirectives()[pkg];

         BOOST_FOREACH(const std::string& item, directives)
         {
            std::vector<std::string>::const_iterator it =
                  std::find(completions.exports.begin(),
                            completions.exports.end(),
                            item);

            std::size_t index = it - completions.exports.begin();

            exports.push_back(completions.exports[index]);
            types.push_back(completions.types[index]);
         }

         child.add("exports", exports);
         child.add("types", types);

      }
      else
      {
         child.add("exports", completions.exports);
         child.add("types", completions.types);
      }

      builder.add(pkg, child);
   }

   return r::sexp::create(builder, &protect);
}

SEXP rs_getInferredCompletions(SEXP packagesSEXP)
{
   using namespace rstudio::core::r_util;

   std::vector<std::string> packages;
   if (!r::sexp::fillVectorString(packagesSEXP, &packages))
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder parent(&protect);

   for (std::vector<std::string>::const_iterator it = packages.begin();
        it != packages.end();
        ++it)
   {
      DEBUG("Adding entry for '" << *it << "'");
      AsyncLibraryCompletions completions = RSourceIndex::getCompletions(*it);

      r::sexp::ListBuilder builder(&protect);
      builder.add("exports", completions.exports);
      builder.add("types", completions.types);
      builder.add("functions", completions.functions);
      parent.add(*it, builder);
   }

   return r::sexp::create(parent, &protect);
}

SEXP rs_listInferredPackages(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   // NOTE: can occur when user edits file not in source index
   if (index == NULL)
      return R_NilValue;

   std::set<std::string> pkgs = index->getInferredPackages();
   pkgs.insert(index->getImportedPackages().begin(),
               index->getImportedPackages().end());

   r::sexp::Protect protect;
   return r::sexp::create(pkgs, &protect);

}

} // end anonymous namespace

Error initialize() {

   RS_REGISTER_CALL_METHOD(rs_finishExpression, 1);
   RS_REGISTER_CALL_METHOD(rs_getSourceIndexCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_scanFiles, 4);
   RS_REGISTER_CALL_METHOD(rs_isSubsequence, 2);
   RS_REGISTER_CALL_METHOD(rs_getActiveFrame, 1);
   RS_REGISTER_CALL_METHOD(rs_listInferredPackages, 1);
   RS_REGISTER_CALL_METHOD(rs_getInferredCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_getNAMESPACEImportedSymbols, 1);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock;
   initBlock.addFunctions()
         (bind(sourceModuleRFile, "SessionRCompletions.R"));
   return initBlock.execute();
}

} // namespace r_completions
} // namespace modules
} // namespace session
} // namespace rstudio
<commit_msg>protect against use of un-initialized structures<commit_after>/*
 * SessionRCompletions.cpp
 *
 * Copyright (C) 2014 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 "SessionRCompletions.hpp"

#include <core/Exec.hpp>

#include <boost/range/adaptors.hpp>

#include <r/RSexp.hpp>
#include <r/RInternal.hpp>
#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/RRoutines.hpp>
#include <r/ROptions.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RSessionUtils.hpp>

#include <core/system/FileScanner.hpp>

#include <core/r_util/RProjectFile.hpp>
#include <core/r_util/RSourceIndex.hpp>
#include <core/r_util/RPackageInfo.hpp>
#include <core/r_util/RSourceIndex.hpp>

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

#include "SessionCodeSearch.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace r_completions {

namespace {

char ends(char begins) {
   switch(begins) {
   case '(': return ')';
   case '[': return ']';
   case '{': return '}';
   }
   return '\0';
}

bool isBinaryOp(char character)
{
   return character == '~' ||
         character == '!' ||
         character == '@' ||
         character == '$' ||
         character == '%' ||
         character == '^' ||
         character == '&' ||
         character == '*' ||
         character == '-' ||
         character == '+' ||
         character == '*' ||
         character == '/' ||
         character == '=' ||
         character == '|' ||
         character == '<' ||
         character == '>' ||
         character == '?';

}

} // end anonymous namespace

std::string finishExpression(const std::string& expression)
{
   std::string result = expression;

   // If the last character of the expression is a binary op, then we
   // place a '.' after it
   int n = expression.length();
   if (isBinaryOp(expression[n - 1]))
      result.append(".");

   std::vector<char> terminators;

   char top = '\0';
   terminators.push_back(top);

   bool in_string = false;
   bool in_escape = false;

   for (int i = 0; i < n; i++) {

      char cur = expression[i];

      if (in_string) {

         if (in_escape) {
            in_escape = false;
            continue;
         }

         if (cur == '\\') {
            in_escape = true;
            continue;
         }

         if (cur != top) {
            continue;
         }

         in_string = false;
         terminators.pop_back();
         top = terminators.back();
         continue;

      }

      if (cur == top) {
         terminators.pop_back();
         top = terminators.back();
      } else if (cur == '(' || cur == '{' || cur == '[') {
         char end = ends(cur);
         top = end;
         terminators.push_back(top);
      } else if (cur == '"' || cur == '`' || cur == '\'') {
         top = cur;
         in_string = true;
         terminators.push_back(top);
      }

   }

   // append to the output
   for (std::size_t i = terminators.size() - 1; i > 0; --i)
      result.push_back(terminators[i]);

   return result;
}

namespace {

SEXP rs_finishExpression(SEXP stringSEXP)
{
   r::sexp::Protect rProtect;
   int n = r::sexp::length(stringSEXP);

   std::vector<std::string> output;
   output.reserve(n);
   for (int i = 0; i < n; ++i)
      output.push_back(finishExpression(CHAR(STRING_ELT(stringSEXP, i))));

   return r::sexp::create(output, &rProtect);
}

struct SourceIndexCompletions {
   std::vector<std::string> completions;
   std::vector<bool> isFunction;
   bool moreAvailable;
};

SourceIndexCompletions getSourceIndexCompletions(const std::string& token)
{
   // get functions from the source index
   std::vector<core::r_util::RSourceItem> items;
   bool moreAvailable = false;

   // TODO: wire up 'moreAvailable'
   modules::code_search::searchSource(token,
                                      1E3,
                                      true,
                                      &items,
                                      &moreAvailable);

   SourceIndexCompletions srcCompletions;
   BOOST_FOREACH(const core::r_util::RSourceItem& item, items)
   {
      if (item.braceLevel() == 0)
      {
         srcCompletions.completions.push_back(item.name());
         srcCompletions.isFunction.push_back(item.isFunction() || item.isMethod());
      }
   }

   srcCompletions.moreAvailable = moreAvailable;
   return srcCompletions;
}

SEXP rs_getSourceIndexCompletions(SEXP tokenSEXP)
{
   r::sexp::Protect protect;
   std::string token = r::sexp::asString(tokenSEXP);
   SourceIndexCompletions srcCompletions = getSourceIndexCompletions(token);

   std::vector<std::string> names;
   names.push_back("completions");
   names.push_back("isFunction");
   names.push_back("moreAvailable");

   SEXP resultSEXP = r::sexp::createList(names, &protect);
   r::sexp::setNamedListElement(resultSEXP, "completions", srcCompletions.completions);
   r::sexp::setNamedListElement(resultSEXP, "isFunction", srcCompletions.isFunction);
   r::sexp::setNamedListElement(resultSEXP, "moreAvailable", srcCompletions.moreAvailable);

   return resultSEXP;
}

bool subsequenceFilter(const FileInfo& fileInfo,
                       const std::string& pattern,
                       int parentPathLength,
                       int maxCount,
                       std::vector<std::string>* pPaths,
                       int* pCount,
                       bool* pMoreAvailable)
{
   if (*pCount >= maxCount)
   {
      *pMoreAvailable = true;
      return false;
   }

   bool isSubsequence = string_utils::isSubsequence(
            fileInfo.absolutePath().substr(parentPathLength + 2),
            pattern,
            true);

   if (isSubsequence)
   {
      ++*pCount;
      pPaths->push_back(fileInfo.absolutePath());
   }

   // Always add subdirectories
   if (fileInfo.isDirectory())
   {
      return true;
   }

   return false;
}

SEXP rs_scanFiles(SEXP pathSEXP,
                  SEXP patternSEXP,
                  SEXP maxCountSEXP)
{
   std::string path = r::sexp::asString(pathSEXP);
   std::string pattern = r::sexp::asString(patternSEXP);
   int maxCount = r::sexp::asInteger(maxCountSEXP);

   FilePath filePath(path);
   FileInfo fileInfo(filePath);
   tree<FileInfo> tree;

   core::system::FileScannerOptions options;
   options.recursive = true;
   options.yield = true;

   // Use a subsequence filter, and bail after too many files
   std::vector<std::string> paths;

   int count = 0;
   bool moreAvailable = false;
   options.filter = boost::bind(subsequenceFilter,
                                _1,
                                pattern,
                                path.length(),
                                maxCount,
                                &paths,
                                &count,
                                &moreAvailable);

   Error error = scanFiles(fileInfo, options, &tree);
   if (error)
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder builder(&protect);

   builder.add("paths", paths);
   builder.add("more_available", moreAvailable);

   return r::sexp::create(builder, &protect);
}

SEXP rs_isSubsequence(SEXP stringsSEXP, SEXP querySEXP)
{
   std::vector<std::string> strings;
   if (!r::sexp::fillVectorString(stringsSEXP, &strings))
      return R_NilValue;

   std::string query = r::sexp::asString(querySEXP);

   std::vector<bool> result(strings.size());

   std::transform(strings.begin(),
                  strings.end(),
                  result.begin(),
                  boost::bind(
                     string_utils::isSubsequence,
                     _1,
                     query));

   r::sexp::Protect protect;
   return r::sexp::create(result, &protect);

}

SEXP rs_getActiveFrame(SEXP depthSEXP)
{
   int depth = r::sexp::asInteger(depthSEXP);
   RCNTXT* context = r::getGlobalContext();
   for (int i = 0; i < depth; ++i)
   {
      context = context->nextcontext;
      if (context == NULL)
         return R_NilValue;
   }
   return context->cloenv;
}

SEXP rs_getNAMESPACEImportedSymbols(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   using namespace core::r_util;
   std::vector<std::string> pkgs;

   BOOST_FOREACH(const std::string& pkg, RSourceIndex::getImportedPackages())
   {
      pkgs.push_back(pkg);
   }

   BOOST_FOREACH(const std::string& pkg,
                 RSourceIndex::getImportFromDirectives() | boost::adaptors::map_keys)
   {
      pkgs.push_back(pkg);
   }

   using namespace r::sexp;
   Protect protect;
   r::sexp::ListBuilder builder(&protect);

   BOOST_FOREACH(const std::string& pkg, pkgs)
   {
      const AsyncLibraryCompletions& completions = RSourceIndex::getCompletions(pkg);
      r::sexp::ListBuilder child(&protect);

      // If the inferred package is listed _only_ in the NAMESPACE 'importFrom',
      // then we want to selectively return symbols.
      if ((index && index->getInferredPackages().count(pkg) == 0) &&
          RSourceIndex::getImportedPackages().count(pkg) == 0 &&
          RSourceIndex::getImportFromDirectives().count(pkg) != 0)
      {
         std::vector<std::string> exports;
         std::vector<int> types;

         std::set<std::string>& directives =
               RSourceIndex::getImportFromDirectives()[pkg];

         BOOST_FOREACH(const std::string& item, directives)
         {
            std::vector<std::string>::const_iterator it =
                  std::find(completions.exports.begin(),
                            completions.exports.end(),
                            item);

            if (it == completions.exports.end())
               continue;

            std::size_t index = it - completions.exports.begin();

            exports.push_back(completions.exports[index]);
            types.push_back(completions.types[index]);
         }

         child.add("exports", exports);
         child.add("types", types);

      }
      else
      {
         child.add("exports", completions.exports);
         child.add("types", completions.types);
      }

      builder.add(pkg, child);
   }

   return r::sexp::create(builder, &protect);
}

SEXP rs_getInferredCompletions(SEXP packagesSEXP)
{
   using namespace rstudio::core::r_util;

   std::vector<std::string> packages;
   if (!r::sexp::fillVectorString(packagesSEXP, &packages))
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder parent(&protect);

   for (std::vector<std::string>::const_iterator it = packages.begin();
        it != packages.end();
        ++it)
   {
      DEBUG("Adding entry for '" << *it << "'");
      AsyncLibraryCompletions completions = RSourceIndex::getCompletions(*it);

      r::sexp::ListBuilder builder(&protect);
      builder.add("exports", completions.exports);
      builder.add("types", completions.types);
      builder.add("functions", completions.functions);
      parent.add(*it, builder);
   }

   return r::sexp::create(parent, &protect);
}

SEXP rs_listInferredPackages(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   // NOTE: can occur when user edits file not in source index
   if (index == NULL)
      return R_NilValue;

   std::set<std::string> pkgs = index->getInferredPackages();
   pkgs.insert(index->getImportedPackages().begin(),
               index->getImportedPackages().end());

   r::sexp::Protect protect;
   return r::sexp::create(pkgs, &protect);

}

} // end anonymous namespace

Error initialize() {

   RS_REGISTER_CALL_METHOD(rs_finishExpression, 1);
   RS_REGISTER_CALL_METHOD(rs_getSourceIndexCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_scanFiles, 4);
   RS_REGISTER_CALL_METHOD(rs_isSubsequence, 2);
   RS_REGISTER_CALL_METHOD(rs_getActiveFrame, 1);
   RS_REGISTER_CALL_METHOD(rs_listInferredPackages, 1);
   RS_REGISTER_CALL_METHOD(rs_getInferredCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_getNAMESPACEImportedSymbols, 1);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock;
   initBlock.addFunctions()
         (bind(sourceModuleRFile, "SessionRCompletions.R"));
   return initBlock.execute();
}

} // namespace r_completions
} // namespace modules
} // namespace session
} // namespace rstudio
<|endoftext|>


<commit_before>#include "opencv_video_source.h"
#include <string>
#include <iostream>

VideoSourceOpenCV::VideoSourceOpenCV(const char * path)
    :IVideoSource()
    , _frame_rate(0)
{
    _cap.open(path);
    if (!_cap.isOpened()) {
        std::string error = std::string("Could not open the video source: ")
                            + path;
        throw std::runtime_error(error);
    }
}

VideoSourceOpenCV::VideoSourceOpenCV(int deviceId)
    : IVideoSource()
    , _frame_rate(0)
{
    _cap.open(deviceId);
    if (!_cap.isOpened()) {
        std::string error("Device with id ");
        error.append(std::to_string(deviceId));
        error.append(" could not be opened");
        throw gg::DeviceNotFound(error);
    }
}

double VideoSourceOpenCV::get_frame_rate()
{
    if (!_cap.isOpened())
    {
        _frame_rate = 0;
        return _frame_rate;
    }

    if (_frame_rate > 0) // already obtained or estimated
        return _frame_rate;

    // will work for files, but <= 0 for most online devices
    _frame_rate = _cap.get(CV_CAP_PROP_FPS);

    if (_frame_rate <= 0) // i.e. not a file, see:
    // http://www.learnopencv.com/how-to-find-frame-rate-or-frames-per-second-fps-in-opencv-python-cpp/
    {
        // Number of frames to capture
        int num_frames = 120;

        // Start and end times
        time_t start, end;

        VideoFrame_BGRA buffer(true);

        // Start time
        time(&start);

        // Grab a few frames
        for(int i = 0; i < num_frames; i++)
        {
            get_frame(buffer);
        }

        // End Time
        time(&end);

        // Time elapsed
        float seconds = difftime(end, start);

        // Calculate frames per second
        _frame_rate  = num_frames / seconds;
    }

    // to make sure e.g. -1 is not returned,
    // which could lead to bugs in computations
    if (_frame_rate < 0) _frame_rate = 0;

    return _frame_rate;
}

bool VideoSourceOpenCV::get_frame_dimensions(int &width, int & height)
{
    width = height = 0;
    if (!_cap.isOpened()) return false;

    width = (int)_cap.get(CV_CAP_PROP_FRAME_WIDTH);
    height = (int)_cap.get(CV_CAP_PROP_FRAME_HEIGHT);

    return (width != 0 && height != 0);
}

bool VideoSourceOpenCV::get_frame(gg::VideoFrame & frame)
{
    if (!_cap.isOpened()) return false;

    bool has_read = _cap.read(_buffer);

    if (has_read) {
        // Initialize the BGRA buffer, if not only done so.
        if (_buffer_bgra.empty() ||
            _buffer_bgra.rows != _buffer.rows ||
            _buffer_bgra.cols != _buffer.cols) {
            _buffer_bgra = cv::Mat::zeros(_buffer.rows, _buffer.cols, CV_8UC4);
        }
        // Convert to BGRA
        cv::cvtColor(_buffer, _buffer_bgra, CV_BGR2BGRA);
        if (_get_sub_frame) {
            _buffer_bgra(_sub_frame).copyTo(_buffer_sub_bgra);
            frame.init_from_opencv_mat(_buffer_sub_bgra);
        }

        else {
            frame.init_from_opencv_mat(_buffer_bgra);
        }
    }
    return has_read;
}
<commit_msg>Issue #47: revised get_frame of OpenCV video source<commit_after>#include "opencv_video_source.h"
#include <string>
#include <iostream>

VideoSourceOpenCV::VideoSourceOpenCV(const char * path)
    :IVideoSource()
    , _frame_rate(0)
{
    _cap.open(path);
    if (!_cap.isOpened()) {
        std::string error = std::string("Could not open the video source: ")
                            + path;
        throw std::runtime_error(error);
    }
}

VideoSourceOpenCV::VideoSourceOpenCV(int deviceId)
    : IVideoSource()
    , _frame_rate(0)
{
    _cap.open(deviceId);
    if (!_cap.isOpened()) {
        std::string error("Device with id ");
        error.append(std::to_string(deviceId));
        error.append(" could not be opened");
        throw gg::DeviceNotFound(error);
    }
}

double VideoSourceOpenCV::get_frame_rate()
{
    if (!_cap.isOpened())
    {
        _frame_rate = 0;
        return _frame_rate;
    }

    if (_frame_rate > 0) // already obtained or estimated
        return _frame_rate;

    // will work for files, but <= 0 for most online devices
    _frame_rate = _cap.get(CV_CAP_PROP_FPS);

    if (_frame_rate <= 0) // i.e. not a file, see:
    // http://www.learnopencv.com/how-to-find-frame-rate-or-frames-per-second-fps-in-opencv-python-cpp/
    {
        // Number of frames to capture
        int num_frames = 120;

        // Start and end times
        time_t start, end;

        gg::VideoFrame buffer(gg::ColourSpace::BGRA, true);

        // Start time
        time(&start);

        // Grab a few frames
        for(int i = 0; i < num_frames; i++)
        {
            get_frame(buffer);
        }

        // End Time
        time(&end);

        // Time elapsed
        float seconds = difftime(end, start);

        // Calculate frames per second
        _frame_rate  = num_frames / seconds;
    }

    // to make sure e.g. -1 is not returned,
    // which could lead to bugs in computations
    if (_frame_rate < 0) _frame_rate = 0;

    return _frame_rate;
}

bool VideoSourceOpenCV::get_frame_dimensions(int &width, int & height)
{
    width = height = 0;
    if (!_cap.isOpened()) return false;

    width = (int)_cap.get(CV_CAP_PROP_FRAME_WIDTH);
    height = (int)_cap.get(CV_CAP_PROP_FRAME_HEIGHT);

    return (width != 0 && height != 0);
}

bool VideoSourceOpenCV::get_frame(gg::VideoFrame & frame)
{
    if (!_cap.isOpened()) return false;

    bool has_read = _cap.read(_buffer);

    if (has_read) {
        // Initialize the BGRA buffer, only if not already done so.
        if (_buffer_bgra.empty() ||
            _buffer_bgra.rows != _buffer.rows ||
            _buffer_bgra.cols != _buffer.cols) {
            _buffer_bgra = cv::Mat::zeros(_buffer.rows, _buffer.cols, CV_8UC4);
        }
        // Convert to BGRA
        cv::cvtColor(_buffer, _buffer_bgra, CV_BGR2BGRA);
        unsigned char * data = nullptr;
        size_t data_length = 0;
        size_t cols = 0, rows = 0;
        if (_get_sub_frame) {
            _buffer_bgra(_sub_frame).copyTo(_buffer_sub_bgra);
            data = _buffer_sub_bgra.data;
            cols = _buffer_sub_bgra.cols;
            rows = _buffer_sub_bgra.rows;
            data_length = _buffer_sub_bgra.channels() * cols * rows;
        }

        else {
            data = _buffer_bgra.data;
            cols = _buffer_bgra.cols;
            rows = _buffer_bgra.rows;
            data_length = _buffer_bgra.channels() * cols * rows;
        }

        frame.init_from_pointer(data, data_length, cols, rows);
    }
    return has_read;
}
<|endoftext|>


<commit_before>
/**
 *
 * Copyright (C) 2013 - 2014 Jolla Ltd.
 * Contact: Thomas Perl <thomas.perl@jollamobile.com>
 * All rights reserved.
 *
 * This file is part of libsailfishapp
 *
 * You may use this file under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * 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
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * 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.
 *
 **/

#include "sailfishapp.h"
#include "sailfishapp_priv.h"

#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <appname>" << std::endl;
        return 1;
    }

    // Application name is first parameter (private API for launcher)
    SailfishAppPriv::_PrivateAPI_DoNotUse_setAppName(argv[1]);

    return SailfishApp::main(argc, argv);
}
<commit_msg>[libsailfishapp] Launcher: accept std Qt command line options. Contributes to JB#7833<commit_after>
/**
 *
 * Copyright (C) 2013 - 2014 Jolla Ltd.
 * Contact: Thomas Perl <thomas.perl@jollamobile.com>
 * All rights reserved.
 *
 * This file is part of libsailfishapp
 *
 * You may use this file under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * 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
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * 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.
 *
 **/

#include "sailfishapp.h"
#include "sailfishapp_priv.h"

#include <QDebug>
#include <QGuiApplication>
#include <QQuickView>
#include <QScopedPointer>

int main(int argc, char *argv[])
{
    QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));

    if (app->arguments().count() != 2) {
        qWarning() << "Usage: " << qPrintable(app->arguments().first()) << " <appname>";
        return 1;
    }

    // Application name is first parameter (private API for launcher)
    SailfishAppPriv::_PrivateAPI_DoNotUse_setAppName(app->arguments().at(1));

    QScopedPointer<QQuickView> view(SailfishApp::createView());

    view->setSource(SailfishApp::pathToMainQml());
    view->show();

    return app->exec();
}
<|endoftext|>


<commit_before>//
// examples/offset_fetch_cxx03.cpp
// -------------------------------
//
// Copyright (c) 2015 Daniel Joos
//
// Distributed under MIT license. (See file LICENSE)
//
// ----------------------------------
//
// This example shows how to fetch offset data for a consumer group using the
// 'OffsetFetch' API of Kafka 0.8.2. On the other side it demonstrates how
// the library can be used in combination with promised/futures and is
// therefore running all IO related work inside of a separate thread.
// The example is mainly a port of the C++11-based example but is using the
// boost library instead of the C++11 standard library.
//

#include <boost/exception_ptr.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <libkafka_asio/libkafka_asio.h>

using libkafka_asio::Connection;
using libkafka_asio::String;
using libkafka_asio::Int32;
using libkafka_asio::ConsumerMetadataRequest;
using libkafka_asio::ConsumerMetadataResponse;
using libkafka_asio::OffsetFetchRequest;
using libkafka_asio::OffsetFetchResponse;

// This will create handler functions which will set the value of the given
// promise on success or set the exception on error.
// The promise will be bound to the handler function.
template<typename T>
boost::function<
  void(const Connection::ErrorCodeType&, const typename T::OptionalType&)>
PromiseHandler(boost::shared_ptr<boost::promise<T> > pr)
{
  struct local
  {
    static void Handle(const Connection::ErrorCodeType& err,
                       const typename T::OptionalType& response,
                       boost::shared_ptr<boost::promise<T> > result)
    {
      if (err || !response)
      {
        result->set_exception(
          boost::copy_exception(boost::system::system_error(err)));
        return;
      }
      result->set_value(*response);
    }
  };
  return boost::bind(local::Handle, ::_1, ::_2, pr);
}

// Overload of the above function for boolean promises.
// We will use this as handler for the re-connect operation.
boost::function<void(const Connection::ErrorCodeType&)>
PromiseHandler(boost::shared_ptr<boost::promise<bool> > pr)
{
  struct local
  {
    static void Handle(const Connection::ErrorCodeType& err,
                       boost::shared_ptr<boost::promise<bool> > result)
    {
      if (err)
      {
        result->set_exception(
          boost::copy_exception(boost::system::system_error(err)));
        return;
      }
      result->set_value(true);
    }
  };
  return boost::bind(local::Handle, ::_1, pr);
}

// Discover the coordinating broker for the given consumer group.
// The function schedules a ConsumerMetadata request. The returned future
// object is used to wait for the requested data to be available.
boost::BOOST_THREAD_FUTURE<ConsumerMetadataResponse>
DiscoverCoordinator(Connection& connection, const String& consumer_group)
{
  boost::shared_ptr<boost::promise<ConsumerMetadataResponse> >
    result(new boost::promise<ConsumerMetadataResponse>());
  ConsumerMetadataRequest request;
  request.set_consumer_group(consumer_group);
  connection.AsyncRequest(request, PromiseHandler(result));
  return result->get_future();
}

// Re-connects the given connection to the provided hostname and port.
// This also shows how the connection can be connected without scheduling a
// request. Again, the returned future is used to wait until the operation
// completes successfully.
boost::BOOST_THREAD_FUTURE<bool>
ReConnect(Connection& connection, const String& hostname, Int32 port)
{
  boost::shared_ptr<boost::promise<bool> > result(new boost::promise<bool>());
  connection.Close();
  connection.AsyncConnect(hostname, port, PromiseHandler(result));
  return result->get_future();
}

// Fetch offset data for the given consumer group and topic-partition.
// Same as above: the function returns a future object.
boost::BOOST_THREAD_FUTURE<OffsetFetchResponse>
FetchOffset(Connection& connection,
            const String& consumer_group,
            const String& topic_name,
            Int32 partition)
{
  boost::shared_ptr<boost::promise<OffsetFetchResponse> >
    result(new boost::promise<OffsetFetchResponse>());
  OffsetFetchRequest request;
  request.set_consumer_group(consumer_group);
  request.FetchOffset(topic_name, partition);
  connection.AsyncRequest(request, PromiseHandler(result));
  return result->get_future();
}

// The starting point of our program...
int main(int argc, char **argv)
{
  // Run all IO work inside of another thread.
  // All request handlers are invoked from inside that thread as well.
  boost::asio::io_service ios;
  boost::asio::io_service::work work(ios);
  boost::thread worker(boost::bind(&boost::asio::io_service::run, &ios));

  // Construct a `libkafka_asio` connection object
  Connection::Configuration configuration;
  configuration.auto_connect = true;
  configuration.client_id = "libkafka_asio_example";
  configuration.socket_timeout = 2000;
  configuration.SetBrokerFromString("192.168.59.104:49158");
  String consumer_group = "ExampleGroup";
  String topic_name = "example";
  Int32 partition = 0;
  Connection connection(ios, configuration);

  try
  {
    // First get the broker that is currently coordinating the offset management
    ConsumerMetadataResponse coordinator =
      DiscoverCoordinator(connection, consumer_group).get();

    // Then re-connect the connection to the coordinator
    bool is_connected =
      ReConnect(connection,
                coordinator.coordinator_host(),
                coordinator.coordinator_port()).get();

    // Finally, fetch offset data from the coordinator and print it
    if (is_connected)
    {
      OffsetFetchResponse offset =
        FetchOffset(connection, consumer_group, topic_name, partition).get();
      std::cout
      << "Offset: "
      << offset.topics().at(topic_name).partitions.at(partition).offset
      << std::endl;
    }
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  ios.stop();
  worker.join();
  return 0;
}
<commit_msg>FIX: map.at was only added with C++11<commit_after>//
// examples/offset_fetch_cxx03.cpp
// -------------------------------
//
// Copyright (c) 2015 Daniel Joos
//
// Distributed under MIT license. (See file LICENSE)
//
// ----------------------------------
//
// This example shows how to fetch offset data for a consumer group using the
// 'OffsetFetch' API of Kafka 0.8.2. On the other side it demonstrates how
// the library can be used in combination with promised/futures and is
// therefore running all IO related work inside of a separate thread.
// The example is mainly a port of the C++11-based example but is using the
// boost library instead of the C++11 standard library.
//

#include <boost/exception_ptr.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>
#include <boost/system/system_error.hpp>
#include <libkafka_asio/libkafka_asio.h>

using libkafka_asio::Connection;
using libkafka_asio::String;
using libkafka_asio::Int32;
using libkafka_asio::ConsumerMetadataRequest;
using libkafka_asio::ConsumerMetadataResponse;
using libkafka_asio::OffsetFetchRequest;
using libkafka_asio::OffsetFetchResponse;

// This will create handler functions which will set the value of the given
// promise on success or set the exception on error.
// The promise will be bound to the handler function.
template<typename T>
boost::function<
  void(const Connection::ErrorCodeType&, const typename T::OptionalType&)>
PromiseHandler(boost::shared_ptr<boost::promise<T> > pr)
{
  struct local
  {
    static void Handle(const Connection::ErrorCodeType& err,
                       const typename T::OptionalType& response,
                       boost::shared_ptr<boost::promise<T> > result)
    {
      if (err || !response)
      {
        result->set_exception(
          boost::copy_exception(boost::system::system_error(err)));
        return;
      }
      result->set_value(*response);
    }
  };
  return boost::bind(local::Handle, ::_1, ::_2, pr);
}

// Overload of the above function for boolean promises.
// We will use this as handler for the re-connect operation.
boost::function<void(const Connection::ErrorCodeType&)>
PromiseHandler(boost::shared_ptr<boost::promise<bool> > pr)
{
  struct local
  {
    static void Handle(const Connection::ErrorCodeType& err,
                       boost::shared_ptr<boost::promise<bool> > result)
    {
      if (err)
      {
        result->set_exception(
          boost::copy_exception(boost::system::system_error(err)));
        return;
      }
      result->set_value(true);
    }
  };
  return boost::bind(local::Handle, ::_1, pr);
}

// Discover the coordinating broker for the given consumer group.
// The function schedules a ConsumerMetadata request. The returned future
// object is used to wait for the requested data to be available.
boost::BOOST_THREAD_FUTURE<ConsumerMetadataResponse>
DiscoverCoordinator(Connection& connection, const String& consumer_group)
{
  boost::shared_ptr<boost::promise<ConsumerMetadataResponse> >
    result(new boost::promise<ConsumerMetadataResponse>());
  ConsumerMetadataRequest request;
  request.set_consumer_group(consumer_group);
  connection.AsyncRequest(request, PromiseHandler(result));
  return result->get_future();
}

// Re-connects the given connection to the provided hostname and port.
// This also shows how the connection can be connected without scheduling a
// request. Again, the returned future is used to wait until the operation
// completes successfully.
boost::BOOST_THREAD_FUTURE<bool>
ReConnect(Connection& connection, const String& hostname, Int32 port)
{
  boost::shared_ptr<boost::promise<bool> > result(new boost::promise<bool>());
  connection.Close();
  connection.AsyncConnect(hostname, port, PromiseHandler(result));
  return result->get_future();
}

// Fetch offset data for the given consumer group and topic-partition.
// Same as above: the function returns a future object.
boost::BOOST_THREAD_FUTURE<OffsetFetchResponse>
FetchOffset(Connection& connection,
            const String& consumer_group,
            const String& topic_name,
            Int32 partition)
{
  boost::shared_ptr<boost::promise<OffsetFetchResponse> >
    result(new boost::promise<OffsetFetchResponse>());
  OffsetFetchRequest request;
  request.set_consumer_group(consumer_group);
  request.FetchOffset(topic_name, partition);
  connection.AsyncRequest(request, PromiseHandler(result));
  return result->get_future();
}

// The starting point of our program...
int main(int argc, char **argv)
{
  // Run all IO work inside of another thread.
  // All request handlers are invoked from inside that thread as well.
  boost::asio::io_service ios;
  boost::asio::io_service::work work(ios);
  boost::thread worker(boost::bind(&boost::asio::io_service::run, &ios));

  // Construct a `libkafka_asio` connection object
  Connection::Configuration configuration;
  configuration.auto_connect = true;
  configuration.client_id = "libkafka_asio_example";
  configuration.socket_timeout = 2000;
  configuration.SetBrokerFromString("192.168.59.104:49158");
  String consumer_group = "ExampleGroup";
  String topic_name = "example";
  Int32 partition = 0;
  Connection connection(ios, configuration);

  try
  {
    // First get the broker that is currently coordinating the offset management
    ConsumerMetadataResponse coordinator =
      DiscoverCoordinator(connection, consumer_group).get();

    // Then re-connect the connection to the coordinator
    bool is_connected =
      ReConnect(connection,
                coordinator.coordinator_host(),
                coordinator.coordinator_port()).get();

    // Finally, fetch offset data from the coordinator and print it
    if (is_connected)
    {
      OffsetFetchResponse offset =
        FetchOffset(connection, consumer_group, topic_name, partition).get();
      std::cout
      << "Offset: "
      << offset.topics().find(topic_name)->second.partitions.find(partition)->second.offset
      << std::endl;
    }
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  ios.stop();
  worker.join();
  return 0;
}
<|endoftext|>