Kaydet (Commit) 7f64aa4d authored tarafından Jens-Heiner Rechtien's avatar Jens-Heiner Rechtien

CWS-TOOLING: integrate CWS jl161

...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "com/sun/star/deployment/VersionException.hpp" #include "com/sun/star/deployment/VersionException.hpp"
#include "com/sun/star/deployment/LicenseException.hpp" #include "com/sun/star/deployment/LicenseException.hpp"
#include "com/sun/star/deployment/InstallException.hpp" #include "com/sun/star/deployment/InstallException.hpp"
#include "com/sun/star/deployment/DependencyException.hpp"
#include "com/sun/star/deployment/PlatformException.hpp"
#include "com/sun/star/task/XInteractionApprove.hpp" #include "com/sun/star/task/XInteractionApprove.hpp"
#include "com/sun/star/task/XInteractionAbort.hpp" #include "com/sun/star/task/XInteractionAbort.hpp"
#include "com/sun/star/task/XInteractionHandler.hpp" #include "com/sun/star/task/XInteractionHandler.hpp"
...@@ -250,7 +252,43 @@ void NoLicenseCommandEnv::handle( ...@@ -250,7 +252,43 @@ void NoLicenseCommandEnv::handle(
handle_(approve, abort, xRequest); handle_(approve, abort, xRequest);
} }
// SilentCheckPrerequisitesCommandEnv::SilentCheckPrerequisitesCommandEnv(
// css::uno::Reference< css::task::XInteractionHandler> const & handler):
// BaseCommandEnv(handler)
// {
// }
SilentCheckPrerequisitesCommandEnv::SilentCheckPrerequisitesCommandEnv()
{
}
void SilentCheckPrerequisitesCommandEnv::handle(
Reference< task::XInteractionRequest> const & xRequest )
throw (uno::RuntimeException)
{
uno::Any request( xRequest->getRequest() );
OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
deployment::LicenseException licExc;
deployment::PlatformException platformExc;
deployment::DependencyException depExc;
bool approve = false;
bool abort = false;
if (request >>= licExc)
{
approve = true;
handle_(approve, abort, xRequest);
}
else if ((request >>= platformExc)
|| (request >>= depExc))
{
m_Exception = request;
}
else
{
m_UnknownException = request;
}
}
// NoExceptionCommandEnv::NoExceptionCommandEnv( // NoExceptionCommandEnv::NoExceptionCommandEnv(
// css::uno::Reference< css::task::XInteractionHandler> const & handler, // css::uno::Reference< css::task::XInteractionHandler> const & handler,
// css::uno::Type const & type): // css::uno::Type const & type):
......
...@@ -135,6 +135,29 @@ public: ...@@ -135,6 +135,29 @@ public:
}; };
/* For use in XExtensionManager::addExtension in the call to
XPackage::checkPrerequisites
It prevents all user interactions. The license is always accepted.
It remembers if there was a platform or a dependency exception in
the member m_bException. if there was any other exception then m_bUnknownException
is set.
*/
class SilentCheckPrerequisitesCommandEnv : public BaseCommandEnv
{
public:
SilentCheckPrerequisitesCommandEnv();
// XInteractionHandler
virtual void SAL_CALL handle(
css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
throw (css::uno::RuntimeException);
// Set to true if a PlatformException or a DependencyException were handled.
css::uno::Any m_Exception;
// Set to true if an unknown exception was handled.
css::uno::Any m_UnknownException;
};
// class NoExceptionCommandEnv : public BaseCommandEnv // class NoExceptionCommandEnv : public BaseCommandEnv
// { // {
// css::uno::Type m_type; // css::uno::Type m_type;
......
...@@ -139,6 +139,37 @@ void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const ...@@ -139,6 +139,37 @@ void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const
OUSTR("Failed to update") + url, 0, exc); OUSTR("Failed to update") + url, 0, exc);
} }
} }
class ExtensionRemoveGuard
{
css::uno::Reference<css::deployment::XPackage> m_extension;
css::uno::Reference<css::deployment::XPackageManager> m_xPackageManager;
public:
ExtensionRemoveGuard(
css::uno::Reference<css::deployment::XPackage> const & extension,
css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager):
m_extension(extension), m_xPackageManager(xPackageManager) {}
~ExtensionRemoveGuard();
void reset(css::uno::Reference<css::deployment::XPackage> const & extension) {
m_extension = extension;
}
};
ExtensionRemoveGuard::~ExtensionRemoveGuard()
{
try {
if (m_xPackageManager.is() && m_extension.is())
m_xPackageManager->removePackage(
dp_misc::getIdentifier(m_extension), ::rtl::OUString(),
css::uno::Reference<css::task::XAbortChannel>(),
css::uno::Reference<css::ucb::XCommandEnvironment>());
} catch (...) {
OSL_ASSERT(0);
}
}
} //end namespace } //end namespace
namespace dp_manager { namespace dp_manager {
...@@ -500,6 +531,107 @@ ExtensionManager::getSupportedPackageTypes() ...@@ -500,6 +531,107 @@ ExtensionManager::getSupportedPackageTypes()
{ {
return m_userRepository->getSupportedPackageTypes(); return m_userRepository->getSupportedPackageTypes();
} }
//Do some necessary checks and user interaction. This function does not
//aquire the extension manager mutex and that mutex must not be aquired
//when this function is called. doChecksForAddExtension does synchronous
//user interactions which may require aquiring the solar mutex.
//Returns true if the extension can be installed.
bool ExtensionManager::doChecksForAddExtension(
Reference<deploy::XPackageManager> const & xPackageMgr,
uno::Sequence<beans::NamedValue> const & properties,
css::uno::Reference<css::deployment::XPackage> const & xTmpExtension,
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<ucb::XCommandEnvironment> const & xCmdEnv,
Reference<deploy::XPackage> & out_existingExtension )
throw (deploy::DeploymentException,
ucb::CommandFailedException,
ucb::CommandAbortedException,
lang::IllegalArgumentException,
uno::RuntimeException)
{
try
{
Reference<deploy::XPackage> xOldExtension;
const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
const OUString sFileName = xTmpExtension->getName();
const OUString sDisplayName = xTmpExtension->getDisplayName();
const OUString sVersion = xTmpExtension->getVersion();
try
{
xOldExtension = xPackageMgr->getDeployedPackage(
sIdentifier, sFileName, xCmdEnv);
out_existingExtension = xOldExtension;
}
catch (lang::IllegalArgumentException &)
{
}
bool bCanInstall = false;
//This part is not guarded against other threads removing, adding, disabling ...
//etc. the same extension.
//checkInstall is safe because it notifies the user if the extension is not yet
//installed in the same repository. Because addExtension has its own guard
//(m_addMutex), another thread cannot add the extension in the meantime.
//checkUpdate is called if the same extension exists in the same
//repository. The user is asked if they want to replace it. Another
//thread
//could already remove the extension. So asking the user was not
//necessary. No harm is done. The other thread may also ask the user
//if he wants to remove the extension. This depends on the
//XCommandEnvironment which it passes to removeExtension.
if (xOldExtension.is())
{
//throws a CommandFailedException if the user cancels
//the action.
checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv);
}
else
{
//throws a CommandFailedException if the user cancels
//the action.
checkInstall(sDisplayName, xCmdEnv);
}
//Prevent showing the license if requested.
Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv);
ExtensionProperties props(OUString(), properties, Reference<ucb::XCommandEnvironment>());
dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL()));
const ::boost::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes =
info.getSimpleLicenseAttributes();
if (licenseAttributes && licenseAttributes->suppressIfRequired
&& props.isSuppressedLicense())
_xCmdEnv = Reference<ucb::XCommandEnvironment>(
new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()));
bCanInstall = xTmpExtension->checkPrerequisites(
xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0 ? true : false;
return bCanInstall;
}
catch (deploy::DeploymentException& ) {
throw;
} catch (ucb::CommandFailedException & ) {
throw;
} catch (ucb::CommandAbortedException & ) {
throw;
} catch (lang::IllegalArgumentException &) {
throw;
} catch (uno::RuntimeException &) {
throw;
} catch (uno::Exception &) {
uno::Any excOccurred = ::cppu::getCaughtException();
deploy::DeploymentException exc(
OUSTR("Extension Manager: exception in doChecksForAddExtension"),
static_cast<OWeakObject*>(this), excOccurred);
throw exc;
} catch (...) {
throw uno::RuntimeException(
OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"),
static_cast<OWeakObject*>(this));
}
}
// Only add to shared and user repository // Only add to shared and user repository
Reference<deploy::XPackage> ExtensionManager::addExtension( Reference<deploy::XPackage> ExtensionManager::addExtension(
...@@ -524,165 +656,183 @@ Reference<deploy::XPackage> ExtensionManager::addExtension( ...@@ -524,165 +656,183 @@ Reference<deploy::XPackage> ExtensionManager::addExtension(
throw lang::IllegalArgumentException( throw lang::IllegalArgumentException(
OUSTR("No valid repository name provided."), OUSTR("No valid repository name provided."),
static_cast<cppu::OWeakObject*>(this), 0); static_cast<cppu::OWeakObject*>(this), 0);
::osl::MutexGuard guard(getMutex()); //We must make sure that the xTmpExtension is not create twice, because this
//would remove the first one.
::osl::MutexGuard addGuard(m_addMutex);
Reference<deploy::XPackage> xTmpExtension = Reference<deploy::XPackage> xTmpExtension =
getTempExtension(url, xAbortChannel, xCmdEnv); getTempExtension(url, xAbortChannel, xCmdEnv);
//Make sure the extension is removed from the tmp repository in case
//of an exception
ExtensionRemoveGuard tmpExtensionRemoveGuard(xTmpExtension, m_tmpRepository);
const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
const OUString sFileName = xTmpExtension->getName(); const OUString sFileName = xTmpExtension->getName();
const OUString sDisplayName = xTmpExtension->getDisplayName();
const OUString sVersion = xTmpExtension->getVersion();
dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL()));
const ::boost::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes =
info.getSimpleLicenseAttributes();
Reference<deploy::XPackage> xOldExtension; Reference<deploy::XPackage> xOldExtension;
Reference<deploy::XPackage> xExtensionBackup; Reference<deploy::XPackage> xExtensionBackup;
uno::Any excOccurred1;
uno::Any excOccurred2; uno::Any excOccurred2;
bool bUserDisabled = false; bool bUserDisabled = false;
try bool bCanInstall = doChecksForAddExtension(
xPackageManager,
properties,
xTmpExtension,
xAbortChannel,
xCmdEnv,
xOldExtension );
{ {
bUserDisabled = isUserDisabled(sIdentifier, sFileName); // In this garded section (getMutex) we must not use the argument xCmdEnv
try // because it may bring up dialogs (XInteractionHandler::handle) this
{ //may potententially deadlock. See issue
xOldExtension = xPackageManager->getDeployedPackage( //http://qa.openoffice.org/issues/show_bug.cgi?id=114933
sIdentifier, sFileName, xCmdEnv); //By not providing xCmdEnv the underlying APIs will throw an exception if
} //the XInteractionRequest cannot be handled
catch (lang::IllegalArgumentException &) ::osl::MutexGuard guard(getMutex());
{
} if (bCanInstall)
bool bCanInstall = false;
try
{ {
if (xOldExtension.is()) try
{ {
//throws a CommandFailedException if the user cancels bUserDisabled = isUserDisabled(sIdentifier, sFileName);
//the action. if (xOldExtension.is())
checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv); {
try
{
xOldExtension->revokePackage(
xAbortChannel, Reference<ucb::XCommandEnvironment>());
//save the old user extension in case the user aborts
//store the extension in the tmp repository, this will overwrite
//xTmpPackage (same identifier). Do not let the user abort or
//interact
//importing the old extension in the tmp repository will remove
//the xTmpExtension
//no command environment supplied, only this class shall interact
//with the user!
xExtensionBackup = m_tmpRepository->importExtension(
xOldExtension, Reference<task::XAbortChannel>(),
Reference<ucb::XCommandEnvironment>());
tmpExtensionRemoveGuard.reset(xExtensionBackup);
//xTmpExtension will later be used to check the dependencies
//again. However, only xExtensionBackup will be later removed
//from the tmp repository
xTmpExtension = xExtensionBackup;
OSL_ASSERT(xTmpExtension.is());
}
catch (lang::DisposedException &)
{
//Another thread might have removed the extension meanwhile
}
}
//check again dependencies but prevent user interaction,
//We can disregard the license, because the user must have already
//accepted it, whe we called checkPrerequisites the first time
SilentCheckPrerequisitesCommandEnv * pSilentCommandEnv =
new SilentCheckPrerequisitesCommandEnv();
Reference<ucb::XCommandEnvironment> silentCommandEnv(pSilentCommandEnv);
sal_Int32 failedPrereq = xTmpExtension->checkPrerequisites(
xAbortChannel, silentCommandEnv, true);
if (failedPrereq == 0)
{
xNewExtension = xPackageManager->addPackage(
url, properties, OUString(), xAbortChannel,
Reference<ucb::XCommandEnvironment>());
//If we add a user extension and there is already one which was
//disabled by a user, then the newly installed one is enabled. If we
//add to another repository then the user extension remains
//disabled.
bool bUserDisabled2 = bUserDisabled;
if (repository.equals(OUSTR("user")))
bUserDisabled2 = false;
activateExtension(
dp_misc::getIdentifier(xNewExtension),
xNewExtension->getName(), bUserDisabled2, false, xAbortChannel,
Reference<ucb::XCommandEnvironment>());
}
else
{
if (pSilentCommandEnv->m_Exception.hasValue())
::cppu::throwException(pSilentCommandEnv->m_Exception);
else if ( pSilentCommandEnv->m_UnknownException.hasValue())
::cppu::throwException(pSilentCommandEnv->m_UnknownException);
else
throw deploy::DeploymentException (
OUSTR("Extension Manager: exception during addExtension, ckeckPrerequisites failed"),
static_cast<OWeakObject*>(this), uno::Any());
}
} }
else catch (deploy::DeploymentException& ) {
{ excOccurred2 = ::cppu::getCaughtException();
//throws a CommandFailedException if the user cancels } catch (ucb::CommandFailedException & ) {
//the action. excOccurred2 = ::cppu::getCaughtException();
checkInstall(sDisplayName, xCmdEnv); } catch (ucb::CommandAbortedException & ) {
excOccurred2 = ::cppu::getCaughtException();
} catch (lang::IllegalArgumentException &) {
excOccurred2 = ::cppu::getCaughtException();
} catch (uno::RuntimeException &) {
excOccurred2 = ::cppu::getCaughtException();
} catch (...) {
excOccurred2 = ::cppu::getCaughtException();
deploy::DeploymentException exc(
OUSTR("Extension Manager: exception during addExtension, url: ")
+ url, static_cast<OWeakObject*>(this), excOccurred2);
excOccurred2 <<= exc;
} }
//Prevent showing the license if requested.
Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv);
ExtensionProperties props(OUString(), properties, Reference<ucb::XCommandEnvironment>());
if (licenseAttributes && licenseAttributes->suppressIfRequired
&& props.isSuppressedLicense())
_xCmdEnv = Reference<ucb::XCommandEnvironment>(
new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()));
bCanInstall = xTmpExtension->checkPrerequisites(
xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0 ? true : false;
}
catch (deploy::DeploymentException& ) {
excOccurred1 = ::cppu::getCaughtException();
} catch (ucb::CommandFailedException & ) {
excOccurred1 = ::cppu::getCaughtException();
} catch (ucb::CommandAbortedException & ) {
excOccurred1 = ::cppu::getCaughtException();
} catch (lang::IllegalArgumentException &) {
excOccurred1 = ::cppu::getCaughtException();
} catch (uno::RuntimeException &) {
excOccurred1 = ::cppu::getCaughtException();
} catch (...) {
excOccurred1 = ::cppu::getCaughtException();
deploy::DeploymentException exc(
OUSTR("Extension Manager: exception during addExtension, url: ")
+ url, static_cast<OWeakObject*>(this), excOccurred1);
excOccurred1 <<= exc;
} }
if (bCanInstall) if (excOccurred2.hasValue())
{ {
if (xOldExtension.is()) //It does not matter what exception is thrown. We try to
//recover the original status.
//If the user aborted installation then a ucb::CommandAbortedException
//is thrown.
//Use a private AbortChannel so the user cannot interrupt.
try
{
if (xExtensionBackup.is())
{
Reference<deploy::XPackage> xRestored =
xPackageManager->importExtension(
xExtensionBackup, Reference<task::XAbortChannel>(),
Reference<ucb::XCommandEnvironment>());
}
activateExtension(
sIdentifier, sFileName, bUserDisabled, false,
Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
}
catch (...)
{ {
xOldExtension->revokePackage(xAbortChannel, xCmdEnv);
//save the old user extension in case the user aborts
//store the extension in the tmp repository, this will overwrite
//xTmpPackage (same identifier). Do not let the user abort or
//interact
Reference<ucb::XCommandEnvironment> tmpCmdEnv(
new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
//importing the old extension in the tmp repository will remove
//the xTmpExtension
xTmpExtension = 0;
xExtensionBackup = m_tmpRepository->importExtension(
xOldExtension, Reference<task::XAbortChannel>(),
tmpCmdEnv);
} }
xNewExtension = xPackageManager->addPackage( ::cppu::throwException(excOccurred2);
url, properties, OUString(), xAbortChannel, xCmdEnv);
//If we add a user extension and there is already one which was
//disabled by a user, then the newly installed one is enabled. If we
//add to another repository then the user extension remains
//disabled.
bool bUserDisabled2 = bUserDisabled;
if (repository.equals(OUSTR("user")))
bUserDisabled2 = false;
activateExtension(
dp_misc::getIdentifier(xNewExtension),
xNewExtension->getName(), bUserDisabled2, false, xAbortChannel, xCmdEnv);
fireModified();
} }
} } // leaving the garded section (getMutex())
catch (deploy::DeploymentException& ) {
excOccurred2 = ::cppu::getCaughtException(); try
{
fireModified();
}catch (deploy::DeploymentException& ) {
throw;
} catch (ucb::CommandFailedException & ) { } catch (ucb::CommandFailedException & ) {
excOccurred2 = ::cppu::getCaughtException(); throw;
} catch (ucb::CommandAbortedException & ) { } catch (ucb::CommandAbortedException & ) {
excOccurred2 = ::cppu::getCaughtException(); throw;
} catch (lang::IllegalArgumentException &) { } catch (lang::IllegalArgumentException &) {
excOccurred2 = ::cppu::getCaughtException(); throw;
} catch (uno::RuntimeException &) { } catch (uno::RuntimeException &) {
excOccurred2 = ::cppu::getCaughtException(); throw;
} catch (...) { } catch (uno::Exception &) {
excOccurred2 = ::cppu::getCaughtException(); uno::Any excOccurred = ::cppu::getCaughtException();
deploy::DeploymentException exc( deploy::DeploymentException exc(
OUSTR("Extension Manager: exception during addExtension, url: ") OUSTR("Extension Manager: exception in doChecksForAddExtension"),
+ url, static_cast<OWeakObject*>(this), excOccurred2); static_cast<OWeakObject*>(this), excOccurred);
excOccurred2 <<= exc; throw exc;
} } catch (...) {
throw uno::RuntimeException(
if (excOccurred2.hasValue()) OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"),
{ static_cast<OWeakObject*>(this));
//It does not matter what exception is thrown. We try to
//recover the original status.
//If the user aborted installation then a ucb::CommandAbortedException
//is thrown.
//Use a private AbortChannel so the user cannot interrupt.
try
{
Reference<ucb::XCommandEnvironment> tmpCmdEnv(
new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
if (xExtensionBackup.is())
{
Reference<deploy::XPackage> xRestored =
xPackageManager->importExtension(
xExtensionBackup, Reference<task::XAbortChannel>(),
tmpCmdEnv);
}
activateExtension(
sIdentifier, sFileName, bUserDisabled, false,
Reference<task::XAbortChannel>(), tmpCmdEnv);
if (xTmpExtension.is() || xExtensionBackup.is())
m_tmpRepository->removePackage(
sIdentifier, OUString(), xAbortChannel, xCmdEnv);
fireModified();
}
catch (...)
{
}
::cppu::throwException(excOccurred2);
} }
if (xTmpExtension.is() || xExtensionBackup.is())
m_tmpRepository->removePackage(
sIdentifier,OUString(), xAbortChannel, xCmdEnv);
if (excOccurred1.hasValue())
::cppu::throwException(excOccurred1);
return xNewExtension; return xNewExtension;
} }
......
...@@ -235,6 +235,8 @@ private: ...@@ -235,6 +235,8 @@ private:
css::uno::Reference<css::deployment::XPackageManager> m_bundledRepository; css::uno::Reference<css::deployment::XPackageManager> m_bundledRepository;
css::uno::Reference<css::deployment::XPackageManager> m_tmpRepository; css::uno::Reference<css::deployment::XPackageManager> m_tmpRepository;
//only to be used within addExtension
::osl::Mutex m_addMutex;
/* contains the names of all repositories (except tmp) in order of there /* contains the names of all repositories (except tmp) in order of there
priority. That is, the first element is "user" follod by "shared" and priority. That is, the first element is "user" follod by "shared" and
then "bundled" then "bundled"
...@@ -296,6 +298,21 @@ private: ...@@ -296,6 +298,21 @@ private:
css::uno::Reference<css::deployment::XPackageManager> css::uno::Reference<css::deployment::XPackageManager>
getPackageManager(::rtl::OUString const & repository) getPackageManager(::rtl::OUString const & repository)
throw (css::lang::IllegalArgumentException); throw (css::lang::IllegalArgumentException);
bool doChecksForAddExtension(
css::uno::Reference<css::deployment::XPackageManager> const & xPackageMgr,
css::uno::Sequence<css::beans::NamedValue> const & properties,
css::uno::Reference<css::deployment::XPackage> const & xTmpExtension,
css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv,
css::uno::Reference<css::deployment::XPackage> & out_existingExtension )
throw (css::deployment::DeploymentException,
css::ucb::CommandFailedException,
css::ucb::CommandAbortedException,
css::lang::IllegalArgumentException,
css::uno::RuntimeException);
}; };
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment