summaryrefslogtreecommitdiff
path: root/desktop/source/deployment/manager/dp_extensionmanager.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/source/deployment/manager/dp_extensionmanager.cxx')
-rw-r--r--desktop/source/deployment/manager/dp_extensionmanager.cxx416
1 files changed, 283 insertions, 133 deletions
diff --git a/desktop/source/deployment/manager/dp_extensionmanager.cxx b/desktop/source/deployment/manager/dp_extensionmanager.cxx
index c82973f1b680..709cca86c631 100644
--- a/desktop/source/deployment/manager/dp_extensionmanager.cxx
+++ b/desktop/source/deployment/manager/dp_extensionmanager.cxx
@@ -139,6 +139,37 @@ void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const
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
namespace dp_manager {
@@ -500,6 +531,107 @@ ExtensionManager::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
Reference<deploy::XPackage> ExtensionManager::addExtension(
@@ -524,165 +656,183 @@ Reference<deploy::XPackage> ExtensionManager::addExtension(
throw lang::IllegalArgumentException(
OUSTR("No valid repository name provided."),
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 =
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 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> xExtensionBackup;
- uno::Any excOccurred1;
uno::Any excOccurred2;
bool bUserDisabled = false;
- try
+ bool bCanInstall = doChecksForAddExtension(
+ xPackageManager,
+ properties,
+ xTmpExtension,
+ xAbortChannel,
+ xCmdEnv,
+ xOldExtension );
+
{
- bUserDisabled = isUserDisabled(sIdentifier, sFileName);
- try
- {
- xOldExtension = xPackageManager->getDeployedPackage(
- sIdentifier, sFileName, xCmdEnv);
- }
- catch (lang::IllegalArgumentException &)
- {
- }
- bool bCanInstall = false;
- try
+ // In this garded section (getMutex) we must not use the argument xCmdEnv
+ // because it may bring up dialogs (XInteractionHandler::handle) this
+ //may potententially deadlock. See issue
+ //http://qa.openoffice.org/issues/show_bug.cgi?id=114933
+ //By not providing xCmdEnv the underlying APIs will throw an exception if
+ //the XInteractionRequest cannot be handled
+ ::osl::MutexGuard guard(getMutex());
+
+ if (bCanInstall)
{
- if (xOldExtension.is())
+ try
{
- //throws a CommandFailedException if the user cancels
- //the action.
- checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv);
+ bUserDisabled = isUserDisabled(sIdentifier, sFileName);
+ if (xOldExtension.is())
+ {
+ 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
- {
- //throws a CommandFailedException if the user cancels
- //the action.
- checkInstall(sDisplayName, xCmdEnv);
+ catch (deploy::DeploymentException& ) {
+ excOccurred2 = ::cppu::getCaughtException();
+ } catch (ucb::CommandFailedException & ) {
+ excOccurred2 = ::cppu::getCaughtException();
+ } 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(
- 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();
+ ::cppu::throwException(excOccurred2);
}
- }
- catch (deploy::DeploymentException& ) {
- excOccurred2 = ::cppu::getCaughtException();
+ } // leaving the garded section (getMutex())
+
+ try
+ {
+ fireModified();
+
+ }catch (deploy::DeploymentException& ) {
+ throw;
} catch (ucb::CommandFailedException & ) {
- excOccurred2 = ::cppu::getCaughtException();
+ throw;
} catch (ucb::CommandAbortedException & ) {
- excOccurred2 = ::cppu::getCaughtException();
+ throw;
} catch (lang::IllegalArgumentException &) {
- excOccurred2 = ::cppu::getCaughtException();
+ throw;
} catch (uno::RuntimeException &) {
- excOccurred2 = ::cppu::getCaughtException();
- } catch (...) {
- excOccurred2 = ::cppu::getCaughtException();
+ throw;
+ } catch (uno::Exception &) {
+ uno::Any excOccurred = ::cppu::getCaughtException();
deploy::DeploymentException exc(
- OUSTR("Extension Manager: exception during addExtension, url: ")
- + url, static_cast<OWeakObject*>(this), excOccurred2);
- excOccurred2 <<= exc;
- }
-
- if (excOccurred2.hasValue())
- {
- //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);
+ 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));
}
- if (xTmpExtension.is() || xExtensionBackup.is())
- m_tmpRepository->removePackage(
- sIdentifier,OUString(), xAbortChannel, xCmdEnv);
-
- if (excOccurred1.hasValue())
- ::cppu::throwException(excOccurred1);
return xNewExtension;
}