/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
bool ODbDataSourceAdministrationHelper::getCurrentSettings(Sequence< PropertyValue >& _rDriverParam)
{
OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::getCurrentSettings : not to be called without an example set!"); if (!m_pItemSetHelper->getOutputSet()) returnfalse;
std::vector< PropertyValue > aReturn; // collecting this in a vector because it has a push_back, in opposite to sequences
// check if the connection type requires a password if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
{ // password: DSID_PASSWORD -> password const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD);
OUString sPassword = pPassword ? pPassword->GetValue() : OUString(); const SfxBoolItem* pPasswordRequired = m_pItemSetHelper->getOutputSet()->GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED); // if the set does not contain a password, but the item set says it requires one, ask the user if ((!pPassword || !pPassword->GetValue().getLength()) && (pPasswordRequired && pPasswordRequired->GetValue()))
{ const SfxStringItem* pName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_NAME);
rtl::Reference<comphelper::OInteractionRequest> pRequest = new comphelper::OInteractionRequest(Any(aRequest));
// build an interaction request // two continuations (Ok and Cancel)
::rtl::Reference< comphelper::OInteractionAbort > pAbort = new comphelper::OInteractionAbort;
::rtl::Reference< dbaccess::OAuthenticationContinuation > pAuthenticate = new dbaccess::OAuthenticationContinuation;
pAuthenticate->setCanChangeUserName( false );
pAuthenticate->setRememberPassword( RememberAuthentication_SESSION );
// some knittings
pRequest->addContinuation(pAbort);
pRequest->addContinuation(pAuthenticate);
// handle the request try
{
SolarMutexGuard aSolarGuard; // release the mutex when calling the handler, it may need to lock the SolarMutex
xHandler->handle(pRequest);
} catch(Exception&)
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
} if (!pAuthenticate->wasSelected()) returnfalse;
sPassword = pAuthenticate->getPassword(); if (pAuthenticate->getRememberPassword())
m_pItemSetHelper->getWriteOutputSet()->Put(SfxStringItem(DSID_PASSWORD, sPassword));
}
if (!sPassword.isEmpty())
aReturn.emplace_back( "password", 0,
Any(sPassword), PropertyState_DIRECT_VALUE);
}
if ( !aReturn.empty() )
_rDriverParam = comphelper::containerToSequence(aReturn);
// append all the other stuff (charset etc.)
fillDatasourceInfo(*m_pItemSetHelper->getOutputSet(), _rDriverParam);
returntrue;
}
void ODbDataSourceAdministrationHelper::successfullyConnected()
{
OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::successfullyConnected: not to be called without an example set!"); if (!m_pItemSetHelper->getOutputSet()) return;
if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
{ const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD); if (pPassword && (0 != pPassword->GetValue().getLength()))
{
OUString sPassword = pPassword->GetValue();
assert(pUrlItem && "Connection URL is NULL. -> GPF!");
assert(pTypeCollection && "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
assert(pCollection && "ODbDataSourceAdministrationHelper::getDatasourceType: invalid type collection!");
switch( pCollection->determineType(eType) )
{ case ::dbaccess::DST_DBASE: case ::dbaccess::DST_FLAT: case ::dbaccess::DST_CALC: case ::dbaccess::DST_WRITER: break; case ::dbaccess::DST_MSACCESS:
{
OUString sFileName = pCollection->cutPrefix(pUrlItem->GetValue());
OUString sNewFileName; if ( ::osl::FileBase::getSystemPathFromFileURL( sFileName, sNewFileName ) == ::osl::FileBase::E_None )
{
sNewUrl += sNewFileName;
}
} break; case ::dbaccess::DST_MYSQL_NATIVE: case ::dbaccess::DST_MYSQL_JDBC:
{ const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER); const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
sNewUrl = lcl_createHostWithPort(pHostName,pPortNumber);
OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString(); if ( !sDatabaseName.getLength() && pUrlItem )
sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() ); // TODO: what's that? Why is the database name transported via the URL Item? // Huh? Anybody there? // OJ: It is needed when the connection properties are changed. There the URL is used for every type.
if ( !sDatabaseName.isEmpty() )
{
sNewUrl += "/" + sDatabaseName;
}
} break; case ::dbaccess::DST_ORACLE_JDBC:
{ const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_ORACLE_PORTNUMBER); const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME); if ( pHostName && pHostName->GetValue().getLength() )
{
sNewUrl = "@" + lcl_createHostWithPort(pHostName,pPortNumber);
OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString(); if ( sDatabaseName.isEmpty() && pUrlItem )
sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() ); if ( !sDatabaseName.isEmpty() )
{
sNewUrl += ":" + sDatabaseName;
}
} else
{ // here someone entered a JDBC url which looks like oracle, so we have to use the url property
}
} break; case ::dbaccess::DST_LDAP:
{ const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER);
sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber);
} break; case ::dbaccess::DST_POSTGRES:
{
OUString rURL(comphelper::string::stripEnd(pUrlItem->GetValue(), '*')); const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME); const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_POSTGRES_PORTNUMBER); const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME); if (pHostName && pHostName->GetValue().getLength())
{
OUString hostname( pHostName->GetValue() );
hostname = hostname.replaceAll( "\\", "\\\\");
hostname = hostname.replaceAll( "\'", "\\'");
hostname = "'" + hostname + "'";
rURL += " host=" + hostname;
} // tdf#157260: if port is already in the URL, don't add another one if (pPortNumber && pPortNumber->GetValue() && (rURL.indexOf("port=") == -1))
{
OUString port = "'" + OUString::number(pPortNumber->GetValue()) + "'";
rURL += " port=" + port;
} if (pDatabaseName && pDatabaseName->GetValue().getLength())
{
OUString dbname( pDatabaseName->GetValue() );
dbname = dbname.replaceAll( "\\", "\\\\");
dbname = dbname.replaceAll( "\'", "\\'");
dbname = "'" + dbname + "'";
rURL += " dbname=" + dbname;
} return rURL;
} break; case ::dbaccess::DST_JDBC: // run through default: break;
} if ( !sNewUrl.isEmpty() )
sNewUrl = pCollection->getPrefix(eType) + sNewUrl; elseif (pUrlItem)
sNewUrl = pUrlItem->GetValue();
void ODbDataSourceAdministrationHelper::translateProperties(const Reference< XPropertySet >& _rxSource, SfxItemSet& _rDest)
{ if (_rxSource.is())
{ for (autoconst& elem : m_aDirectPropTranslator)
{ // get the property value
Any aValue; try
{
aValue = _rxSource->getPropertyValue(elem.second);
} catch(Exception&)
{
SAL_WARN("dbaccess", "ODbDataSourceAdministrationHelper::translateProperties: could not extract the property "
<< elem.second);
} // transfer it into an item
implTranslateProperty(_rDest, elem.first, aValue);
}
// get the additional information
Sequence< PropertyValue > aAdditionalInfo; try
{
_rxSource->getPropertyValue(PROPERTY_INFO) >>= aAdditionalInfo;
} catch(Exception&) { }
// collect the names of the additional settings
PropertyValueSet aInfos; for (const PropertyValue& rAdditionalInfo : aAdditionalInfo)
{ if( rAdditionalInfo.Name == "JDBCDRV" )
{ // compatibility
PropertyValue aCompatibility(rAdditionalInfo);
aCompatibility.Name = "JavaDriverClass";
aInfos.insert(aCompatibility);
} else
aInfos.insert(rAdditionalInfo);
}
// go through all known translations and check if we have such a setting if ( !aInfos.empty() )
{
PropertyValue aSearchFor; for (autoconst& elem : m_aIndirectPropTranslator)
{
aSearchFor.Name = elem.second;
PropertyValueSet::const_iterator aInfoPos = aInfos.find(aSearchFor); if (aInfos.end() != aInfoPos) // the property is contained in the info sequence // -> transfer it into an item
implTranslateProperty(_rDest, elem.first, aInfoPos->Value);
}
}
// the property set info
Reference< XPropertySetInfo > xInfo; try { xInfo = _rxDest->getPropertySetInfo(); } catch(Exception&) { }
static constexpr OUStringLiteral sUrlProp(u"URL"); // transfer the direct properties for (autoconst& elem : m_aDirectPropTranslator)
{ const SfxPoolItem* pCurrentItem = _rSource.GetItem(static_cast<sal_uInt16>(elem.first)); if (pCurrentItem)
{
sal_Int16 nAttributes = PropertyAttribute::READONLY; if (xInfo.is())
{ try { nAttributes = xInfo->getPropertyByName(elem.second).Attributes; } catch(Exception&) { }
} if ((nAttributes & PropertyAttribute::READONLY) == 0)
{ if ( sUrlProp == elem.second )
{
Any aValue(getConnectionURL()); // aValue <<= OUString();
lcl_putProperty(_rxDest, elem.second,aValue);
} else
implTranslateProperty(_rxDest, elem.second, pCurrentItem);
}
}
}
// now for the indirect properties
Sequence< PropertyValue > aInfo; // the original properties try
{
_rxDest->getPropertyValue(PROPERTY_INFO) >>= aInfo;
} catch(Exception&) { }
// overwrite and extend them
fillDatasourceInfo(_rSource, aInfo); // and propagate the (newly composed) sequence to the set
lcl_putProperty(_rxDest,PROPERTY_INFO, Any(aInfo));
}
void ODbDataSourceAdministrationHelper::fillDatasourceInfo(const SfxItemSet& _rSource, Sequence< css::beans::PropertyValue >& _rInfo)
{ // within the current "Info" sequence, replace the ones we can examine from the item set // (we don't just fill a completely new sequence with our own items, but we preserve any properties unknown to // us)
// first determine which of all the items are relevant for the data source (depends on the connection url) const OUString eType = getDatasourceType(_rSource); const ::connectivity::DriversConfig aDriverConfig(getORB()); const ::comphelper::NamedValueCollection& aProperties = aDriverConfig.getProperties(eType);
// settings to preserve
MapInt2String aPreservedSettings;
// now aRelevantSettings contains all the property values relevant for the current data source type, // check the original sequence if it already contains any of these values (which have to be overwritten, then)
PropertyValue* pInfo = _rInfo.getArray();
PropertyValue aSearchFor;
sal_Int32 nObsoleteSetting = -1;
sal_Int32 nCount = _rInfo.getLength(); for (sal_Int32 i = 0; i < nCount; ++i, ++pInfo)
{
aSearchFor.Name = pInfo->Name;
PropertyValueSet::const_iterator aOverwrittenSetting = aRelevantSettings.find(aSearchFor); if (aRelevantSettings.end() != aOverwrittenSetting)
{ // the setting was present in the original sequence, and it is to be overwritten -> replace it if ( pInfo->Value != aOverwrittenSetting->Value )
*pInfo = *aOverwrittenSetting;
aRelevantSettings.erase(aOverwrittenSetting);
} elseif( pInfo->Name == "JDBCDRV" )
{ // this is a compatibility setting, remove it from the sequence (it's replaced by JavaDriverClass)
nObsoleteSetting = i;
} else
aPreservedSettings[i] = pInfo->Name;
} if (-1 != nObsoleteSetting)
::comphelper::removeElementAt(_rInfo, nObsoleteSetting);
if ( !aPreservedSettings.empty() )
{ // check if there are settings which // * are known as indirect properties // * but not relevant for the current data source type // These settings have to be removed: If they're not relevant, we have no UI for changing them.
// for this, we need a string-controlled quick access to m_aIndirectPropTranslator
std::set<OUString> aIndirectProps;
std::transform(m_aIndirectPropTranslator.begin(),
m_aIndirectPropTranslator.end(),
std::inserter(aIndirectProps,aIndirectProps.begin()),
::o3tl::select2nd< MapInt2String::value_type >());
// now check the to-be-preserved props
std::vector< sal_Int32 > aRemoveIndexes;
sal_Int32 nPositionCorrector = 0; for (autoconst& preservedSetting : aPreservedSettings)
{ if (aIndirectProps.end() != aIndirectProps.find(preservedSetting.second))
{
aRemoveIndexes.push_back(preservedSetting.first - nPositionCorrector);
++nPositionCorrector;
}
} // now finally remove all such props for (autoconst& removeIndex : aRemoveIndexes)
::comphelper::removeElementAt(_rInfo, removeIndex);
}
Sequence< Any> aTypeSettings;
aTypeSettings = aProperties.getOrDefault(u"TypeInfoSettings"_ustr,aTypeSettings); // here we have a special entry for types from oracle if ( aTypeSettings.hasElements() )
{
aRelevantSettings.insert(PropertyValue(u"TypeInfoSettings"_ustr, 0, Any(aTypeSettings), PropertyState_DIRECT_VALUE));
}
// check which values are still left ('cause they were not present in the original sequence, but are to be set) if ( aRelevantSettings.empty() ) return;
bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource)
{ // put the remembered settings into the property set
Reference<XPropertySet> xDatasource = getCurrentDataSource(); if ( !xDatasource.is() ) returnfalse;
translateProperties(_rSource,xDatasource );
returntrue;
}
void ODbDataSourceAdministrationHelper::setDataSourceOrName( const Any& _rDataSourceOrName )
{
OSL_ENSURE( !m_aDataSourceOrName.hasValue(), "ODbDataSourceAdministrationHelper::setDataSourceOrName: already have one!" ); // hmm. We could reset m_xDatasource/m_xModel, probably, and continue working
m_aDataSourceOrName = _rDataSourceOrName;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.