| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_desktop.hxx" |
| |
| #include <cppuhelper/implbase1.hxx> |
| |
| #include "comphelper/servicedecl.hxx" |
| #include "cppuhelper/exc_hlp.hxx" |
| #include "rtl/bootstrap.hxx" |
| #include "com/sun/star/deployment/ExtensionManager.hpp" |
| #include "com/sun/star/deployment/XExtensionManager.hpp" |
| #include "com/sun/star/deployment/thePackageManagerFactory.hpp" |
| #include "com/sun/star/deployment/XPackageManager.hpp" |
| #include "com/sun/star/deployment/XPackageManagerFactory.hpp" |
| #include "com/sun/star/deployment/XPackage.hpp" |
| #include "com/sun/star/deployment/InstallException.hpp" |
| #include "com/sun/star/deployment/VersionException.hpp" |
| #include "com/sun/star/deployment/LicenseException.hpp" |
| #include "com/sun/star/lang/XServiceInfo.hpp" |
| #include "com/sun/star/registry/XRegistryKey.hpp" |
| #include "com/sun/star/beans/Optional.hpp" |
| #include "com/sun/star/task/XInteractionApprove.hpp" |
| #include "com/sun/star/beans/Ambiguous.hpp" |
| #include "com/sun/star/uno/XComponentContext.hpp" |
| #include "com/sun/star/io/XInputStream.hpp" |
| #include "com/sun/star/util/XModifyBroadcaster.hpp" |
| #include "comphelper/sequence.hxx" |
| #include "xmlscript/xml_helper.hxx" |
| #include "osl/diagnose.h" |
| #include "dp_interact.h" |
| #include "dp_resource.h" |
| #include "dp_ucb.h" |
| #include "dp_identifier.hxx" |
| #include "dp_descriptioninfoset.hxx" |
| #include "dp_extensionmanager.hxx" |
| #include "dp_commandenvironments.hxx" |
| #include "dp_properties.hxx" |
| #include "boost/bind.hpp" |
| |
| #include <list> |
| #include <hash_map> |
| #include <algorithm> |
| |
| namespace deploy = com::sun::star::deployment; |
| namespace lang = com::sun::star::lang; |
| namespace registry = com::sun::star::registry; |
| namespace task = com::sun::star::task; |
| namespace ucb = com::sun::star::ucb; |
| namespace uno = com::sun::star::uno; |
| namespace beans = com::sun::star::beans; |
| namespace util = com::sun::star::util; |
| namespace css = com::sun::star; |
| |
| |
| //#define OUSTR(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) |
| |
| using ::com::sun::star::uno::Reference; |
| using ::rtl::OUString; |
| |
| namespace { |
| |
| struct CompIdentifiers |
| { |
| bool operator() (::std::vector<Reference<deploy::XPackage> > const & a, |
| ::std::vector<Reference<deploy::XPackage> > const & b) |
| { |
| |
| if (getName(a).compareTo(getName(b)) < 0) |
| return true; |
| return false; |
| } |
| |
| OUString getName(::std::vector<Reference<deploy::XPackage> > const & a); |
| }; |
| |
| OUString CompIdentifiers::getName(::std::vector<Reference<deploy::XPackage> > const & a) |
| { |
| OSL_ASSERT(a.size() == 3); |
| //get the first non-null reference |
| Reference<deploy::XPackage> extension; |
| ::std::vector<Reference<deploy::XPackage> >::const_iterator it = a.begin(); |
| for (; it != a.end(); it++) |
| { |
| if (it->is()) |
| { |
| extension = *it; |
| break; |
| } |
| } |
| OSL_ASSERT(extension.is()); |
| return extension->getDisplayName(); |
| } |
| |
| void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const & xCmdEnv) |
| { |
| //Write the lastmodified file |
| try { |
| ::rtl::Bootstrap::expandMacros(url); |
| ::ucbhelper::Content ucbStamp(url, xCmdEnv ); |
| dp_misc::erase_path( url, xCmdEnv ); |
| ::rtl::OString stamp("1" ); |
| Reference<css::io::XInputStream> xData( |
| ::xmlscript::createInputStream( |
| ::rtl::ByteSequence( |
| reinterpret_cast<sal_Int8 const *>(stamp.getStr()), |
| stamp.getLength() ) ) ); |
| ucbStamp.writeStream( xData, true /* replace existing */ ); |
| } |
| catch(...) |
| { |
| uno::Any exc(::cppu::getCaughtException()); |
| throw deploy::DeploymentException( |
| 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(){}; |
| 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 set(css::uno::Reference<css::deployment::XPackage> const & extension, |
| css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager) { |
| m_extension = extension; |
| m_xPackageManager = xPackageManager; |
| } |
| }; |
| |
| ExtensionRemoveGuard::~ExtensionRemoveGuard() |
| { |
| try { |
| OSL_ASSERT(!(m_extension.is() && !m_xPackageManager.is())); |
| 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 { |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| |
| //ToDo: bundled extension |
| ExtensionManager::ExtensionManager( Reference< uno::XComponentContext > const& xContext) : |
| ::cppu::WeakComponentImplHelper1< css::deployment::XExtensionManager >(getMutex()), |
| m_xContext( xContext ) |
| { |
| m_xPackageManagerFactory = deploy::thePackageManagerFactory::get(m_xContext); |
| OSL_ASSERT(m_xPackageManagerFactory.is()); |
| |
| m_repositoryNames.push_back(OUSTR("user")); |
| m_repositoryNames.push_back(OUSTR("shared")); |
| m_repositoryNames.push_back(OUSTR("bundled")); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| ExtensionManager::~ExtensionManager() |
| { |
| } |
| |
| Reference<deploy::XPackageManager> ExtensionManager::getUserRepository() |
| { |
| return m_xPackageManagerFactory->getPackageManager(OUSTR("user")); |
| } |
| Reference<deploy::XPackageManager> ExtensionManager::getSharedRepository() |
| { |
| return m_xPackageManagerFactory->getPackageManager(OUSTR("shared")); |
| } |
| Reference<deploy::XPackageManager> ExtensionManager::getBundledRepository() |
| { |
| return m_xPackageManagerFactory->getPackageManager(OUSTR("bundled")); |
| } |
| Reference<deploy::XPackageManager> ExtensionManager::getTmpRepository() |
| { |
| return m_xPackageManagerFactory->getPackageManager(OUSTR("tmp")); |
| } |
| Reference<deploy::XPackageManager> ExtensionManager::getBakRepository() |
| { |
| return m_xPackageManagerFactory->getPackageManager(OUSTR("bak")); |
| } |
| |
| Reference<task::XAbortChannel> ExtensionManager::createAbortChannel() |
| throw (uno::RuntimeException) |
| { |
| return new dp_misc::AbortChannel; |
| } |
| |
| css::uno::Reference<css::deployment::XPackageManager> |
| ExtensionManager::getPackageManager(::rtl::OUString const & repository) |
| throw (css::lang::IllegalArgumentException) |
| { |
| Reference<deploy::XPackageManager> xPackageManager; |
| if (repository.equals(OUSTR("user"))) |
| xPackageManager = getUserRepository(); |
| else if (repository.equals(OUSTR("shared"))) |
| xPackageManager = getSharedRepository(); |
| else if (repository.equals(OUSTR("bundled"))) |
| xPackageManager = getBundledRepository(); |
| else if (repository.equals(OUSTR("tmp"))) |
| xPackageManager = getTmpRepository(); |
| else if (repository.equals(OUSTR("bak"))) |
| xPackageManager = getBakRepository(); |
| else if (repository.equals(OUSTR("bundled_prereg"))) |
| xPackageManager = m_xPackageManagerFactory->getPackageManager(repository); |
| else |
| throw lang::IllegalArgumentException( |
| OUSTR("No valid repository name provided."), |
| static_cast<cppu::OWeakObject*>(this), 0); |
| return xPackageManager; |
| } |
| |
| |
| /* |
| Enters the XPackage objects into a map. They must be all from the |
| same repository. The value type of the map is a vector, where each vector |
| represents an extension with a particular identifier. The first member |
| is represents the user extension, the second the shared extension and the |
| third the bundled extension. |
| */ |
| void ExtensionManager::addExtensionsToMap( |
| id2extensions & mapExt, |
| uno::Sequence<Reference<deploy::XPackage> > const & seqExt, |
| OUString const & repository) |
| { |
| //Determine the index in the vector where these extensions are to be |
| //added. |
| ::std::list<OUString>::const_iterator citNames = |
| m_repositoryNames.begin(); |
| int index = 0; |
| for (;citNames != m_repositoryNames.end(); citNames++, index++) |
| { |
| if (citNames->equals(repository)) |
| break; |
| } |
| |
| for (int i = 0; i < seqExt.getLength(); i++) |
| { |
| Reference<deploy::XPackage> const & xExtension = seqExt[i]; |
| OUString id = dp_misc::getIdentifier(xExtension); |
| id2extensions::iterator ivec = mapExt.find(id); |
| if (ivec == mapExt.end()) |
| { |
| ::std::vector<Reference<deploy::XPackage> > vec(3); |
| vec[index] = xExtension; |
| mapExt[id] = vec; |
| } |
| else |
| { |
| ivec->second[index] = xExtension; |
| } |
| } |
| } |
| |
| /* |
| returns a list containing extensions with the same identifier from |
| all repositories (user, shared, bundled) If one repository does not |
| have this extension, then the list contains an empty Referenc. The list |
| is ordered according to the priority of the repostories: |
| 1. user |
| 2. shared |
| 3. bundled |
| |
| The number of elements is always three, unless the number of repository |
| changes. |
| */ |
| ::std::list<Reference<deploy::XPackage> > |
| ExtensionManager::getExtensionsWithSameId( |
| OUString const & identifier, OUString const & fileName, |
| Reference< ucb::XCommandEnvironment> const & /*xCmdEnv*/) |
| |
| { |
| ::std::list<Reference<deploy::XPackage> > extensionList; |
| try |
| { //will throw an exception if the extension does not exist |
| extensionList.push_back(getUserRepository()->getDeployedPackage( |
| identifier, fileName, Reference<ucb::XCommandEnvironment>())); |
| } |
| catch(lang::IllegalArgumentException &) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| // catch deploy::DeploymentException and ucb::CommandFailedException to avoid unhandled exceptions causing crashes |
| catch( deploy::DeploymentException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| catch( ucb::CommandFailedException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| |
| try |
| { |
| extensionList.push_back(getSharedRepository()->getDeployedPackage( |
| identifier, fileName, Reference<ucb::XCommandEnvironment>())); |
| } |
| catch (lang::IllegalArgumentException &) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| // catch deploy::DeploymentException and ucb::CommandFailedException to avoid unhandled exceptions causing crashes |
| catch( deploy::DeploymentException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| catch( ucb::CommandFailedException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| |
| try |
| { |
| extensionList.push_back(getBundledRepository()->getDeployedPackage( |
| identifier, fileName, Reference<ucb::XCommandEnvironment>())); |
| } |
| catch (lang::IllegalArgumentException &) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| // catch deploy::DeploymentException and ucb::CommandFailedException to avoid unhandled exceptions causing crashes |
| catch( deploy::DeploymentException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| catch( ucb::CommandFailedException & ) |
| { |
| extensionList.push_back(Reference<deploy::XPackage>()); |
| } |
| |
| OSL_ASSERT(extensionList.size() == 3); |
| return extensionList; |
| } |
| |
| uno::Sequence<Reference<deploy::XPackage> > |
| ExtensionManager::getExtensionsWithSameIdentifier( |
| OUString const & identifier, |
| OUString const & fileName, |
| Reference< ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw ( |
| deploy::DeploymentException, |
| ucb::CommandFailedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| try |
| { |
| ::std::list<Reference<deploy::XPackage> > listExtensions = |
| getExtensionsWithSameId( |
| identifier, fileName, xCmdEnv); |
| sal_Bool bHasExtension = false; |
| |
| //throw an IllegalArgumentException if there is no extension at all. |
| typedef ::std::list<Reference<deploy::XPackage> >::const_iterator CIT; |
| for (CIT i = listExtensions.begin(); i != listExtensions.end(); i++) |
| bHasExtension |= i->is(); |
| if (!bHasExtension) |
| throw lang::IllegalArgumentException( |
| OUSTR("Could not find extension: ") + identifier + OUSTR(", ") + fileName, |
| static_cast<cppu::OWeakObject*>(this), -1); |
| |
| return comphelper::containerToSequence< |
| Reference<deploy::XPackage>, |
| ::std::list<Reference<deploy::XPackage> > |
| > (listExtensions); |
| } |
| catch (deploy::DeploymentException & ) |
| { |
| throw; |
| } |
| catch ( ucb::CommandFailedException & ) |
| { |
| throw; |
| } |
| catch (lang::IllegalArgumentException &) |
| { |
| throw; |
| } |
| catch (...) |
| { |
| uno::Any exc = ::cppu::getCaughtException(); |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: exception during getExtensionsWithSameIdentifier"), |
| static_cast<OWeakObject*>(this), exc); |
| } |
| } |
| |
| |
| |
| bool ExtensionManager::isUserDisabled( |
| OUString const & identifier, OUString const & fileName) |
| { |
| ::std::list<Reference<deploy::XPackage> > listExtensions; |
| |
| try { |
| listExtensions = getExtensionsWithSameId(identifier, fileName); |
| } catch (lang::IllegalArgumentException & ) { |
| } |
| OSL_ASSERT(listExtensions.size() == 3); |
| |
| return isUserDisabled( ::comphelper::containerToSequence< |
| Reference<deploy::XPackage>, |
| ::std::list<Reference<deploy::XPackage> > |
| > (listExtensions)); |
| } |
| |
| bool ExtensionManager::isUserDisabled( |
| uno::Sequence<Reference<deploy::XPackage> > const & seqExtSameId) |
| { |
| OSL_ASSERT(seqExtSameId.getLength() == 3); |
| Reference<deploy::XPackage> const & userExtension = seqExtSameId[0]; |
| if (userExtension.is()) |
| { |
| beans::Optional<beans::Ambiguous<sal_Bool> > reg = |
| userExtension->isRegistered(Reference<task::XAbortChannel>(), |
| Reference<ucb::XCommandEnvironment>()); |
| //If the value is ambiguous is than we assume that the extension |
| //is enabled, but something went wrong during enabling. We do not |
| //automatically disable user extensions. |
| if (reg.IsPresent && |
| ! reg.Value.IsAmbiguous && ! reg.Value.Value) |
| return true; |
| } |
| return false; |
| } |
| |
| /* |
| This method determines the active extension (XPackage.registerPackage) with a |
| particular identifier. |
| |
| The parameter bUserDisabled determines if the user extension is disabled. |
| |
| When the user repository contains an extension with the given identifier and |
| it is not disabled by the user, then it is always registered. Otherwise an |
| extension is only registered when there is no registered extension in one of |
| the repositories with a higher priority. That is, if the extension is from |
| the shared repository and an active extension with the same identifer is in |
| the user repository, then the extension is not registered. Similarly a |
| bundled extension is not registered if there is an active extension with the |
| same identifier in the shared or user repository. |
| */ |
| void ExtensionManager::activateExtension( |
| OUString const & identifier, OUString const & fileName, |
| bool bUserDisabled, |
| bool bStartup, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| { |
| ::std::list<Reference<deploy::XPackage> > listExtensions; |
| try { |
| listExtensions = getExtensionsWithSameId(identifier, fileName); |
| } catch (lang::IllegalArgumentException &) { |
| } |
| OSL_ASSERT(listExtensions.size() == 3); |
| |
| activateExtension( |
| ::comphelper::containerToSequence< |
| Reference<deploy::XPackage>, |
| ::std::list<Reference<deploy::XPackage> > |
| > (listExtensions), |
| bUserDisabled, bStartup, xAbortChannel, xCmdEnv); |
| |
| fireModified(); |
| } |
| |
| void ExtensionManager::activateExtension( |
| uno::Sequence<Reference<deploy::XPackage> > const & seqExt, |
| bool bUserDisabled, |
| bool bStartup, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| { |
| bool bActive = false; |
| sal_Int32 len = seqExt.getLength(); |
| for (sal_Int32 i = 0; i < len; i++) |
| { |
| Reference<deploy::XPackage> const & aExt = seqExt[i]; |
| if (aExt.is()) |
| { |
| //get the registration value of the current iteration |
| beans::Optional<beans::Ambiguous<sal_Bool> > optReg = |
| aExt->isRegistered(xAbortChannel, xCmdEnv); |
| //If nothing can be registered then break |
| if (!optReg.IsPresent) |
| break; |
| |
| //Check if this is a disabled user extension, |
| if (i == 0 && bUserDisabled) |
| { |
| aExt->revokePackage(xAbortChannel, xCmdEnv); |
| continue; |
| } |
| |
| //If we have already determined an active extension then we must |
| //make sure to unregister all extensions with the same id in |
| //repositories with a lower priority |
| if (bActive) |
| { |
| aExt->revokePackage(xAbortChannel, xCmdEnv); |
| } |
| else |
| { |
| //This is the first extension in the ordered list, which becomes |
| //the active extension |
| bActive = true; |
| //Register if not already done. |
| //reregister if the value is ambiguous, which indicates that |
| //something went wrong during last registration. |
| aExt->registerPackage(bStartup, xAbortChannel, xCmdEnv); |
| } |
| } |
| } |
| } |
| |
| Reference<deploy::XPackage> ExtensionManager::backupExtension( |
| OUString const & identifier, OUString const & fileName, |
| Reference<deploy::XPackageManager> const & xPackageManager, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| { |
| Reference<deploy::XPackage> xBackup; |
| Reference<ucb::XCommandEnvironment> tmpCmdEnv( |
| new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler())); |
| Reference<deploy::XPackage> xOldExtension; |
| xOldExtension = xPackageManager->getDeployedPackage( |
| identifier, fileName, tmpCmdEnv); |
| |
| if (xOldExtension.is()) |
| { |
| xBackup = getTmpRepository()->addPackage( |
| xOldExtension->getURL(), uno::Sequence<beans::NamedValue>(), |
| OUString(), Reference<task::XAbortChannel>(), tmpCmdEnv); |
| |
| OSL_ENSURE(xBackup.is(), "Failed to backup extension"); |
| } |
| return xBackup; |
| } |
| |
| //The supported package types are actually determined by the registry. However |
| //creating a registry |
| //(desktop/source/deployment/registry/dp_registry.cxx:PackageRegistryImpl) will |
| //create all the backends, so that the registry can obtain from them the package |
| //types. Creating the registry will also set up the registry folder containing |
| //all the subfolders for the respective backends. |
| //Because all repositories support the same backends, we can just delegate this |
| //call to one of the repositories. |
| uno::Sequence< Reference<deploy::XPackageTypeInfo> > |
| ExtensionManager::getSupportedPackageTypes() |
| throw (uno::RuntimeException) |
| { |
| return getUserRepository()->getSupportedPackageTypes(); |
| } |
| //Do some necessary checks and user interaction. This function does not |
| //acquire the extension manager mutex and that mutex must not be acquired |
| //when this function is called. doChecksForAddExtension does synchronous |
| //user interactions which may require acquiring 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( |
| OUString const & url, uno::Sequence<beans::NamedValue> const & properties, |
| OUString const & repository, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| Reference<deploy::XPackage> xNewExtension; |
| //Determine the repository to use |
| Reference<deploy::XPackageManager> xPackageManager; |
| if (repository.equals(OUSTR("user"))) |
| xPackageManager = getUserRepository(); |
| else if (repository.equals(OUSTR("shared"))) |
| xPackageManager = getSharedRepository(); |
| else |
| throw lang::IllegalArgumentException( |
| OUSTR("No valid repository name provided."), |
| static_cast<cppu::OWeakObject*>(this), 0); |
| //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, getTmpRepository()); |
| ExtensionRemoveGuard bakExtensionRemoveGuard; |
| const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); |
| const OUString sFileName = xTmpExtension->getName(); |
| Reference<deploy::XPackage> xOldExtension; |
| Reference<deploy::XPackage> xExtensionBackup; |
| |
| uno::Any excOccurred2; |
| bool bUserDisabled = false; |
| bool bCanInstall = doChecksForAddExtension( |
| xPackageManager, |
| properties, |
| xTmpExtension, |
| xAbortChannel, |
| xCmdEnv, |
| xOldExtension ); |
| |
| { |
| // 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) |
| { |
| try |
| { |
| bUserDisabled = isUserDisabled(sIdentifier, sFileName); |
| if (xOldExtension.is()) |
| { |
| try |
| { |
| xOldExtension->revokePackage( |
| xAbortChannel, Reference<ucb::XCommandEnvironment>()); |
| //save the old user extension in case the user aborts |
| xExtensionBackup = getBakRepository()->importExtension( |
| xOldExtension, Reference<task::XAbortChannel>(), |
| Reference<ucb::XCommandEnvironment>()); |
| bakExtensionRemoveGuard.set(xExtensionBackup, getBakRepository()); |
| } |
| 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; |
| |
| ::rtl::OUString const name(xNewExtension->getName()); |
| activateExtension( |
| dp_misc::getIdentifier(xNewExtension), |
| name, 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()); |
| } |
| } |
| 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; |
| } |
| } |
| |
| 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 |
| { |
| 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 (...) |
| { |
| } |
| ::cppu::throwException(excOccurred2); |
| } |
| } // leaving the garded section (getMutex()) |
| |
| try |
| { |
| fireModified(); |
| |
| }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)); |
| } |
| |
| return xNewExtension; |
| } |
| |
| void ExtensionManager::removeExtension( |
| OUString const & identifier, OUString const & fileName, |
| OUString const & repository, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| uno::Any excOccurred1; |
| Reference<deploy::XPackage> xExtensionBackup; |
| Reference<deploy::XPackageManager> xPackageManager; |
| bool bUserDisabled = false; |
| ::osl::MutexGuard guard(getMutex()); |
| try |
| { |
| //Determine the repository to use |
| if (repository.equals(OUSTR("user"))) |
| xPackageManager = getUserRepository(); |
| else if (repository.equals(OUSTR("shared"))) |
| xPackageManager = getSharedRepository(); |
| else |
| throw lang::IllegalArgumentException( |
| OUSTR("No valid repository name provided."), |
| static_cast<cppu::OWeakObject*>(this), 0); |
| |
| bUserDisabled = isUserDisabled(identifier, fileName); |
| //Backup the extension, in case the user cancels the action |
| xExtensionBackup = backupExtension( |
| identifier, fileName, xPackageManager, xCmdEnv); |
| |
| //revoke the extension if it is active |
| Reference<deploy::XPackage> xOldExtension = |
| xPackageManager->getDeployedPackage( |
| identifier, fileName, xCmdEnv); |
| xOldExtension->revokePackage(xAbortChannel, xCmdEnv); |
| |
| xPackageManager->removePackage( |
| identifier, fileName, xAbortChannel, xCmdEnv); |
| activateExtension(identifier, fileName, bUserDisabled, false, |
| xAbortChannel, xCmdEnv); |
| fireModified(); |
| } |
| 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 removeEtension"), |
| static_cast<OWeakObject*>(this), excOccurred1); |
| excOccurred1 <<= exc; |
| } |
| |
| if (excOccurred1.hasValue()) |
| { |
| //User aborted installation, restore the previous situation. |
| //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( |
| identifier, fileName, bUserDisabled, false, |
| Reference<task::XAbortChannel>(), |
| tmpCmdEnv); |
| |
| getTmpRepository()->removePackage( |
| dp_misc::getIdentifier(xExtensionBackup), |
| xExtensionBackup->getName(), xAbortChannel, xCmdEnv); |
| fireModified(); |
| } |
| } |
| catch (...) |
| { |
| } |
| ::cppu::throwException(excOccurred1); |
| } |
| |
| if (xExtensionBackup.is()) |
| getTmpRepository()->removePackage( |
| dp_misc::getIdentifier(xExtensionBackup), |
| xExtensionBackup->getName(), xAbortChannel, xCmdEnv); |
| } |
| |
| // Only enable extensions from shared and user repository |
| void ExtensionManager::enableExtension( |
| Reference<deploy::XPackage> const & extension, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| ::osl::MutexGuard guard(getMutex()); |
| bool bUserDisabled = false; |
| uno::Any excOccurred; |
| try |
| { |
| if (!extension.is()) |
| return; |
| OUString repository = extension->getRepositoryName(); |
| if (!repository.equals(OUSTR("user"))) |
| throw lang::IllegalArgumentException( |
| OUSTR("No valid repository name provided."), |
| static_cast<cppu::OWeakObject*>(this), 0); |
| |
| bUserDisabled = isUserDisabled(dp_misc::getIdentifier(extension), |
| extension->getName()); |
| |
| activateExtension(dp_misc::getIdentifier(extension), |
| extension->getName(), false, false, |
| xAbortChannel, xCmdEnv); |
| } |
| catch (deploy::DeploymentException& ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (ucb::CommandFailedException & ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (ucb::CommandAbortedException & ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (lang::IllegalArgumentException &) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (uno::RuntimeException &) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (...) { |
| excOccurred = ::cppu::getCaughtException(); |
| deploy::DeploymentException exc( |
| OUSTR("Extension Manager: exception during enableExtension"), |
| static_cast<OWeakObject*>(this), excOccurred); |
| excOccurred <<= exc; |
| } |
| |
| if (excOccurred.hasValue()) |
| { |
| try |
| { |
| activateExtension(dp_misc::getIdentifier(extension), |
| extension->getName(), bUserDisabled, false, |
| xAbortChannel, xCmdEnv); |
| } |
| catch (...) |
| { |
| } |
| ::cppu::throwException(excOccurred); |
| } |
| } |
| |
| /** |
| */ |
| sal_Int32 ExtensionManager::checkPrerequisitesAndEnable( |
| Reference<deploy::XPackage> const & extension, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| try |
| { |
| if (!extension.is()) |
| return 0; |
| ::osl::MutexGuard guard(getMutex()); |
| sal_Int32 ret = 0; |
| Reference<deploy::XPackageManager> mgr = |
| getPackageManager(extension->getRepositoryName()); |
| ret = mgr->checkPrerequisites(extension, xAbortChannel, xCmdEnv); |
| if (ret) |
| { |
| //There are some unfulfilled prerequisites, try to revoke |
| extension->revokePackage(xAbortChannel, xCmdEnv); |
| } |
| const OUString id(dp_misc::getIdentifier(extension)); |
| activateExtension(id, extension->getName(), |
| isUserDisabled(id, extension->getName()), false, |
| xAbortChannel, xCmdEnv); |
| return ret; |
| } |
| catch (deploy::DeploymentException& ) { |
| throw; |
| } catch (ucb::CommandFailedException & ) { |
| throw; |
| } catch (ucb::CommandAbortedException & ) { |
| throw; |
| } catch (lang::IllegalArgumentException &) { |
| throw; |
| } catch (uno::RuntimeException &) { |
| throw; |
| } catch (...) { |
| uno::Any excOccurred = ::cppu::getCaughtException(); |
| deploy::DeploymentException exc( |
| OUSTR("Extension Manager: exception during disableExtension"), |
| static_cast<OWeakObject*>(this), excOccurred); |
| throw exc; |
| } |
| } |
| |
| |
| void ExtensionManager::disableExtension( |
| Reference<deploy::XPackage> const & extension, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| ::osl::MutexGuard guard(getMutex()); |
| uno::Any excOccurred; |
| bool bUserDisabled = false; |
| try |
| { |
| if (!extension.is()) |
| return; |
| const OUString repository( extension->getRepositoryName()); |
| if (!repository.equals(OUSTR("user"))) |
| throw lang::IllegalArgumentException( |
| OUSTR("No valid repository name provided."), |
| static_cast<cppu::OWeakObject*>(this), 0); |
| |
| const OUString id(dp_misc::getIdentifier(extension)); |
| bUserDisabled = isUserDisabled(id, extension->getName()); |
| |
| activateExtension(id, extension->getName(), true, false, |
| xAbortChannel, xCmdEnv); |
| } |
| catch (deploy::DeploymentException& ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (ucb::CommandFailedException & ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (ucb::CommandAbortedException & ) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (lang::IllegalArgumentException &) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (uno::RuntimeException &) { |
| excOccurred = ::cppu::getCaughtException(); |
| } catch (...) { |
| excOccurred = ::cppu::getCaughtException(); |
| deploy::DeploymentException exc( |
| OUSTR("Extension Manager: exception during disableExtension"), |
| static_cast<OWeakObject*>(this), excOccurred); |
| excOccurred <<= exc; |
| } |
| |
| if (excOccurred.hasValue()) |
| { |
| try |
| { |
| activateExtension(dp_misc::getIdentifier(extension), |
| extension->getName(), bUserDisabled, false, |
| xAbortChannel, xCmdEnv); |
| } |
| catch (...) |
| { |
| } |
| ::cppu::throwException(excOccurred); |
| } |
| } |
| |
| uno::Sequence< Reference<deploy::XPackage> > |
| ExtensionManager::getDeployedExtensions( |
| OUString const & repository, |
| Reference<task::XAbortChannel> const &xAbort, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| return getPackageManager(repository)->getDeployedPackages( |
| xAbort, xCmdEnv); |
| } |
| |
| Reference<deploy::XPackage> |
| ExtensionManager::getDeployedExtension( |
| OUString const & repository, |
| OUString const & identifier, |
| OUString const & filename, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| return getPackageManager(repository)->getDeployedPackage( |
| identifier, filename, xCmdEnv); |
| } |
| |
| uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > |
| ExtensionManager::getAllExtensions( |
| Reference<task::XAbortChannel> const & xAbort, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| try |
| { |
| id2extensions mapExt; |
| |
| uno::Sequence<Reference<deploy::XPackage> > userExt = |
| getUserRepository()->getDeployedPackages(xAbort, xCmdEnv); |
| addExtensionsToMap(mapExt, userExt, OUSTR("user")); |
| uno::Sequence<Reference<deploy::XPackage> > sharedExt = |
| getSharedRepository()->getDeployedPackages(xAbort, xCmdEnv); |
| addExtensionsToMap(mapExt, sharedExt, OUSTR("shared")); |
| uno::Sequence<Reference<deploy::XPackage> > bundledExt = |
| getBundledRepository()->getDeployedPackages(xAbort, xCmdEnv); |
| addExtensionsToMap(mapExt, bundledExt, OUSTR("bundled")); |
| |
| // Create the tmp repository to trigger its clean up (deletion |
| // of old temporary data.) |
| getTmpRepository(); |
| |
| //copy the values of the map to a vector for sorting |
| ::std::vector< ::std::vector<Reference<deploy::XPackage> > > |
| vecExtensions; |
| id2extensions::const_iterator mapIt = mapExt.begin(); |
| for (;mapIt != mapExt.end(); mapIt++) |
| vecExtensions.push_back(mapIt->second); |
| |
| //sort the element according to the identifier |
| ::std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers()); |
| |
| ::std::vector< ::std::vector<Reference<deploy::XPackage> > >::const_iterator |
| citVecVec = vecExtensions.begin(); |
| sal_Int32 j = 0; |
| uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > seqSeq(vecExtensions.size()); |
| for (;citVecVec != vecExtensions.end(); citVecVec++, j++) |
| { |
| seqSeq[j] = comphelper::containerToSequence(*citVecVec); |
| } |
| return seqSeq; |
| |
| } catch (deploy::DeploymentException& ) { |
| throw; |
| } catch (ucb::CommandFailedException & ) { |
| throw; |
| } catch (ucb::CommandAbortedException & ) { |
| throw; |
| } catch (lang::IllegalArgumentException &) { |
| throw; |
| } catch (uno::RuntimeException &) { |
| throw; |
| } catch (...) { |
| uno::Any exc = ::cppu::getCaughtException(); |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: exception during enableExtension"), |
| static_cast<OWeakObject*>(this), exc); |
| } |
| } |
| |
| //only to be called from unopkg!!! |
| void ExtensionManager::reinstallDeployedExtensions( |
| OUString const & repository, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, ucb::CommandAbortedException, |
| lang::IllegalArgumentException, uno::RuntimeException) |
| { |
| try |
| { |
| Reference<deploy::XPackageManager> |
| xPackageManager = getPackageManager(repository); |
| |
| ::osl::MutexGuard guard(getMutex()); |
| xPackageManager->reinstallDeployedPackages(xAbortChannel, xCmdEnv); |
| //We must sync here, otherwise we will get exceptions when extensions |
| //are removed. |
| dp_misc::syncRepositories(xCmdEnv); |
| const uno::Sequence< Reference<deploy::XPackage> > extensions( |
| xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv)); |
| |
| for ( sal_Int32 pos = 0; pos < extensions.getLength(); ++pos ) |
| { |
| try |
| { |
| const OUString id = dp_misc::getIdentifier(extensions[ pos ]); |
| const OUString fileName = extensions[ pos ]->getName(); |
| OSL_ASSERT(id.getLength()); |
| activateExtension(id, fileName, false, true, xAbortChannel, xCmdEnv ); |
| } |
| catch (lang::DisposedException &) |
| { |
| } |
| } |
| } catch (deploy::DeploymentException& ) { |
| throw; |
| } catch (ucb::CommandFailedException & ) { |
| throw; |
| } catch (ucb::CommandAbortedException & ) { |
| throw; |
| } catch (lang::IllegalArgumentException &) { |
| throw; |
| } catch (uno::RuntimeException &) { |
| throw; |
| } catch (...) { |
| uno::Any exc = ::cppu::getCaughtException(); |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: exception during enableExtension"), |
| static_cast<OWeakObject*>(this), exc); |
| } |
| } |
| |
| /** Works on the bundled repository. That is using the variables |
| BUNDLED_EXTENSIONS and BUNDLED_EXTENSIONS_USER. |
| */ |
| void ExtensionManager::synchronizeBundledPrereg( |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| uno::RuntimeException) |
| { |
| try |
| { |
| String sSynchronizingBundled(StrSyncRepository::get()); |
| sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled")); |
| dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled); |
| |
| Reference<deploy::XPackageManagerFactory> xPackageManagerFactory( |
| deploy::thePackageManagerFactory::get(m_xContext)); |
| |
| Reference<deploy::XPackageManager> xMgr = |
| xPackageManagerFactory->getPackageManager(OUSTR("bundled_prereg")); |
| xMgr->synchronize(xAbortChannel, xCmdEnv); |
| progressBundled.update(OUSTR("\n\n")); |
| |
| uno::Sequence<Reference<deploy::XPackage> > extensions = xMgr->getDeployedPackages( |
| xAbortChannel, xCmdEnv); |
| try |
| { |
| for (sal_Int32 i = 0; i < extensions.getLength(); i++) |
| { |
| extensions[i]->registerPackage(true, xAbortChannel, xCmdEnv); |
| } |
| } |
| catch (...) |
| { |
| OSL_ASSERT(0); |
| } |
| OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM( |
| "$BUNDLED_EXTENSIONS_PREREG/lastsynchronized")); |
| writeLastModified(lastSyncBundled, xCmdEnv); |
| |
| } catch (deploy::DeploymentException& ) { |
| throw; |
| } catch (ucb::CommandFailedException & ) { |
| throw; |
| } catch (ucb::CommandAbortedException & ) { |
| throw; |
| } catch (lang::IllegalArgumentException &) { |
| throw; |
| } catch (uno::RuntimeException &) { |
| throw; |
| } catch (...) { |
| uno::Any exc = ::cppu::getCaughtException(); |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: exception in synchronize"), |
| static_cast<OWeakObject*>(this), exc); |
| } |
| } |
| |
| sal_Bool ExtensionManager::synchronize( |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| throw (deploy::DeploymentException, |
| ucb::CommandFailedException, |
| ucb::CommandAbortedException, |
| lang::IllegalArgumentException, |
| uno::RuntimeException) |
| { |
| try |
| { |
| sal_Bool bModified = sal_False; |
| |
| ::osl::MutexGuard guard(getMutex()); |
| String sSynchronizingShared(StrSyncRepository::get()); |
| sSynchronizingShared.SearchAndReplaceAllAscii( "%NAME", OUSTR("shared")); |
| dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared); |
| bModified = getSharedRepository()->synchronize(xAbortChannel, xCmdEnv); |
| progressShared.update(OUSTR("\n\n")); |
| |
| String sSynchronizingBundled(StrSyncRepository::get()); |
| sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled")); |
| dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled); |
| bModified |= getBundledRepository()->synchronize(xAbortChannel, xCmdEnv); |
| progressBundled.update(OUSTR("\n\n")); |
| |
| //Always determine the active extension. This is necessary for the |
| //first-start optimization. The setup creates the registration data for the |
| //bundled extensions (brand_layer/share/prereg/bundled), which is copied to the user |
| //installation (user_installation/extension/bundled) when a user starts OOo |
| //for the first time after running setup. All bundled extensions are registered |
| //at that moment. However, extensions with the same identifier can be in the |
| //shared or user repository, in which case the respective bundled extensions must |
| //be revoked. |
| try |
| { |
| const uno::Sequence<uno::Sequence<Reference<deploy::XPackage> > > |
| seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv); |
| for (sal_Int32 i = 0; i < seqSeqExt.getLength(); i++) |
| { |
| uno::Sequence<Reference<deploy::XPackage> > const & seqExt = |
| seqSeqExt[i]; |
| activateExtension(seqExt, isUserDisabled(seqExt), true, |
| xAbortChannel, xCmdEnv); |
| } |
| } |
| catch (...) |
| { |
| //We catch the exception, so we can write the lastmodified file |
| //so we will no repeat this every time AOO starts. |
| OSL_ENSURE(0, "Extensions Manager: synchronize"); |
| } |
| OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM( |
| "$BUNDLED_EXTENSIONS_USER/lastsynchronized")); |
| writeLastModified(lastSyncBundled, xCmdEnv); |
| OUString lastSyncShared(RTL_CONSTASCII_USTRINGPARAM( |
| "$SHARED_EXTENSIONS_USER/lastsynchronized")); |
| writeLastModified(lastSyncShared, xCmdEnv); |
| return bModified; |
| } catch (deploy::DeploymentException& ) { |
| throw; |
| } catch (ucb::CommandFailedException & ) { |
| throw; |
| } catch (ucb::CommandAbortedException & ) { |
| throw; |
| } catch (lang::IllegalArgumentException &) { |
| throw; |
| } catch (uno::RuntimeException &) { |
| throw; |
| } catch (...) { |
| uno::Any exc = ::cppu::getCaughtException(); |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: exception in synchronize"), |
| static_cast<OWeakObject*>(this), exc); |
| } |
| } |
| |
| // Notify the user when a new extension is to be installed. This is only the |
| // case when one uses the system integration to install an extension (double |
| // clicking on .oxt file etc.)). The function must only be called if there is no |
| // extension with the same identifier already deployed. Then the checkUpdate |
| // function will inform the user that the extension is about to be installed In |
| // case the user cancels the installation a CommandFailed exception is |
| // thrown. |
| void ExtensionManager::checkInstall( |
| OUString const & displayName, |
| Reference<ucb::XCommandEnvironment> const & cmdEnv) |
| { |
| uno::Any request( |
| deploy::InstallException( |
| OUSTR("Extension ") + displayName + |
| OUSTR(" is about to be installed."), |
| static_cast<OWeakObject *>(this), displayName)); |
| bool approve = false, abort = false; |
| if (! dp_misc::interactContinuation( |
| request, task::XInteractionApprove::static_type(), |
| cmdEnv, &approve, &abort )) |
| { |
| OSL_ASSERT( !approve && !abort ); |
| throw deploy::DeploymentException( |
| dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, |
| static_cast<OWeakObject *>(this), request ); |
| } |
| if (abort || !approve) |
| throw ucb::CommandFailedException( |
| dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, |
| static_cast<OWeakObject *>(this), request ); |
| } |
| |
| /* The function will make the user interaction in case there is an extension |
| installed with the same id. This function may only be called if there is already |
| an extension. |
| */ |
| void ExtensionManager::checkUpdate( |
| OUString const & newVersion, |
| OUString const & newDisplayName, |
| Reference<deploy::XPackage> const & oldExtension, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv ) |
| { |
| // package already deployed, interact --force: |
| uno::Any request( |
| (deploy::VersionException( |
| dp_misc::getResourceString( |
| RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName, |
| static_cast<OWeakObject *>(this), newVersion, newDisplayName, |
| oldExtension ) ) ); |
| bool replace = false, abort = false; |
| if (! dp_misc::interactContinuation( |
| request, task::XInteractionApprove::static_type(), |
| xCmdEnv, &replace, &abort )) { |
| OSL_ASSERT( !replace && !abort ); |
| throw deploy::DeploymentException( |
| dp_misc::getResourceString( |
| RID_STR_ERROR_WHILE_ADDING) + newDisplayName, |
| static_cast<OWeakObject *>(this), request ); |
| } |
| if (abort || !replace) |
| throw ucb::CommandFailedException( |
| dp_misc::getResourceString( |
| RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName, |
| static_cast<OWeakObject *>(this), request ); |
| } |
| |
| Reference<deploy::XPackage> ExtensionManager::getTempExtension( |
| OUString const & url, |
| Reference<task::XAbortChannel> const & xAbortChannel, |
| Reference<ucb::XCommandEnvironment> const & /*xCmdEnv*/) |
| |
| { |
| Reference<ucb::XCommandEnvironment> tmpCmdEnvA(new TmpRepositoryCommandEnv()); |
| Reference<deploy::XPackage> xTmpPackage = getTmpRepository()->addPackage( |
| url, uno::Sequence<beans::NamedValue>(),OUString(), xAbortChannel, tmpCmdEnvA); |
| if (!xTmpPackage.is()) |
| { |
| throw deploy::DeploymentException( |
| OUSTR("Extension Manager: Failed to create temporary XPackage for url: ") + url, |
| static_cast<OWeakObject*>(this), uno::Any()); |
| |
| } |
| return xTmpPackage; |
| } |
| |
| uno::Sequence<Reference<deploy::XPackage> > SAL_CALL |
| ExtensionManager::getExtensionsWithUnacceptedLicenses( |
| OUString const & repository, |
| Reference<ucb::XCommandEnvironment> const & xCmdEnv) |
| throw (deploy::DeploymentException, |
| uno::RuntimeException) |
| { |
| Reference<deploy::XPackageManager> |
| xPackageManager = getPackageManager(repository); |
| ::osl::MutexGuard guard(getMutex()); |
| return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv); |
| } |
| |
| sal_Bool ExtensionManager::isReadOnlyRepository(::rtl::OUString const & repository) |
| throw (uno::RuntimeException) |
| { |
| return getPackageManager(repository)->isReadOnly(); |
| } |
| //------------------------------------------------------------------------------ |
| //------------------------------------------------------------------------------ |
| //------------------------------------------------------------------------------ |
| |
| namespace sdecl = comphelper::service_decl; |
| sdecl::class_<ExtensionManager> servicePIP; |
| extern sdecl::ServiceDecl const serviceDecl( |
| servicePIP, |
| // a private one: |
| "com.sun.star.comp.deployment.ExtensionManager", |
| "com.sun.star.comp.deployment.ExtensionManager"); |
| |
| //------------------------------------------------------------------------------ |
| bool singleton_entries( |
| uno::Reference< registry::XRegistryKey > const & xRegistryKey ) |
| { |
| try { |
| uno::Reference< registry::XRegistryKey > xKey( |
| xRegistryKey->createKey( |
| serviceDecl.getImplementationName() + |
| // xxx todo: use future generated function to get singleton name |
| OUSTR("/UNO/SINGLETONS/" |
| "com.sun.star.deployment.ExtensionManager") ) ); |
| xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] ); |
| return true; |
| } |
| catch (registry::InvalidRegistryException & exc) { |
| (void) exc; // avoid warnings |
| OSL_ENSURE( 0, ::rtl::OUStringToOString( |
| exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| return false; |
| } |
| } |
| |
| // XModifyBroadcaster |
| //______________________________________________________________________________ |
| void ExtensionManager::addModifyListener( |
| Reference<util::XModifyListener> const & xListener ) |
| throw (uno::RuntimeException) |
| { |
| check(); |
| rBHelper.addListener( ::getCppuType( &xListener ), xListener ); |
| } |
| |
| //______________________________________________________________________________ |
| void ExtensionManager::removeModifyListener( |
| Reference<util::XModifyListener> const & xListener ) |
| throw (uno::RuntimeException) |
| { |
| check(); |
| rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); |
| } |
| |
| void ExtensionManager::check() |
| { |
| ::osl::MutexGuard guard( getMutex() ); |
| if (rBHelper.bInDispose || rBHelper.bDisposed) { |
| throw lang::DisposedException( |
| OUSTR("ExtensionManager instance has already been disposed!"), |
| static_cast<OWeakObject *>(this) ); |
| } |
| } |
| |
| void ExtensionManager::fireModified() |
| { |
| ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer( |
| util::XModifyListener::static_type() ); |
| if (pContainer != 0) { |
| pContainer->forEach<util::XModifyListener>( |
| boost::bind(&util::XModifyListener::modified, _1, |
| lang::EventObject(static_cast<OWeakObject *>(this))) ); |
| } |
| } |
| |
| } // namespace dp_manager |
| |
| |