diff options
Diffstat (limited to 'desktop/source/deployment/registry')
50 files changed, 11151 insertions, 0 deletions
diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.cxx b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx new file mode 100644 index 000000000000..898e7c931f6d --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_compbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/component-registry/2010" +#define NS_PREFIX "comp" +#define ROOT_ELEMENT_NAME "component-backend-db" +#define KEY_ELEMENT_NAME "component" + +namespace dp_registry { +namespace backend { +namespace component { + +ComponentBackendDb::ComponentBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ComponentBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ComponentBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ComponentBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ComponentBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + +void ComponentBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> componentNode = writeKeyElement(url); + writeSimpleElement(OUSTR("java-type-library"), + OUString::valueOf((sal_Bool) data.javaTypeLibrary), + componentNode); + + writeSimpleList( + data.implementationNames, + OUSTR("implementation-names"), + OUSTR("name"), + componentNode); + + writeVectorOfPair( + data.singletons, + OUSTR("singletons"), + OUSTR("item"), + OUSTR("key"), + OUSTR("value"), + componentNode); + + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +ComponentBackendDb::Data ComponentBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ComponentBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + bool bJava = readSimpleElement(OUSTR("java-type-library"), aNode) + .equals(OUSTR("true")) ? true : false; + retData.javaTypeLibrary = bJava; + + retData.implementationNames = + readList( + aNode, + OUSTR("implementation-names"), + OUSTR("name")); + + retData.singletons = + readVectorOfPair( + aNode, + OUSTR("singletons"), + OUSTR("item"), + OUSTR("key"), + OUSTR("value")); + } + return retData; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.hxx b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx new file mode 100644 index 000000000000..b9a5ed737b7c --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_COMPBACKENDDB_HXX +#define INCLUDED_DP_COMPBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "rtl/string.hxx" +#include <vector> +#include <list> +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { +namespace component { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + The format looks like this: + +<?xml version="1.0"?> +<component-backend-db xmlns="http://openoffice.org/extensionmanager/component-registry/2010"> + <component url="vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages/5CD5.tmp_/leaves1.oxt/extensionoptions.jar"> + <name>FileName</name> + <java-type-library>true</java-type-library> + <implementation-names> + <name>com.sun.star.comp.extensionoptions.OptionsEventHandler$_OptionsEventHandler</name> + ... + </implementation-names> + <singletons> + <item> + <key>com.sun.star.java.theJavaVirtualMachine</key> + <value>com.sun.star.java.JavaVirtualMachine</value> + </item> + ... + </singletons> + </component> + + <component ...> + ... +</component-backend-db> + */ +class ComponentBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + virtual ::rtl::OUString getNSPrefix(); + virtual ::rtl::OUString getRootElementName(); + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + Data(): javaTypeLibrary(false) {}; + + ::std::list< ::rtl::OUString> implementationNames; + /* every singleton has a key and a value + */ + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> >singletons; + bool javaTypeLibrary; + }; + +public: + + ComponentBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + Data getEntry(::rtl::OUString const & url); + + +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/component/dp_component.cxx b/desktop/source/deployment/registry/component/dp_component.cxx new file mode 100644 index 000000000000..e0844c227669 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.cxx @@ -0,0 +1,1586 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_component.hrc" +#include "dp_backend.h" +#include "dp_platform.hxx" +#include "dp_ucb.h" +#include "rtl/string.hxx" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/sequence.hxx" +#include "xmlscript/xml_helper.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/container/XNameContainer.hpp" +#include "com/sun/star/container/XHierarchicalNameAccess.hpp" +#include "com/sun/star/container/XSet.hpp" +#include "com/sun/star/registry/XSimpleRegistry.hpp" +#include "com/sun/star/registry/XImplementationRegistration.hpp" +#include "com/sun/star/loader/XImplementationLoader.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/util/XMacroExpander.hpp" +#include <list> +#include <hash_map> +#include <vector> +#include <memory> +#include <algorithm> +#include "dp_compbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace component { +namespace { + +typedef ::std::list<OUString> t_stringlist; +typedef ::std::vector< ::std::pair<OUString, OUString> > t_stringpairvec; + +#define IMPLEMENTATION_NAME "com.sun.star.comp.deployment.component.PackageRegistryBackend" + +/** return a vector of bootstrap variables which have been provided + as command arguments. +*/ +::std::vector<OUString> getCmdBootstrapVariables() +{ + ::std::vector<OUString> ret; + sal_uInt32 count = osl_getCommandArgCount(); + for (sal_uInt32 i = 0; i < count; i++) + { + OUString arg; + osl_getCommandArg(i, &arg.pData); + if (arg.matchAsciiL("-env:", 5)) + ret.push_back(arg); + } + return ret; +} + +bool jarManifestHeaderPresent( + OUString const & url, OUString const & name, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); + buf.append( + ::rtl::Uri::encode( + url, rtl_UriCharClassRegName, rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("/META-INF/MANIFEST.MF") ); + ::ucbhelper::Content manifestContent; + OUString line; + return + create_ucb_content( + &manifestContent, buf.makeStringAndClear(), xCmdEnv, + false /* no throw */ ) + && readLine( &line, name, manifestContent, RTL_TEXTENCODING_ASCII_US ); +} + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class ComponentPackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const OUString m_loader; + ComponentBackendDb::Data m_registeredComponentsDb; + + enum reg { + REG_UNINIT, REG_VOID, REG_REGISTERED, REG_NOT_REGISTERED, REG_MAYBE_REGISTERED + } m_registered; + + Reference<loader::XImplementationLoader> getComponentInfo( + t_stringlist * pImplNames, t_stringpairvec * pSingletons, + Reference<XComponentContext> const & xContext ); + + virtual void SAL_CALL disposing(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + const Reference<registry::XSimpleRegistry> getRDB() const; + + //Provides the read-only registry (e.g. not the one based on the duplicated + //rdb files + const Reference<registry::XSimpleRegistry> getRDB_RO() const; + + public: + ComponentPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + OUString const & loader, bool bRemoved, + OUString const & identifier); + }; + friend class ComponentPackageImpl; + + class TypelibraryPackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const bool m_jarFile; + Reference<container::XHierarchicalNameAccess> m_xTDprov; + + virtual void SAL_CALL disposing(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + TypelibraryPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool jarFile, bool bRemoved, + OUString const & identifier); + }; + friend class TypelibraryPackageImpl; + + t_stringlist m_jar_typelibs; + t_stringlist m_rdb_typelibs; + t_stringlist & getTypelibs( bool jar ) { + return jar ? m_jar_typelibs : m_rdb_typelibs; + } + + bool m_unorc_inited; + bool m_unorc_modified; + bool bSwitchedRdbFiles; + + typedef ::std::hash_map< OUString, Reference<XInterface>, + ::rtl::OUStringHash > t_string2object; + t_string2object m_backendObjects; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + + const Reference<deployment::XPackageTypeInfo> m_xDynComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xPythonComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xRDBTypelibTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaTypelibTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + OUString m_commonRDB; + OUString m_nativeRDB; + + //URLs of the read-only rdbs (e.g. not the ones of the duplicated files) + OUString m_commonRDB_RO; + OUString m_nativeRDB_RO; + + std::auto_ptr<ComponentBackendDb> m_backendDb; + + void addDataToDb(OUString const & url, ComponentBackendDb::Data const & data); + void deleteDataFromDb(OUString const & url); + ComponentBackendDb::Data readDataFromDb(OUString const & url); + + + //These rdbs are for writing new service entries. The rdb files are copies + //which are created when services are added or removed. + Reference<registry::XSimpleRegistry> m_xCommonRDB; + Reference<registry::XSimpleRegistry> m_xNativeRDB; + + //These rdbs are created on the read-only rdbs which are already used + //by UNO since the startup of the current session. + Reference<registry::XSimpleRegistry> m_xCommonRDB_RO; + Reference<registry::XSimpleRegistry> m_xNativeRDB_RO; + + + void unorc_verify_init( Reference<XCommandEnvironment> const & xCmdEnv ); + void unorc_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + Reference<XInterface> getObject( OUString const & id ); + Reference<XInterface> insertObject( + OUString const & id, Reference<XInterface> const & xObject ); + void releaseObject( OUString const & id ); + + bool addToUnoRc( bool jarFile, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool removeFromUnoRc( bool jarFile, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool hasInUnoRc( bool jarFile, OUString const & url ); + + + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; + + //Will be called from ComponentPackageImpl + void initServiceRdbFiles(); + + //Creates the READ ONLY registries (m_xCommonRDB_RO,m_xNativeRDB_RO) + void initServiceRdbFiles_RO(); +}; + +//______________________________________________________________________________ + +BackendImpl::ComponentPackageImpl::ComponentPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + OUString const & loader, bool bRemoved, + OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_loader( loader ), + m_registered( REG_UNINIT ) +{ + if (bRemoved) + { + m_registeredComponentsDb = getMyBackend()->readDataFromDb(url); + } +} + + +const Reference<registry::XSimpleRegistry> +BackendImpl::ComponentPackageImpl::getRDB() const +{ + BackendImpl * that = getMyBackend(); + + //Late "initialization" of the services rdb files + //This is to prevent problems when running several + //instances of OOo with root rights in parallel. This + //would otherwise cause problems when copying the rdbs. + //See http://qa.openoffice.org/issues/show_bug.cgi?id=99257 + { + const ::osl::MutexGuard guard( getMutex() ); + if (!that->bSwitchedRdbFiles) + { + that->bSwitchedRdbFiles = true; + that->initServiceRdbFiles(); + } + } + if (m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.SharedLibrary") )) + return that->m_xNativeRDB; + else + return that->m_xCommonRDB; +} + +//Returns the read only RDB. +const Reference<registry::XSimpleRegistry> +BackendImpl::ComponentPackageImpl::getRDB_RO() const +{ + BackendImpl * that = getMyBackend(); + + if (m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.SharedLibrary") )) + return that->m_xNativeRDB_RO; + else + return that->m_xCommonRDB_RO; +} + +BackendImpl * BackendImpl::ComponentPackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //Throws a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<ComponentPackageImpl *>(this))); + } + return pBackend; +} + + +//______________________________________________________________________________ +void BackendImpl::ComponentPackageImpl::disposing() +{ +// m_xRemoteContext.clear(); + Package::disposing(); +} + +//______________________________________________________________________________ +void BackendImpl::TypelibraryPackageImpl::disposing() +{ + m_xTDprov.clear(); + Package::disposing(); +} + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + try { + m_backendObjects = t_string2object(); + if (m_xNativeRDB.is()) { + m_xNativeRDB->close(); + m_xNativeRDB.clear(); + } + if (m_xCommonRDB.is()) { + m_xCommonRDB->close(); + m_xCommonRDB.clear(); + } + unorc_flush( Reference<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing..."), + static_cast<OWeakObject *>(this), exc ); + } +} + + +void BackendImpl::initServiceRdbFiles() +{ + const Reference<XCommandEnvironment> xCmdEnv; + + ::ucbhelper::Content cacheDir( getCachePath(), xCmdEnv ); + ::ucbhelper::Content oldRDB; + // switch common rdb: + if (m_commonRDB_RO.getLength() > 0) + { + create_ucb_content( + &oldRDB, makeURL( getCachePath(), m_commonRDB_RO), + xCmdEnv, false /* no throw */ ); + } + m_commonRDB = m_commonRDB_RO.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("common.rdb") ) + ? OUSTR("common_.rdb") : OUSTR("common.rdb"); + if (oldRDB.get().is()) + { + if (! cacheDir.transferContent( + oldRDB, ::ucbhelper::InsertOperation_COPY, + m_commonRDB, NameClash::OVERWRITE )) + { + + throw RuntimeException( + OUSTR("UCB transferContent() failed!"), 0 ); + } + oldRDB = ::ucbhelper::Content(); + } + // switch native rdb: + if (m_nativeRDB_RO.getLength() > 0) + { + create_ucb_content( + &oldRDB, makeURL(getCachePath(), m_nativeRDB_RO), + xCmdEnv, false /* no throw */ ); + } + const OUString plt_rdb( getPlatformString() + OUSTR(".rdb") ); + const OUString plt_rdb_( getPlatformString() + OUSTR("_.rdb") ); + m_nativeRDB = m_nativeRDB_RO.equals( plt_rdb ) ? plt_rdb_ : plt_rdb; + if (oldRDB.get().is()) + { + if (! cacheDir.transferContent( + oldRDB, ::ucbhelper::InsertOperation_COPY, + m_nativeRDB, NameClash::OVERWRITE )) + throw RuntimeException( + OUSTR("UCB transferContent() failed!"), 0 ); + } + + // UNO is bootstrapped, flush for next process start: + m_unorc_modified = true; + unorc_flush( Reference<XCommandEnvironment>() ); + + + // common rdb for java, native rdb for shared lib components + if (m_commonRDB.getLength() > 0) { + m_xCommonRDB.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext ), UNO_QUERY_THROW ); + m_xCommonRDB->open( + makeURL( expandUnoRcUrl(getCachePath()), m_commonRDB ), +// m_readOnly, !m_readOnly ); + false, true); + } + if (m_nativeRDB.getLength() > 0) { + m_xNativeRDB.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext ), UNO_QUERY_THROW ); + m_xNativeRDB->open( + makeURL( expandUnoRcUrl(getCachePath()), m_nativeRDB ), +// m_readOnly, !m_readOnly ); + false, true); + } +} + +void BackendImpl::initServiceRdbFiles_RO() +{ + const Reference<XCommandEnvironment> xCmdEnv; + + // common rdb for java, native rdb for shared lib components + if (m_commonRDB_RO.getLength() > 0) + { + m_xCommonRDB_RO.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext), UNO_QUERY_THROW); + m_xCommonRDB_RO->open( + makeURL(expandUnoRcUrl(getCachePath()), m_commonRDB_RO), + sal_True, //read-only + sal_True); // create data source if necessary + } + if (m_nativeRDB_RO.getLength() > 0) + { + m_xNativeRDB_RO.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext), UNO_QUERY_THROW); + m_xNativeRDB_RO->open( + makeURL(expandUnoRcUrl(getCachePath()), m_nativeRDB_RO), + sal_True, //read-only + sal_True); // create data source if necessary + } +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_unorc_inited( false ), + m_unorc_modified( false ), + bSwitchedRdbFiles(false), + m_xDynComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=native;platform=") + + getPlatformString(), + OUSTR("*" SAL_DLLEXTENSION), + getResourceString(RID_STR_DYN_COMPONENT), + RID_IMG_COMPONENT, + RID_IMG_COMPONENT_HC ) ), + m_xJavaComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=Java"), + OUSTR("*.jar"), + getResourceString(RID_STR_JAVA_COMPONENT), + RID_IMG_JAVA_COMPONENT, + RID_IMG_JAVA_COMPONENT_HC ) ), + m_xPythonComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=Python"), + OUSTR("*.py"), + getResourceString( + RID_STR_PYTHON_COMPONENT), + RID_IMG_COMPONENT, + RID_IMG_COMPONENT_HC ) ), + m_xRDBTypelibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-typelibrary;" + "type=RDB"), + OUSTR("*.rdb"), + getResourceString(RID_STR_RDB_TYPELIB), + RID_IMG_TYPELIB, RID_IMG_TYPELIB_HC ) ), + m_xJavaTypelibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-typelibrary;" + "type=Java"), + OUSTR("*.jar"), + getResourceString(RID_STR_JAVA_TYPELIB), + RID_IMG_JAVA_TYPELIB, + RID_IMG_JAVA_TYPELIB_HC ) ), + m_typeInfos( 5 ) +{ + m_typeInfos[ 0 ] = m_xDynComponentTypeInfo; + m_typeInfos[ 1 ] = m_xJavaComponentTypeInfo; + m_typeInfos[ 2 ] = m_xPythonComponentTypeInfo; + m_typeInfos[ 3 ] = m_xRDBTypelibTypeInfo; + m_typeInfos[ 4 ] = m_xJavaTypelibTypeInfo; + + const Reference<XCommandEnvironment> xCmdEnv; + + if (transientMode()) + { + // in-mem rdbs: + // common rdb for java, native rdb for shared lib components + m_xCommonRDB.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xComponentContext ), UNO_QUERY_THROW ); + m_xCommonRDB->open( OUString() /* in-mem */, + false /* ! read-only */, true /* create */ ); + m_xNativeRDB.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xComponentContext ), UNO_QUERY_THROW ); + m_xNativeRDB->open( OUString() /* in-mem */, + false /* ! read-only */, true /* create */ ); + } + else + { + //do this before initServiceRdbFiles_RO, because it determines + //m_commonRDB and m_nativeRDB + unorc_verify_init( xCmdEnv ); + + initServiceRdbFiles_RO(); + + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ComponentBackendDb(getComponentContext(), dbFile)); + } +} + +void BackendImpl::addDataToDb( + OUString const & url, ComponentBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +ComponentBackendDb::Data BackendImpl::readDataFromDb(OUString const & url) +{ + ComponentBackendDb::Data data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType(mediaType_); + if (mediaType.getLength() == 0 || + mediaType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-component") ) || + mediaType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-typelibrary") )) + { + // detect exact media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION) )) + { + mediaType = OUSTR("application/vnd.sun.star.uno-component;" + "type=native;platform=") + + getPlatformString(); + } + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".jar") )) + { + if (jarManifestHeaderPresent( + url, OUSTR("RegistrationClassName"), xCmdEnv )) + mediaType = OUSTR( + "application/vnd.sun.star.uno-component;type=Java"); + if (mediaType.getLength() == 0) + mediaType = OUSTR( + "application/vnd.sun.star.uno-typelibrary;type=Java"); + } + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".py") )) + mediaType = + OUSTR("application/vnd.sun.star.uno-component;type=Python"); + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".rdb") )) + mediaType = + OUSTR("application/vnd.sun.star.uno-typelibrary;type=RDB"); + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.uno-component")) + { + // xxx todo: probe and evaluate component xml description + + INetContentTypeParameter const * param = params.find( + ByteString("platform") ); + if (param == 0 || platform_fits( param->m_sValue )) { + param = params.find( ByteString("type") ); + if (param != 0) + { + String const & value = param->m_sValue; + if (value.EqualsIgnoreCaseAscii("native")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xDynComponentTypeInfo, + OUSTR("com.sun.star.loader.SharedLibrary"), + bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Java")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xJavaComponentTypeInfo, + OUSTR("com.sun.star.loader.Java2"), + bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Python")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xPythonComponentTypeInfo, + OUSTR("com.sun.star.loader.Python"), + bRemoved, identifier); + } + } + } + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.uno-typelibrary")) + { + INetContentTypeParameter const * param = params.find( + ByteString("type") ); + if (param != 0) { + String const & value = param->m_sValue; + if (value.EqualsIgnoreCaseAscii("RDB")) + { + return new BackendImpl::TypelibraryPackageImpl( + this, url, name, m_xRDBTypelibTypeInfo, + false /* rdb */, bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Java")) { + return new BackendImpl::TypelibraryPackageImpl( + this, url, name, m_xJavaTypelibTypeInfo, + true /* jar */, bRemoved, identifier); + } + } + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +//______________________________________________________________________________ +void BackendImpl::unorc_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + const ::osl::MutexGuard guard( getMutex() ); + if (! m_unorc_inited) + { + // common rc: + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), OUSTR("unorc") ), + xCmdEnv, false /* no throw */ )) + { + OUString line; + if (readLine( &line, OUSTR("UNO_JAVA_CLASSPATH="), ucb_content, + RTL_TEXTENCODING_UTF8 )) + { + sal_Int32 index = sizeof ("UNO_JAVA_CLASSPATH=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (create_ucb_content( + 0, expandUnoRcTerm(token), xCmdEnv, + false /* no throw */ )) + { + //The jar file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the unorc + //After running XExtensionManager::synchronize, the unorc is + //cleaned up + m_jar_typelibs.push_back( token ); + } + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("UNO_TYPES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 index = sizeof ("UNO_TYPES=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (token[ 0 ] == '?') + token = token.copy( 1 ); + if (create_ucb_content( + 0, expandUnoRcTerm(token), xCmdEnv, + false /* no throw */ )) + { + //The RDB file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the unorc. + //After running XExtensionManager::synchronize, the unorc is + //cleaned up + m_rdb_typelibs.push_back( token ); + } + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("UNO_SERVICES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 start = sizeof ("UNO_SERVICES=?$ORIGIN/") - 1; + sal_Int32 sep = line.indexOf( ' ', start ); + OSL_ASSERT( sep > 0 ); + m_commonRDB_RO = line.copy( start, sep - start ); + } + + // native rc: + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), getPlatformString() + OUSTR("rc")), + xCmdEnv, false /* no throw */ )) { + if (readLine( &line, OUSTR("UNO_SERVICES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + m_nativeRDB_RO = line.copy( + sizeof ("UNO_SERVICES=?$ORIGIN/") - 1 ); + } + } + } + m_unorc_modified = false; + m_unorc_inited = true; + } +} + +//______________________________________________________________________________ +void BackendImpl::unorc_flush( Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + if (!m_unorc_inited || !m_unorc_modified) + return; + + ::rtl::OStringBuffer buf; + + buf.append(RTL_CONSTASCII_STRINGPARAM("ORIGIN=")); + OUString sOrigin = dp_misc::makeRcTerm(m_cachePath); + ::rtl::OString osOrigin = ::rtl::OUStringToOString(sOrigin, RTL_TEXTENCODING_UTF8); + buf.append(osOrigin); + buf.append(LF); + + if (! m_jar_typelibs.empty()) + { + t_stringlist::const_iterator iPos( m_jar_typelibs.begin() ); + t_stringlist::const_iterator const iEnd( m_jar_typelibs.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_JAVA_CLASSPATH=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + if (! m_rdb_typelibs.empty()) + { + t_stringlist::const_iterator iPos( m_rdb_typelibs.begin() ); + t_stringlist::const_iterator const iEnd( m_rdb_typelibs.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_TYPES=") ); + while (iPos != iEnd) { + buf.append( '?' ); + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + + // If we duplicated the common or native rdb then we must use those urls + //otherwise we use those of the original files. That is, m_commonRDB_RO and + //m_nativeRDB_RO; + OUString sCommonRDB(m_commonRDB.getLength() > 0 ? m_commonRDB : m_commonRDB_RO); + OUString sNativeRDB(m_nativeRDB.getLength() > 0 ? m_nativeRDB : m_nativeRDB_RO); + + if (sCommonRDB.getLength() > 0 || sNativeRDB.getLength() > 0) + { + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_SERVICES=?$ORIGIN/") ); + buf.append( ::rtl::OUStringToOString( + sCommonRDB, RTL_TEXTENCODING_ASCII_US ) ); + if (sNativeRDB.getLength() > 0) + { + buf.append( RTL_CONSTASCII_STRINGPARAM( + " ${$ORIGIN/${_OS}_${_ARCH}rc:UNO_SERVICES}") ); + buf.append(LF); + + // write native rc: + ::rtl::OStringBuffer buf2; + buf2.append(RTL_CONSTASCII_STRINGPARAM("ORIGIN=")); + buf2.append(osOrigin); + buf2.append(LF); + buf2.append( RTL_CONSTASCII_STRINGPARAM("UNO_SERVICES=?$ORIGIN/") ); + buf2.append( ::rtl::OUStringToOString( + sNativeRDB, RTL_TEXTENCODING_ASCII_US ) ); + buf2.append(LF); + + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf2.getStr()), + buf2.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), getPlatformString() + OUSTR("rc") ), + xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + } + } + + // write unorc: + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf.getStr()), + buf.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), OUSTR("unorc") ), xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + + m_unorc_modified = false; +} + +//______________________________________________________________________________ +bool BackendImpl::addToUnoRc( bool jarFile, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + t_stringlist & rSet = getTypelibs(jarFile); + if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { + rSet.push_front( rcterm ); // prepend to list, thus overriding + // write immediately: + m_unorc_modified = true; + unorc_flush( xCmdEnv ); + return true; + } + else + return false; +} + +//______________________________________________________________________________ +bool BackendImpl::removeFromUnoRc( + bool jarFile, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + getTypelibs(jarFile).remove( rcterm ); + // write immediately: + m_unorc_modified = true; + unorc_flush( xCmdEnv ); + return true; +} + +//______________________________________________________________________________ +bool BackendImpl::hasInUnoRc( + bool jarFile, OUString const & url_ ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + t_stringlist const & rSet = getTypelibs(jarFile); + return ::std::find( rSet.begin(), rSet.end(), rcterm ) != rSet.end(); +} + +//______________________________________________________________________________ +void BackendImpl::releaseObject( OUString const & id ) +{ + const ::osl::MutexGuard guard( getMutex() ); + if ( m_backendObjects.erase( id ) != 1 ) + { + OSL_ASSERT( false ); + } +} + +//______________________________________________________________________________ +Reference<XInterface> BackendImpl::getObject( OUString const & id ) +{ + const ::osl::MutexGuard guard( getMutex() ); + const t_string2object::const_iterator iFind( m_backendObjects.find( id ) ); + if (iFind == m_backendObjects.end()) + return Reference<XInterface>(); + else + return iFind->second; +} + +//______________________________________________________________________________ +Reference<XInterface> BackendImpl::insertObject( + OUString const & id, Reference<XInterface> const & xObject ) +{ + const ::osl::MutexGuard guard( getMutex() ); + const ::std::pair<t_string2object::iterator, bool> insertion( + m_backendObjects.insert( t_string2object::value_type( + id, xObject ) ) ); + return insertion.first->second; +} + +//------------------------------------------------------------------------------ +Reference<XComponentContext> raise_uno_process( + Reference<XComponentContext> const & xContext, + ::rtl::Reference<AbortChannel> const & abortChannel ) +{ + OSL_ASSERT( xContext.is() ); + + ::rtl::OUString url( + Reference<util::XMacroExpander>( + xContext->getValueByName( + OUSTR("/singletons/com.sun.star.util.theMacroExpander") ), + UNO_QUERY_THROW )-> + expandMacros( OUSTR("$URE_BIN_DIR/uno") ) ); + + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("uno:pipe,name=") ); + OUString pipeId( generateRandomPipeId() ); + buf.append( pipeId ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM(";urp;uno.ComponentContext") ); + const OUString connectStr( buf.makeStringAndClear() ); + + // raise core UNO process to register/run a component, + // javavm service uses unorc next to executable to retrieve deployed + // jar typelibs + + ::std::vector<OUString> args; +#if OSL_DEBUG_LEVEL <= 1 + args.push_back( OUSTR("--quiet") ); +#endif + args.push_back( OUSTR("--singleaccept") ); + args.push_back( OUSTR("-u") ); + args.push_back( connectStr ); + // don't inherit from unorc: + args.push_back( OUSTR("-env:INIFILENAME=") ); + + //now add the bootstrap variables which were supplied on the command line + ::std::vector<OUString> bootvars = getCmdBootstrapVariables(); + args.insert(args.end(), bootvars.begin(), bootvars.end()); + + oslProcess hProcess = raiseProcess( + url, comphelper::containerToSequence(args) ); + try { + return Reference<XComponentContext>( + resolveUnoURL( connectStr, xContext, abortChannel.get() ), + UNO_QUERY_THROW ); + } + catch (...) { + // try to terminate process: + if ( osl_terminateProcess( hProcess ) != osl_Process_E_None ) + { + OSL_ASSERT( false ); + } + throw; + } +} + +//------------------------------------------------------------------------------ +Reference<loader::XImplementationLoader> +BackendImpl::ComponentPackageImpl::getComponentInfo( + t_stringlist * pImplNames, t_stringpairvec * pSingletons, + Reference<XComponentContext> const & xContext ) +{ + const Reference<loader::XImplementationLoader> xLoader( + xContext->getServiceManager()->createInstanceWithContext( + m_loader, xContext ), UNO_QUERY ); + if (! xLoader.is()) + return Reference<loader::XImplementationLoader>(); + + // HACK: highly dependent on stoc/source/servicemanager + // and stoc/source/implreg implementation which rely on the same + // services.rdb format! + + const Reference<registry::XSimpleRegistry> xMemReg( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), xContext ), + UNO_QUERY_THROW ); + xMemReg->open( OUString() /* in mem */, false, true ); + xLoader->writeRegistryInfo( xMemReg->getRootKey(), OUString(), getURL() ); + + const Sequence< Reference<registry::XRegistryKey> > keys( + xMemReg->getRootKey()->openKeys() ); + for ( sal_Int32 pos = keys.getLength(); pos--; ) + { + Reference<registry::XRegistryKey> const & xImplKey = keys[ pos ]; + const OUString implName( + xImplKey->getKeyName().copy( 1 /*leading slash*/ ) ); + + // check for singletons: + const Reference<registry::XRegistryKey> xSingletonKey( + xImplKey->openKey( OUSTR("UNO/SINGLETONS") ) ); + if (xSingletonKey.is() && xSingletonKey->isValid()) + { + const Sequence< Reference<registry::XRegistryKey> > singletonKeys( + xSingletonKey->openKeys() ); + for ( sal_Int32 i = singletonKeys.getLength(); i--; ) + { + Reference<registry::XRegistryKey> const & xSingleton = + singletonKeys[ i ]; + pSingletons->push_back( + ::std::pair<OUString, OUString>( + xSingleton->getKeyName().copy( + implName.getLength() + + sizeof ("//UNO/SINGLETONS/") - 1 ), + xSingleton->getStringValue() ) ); + } + } + else + { + pImplNames->push_back( implName ); + } + } + + return xLoader; +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::ComponentPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & ) +{ + if (m_registered == REG_UNINIT) + { + m_registered = REG_NOT_REGISTERED; + bool bAmbiguousComponentName = false; + const Reference<registry::XSimpleRegistry> xRDB( getRDB_RO() ); + if (xRDB.is()) + { + // lookup rdb for location URL: + const Reference<registry::XRegistryKey> xRootKey( + xRDB->getRootKey() ); + const Reference<registry::XRegistryKey> xImplKey( + xRootKey->openKey( OUSTR("IMPLEMENTATIONS") ) ); + Sequence<OUString> implNames; + if (xImplKey.is() && xImplKey->isValid()) + implNames = xImplKey->getKeyNames(); + OUString const * pImplNames = implNames.getConstArray(); + sal_Int32 pos = implNames.getLength(); + for ( ; pos--; ) + { + checkAborted( abortChannel ); + const OUString key( + pImplNames[ pos ] + OUSTR("/UNO/LOCATION") ); + const Reference<registry::XRegistryKey> xKey( + xRootKey->openKey(key) ); + if (xKey.is() && xKey->isValid()) + { + const OUString location( xKey->getAsciiValue() ); + if (location.equalsIgnoreAsciiCase( getURL() )) + { + break; + } + else + { + //try to match only the file name + OUString thisUrl(getURL()); + OUString thisFileName(thisUrl.copy(thisUrl.lastIndexOf('/'))); + + OUString locationFileName(location.copy(location.lastIndexOf('/'))); + if (locationFileName.equalsIgnoreAsciiCase(thisFileName)) + bAmbiguousComponentName = true; + } + } + } + if (pos >= 0) + m_registered = REG_REGISTERED; + else if (bAmbiguousComponentName) + m_registered = REG_MAYBE_REGISTERED; + } + } + + //Different extensions can use the same service implementations. Then the extensions + //which was installed last will overwrite the one from the other extension. That is + //the registry will contain the path (the location) of the library or jar of the + //second extension. In this case isRegistered called for the lib of the first extension + //would return "not registered". That would mean that during uninstallation + //XPackage::registerPackage is not called, because it just was not registered. This is, + //however, necessary for jar files. Registering and unregistering update + //uno_packages/cache/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc + //Therefore, we will return always "is ambiguous" if the path of this component cannot + //be found in the registry and if there is another path and both have the same file name (but + //the rest of the path is different). + //If the caller cannot precisely determine that this package was registered, then it must + //call registerPackage. + sal_Bool bAmbiguous = m_registered == REG_VOID // REG_VOID == we are in the progress of unregistration + || m_registered == REG_MAYBE_REGISTERED; + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + m_registered == REG_REGISTERED, bAmbiguous) ); +} + +//______________________________________________________________________________ +void BackendImpl::ComponentPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + + + const bool java = m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.Java2") ); + const OUString url( getURL() ); + bool isJavaTypelib; + if (m_bRemoved) + isJavaTypelib = m_registeredComponentsDb.javaTypeLibrary; + else + isJavaTypelib = java && + !jarManifestHeaderPresent( url, OUSTR("UNO-Type-Path"), xCmdEnv ); + + ComponentBackendDb::Data data; + data.javaTypeLibrary = isJavaTypelib; + if (doRegisterPackage) + { + Reference <uno::XComponentContext> context(that->getComponentContext()); + if (! startup) + { + context.set( + that->getObject( url ), UNO_QUERY ); + + if (! context.is()) { + context.set( + that->insertObject( url, raise_uno_process( + that->getComponentContext(), + abortChannel ) ), + UNO_QUERY_THROW ); + } + } + + const Reference<registry::XSimpleRegistry> xServicesRDB( getRDB() ); + const Reference<registry::XImplementationRegistration> xImplReg( + context->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.ImplementationRegistration"), + context ), UNO_QUERY_THROW ); + + xImplReg->registerImplementation( m_loader, url, xServicesRDB ); + //only write to unorc if registration was successful. + //It may fail if there is no suitable java. + if (isJavaTypelib) + { + that->addToUnoRc( java, url, xCmdEnv ); + data.javaTypeLibrary = true; + } + + t_stringlist implNames; + t_stringpairvec singletons; + const Reference<loader::XImplementationLoader> xLoader( + getComponentInfo( &implNames, &singletons, context ) ); + data.implementationNames = implNames; + data.singletons = singletons; + + if (!startup) + { + // factories live insertion: + const Reference<container::XSet> xSet( + that->getComponentContext()->getServiceManager(), UNO_QUERY_THROW ); + for ( t_stringlist::const_iterator iPos( implNames.begin() ); + iPos != implNames.end(); ++iPos ) + { + checkAborted( abortChannel ); + OUString const & implName = *iPos; + // activate factory: + const Reference<XInterface> xFactory( + xLoader->activate( + implName, OUString(), url, + xServicesRDB->getRootKey()->openKey( + OUSTR("/IMPLEMENTATIONS/") + implName ) ) ); + try { + xSet->insert( Any(xFactory) ); + } // ignore if factory has already been inserted: + catch (container::ElementExistException &) { + OSL_ENSURE( 0, "### factory already registered?" ); + } + } + + if (! singletons.empty()) + { + // singletons live insertion: + const Reference<container::XNameContainer> xRootContext( + that->getComponentContext()->getValueByName( + OUSTR("_root") ), UNO_QUERY ); + if (xRootContext.is()) + { + for ( t_stringpairvec::const_iterator iPos( + singletons.begin() ); + iPos != singletons.end(); ++iPos ) + { + ::std::pair<OUString, OUString> const & sp = *iPos; + const OUString name( OUSTR("/singletons/") + sp.first ); + // assure no arguments: + try { + xRootContext->removeByName( name + OUSTR("/arguments")); + } catch (container::NoSuchElementException &) {} + // used service: + try { + xRootContext->insertByName( + name + OUSTR("/service"), Any(sp.second) ); + } catch (container::ElementExistException &) { + xRootContext->replaceByName( + name + OUSTR("/service"), Any(sp.second) ); + } + // singleton entry: + try { + xRootContext->insertByName( name, Any() ); + } catch (container::ElementExistException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( + 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + xRootContext->replaceByName( name, Any() ); + } + } + } + } + } + + m_registered = REG_REGISTERED; + getMyBackend()->addDataToDb(url, data); + } + else // revokePackage() + { + // set to VOID during revocation process: + m_registered = REG_VOID; + + //get the remote context. If it does not exist then use the local one + Reference<XComponentContext> xContext( + that->getObject( url ), UNO_QUERY ); + bool bRemoteContext = false; + if (!xContext.is()) + xContext = that->getComponentContext(); + else + bRemoteContext = true; + + t_stringlist implNames; + t_stringpairvec singletons; + if (m_bRemoved) + { + implNames = m_registeredComponentsDb.implementationNames; + singletons = m_registeredComponentsDb.singletons; + } + else + { + getComponentInfo( &implNames, &singletons, xContext ); + } + + if (!startup) + { + // factories live removal: + const Reference<container::XSet> xSet( + that->getComponentContext()->getServiceManager(), UNO_QUERY_THROW ); + for ( t_stringlist::const_iterator iPos( implNames.begin() ); + iPos != implNames.end(); ++iPos ) + { + OUString const & implName = *iPos; + try { + xSet->remove( Any(implName) ); + } // ignore if factory has not been live deployed: + catch (container::NoSuchElementException &) { + } + } + + if (! singletons.empty()) + { + // singletons live removal: + const Reference<container::XNameContainer> xRootContext( + that->getComponentContext()->getValueByName( + OUSTR("_root") ), UNO_QUERY ); + if (xRootContext.is()) + { + for ( t_stringpairvec::const_iterator iPos( + singletons.begin() ); + iPos != singletons.end(); ++iPos ) + { + ::std::pair<OUString, OUString> const & sp = *iPos; + const OUString name( OUSTR("/singletons/") + sp.first ); + // arguments: + try { + xRootContext->removeByName( name + OUSTR("/arguments")); + } + catch (container::NoSuchElementException &) {} + // used service: + try { + xRootContext->removeByName( name + OUSTR("/service") ); + } + catch (container::NoSuchElementException &) {} + // singleton entry: + try { + xRootContext->removeByName( name ); + } + catch (container::NoSuchElementException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( + 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + } + } + } + + const Reference<registry::XSimpleRegistry> xServicesRDB( getRDB() ); + const Reference<registry::XImplementationRegistration> xImplReg( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.ImplementationRegistration"), + xContext ), UNO_QUERY_THROW ); + xImplReg->revokeImplementation( url, xServicesRDB ); + + if (isJavaTypelib) + that->removeFromUnoRc( java, url, xCmdEnv ); + + if (bRemoteContext) + that->releaseObject( url ); + + m_registered = REG_NOT_REGISTERED; + getMyBackend()->deleteDataFromDb(url); + } +} + +//############################################################################## +BackendImpl::TypelibraryPackageImpl::TypelibraryPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool jarFile, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_jarFile( jarFile ) +{ +} + +// Package +BackendImpl * BackendImpl::TypelibraryPackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<TypelibraryPackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::TypelibraryPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + that->hasInUnoRc( m_jarFile, getURL() ), + false /* IsAmbiguous */ ) ); +} + +//______________________________________________________________________________ +void BackendImpl::TypelibraryPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /*startup*/, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + const OUString url( getURL() ); + + if (doRegisterPackage) + { + // live insertion: + if (m_jarFile) { + // xxx todo add to classpath at runtime: ??? + //SB: It is probably not worth it to add the live inserted type + // library JAR to the UnoClassLoader in the soffice process. Any + // live inserted component JAR that might reference this type + // library JAR runs in its own uno process, so there is probably no + // Java code in the soffice process that would see any UNO types + // introduced by this type library JAR. + } + else // RDB: + { + Reference<XComponentContext> const & xContext = + that->getComponentContext(); + if (! m_xTDprov.is()) + { + m_xTDprov.set( that->getObject( url ), UNO_QUERY ); + if (! m_xTDprov.is()) + { + const Reference<registry::XSimpleRegistry> xReg( + xContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xContext ), UNO_QUERY_THROW ); + xReg->open( expandUnoRcUrl(url), + true /* read-only */, false /* ! create */ ); + const Any arg(xReg); + Reference<container::XHierarchicalNameAccess> xTDprov( + xContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + OUSTR("com.sun.star.comp.stoc." + "RegistryTypeDescriptionProvider"), + Sequence<Any>( &arg, 1 ), xContext ), UNO_QUERY ); + OSL_ASSERT( xTDprov.is() ); + if (xTDprov.is()) + m_xTDprov.set( that->insertObject( url, xTDprov ), + UNO_QUERY_THROW ); + } + } + if (m_xTDprov.is()) { + Reference<container::XSet> xSet( + xContext->getValueByName( + OUSTR("/singletons/com.sun.star." + "reflection.theTypeDescriptionManager") ), + UNO_QUERY_THROW ); + xSet->insert( Any(m_xTDprov) ); + } + } + + that->addToUnoRc( m_jarFile, url, xCmdEnv ); + } + else // revokePackage() + { + that->removeFromUnoRc( m_jarFile, url, xCmdEnv ); + + // revoking types at runtime, possible, sensible? + if (!m_xTDprov.is()) + m_xTDprov.set( that->getObject( url ), UNO_QUERY ); + if (m_xTDprov.is()) { + // remove live: + const Reference<container::XSet> xSet( + that->getComponentContext()->getValueByName( + OUSTR("/singletons/com.sun.star." + "reflection.theTypeDescriptionManager") ), + UNO_QUERY_THROW ); + xSet->remove( Any(m_xTDprov) ); + + that->releaseObject( url ); + m_xTDprov.clear(); + } + } +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + IMPLEMENTATION_NAME, + BACKEND_SERVICE_NAME ); + +} // namespace component +} // namespace backend +} // namespace dp_registry + + diff --git a/desktop/source/deployment/registry/component/dp_component.hrc b/desktop/source/deployment/registry/component/dp_component.hrc new file mode 100644 index 000000000000..53085a48d185 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_COMPONENT_HRC +#define INCLUDED_DP_COMPONENT_HRC + +#include "deployment.hrc" + +#define RID_STR_DYN_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+10) +#define RID_STR_JAVA_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+11) +#define RID_STR_PYTHON_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+12) +#define RID_STR_RDB_TYPELIB (RID_DEPLOYMENT_COMPONENT_START+20) +#define RID_STR_JAVA_TYPELIB (RID_DEPLOYMENT_COMPONENT_START+21) + +#endif diff --git a/desktop/source/deployment/registry/component/dp_component.src b/desktop/source/deployment/registry/component/dp_component.src new file mode 100644 index 000000000000..36f2a1cc4a5c --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.src @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_component.hrc" + +String RID_STR_DYN_COMPONENT +{ + Text [ en-US ] = "UNO Dynamic Library Component"; +}; + +String RID_STR_JAVA_COMPONENT +{ + Text [ en-US ] = "UNO Java Component"; +}; + +String RID_STR_PYTHON_COMPONENT +{ + Text [ en-US ] = "UNO Python Component"; +}; + +String RID_STR_RDB_TYPELIB +{ + Text [ en-US ] = "UNO RDB Type Library"; +}; + +String RID_STR_JAVA_TYPELIB +{ + Text [ en-US ] = "UNO Java Type Library"; +}; + diff --git a/desktop/source/deployment/registry/component/makefile.mk b/desktop/source/deployment/registry/component/makefile.mk new file mode 100644 index 000000000000..b7ee5c203cd5 --- /dev/null +++ b/desktop/source/deployment/registry/component/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_component +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_component.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_component.obj \ + $(SLO)$/dp_compbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.cxx b/desktop/source/deployment/registry/configuration/dp_configuration.cxx new file mode 100644 index 000000000000..1e7ee5bfac8a --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.cxx @@ -0,0 +1,783 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +//TODO: Large parts of this file were copied from dp_component.cxx; those parts +// should be consolidated. + +#include "dp_configuration.hrc" +#include "dp_backend.h" +#include "dp_persmap.h" +#include "dp_ucb.h" +#include "rtl/string.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "rtl/memory.h" +#include "osl/file.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/servicedecl.hxx" +#include "xmlscript/xml_helper.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/configuration/Update.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/io/XActiveDataSink.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/util/XRefreshable.hpp" +#include <list> +#include <memory> + +#include "dp_configurationbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace configuration { +namespace { + +typedef ::std::list<OUString> t_stringlist; + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const ; + + const bool m_isSchema; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + inline PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool isSchema, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_isSchema( isSchema ) + {} + }; + friend class PackageImpl; + + t_stringlist m_xcs_files; + t_stringlist m_xcu_files; + t_stringlist & getFiles( bool xcs ) { + return xcs ? m_xcs_files : m_xcu_files; + } + + bool m_configmgrini_inited; + bool m_configmgrini_modified; + std::auto_ptr<ConfigurationBackendDb> m_backendDb; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + ::std::auto_ptr<PersistentMap> m_registeredPackages; + // for backwards compatibility + + virtual void SAL_CALL disposing(); + + const Reference<deployment::XPackageTypeInfo> m_xConfDataTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xConfSchemaTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + void configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ); + void configmgrini_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + bool addToConfigmgrIni( bool isSchema, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool removeFromConfigmgrIni( bool isSchema, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url, ConfigurationBackendDb::Data const & data); + ::boost::optional<ConfigurationBackendDb::Data> readDataFromDb(OUString const & url); + OUString deleteDataFromDb(OUString const & url); + ::std::list<OUString> getAllIniEntries(); + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; +}; + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + try { + configmgrini_flush( Reference<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing..."), + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_configmgrini_inited( false ), + m_configmgrini_modified( false ), + m_xConfDataTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.configuration-data"), + OUSTR("*.xcu"), + getResourceString(RID_STR_CONF_DATA), + RID_IMG_CONF_XML, RID_IMG_CONF_XML_HC ) ), + m_xConfSchemaTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.configuration-schema"), + OUSTR("*.xcs"), + getResourceString(RID_STR_CONF_SCHEMA), + RID_IMG_CONF_XML, RID_IMG_CONF_XML_HC ) ), + m_typeInfos( 2 ) +{ + m_typeInfos[ 0 ] = m_xConfDataTypeInfo; + m_typeInfos[ 1 ] = m_xConfSchemaTypeInfo; + + const Reference<XCommandEnvironment> xCmdEnv; + + if (transientMode()) + { + //TODO + } + else + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ConfigurationBackendDb(getComponentContext(), dbFile)); + //clean up data folders which are no longer used. + //This must not be done in the same process where the help files + //are still registers. Only after revoking and restarting OOo the folders + //can be removed. This works now, because the extension manager is a singleton + //and the backends are only create once per process. + ::std::list<OUString> folders = m_backendDb->getAllDataUrls(); + deleteUnusedFolders(OUString(), folders); + + + configmgrini_verify_init( xCmdEnv ); + m_registeredPackages.reset( + new PersistentMap( + makeURL( getCachePath(), OUSTR("registered_packages.db") ), + false ) ); + } +} + +void BackendImpl::addDataToDb( + OUString const & url, ConfigurationBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +::boost::optional<ConfigurationBackendDb::Data> BackendImpl::readDataFromDb( + OUString const & url) +{ + ::boost::optional<ConfigurationBackendDb::Data> data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +OUString BackendImpl::deleteDataFromDb(OUString const & url) +{ + OUString url2(url); + if (m_backendDb.get()) { + boost::optional< ConfigurationBackendDb::Data > data( + m_backendDb->getEntry(url)); + if (data) { + url2 = expandUnoRcTerm(data->iniEntry); + } + m_backendDb->removeEntry(url); + } + return url2; +} + +::std::list<OUString> BackendImpl::getAllIniEntries() +{ + if (m_backendDb.get()) + return m_backendDb->getAllIniEntries(); + else + return ::std::list<OUString>(); +} + + + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) + { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".xcu") )) { + mediaType = OUSTR("application/" + "vnd.sun.star.configuration-data"); + } + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".xcs") )) { + mediaType = OUSTR("application/" + "vnd.sun.star.configuration-schema"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-data")) + { + return new PackageImpl( + this, url, name, m_xConfDataTypeInfo, false /* data file */, + bRemoved, identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-schema")) { + return new PackageImpl( + this, url, name, m_xConfSchemaTypeInfo, true /* schema file */, + bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +//______________________________________________________________________________ +void BackendImpl::configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + const ::osl::MutexGuard guard( getMutex() ); + if (! m_configmgrini_inited) + { + // common rc: + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), OUSTR("configmgr.ini") ), + xCmdEnv, false /* no throw */ )) + { + OUString line; + if (readLine( &line, OUSTR("SCHEMA="), ucb_content, + RTL_TEXTENCODING_UTF8 )) + { + sal_Int32 index = sizeof ("SCHEMA=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) { + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcs_files.push_back( token ); + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("DATA="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 index = sizeof ("DATA=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (token[ 0 ] == '?') + token = token.copy( 1 ); + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcu_files.push_back( token ); + } + } + while (index >= 0); + } + } + m_configmgrini_modified = false; + m_configmgrini_inited = true; + } +} + +//______________________________________________________________________________ +void BackendImpl::configmgrini_flush( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + if (!m_configmgrini_inited || !m_configmgrini_modified) + return; + + ::rtl::OStringBuffer buf; + if (! m_xcs_files.empty()) + { + t_stringlist::const_iterator iPos( m_xcs_files.begin() ); + t_stringlist::const_iterator const iEnd( m_xcs_files.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("SCHEMA=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + if (! m_xcu_files.empty()) + { + t_stringlist::const_iterator iPos( m_xcu_files.begin() ); + t_stringlist::const_iterator const iEnd( m_xcu_files.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("DATA=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + + // write configmgr.ini: + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf.getStr()), + buf.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), OUSTR("configmgr.ini") ), xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + + m_configmgrini_modified = false; +} + +//______________________________________________________________________________ +bool BackendImpl::addToConfigmgrIni( bool isSchema, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + configmgrini_verify_init( xCmdEnv ); + t_stringlist & rSet = getFiles(isSchema); + if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { + rSet.push_front( rcterm ); // prepend to list, thus overriding + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + return true; + } + else + return false; +} + +//______________________________________________________________________________ +bool BackendImpl::removeFromConfigmgrIni( + bool isSchema, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + configmgrini_verify_init( xCmdEnv ); + t_stringlist & rSet = getFiles(isSchema); + t_stringlist::iterator i(std::find(rSet.begin(), rSet.end(), rcterm)); + if (i == rSet.end() && !isSchema) + { + //in case the xcu contained %origin% then the configmr.ini contains the + //url to the file in the user installation (e.g. $BUNDLED_EXTENSIONS_USER) + //However, m_url (getURL()) contains the URL for the file in the actual + //extension installatation. + ::boost::optional<ConfigurationBackendDb::Data> data = readDataFromDb(url_); + if (data) + i = std::find(rSet.begin(), rSet.end(), data->iniEntry); + } + if (i == rSet.end()) { + return false; + } + rSet.erase(i); + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + return true; +} + +//############################################################################## + +// Package +//______________________________________________________________________________ +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + const rtl::OUString url(getURL()); + + bool bReg = false; + if (that->readDataFromDb(getURL())) + bReg = true; + if (!bReg) + //fallback for user extension registered in berkeley DB + bReg = that->m_registeredPackages->has( + rtl::OUStringToOString( url, RTL_TEXTENCODING_UTF8 )); + + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true, beans::Ambiguous<sal_Bool>( bReg, false ) ); +} + +//------------------------------------------------------------------------------ +OUString encodeForXml( OUString const & text ) +{ + // encode conforming xml: + sal_Int32 len = text.getLength(); + ::rtl::OUStringBuffer buf; + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + sal_Unicode c = text[ pos ]; + switch (c) { + case '<': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<") ); + break; + case '>': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(">") ); + break; + case '&': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") ); + break; + case '\'': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") ); + break; + case '\"': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") ); + break; + default: + buf.append( c ); + break; + } + } + return buf.makeStringAndClear(); +} + +//______________________________________________________________________________ +OUString replaceOrigin( + OUString const & url, OUString const & destFolder, Reference< XCommandEnvironment > const & xCmdEnv, bool & out_replaced) +{ + // looking for %origin%: + ::ucbhelper::Content ucb_content( url, xCmdEnv ); + ::rtl::ByteSequence bytes( readFile( ucb_content ) ); + ::rtl::ByteSequence filtered( bytes.getLength() * 2, + ::rtl::BYTESEQ_NODEFAULT ); + bool use_filtered = false; + ::rtl::OString origin; + sal_Char const * pBytes = reinterpret_cast<sal_Char const *>( + bytes.getConstArray()); + sal_Size nBytes = bytes.getLength(); + sal_Int32 write_pos = 0; + while (nBytes > 0) + { + sal_Int32 index = rtl_str_indexOfChar_WithLength( pBytes, nBytes, '%' ); + if (index < 0) { + if (! use_filtered) // opt + break; + index = nBytes; + } + + if ((write_pos + index) > filtered.getLength()) + filtered.realloc( (filtered.getLength() + index) * 2 ); + rtl_copyMemory( filtered.getArray() + write_pos, pBytes, index ); + write_pos += index; + pBytes += index; + nBytes -= index; + if (nBytes == 0) + break; + + // consume %: + ++pBytes; + --nBytes; + sal_Char const * pAdd = "%"; + sal_Int32 nAdd = 1; + if (nBytes > 1 && pBytes[ 0 ] == '%') + { + // %% => % + ++pBytes; + --nBytes; + use_filtered = true; + } + else if (rtl_str_shortenedCompare_WithLength( + pBytes, nBytes, + RTL_CONSTASCII_STRINGPARAM("origin%"), + sizeof ("origin%") - 1 ) == 0) + { + if (origin.getLength() == 0) { + // encode only once + origin = ::rtl::OUStringToOString( + encodeForXml( url.copy( 0, url.lastIndexOf( '/' ) ) ), + // xxx todo: encode always for UTF-8? => lookup doc-header? + RTL_TEXTENCODING_UTF8 ); + } + pAdd = origin.getStr(); + nAdd = origin.getLength(); + pBytes += (sizeof ("origin%") - 1); + nBytes -= (sizeof ("origin%") - 1); + use_filtered = true; + } + if ((write_pos + nAdd) > filtered.getLength()) + filtered.realloc( (filtered.getLength() + nAdd) * 2 ); + rtl_copyMemory( filtered.getArray() + write_pos, pAdd, nAdd ); + write_pos += nAdd; + } + if (!use_filtered) + return url; + if (write_pos < filtered.getLength()) + filtered.realloc( write_pos ); + rtl::OUString newUrl(url); + if (destFolder.getLength()) + { + //get the file name of the xcu and add it to the url of the temporary folder + sal_Int32 i = url.lastIndexOf('/'); + newUrl = destFolder + url.copy(i); + } + + ucbhelper::Content(newUrl, xCmdEnv).writeStream( + xmlscript::createInputStream(filtered), true); + out_replaced = true; + return newUrl; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + OUString url( getURL() ); + + if (doRegisterPackage) + { + ConfigurationBackendDb::Data data; + if (!m_isSchema) + { + const OUString sModFolder = that->createFolder(OUString(), xCmdEnv); + bool out_replaced = false; + url = replaceOrigin(url, sModFolder, xCmdEnv, out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + //No need for live-deployment for bundled extension, because OOo + //restarts after installation + if (that->m_eContext != CONTEXT_BUNDLED + && !startup) + { + if (m_isSchema) + { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcsFile( + that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url)); + } + else + { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcuFile( + that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url)); + } + } + that->addToConfigmgrIni( m_isSchema, url, xCmdEnv ); + data.iniEntry = dp_misc::makeRcTerm(url); + that->addDataToDb(getURL(), data); + } + else // revoke + { + if (!that->removeFromConfigmgrIni(m_isSchema, url, xCmdEnv)) { + t_string2string_map entries( + that->m_registeredPackages->getEntries()); + for (t_string2string_map::iterator i(entries.begin()); + i != entries.end(); ++i) + { + //If the xcu file was installed before the configmgr was chaned + //to use the configmgr.ini, one needed to rebuild to whole directory + //structur containing the xcu, xcs files from all extensions. Now, + //we just add all other xcu/xcs files to the configmgr.ini instead of + //rebuilding the directory structure. + rtl::OUString url2( + rtl::OStringToOUString(i->first, RTL_TEXTENCODING_UTF8)); + if (url2 != url) { + bool schema = i->second.equalsIgnoreAsciiCase( + "vnd.sun.star.configuration-schema"); + OUString url_replaced(url2); + ConfigurationBackendDb::Data data; + if (!schema) + { + const OUString sModFolder = that->createFolder(OUString(), xCmdEnv); + bool out_replaced = false; + url_replaced = replaceOrigin( + url2, sModFolder, xCmdEnv, out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + that->addToConfigmgrIni(schema, url_replaced, xCmdEnv); + data.iniEntry = dp_misc::makeRcTerm(url_replaced); + that->addDataToDb(url2, data); + } + that->m_registeredPackages->erase(i->first); + } + try + { + ::ucbhelper::Content( + makeURL( that->getCachePath(), OUSTR("registry") ), + xCmdEnv ).executeCommand( + OUSTR("delete"), Any( true /* delete physically */ ) ); + } + catch(Exception&) + { + OSL_ASSERT(0); + } + } + url = that->deleteDataFromDb(url); + if (!m_isSchema) { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->removeExtensionXcuFile( + expandUnoRcUrl(url)); + } + } +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.configuration.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace configuration +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.hrc b/desktop/source/deployment/registry/configuration/dp_configuration.hrc new file mode 100644 index 000000000000..01e1905228b3 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.hrc @@ -0,0 +1,36 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_CONFIGURATION_HRC +#define INCLUDED_DP_CONFIGURATION_HRC + +#include "deployment.hrc" + +#define RID_STR_CONF_SCHEMA (RID_DEPLOYMENT_CONF_START+10) +#define RID_STR_CONF_DATA (RID_DEPLOYMENT_CONF_START+11) + +#endif diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.src b/desktop/source/deployment/registry/configuration/dp_configuration.src new file mode 100644 index 000000000000..7ff749b18459 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.src @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_configuration.hrc" + +String RID_STR_CONF_SCHEMA +{ + Text [ en-US ] = "Configuration Schema"; +}; + +String RID_STR_CONF_DATA +{ + Text [ en-US ] = "Configuration Data"; +}; + diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx new file mode 100644 index 000000000000..2a02c6d8efa0 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_configurationbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/configuration-registry/2010" +#define NS_PREFIX "conf" +#define ROOT_ELEMENT_NAME "configuration-backend-db" +#define KEY_ELEMENT_NAME "configuration" + +namespace dp_registry { +namespace backend { +namespace configuration { + +ConfigurationBackendDb::ConfigurationBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ConfigurationBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ConfigurationBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ConfigurationBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ConfigurationBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + +void ConfigurationBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> helpNode + = writeKeyElement(url); + + writeSimpleElement(OUSTR("data-url"), data.dataUrl, helpNode); + writeSimpleElement(OUSTR("ini-entry"), data.iniEntry, helpNode); + save(); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + + +::boost::optional<ConfigurationBackendDb::Data> +ConfigurationBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ConfigurationBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + retData.dataUrl = readSimpleElement(OUSTR("data-url"), aNode); + retData.iniEntry = readSimpleElement(OUSTR("ini-entry"), aNode); + } + else + { + return ::boost::optional<Data>(); + } + return ::boost::optional<Data>(retData); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> ConfigurationBackendDb::getAllDataUrls() +{ + try + { + ::std::list<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + OUString sExpression( + sPrefix + OUSTR(":configuration/") + sPrefix + OUSTR(":data-url/text()")); + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, sExpression); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> ConfigurationBackendDb::getAllIniEntries() +{ + return getOneChildFromAllEntries(OUSTR("ini-entry")); +} + + + +} // namespace configuration +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx new file mode 100644 index 000000000000..7023897bd8de --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_CONFIGURATIONBACKENDDB_HXX +#define INCLUDED_DP_CONFIGURATIONBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "rtl/string.hxx" +#include <list> +#include "boost/optional.hpp" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace configuration { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ConfigurationBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* the URL to the folder containing the xcu or xcs files which contained + %origin% + */ + ::rtl::OUString dataUrl; + /* the URL of the xcu or xcs file which is written in to the configmgr.ini + */ + ::rtl::OUString iniEntry; + }; + +public: + + ConfigurationBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + ::boost::optional<Data> getEntry(::rtl::OUString const & url); + ::std::list< ::rtl::OUString> getAllDataUrls(); + ::std::list< ::rtl::OUString> getAllIniEntries(); +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/configuration/makefile.mk b/desktop/source/deployment/registry/configuration/makefile.mk new file mode 100644 index 000000000000..9bcbd50d4230 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_configuration +ENABLE_EXCEPTIONS = TRUE + +INCPRE += ..$/..$/inc + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_configuration.src + +SLOFILES = \ + $(SLO)$/dp_configuration.obj \ + $(SLO)$/dp_configurationbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/dp_backend.cxx b/desktop/source/deployment/registry/dp_backend.cxx new file mode 100644 index 000000000000..d781ba9e40ef --- /dev/null +++ b/desktop/source/deployment/registry/dp_backend.cxx @@ -0,0 +1,807 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_backend.h" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "rtl/bootstrap.hxx" +#include "osl/file.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/unwrapargs.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/deployment/InvalidRemovedParameterException.hpp" +#include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp" +#include "com/sun/star/ucb/IOErrorCode.hpp" +#include "com/sun/star/beans/StringPair.hpp" +#include "com/sun/star/sdbc/XResultSet.hpp" +#include "com/sun/star/sdbc/XRow.hpp" + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { + +//______________________________________________________________________________ +PackageRegistryBackend::~PackageRegistryBackend() +{ +} + +//______________________________________________________________________________ +void PackageRegistryBackend::disposing( lang::EventObject const & event ) + throw (RuntimeException) +{ + Reference<deployment::XPackage> xPackage( + event.Source, UNO_QUERY_THROW ); + OUString url( xPackage->getURL() ); + ::osl::MutexGuard guard( getMutex() ); + if ( m_bound.erase( url ) != 1 ) + { + OSL_ASSERT( false ); + } +} + +//______________________________________________________________________________ +PackageRegistryBackend::PackageRegistryBackend( + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) + : t_BackendBase( getMutex() ), + m_xComponentContext( xContext ), + m_eContext( CONTEXT_UNKNOWN ), + m_readOnly( false ) +{ + boost::optional<OUString> cachePath; + boost::optional<bool> readOnly; + comphelper::unwrapArgs( args, m_context, cachePath, readOnly ); + if (cachePath) + m_cachePath = *cachePath; + if (readOnly) + m_readOnly = *readOnly; + + if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) + m_eContext = CONTEXT_USER; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) + m_eContext = CONTEXT_SHARED; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) + m_eContext = CONTEXT_BUNDLED; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("tmp") )) + m_eContext = CONTEXT_TMP; + else if (m_context.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:/") )) + m_eContext = CONTEXT_DOCUMENT; + else + m_eContext = CONTEXT_UNKNOWN; +} + +//______________________________________________________________________________ +void PackageRegistryBackend::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("PackageRegistryBackend instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +//______________________________________________________________________________ +void PackageRegistryBackend::disposing() +{ + try { + m_xComponentContext.clear(); + WeakComponentImplHelperBase::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing!"), + static_cast<OWeakObject *>(this), exc ); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageRegistryBackend::bindPackage( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::InvalidRemovedParameterException, + ucb::CommandFailedException, + lang::IllegalArgumentException, RuntimeException) +{ + ::osl::ResettableMutexGuard guard( getMutex() ); + check(); + + t_string2ref::const_iterator const iFind( m_bound.find( url ) ); + if (iFind != m_bound.end()) + { + Reference<deployment::XPackage> xPackage( iFind->second ); + if (xPackage.is()) + { + if (mediaType.getLength() && + mediaType != xPackage->getPackageType()->getMediaType()) + throw lang::IllegalArgumentException + (OUSTR("XPackageRegistry::bindPackage: media type does not match"), + static_cast<OWeakObject*>(this), 1); + if (xPackage->isRemoved() != bRemoved) + throw deployment::InvalidRemovedParameterException( + OUSTR("XPackageRegistry::bindPackage: bRemoved parameter does not match"), + static_cast<OWeakObject*>(this), xPackage->isRemoved(), xPackage); + return xPackage; + } + } + + guard.clear(); + + Reference<deployment::XPackage> xNewPackage; + try { + xNewPackage = bindPackage_( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (lang::IllegalArgumentException &) { + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("Error binding package: ") + url, + static_cast<OWeakObject *>(this), exc ); + } + + guard.reset(); + + ::std::pair< t_string2ref::iterator, bool > insertion( + m_bound.insert( t_string2ref::value_type( url, xNewPackage ) ) ); + if (insertion.second) + { // first insertion + OSL_ASSERT( Reference<XInterface>(insertion.first->second) + == xNewPackage ); + } + else + { // found existing entry + Reference<deployment::XPackage> xPackage( insertion.first->second ); + if (xPackage.is()) + return xPackage; + insertion.first->second = xNewPackage; + } + + guard.clear(); + xNewPackage->addEventListener( this ); // listen for disposing events + return xNewPackage; +} + +OUString PackageRegistryBackend::createFolder( + OUString const & relUrl, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + OUString sDataFolder = makeURL(getCachePath(), relUrl); + //make sure the folder exist + ucbhelper::Content dataContent; + ::dp_misc::create_folder(&dataContent, sDataFolder, xCmdEnv); + + OUString sDataFolderURL = dp_misc::expandUnoRcUrl(sDataFolder); + + OUString tempEntry; + if (::osl::File::createTempFile( + &sDataFolderURL, 0, &tempEntry ) != ::osl::File::E_None) + throw RuntimeException( + OUSTR("::osl::File::createTempFile() failed!"), 0 ); + tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 ); + OUString destFolder= makeURL(sDataFolder, tempEntry) + OUSTR("_"); + ::ucbhelper::Content destFolderContent; + dp_misc::create_folder( &destFolderContent, destFolder, xCmdEnv ); + + return destFolder; +} + +void PackageRegistryBackend::deleteTempFolder( + OUString const & folderUrl) +{ + OSL_ASSERT(folderUrl.getLength() + && folderUrl[folderUrl.getLength() - 1] == '_'); + if (folderUrl.getLength() + && folderUrl[folderUrl.getLength() - 1] == '_') + { + const OUString tempFile = folderUrl.copy(0, folderUrl.getLength() - 1); + erase_path( folderUrl, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + erase_path( tempFile, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + } +} + +void PackageRegistryBackend::deleteUnusedFolders( + OUString const & relUrl, + ::std::list< OUString> const & usedFolders) +{ + try + { + const OUString sDataFolder = makeURL(getCachePath(), relUrl); + ::ucbhelper::Content tempFolder( + sDataFolder, Reference<ucb::XCommandEnvironment>()); + Reference<sdbc::XResultSet> xResultSet( + tempFolder.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) ); + // get all temp directories: + ::std::vector<OUString> tempEntries; + + char tmp[] = ".tmp"; + + while (xResultSet->next()) + { + OUString title( + Reference<sdbc::XRow>( + xResultSet, UNO_QUERY_THROW )->getString( + 1 /* Title */ ) ); + + if (title.endsWithAsciiL(tmp, sizeof(tmp) - 1)) + tempEntries.push_back( + makeURLAppendSysPathSegment(sDataFolder, title)); + } + + for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos ) + { + //usedFolders contains the urls to the folders which have + //a trailing underscore + const OUString tempFolderName = tempEntries[ pos ] + OUSTR("_"); + + if (::std::find( usedFolders.begin(), usedFolders.end(), tempFolderName ) == + usedFolders.end()) + { + deleteTempFolder(tempFolderName); + } + } + } + catch (ucb::InteractiveAugmentedIOException& e) + { + //In case the folder containing all the data folder does not + //exist yet, we ignore the exception + if (e.Code != ucb::IOErrorCode_NOT_EXISTING) + throw e; + } + +} + +//############################################################################## + +//______________________________________________________________________________ +Package::~Package() +{ +} + +//______________________________________________________________________________ +Package::Package( ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & rName, + OUString const & displayName, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, + OUString const & identifier) + : t_PackageBase( getMutex() ), + m_myBackend( myBackend ), + m_url( url ), + m_name( rName ), + m_displayName( displayName ), + m_xPackageType( xPackageType ), + m_bRemoved(bRemoved), + m_identifier(identifier) +{ + if (m_bRemoved) + { + //We use the last segment of the URL + OSL_ASSERT(m_name.getLength() == 0); + OUString name = m_url; + rtl::Bootstrap::expandMacros(name); + sal_Int32 index = name.lastIndexOf('/'); + if (index != -1 && index < name.getLength()) + m_name = name.copy(index + 1); + } +} + +//______________________________________________________________________________ +void Package::disposing() +{ + m_myBackend.clear(); + WeakComponentImplHelperBase::disposing(); +} + +//______________________________________________________________________________ +void Package::check() const +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("Package instance has already been disposed!"), + static_cast<OWeakObject *>(const_cast<Package *>(this))); + } +} + +// XComponent +//______________________________________________________________________________ +void Package::dispose() throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::dispose(); +} + +//______________________________________________________________________________ +void Package::addEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::addEventListener( xListener ); +} + +//______________________________________________________________________________ +void Package::removeEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::removeEventListener( xListener ); +} + +// XModifyBroadcaster +//______________________________________________________________________________ +void Package::addModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.addListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void Package::removeModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void Package::checkAborted( + ::rtl::Reference<AbortChannel> const & abortChannel ) +{ + if (abortChannel.is() && abortChannel->isAborted()) { + throw CommandAbortedException( + OUSTR("abort!"), static_cast<OWeakObject *>(this) ); + } +} + +// XPackage +//______________________________________________________________________________ +Reference<task::XAbortChannel> Package::createAbortChannel() + throw (RuntimeException) +{ + check(); + return new AbortChannel; +} + +//______________________________________________________________________________ +sal_Bool Package::isBundle() throw (RuntimeException) +{ + return false; // default +} + +//______________________________________________________________________________ +::sal_Int32 Package::checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >&, + const css::uno::Reference< css::ucb::XCommandEnvironment >&, + sal_Bool) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return 0; +} + +//______________________________________________________________________________ +::sal_Bool Package::checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return true; +} + + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > Package::getBundle( + Reference<task::XAbortChannel> const &, + Reference<XCommandEnvironment> const & ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + return Sequence< Reference<deployment::XPackage> >(); +} + +//______________________________________________________________________________ +OUString Package::getName() throw (RuntimeException) +{ + return m_name; +} + +beans::Optional<OUString> Package::getIdentifier() throw (RuntimeException) +{ + if (m_bRemoved) + return beans::Optional<OUString>(true, m_identifier); + + return beans::Optional<OUString>(); +} + +//______________________________________________________________________________ +OUString Package::getVersion() throw ( + deployment::ExtensionRemovedException, + RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return OUString(); +} + +//______________________________________________________________________________ +OUString Package::getURL() throw (RuntimeException) +{ + return m_url; +} + +//______________________________________________________________________________ +OUString Package::getDisplayName() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return m_displayName; +} + +//______________________________________________________________________________ +OUString Package::getDescription() throw ( + deployment::ExtensionRemovedException,RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return OUString(); +} + +//______________________________________________________________________________ +Sequence<OUString> Package::getUpdateInformationURLs() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return Sequence<OUString>(); +} + +//______________________________________________________________________________ +css::beans::StringPair Package::getPublisherInfo() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + css::beans::StringPair aEmptyPair; + return aEmptyPair; +} + +//______________________________________________________________________________ +uno::Reference< css::graphic::XGraphic > Package::getIcon( sal_Bool /*bHighContrast*/ ) + throw (deployment::ExtensionRemovedException, RuntimeException ) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + uno::Reference< css::graphic::XGraphic > aEmpty; + return aEmpty; +} + +//______________________________________________________________________________ +Reference<deployment::XPackageTypeInfo> Package::getPackageType() + throw (RuntimeException) +{ + return m_xPackageType; +} + +//______________________________________________________________________________ +void Package::exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::ExtensionRemovedException, + CommandFailedException, CommandAbortedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::ucbhelper::Content destFolder( destFolderURL, xCmdEnv ); + ::ucbhelper::Content sourceContent( getURL(), xCmdEnv ); + if (! destFolder.transferContent( + sourceContent, ::ucbhelper::InsertOperation_COPY, + newTitle, nameClashAction )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 ); +} + +//______________________________________________________________________________ +void Package::fireModified() +{ + ::cppu::OInterfaceContainerHelper * container = rBHelper.getContainer( + ::getCppuType( static_cast<Reference< + util::XModifyListener> const *>(0) ) ); + if (container != 0) { + Sequence< Reference<XInterface> > elements( + container->getElements() ); + lang::EventObject evt( static_cast<OWeakObject *>(this) ); + for ( sal_Int32 pos = 0; pos < elements.getLength(); ++pos ) + { + Reference<util::XModifyListener> xListener( + elements[ pos ], UNO_QUERY ); + if (xListener.is()) + xListener->modified( evt ); + } + } +} + +// XPackage +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > Package::isRegistered( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, RuntimeException) +{ + try { + ::osl::ResettableMutexGuard guard( getMutex() ); + return isRegistered_( guard, + AbortChannel::get(xAbortChannel), + xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("unexpected exception occured!"), + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +void Package::processPackage_impl( + bool doRegisterPackage, + bool startup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + check(); + bool action = false; + + try { + try { + ::osl::ResettableMutexGuard guard( getMutex() ); + beans::Optional< beans::Ambiguous<sal_Bool> > option( + isRegistered_( guard, AbortChannel::get(xAbortChannel), + xCmdEnv ) ); + action = (option.IsPresent && + (option.Value.IsAmbiguous || + (doRegisterPackage ? !option.Value.Value + : option.Value.Value))); + if (action) { + + OUString displayName = isRemoved() ? getName() : getDisplayName(); + ProgressLevel progress( + xCmdEnv, + (doRegisterPackage + ? PackageRegistryBackend::StrRegisteringPackage::get() + : PackageRegistryBackend::StrRevokingPackage::get()) + + displayName ); + processPackage_( guard, + doRegisterPackage, + startup, + AbortChannel::get(xAbortChannel), + xCmdEnv ); + } + } + catch (RuntimeException &) { + OSL_ENSURE( 0, "### unexpected RuntimeException!" ); + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + (doRegisterPackage + ? getResourceString(RID_STR_ERROR_WHILE_REGISTERING) + : getResourceString(RID_STR_ERROR_WHILE_REVOKING)) + + getDisplayName(), static_cast<OWeakObject *>(this), exc ); + } + } + catch (...) { + if (action) + fireModified(); + throw; + } + if (action) + fireModified(); +} + +//______________________________________________________________________________ +void Package::registerPackage( + sal_Bool startup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + processPackage_impl( true /* register */, startup, xAbortChannel, xCmdEnv ); +} + +//______________________________________________________________________________ +void Package::revokePackage( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + processPackage_impl( false /* revoke */, false, xAbortChannel, xCmdEnv ); + +} + +PackageRegistryBackend * Package::getMyBackend() const +{ + PackageRegistryBackend * pBackend = m_myBackend.get(); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<Package *>(this))); + } + return pBackend; +} +OUString Package::getRepositoryName() + throw (RuntimeException) +{ + PackageRegistryBackend * backEnd = getMyBackend(); + return backEnd->getContext(); +} + +beans::Optional< OUString > Package::getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return beans::Optional<OUString>(); +} + +sal_Bool Package::isRemoved() + throw (RuntimeException) +{ + return m_bRemoved; +} + +//############################################################################## + +//______________________________________________________________________________ +Package::TypeInfo::~TypeInfo() +{ +} + +// XPackageTypeInfo +//______________________________________________________________________________ +OUString Package::TypeInfo::getMediaType() throw (RuntimeException) +{ + return m_mediaType; +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + return getShortDescription(); +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getShortDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + return m_shortDescr; +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getFileFilter() throw (RuntimeException) +{ + return m_fileFilter; +} + +//______________________________________________________________________________ +Any Package::TypeInfo::getIcon( sal_Bool highContrast, sal_Bool smallIcon ) + throw (RuntimeException) +{ + if (! smallIcon) + return Any(); + const sal_uInt16 nIconId = (highContrast ? m_smallIcon_HC : m_smallIcon); + return Any( &nIconId, getCppuType( static_cast<sal_uInt16 const *>(0) ) ); +} + +} +} + diff --git a/desktop/source/deployment/registry/dp_backenddb.cxx b/desktop/source/deployment/registry/dp_backenddb.cxx new file mode 100644 index 000000000000..14b4f2374c5b --- /dev/null +++ b/desktop/source/deployment/registry/dp_backenddb.cxx @@ -0,0 +1,649 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/strbuf.hxx" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "osl/file.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/io/XActiveDataSource.hpp" +#include "com/sun/star/io/XActiveDataControl.hpp" +#include "dp_ucb.h" +#include "dp_misc.h" +#include "ucbhelper/content.hxx" +#include "xmlscript/xml_helper.hxx" +#include "dp_backenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + + +namespace dp_registry { +namespace backend { + +BackendDb::BackendDb( + Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url): + m_xContext(xContext) +{ + m_urlDb = dp_misc::expandUnoRcUrl(url); +} + +void BackendDb::save() +{ + const Reference<css::io::XActiveDataSource> xDataSource(m_doc,css::uno::UNO_QUERY_THROW); + ::rtl::ByteSequence bytes; + xDataSource->setOutputStream(::xmlscript::createOutputStream(&bytes)); + const Reference<css::io::XActiveDataControl> xDataControl(m_doc,css::uno::UNO_QUERY_THROW); + xDataControl->start(); + + const Reference<css::io::XInputStream> xData( + ::xmlscript::createInputStream(bytes)); + ::ucbhelper::Content ucbDb(m_urlDb, 0); + ucbDb.writeStream(xData, true /*replace existing*/); +} + +css::uno::Reference<css::xml::dom::XDocument> BackendDb::getDocument() +{ + if (!m_doc.is()) + { + const Reference<css::xml::dom::XDocumentBuilder> xDocBuilder( + m_xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.dom.DocumentBuilder"), + m_xContext ), css::uno::UNO_QUERY); + if (!xDocBuilder.is()) + throw css::uno::RuntimeException( + OUSTR(" Could not create service com.sun.star.xml.dom.DocumentBuilder"), 0); + + ::osl::DirectoryItem item; + ::osl::File::RC err = ::osl::DirectoryItem::get(m_urlDb, item); + if (err == ::osl::File::E_None) + { + m_doc = xDocBuilder->parseURI(m_urlDb); + } + else if (err == ::osl::File::E_NOENT) + { + //Create a new document and insert some basic stuff + m_doc = xDocBuilder->newDocument(); + const Reference<css::xml::dom::XElement> rootNode = + m_doc->createElementNS(getDbNSName(), getNSPrefix() + + OUSTR(":") + getRootElementName()); + + m_doc->appendChild(Reference<css::xml::dom::XNode>( + rootNode, UNO_QUERY_THROW)); + save(); + } + else + throw css::uno::RuntimeException( + OUSTR("Extension manager could not access database file:" ) + + m_urlDb, 0); + + if (!m_doc.is()) + throw css::uno::RuntimeException( + OUSTR("Extension manager could not get root node of data base file: ") + + m_urlDb, 0); + } + + return m_doc; +} + +Reference<css::xml::xpath::XXPathAPI> BackendDb::getXPathAPI() +{ + if (!m_xpathApi.is()) + { + m_xpathApi = Reference< css::xml::xpath::XXPathAPI >( + m_xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.xpath.XPathAPI"), + m_xContext), css::uno::UNO_QUERY); + + if (!m_xpathApi.is()) + throw css::uno::RuntimeException( + OUSTR(" Could not create service com.sun.star.xml.xpath.XPathAPI"), 0); + + m_xpathApi->registerNS( + getNSPrefix(), getDbNSName()); + } + + return m_xpathApi; +} + +void BackendDb::removeElement(::rtl::OUString const & sXPathExpression) +{ + try + { + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + //find the extension element that is to be removed + const Reference<css::xml::dom::XNode> aNode = + xpathApi->selectSingleNode(root, sXPathExpression); + + if (aNode.is()) + { + root->removeChild(aNode); + save(); + } + +#if OSL_DEBUG_LEVEL > 0 + //There must not be any other entry with the same url + const Reference<css::xml::dom::XNode> nextNode = + xpathApi->selectSingleNode(root, sXPathExpression); + OSL_ASSERT(! nextNode.is()); +#endif + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +void BackendDb::removeEntry(::rtl::OUString const & url) +{ + const OUString sKeyElement = getKeyElementName(); + const OUString sPrefix = getNSPrefix(); + ::rtl::OUStringBuffer sExpression(500); + sExpression.append(sPrefix); + sExpression.appendAscii(":"); + sExpression.append(sKeyElement); + sExpression.append(OUSTR("[@url = \"")); + sExpression.append(url); + sExpression.appendAscii("\"]"); + + removeElement(sExpression.makeStringAndClear()); +} + +Reference<css::xml::dom::XNode> BackendDb::getKeyElement( + ::rtl::OUString const & url) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sKeyElement = getKeyElementName(); + ::rtl::OUStringBuffer sExpression(500); + sExpression.append(sPrefix); + sExpression.appendAscii(":"); + sExpression.append(sKeyElement); + sExpression.append(OUSTR("[@url = \"")); + sExpression.append(url); + sExpression.appendAscii("\"]"); + + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + return xpathApi->selectSingleNode(root, sExpression.makeStringAndClear()); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read key element in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Only writes the data if there is at least one entry +void BackendDb::writeVectorOfPair( + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > const & vecPairs, + OUString const & sVectorTagName, + OUString const & sPairTagName, + OUString const & sFirstTagName, + OUString const & sSecondTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent) +{ + try{ + if (vecPairs.size() == 0) + return; + const OUString sNameSpace = getDbNSName(); + OSL_ASSERT(sNameSpace.getLength()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + const Reference<css::xml::dom::XElement> vectorNode( + doc->createElementNS(sNameSpace, sPrefix + sVectorTagName)); + + xParent->appendChild( + Reference<css::xml::dom::XNode>( + vectorNode, css::uno::UNO_QUERY_THROW)); + typedef ::std::vector< ::std::pair< OUString, OUString > >::const_iterator CIT; + for (CIT i = vecPairs.begin(); i != vecPairs.end(); i++) + { + const Reference<css::xml::dom::XElement> pairNode( + doc->createElementNS(sNameSpace, sPrefix + sPairTagName)); + + vectorNode->appendChild( + Reference<css::xml::dom::XNode>( + pairNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XElement> firstNode( + doc->createElementNS(sNameSpace, sPrefix + sFirstTagName)); + + pairNode->appendChild( + Reference<css::xml::dom::XNode>( + firstNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XText> firstTextNode( + doc->createTextNode( i->first)); + + firstNode->appendChild( + Reference<css::xml::dom::XNode>( + firstTextNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XElement> secondNode( + doc->createElementNS(sNameSpace, sPrefix + sSecondTagName)); + + pairNode->appendChild( + Reference<css::xml::dom::XNode>( + secondNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XText> secondTextNode( + doc->createTextNode( i->second)); + + secondNode->appendChild( + Reference<css::xml::dom::XNode>( + secondTextNode, css::uno::UNO_QUERY_THROW)); + } + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::vector< ::std::pair< OUString, OUString > > +BackendDb::readVectorOfPair( + Reference<css::xml::dom::XNode> const & parent, + OUString const & sListTagName, + OUString const & sPairTagName, + OUString const & sFirstTagName, + OUString const & sSecondTagName) +{ + try + { + OSL_ASSERT(parent.is()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sExprPairs( + sPrefix + sListTagName + OUSTR("/") + sPrefix + sPairTagName); + const Reference<css::xml::dom::XNodeList> listPairs = + xpathApi->selectNodeList(parent, sExprPairs); + + ::std::vector< ::std::pair< OUString, OUString > > retVector; + sal_Int32 length = listPairs->getLength(); + for (sal_Int32 i = 0; i < length; i++) + { + const Reference<css::xml::dom::XNode> aPair = listPairs->item(i); + const OUString sExprFirst(sPrefix + sFirstTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNode> first = + xpathApi->selectSingleNode(aPair, sExprFirst); + + const OUString sExprSecond(sPrefix + sSecondTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNode> second = + xpathApi->selectSingleNode(aPair, sExprSecond); + OSL_ASSERT(first.is() && second.is()); + + retVector.push_back(::std::make_pair( + first->getNodeValue(), second->getNodeValue())); + } + return retVector; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Only writes the data if there is at least one entry +void BackendDb::writeSimpleList( + ::std::list< ::rtl::OUString> const & list, + OUString const & sListTagName, + OUString const & sMemberTagName, + Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + if (list.size() == 0) + return; + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + + const Reference<css::xml::dom::XElement> listNode( + doc->createElementNS(sNameSpace, sPrefix + sListTagName)); + + xParent->appendChild( + Reference<css::xml::dom::XNode>( + listNode, css::uno::UNO_QUERY_THROW)); + + typedef ::std::list<OUString>::const_iterator ITC_ITEMS; + for (ITC_ITEMS i = list.begin(); i != list.end(); i++) + { + const Reference<css::xml::dom::XNode> memberNode( + doc->createElementNS(sNameSpace, sPrefix + sMemberTagName), css::uno::UNO_QUERY_THROW); + + listNode->appendChild(memberNode); + + const Reference<css::xml::dom::XNode> textNode( + doc->createTextNode( *i), css::uno::UNO_QUERY_THROW); + + memberNode->appendChild(textNode); + } + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Writes only the element if is has a value. +//The prefix is automatically added to the element name +void BackendDb::writeSimpleElement( + OUString const & sElementName, OUString const & value, + Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + if (value.getLength() == 0) + return; + const OUString sPrefix = getNSPrefix(); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const OUString sNameSpace = getDbNSName(); + const Reference<css::xml::dom::XNode> dataNode( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sElementName), + UNO_QUERY_THROW); + xParent->appendChild(dataNode); + + const Reference<css::xml::dom::XNode> dataValue( + doc->createTextNode(value), UNO_QUERY_THROW); + dataNode->appendChild(dataValue); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry(writeSimpleElement) in backend db: ") + + m_urlDb, 0, exc); + } + +} + +/** The key elements have an url attribute and are always children of the root + element. +*/ +Reference<css::xml::dom::XNode> BackendDb::writeKeyElement( + ::rtl::OUString const & url) +{ + try + { + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix = getNSPrefix(); + const OUString sElementName = getKeyElementName(); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + //Check if there are an entry with the same url. This can be the case if the + //the status of an XPackage is ambiguous. In this case a call to activateExtension + //(dp_extensionmanager.cxx), will register the package again. See also + //Package::processPackage_impl in dp_backend.cxx. + //A package can become + //invalid after its successful registration, for example if a second extension with + //the same service is installed. + const OUString sExpression( + sPrefix + OUSTR(":") + sElementName + OUSTR("[@url = \"") + url + OUSTR("\"]")); + const Reference<css::xml::dom::XNode> existingNode = + getXPathAPI()->selectSingleNode(root, sExpression); + if (existingNode.is()) + { + OSL_ASSERT(0); + //replace the existing entry. + removeEntry(url); + } + + const Reference<css::xml::dom::XElement> keyElement( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sElementName)); + + keyElement->setAttribute(OUSTR("url"), url); + + const Reference<css::xml::dom::XNode> keyNode( + keyElement, UNO_QUERY_THROW); + root->appendChild(keyNode); + return keyNode; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write key element in backend db: ") + + m_urlDb, 0, exc); + } +} + +OUString BackendDb::readSimpleElement( + OUString const & sElementName, Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sExpr(sPrefix + OUSTR(":") + sElementName + OUSTR("/text()")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const Reference<css::xml::dom::XNode> val = + xpathApi->selectSingleNode(xParent, sExpr); + if (val.is()) + return val->getNodeValue(); + return OUString(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data (readSimpleElement) in backend db: ") + + m_urlDb, 0, exc); + } +} + + +::std::list< OUString> BackendDb::readList( + Reference<css::xml::dom::XNode> const & parent, + OUString const & sListTagName, + OUString const & sMemberTagName) +{ + try + { + OSL_ASSERT(parent.is()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sExprList( + sPrefix + sListTagName + OUSTR("/") + sPrefix + sMemberTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNodeList> list = + xpathApi->selectNodeList(parent, sExprList); + + ::std::list<OUString > retList; + sal_Int32 length = list->getLength(); + for (sal_Int32 i = 0; i < length; i++) + { + const Reference<css::xml::dom::XNode> member = list->item(i); + retList.push_back(member->getNodeValue()); + } + return retList; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> BackendDb::getOneChildFromAllEntries( + OUString const & name) +{ + try + { + ::std::list<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + const OUString sKeyElement = getKeyElementName(); + ::rtl::OUStringBuffer buf(512); + buf.append(sPrefix); + buf.appendAscii(":"); + buf.append(sKeyElement); + buf.appendAscii("/"); + buf.append(sPrefix); + buf.appendAscii(":"); + buf.append(name); + buf.append(OUSTR("/text()")); + + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, buf.makeStringAndClear()); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + + + +//================================================================================ +RegisteredDb::RegisteredDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +void RegisteredDb::addEntry(::rtl::OUString const & url) +{ + try{ + + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix = getNSPrefix(); + const OUString sEntry = getKeyElementName(); + + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + +#if OSL_DEBUG_LEVEL > 0 + //There must not be yet an entry with the same url + OUString sExpression( + sPrefix + OUSTR(":") + sEntry + OUSTR("[@url = \"") + url + OUSTR("\"]")); + Reference<css::xml::dom::XNode> _extensionNode = + getXPathAPI()->selectSingleNode(root, sExpression); + OSL_ASSERT(! _extensionNode.is()); +#endif + Reference<css::xml::dom::XElement> helpElement( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sEntry)); + + helpElement->setAttribute(OUSTR("url"), url); + + Reference<css::xml::dom::XNode> helpNode( + helpElement, UNO_QUERY_THROW); + root->appendChild(helpNode); + + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +bool RegisteredDb::getEntry(::rtl::OUString const & url) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sEntry = getKeyElementName(); + const OUString sExpression( + sPrefix + OUSTR(":") + sEntry + OUSTR("[@url = \"") + url + OUSTR("\"]")); + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + //find the extension element that is to be removed + Reference<css::xml::dom::XNode> aNode = + xpathApi->selectSingleNode(root, sExpression); + if (!aNode.is()) + { + return false; + } + return true; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + + +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/dp_registry.cxx b/desktop/source/deployment/registry/dp_registry.cxx new file mode 100644 index 000000000000..0f309a5b729f --- /dev/null +++ b/desktop/source/deployment/registry/dp_registry.cxx @@ -0,0 +1,558 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_registry.hrc" +#include "dp_misc.h" +#include "dp_resource.h" +#include "dp_interact.h" +#include "dp_ucb.h" +#include "osl/diagnose.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/compbase2.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/sequence.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/uno/DeploymentException.hpp" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/util/XUpdatable.hpp" +#include "com/sun/star/container/XContentEnumerationAccess.hpp" +#include "com/sun/star/deployment/PackageRegistryBackend.hpp" +#include <hash_map> +#include <set> +#include <hash_set> +#include <memory> + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + + +namespace dp_registry { + +namespace backend { +namespace bundle { +Reference<deployment::XPackageRegistry> create( + Reference<deployment::XPackageRegistry> const & xRootRegistry, + OUString const & context, OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ); +} +} + +namespace { + +typedef ::cppu::WeakComponentImplHelper2< + deployment::XPackageRegistry, util::XUpdatable > t_helper; + +//============================================================================== +class PackageRegistryImpl : private MutexHolder, public t_helper +{ + struct ci_string_hash { + ::std::size_t operator () ( OUString const & str ) const { + return str.toAsciiLowerCase().hashCode(); + } + }; + struct ci_string_equals { + bool operator () ( OUString const & str1, OUString const & str2 ) const{ + return str1.equalsIgnoreAsciiCase( str2 ); + } + }; + typedef ::std::hash_map< + OUString, Reference<deployment::XPackageRegistry>, + ci_string_hash, ci_string_equals > t_string2registry; + typedef ::std::hash_map< + OUString, OUString, + ci_string_hash, ci_string_equals > t_string2string; + typedef ::std::set< + Reference<deployment::XPackageRegistry> > t_registryset; + + t_string2registry m_mediaType2backend; + t_string2string m_filter2mediaType; + t_registryset m_ambiguousBackends; + t_registryset m_allBackends; + ::std::vector< Reference<deployment::XPackageTypeInfo> > m_typesInfos; + + void insertBackend( + Reference<deployment::XPackageRegistry> const & xBackend ); + +protected: + inline void check(); + virtual void SAL_CALL disposing(); + + virtual ~PackageRegistryImpl(); + PackageRegistryImpl() : t_helper( getMutex() ) {} + + +public: + static Reference<deployment::XPackageRegistry> create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ); + + // XUpdatable + virtual void SAL_CALL update() throw (RuntimeException); + + // XPackageRegistry + virtual Reference<deployment::XPackage> SAL_CALL bindPackage( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::InvalidRemovedParameterException, + CommandFailedException, + lang::IllegalArgumentException, RuntimeException); + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +inline void PackageRegistryImpl::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("PackageRegistry instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +//______________________________________________________________________________ +void PackageRegistryImpl::disposing() +{ + // dispose all backends: + t_registryset::const_iterator iPos( m_allBackends.begin() ); + t_registryset::const_iterator const iEnd( m_allBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) { + try_dispose( *iPos ); + } + m_mediaType2backend = t_string2registry(); + m_ambiguousBackends = t_registryset(); + m_allBackends = t_registryset(); + + t_helper::disposing(); +} + +//______________________________________________________________________________ +PackageRegistryImpl::~PackageRegistryImpl() +{ +} + +//______________________________________________________________________________ +OUString normalizeMediaType( OUString const & mediaType ) +{ + ::rtl::OUStringBuffer buf; + sal_Int32 index = 0; + for (;;) { + buf.append( mediaType.getToken( 0, '/', index ).trim() ); + if (index < 0) + break; + buf.append( static_cast< sal_Unicode >('/') ); + } + return buf.makeStringAndClear(); +} + +//______________________________________________________________________________ + +void PackageRegistryImpl::insertBackend( + Reference<deployment::XPackageRegistry> const & xBackend ) +{ + m_allBackends.insert( xBackend ); + typedef ::std::hash_set<OUString, ::rtl::OUStringHash> t_stringset; + t_stringset ambiguousFilters; + + const Sequence< Reference<deployment::XPackageTypeInfo> > packageTypes( + xBackend->getSupportedPackageTypes() ); + for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos ) + { + Reference<deployment::XPackageTypeInfo> const & xPackageType = + packageTypes[ pos ]; + m_typesInfos.push_back( xPackageType ); + + const OUString mediaType( normalizeMediaType( + xPackageType->getMediaType() ) ); + ::std::pair<t_string2registry::iterator, bool> mb_insertion( + m_mediaType2backend.insert( t_string2registry::value_type( + mediaType, xBackend ) ) ); + if (mb_insertion.second) + { + // add parameterless media-type, too: + sal_Int32 semi = mediaType.indexOf( ';' ); + if (semi >= 0) { + m_mediaType2backend.insert( + t_string2registry::value_type( + mediaType.copy( 0, semi ), xBackend ) ); + } + const OUString fileFilter( xPackageType->getFileFilter() ); + //The package backend shall also be called to determine the mediatype + //(XPackageRegistry.bindPackage) when the URL points to a directory. + const bool bExtension = mediaType.equals(OUSTR("application/vnd.sun.star.package-bundle")); + if (fileFilter.getLength() == 0 || + fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*.*") ) || + fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*") ) || + bExtension) + { + m_ambiguousBackends.insert( xBackend ); + } + else + { + sal_Int32 nIndex = 0; + do { + OUString token( fileFilter.getToken( 0, ';', nIndex ) ); + if (token.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("*.") )) + token = token.copy( 1 ); + if (token.getLength() == 0) + continue; + // mark any further wildcards ambig: + bool ambig = (token.indexOf('*') >= 0 || + token.indexOf('?') >= 0); + if (! ambig) { + ::std::pair<t_string2string::iterator, bool> ins( + m_filter2mediaType.insert( + t_string2string::value_type( + token, mediaType ) ) ); + ambig = !ins.second; + if (ambig) { + // filter has already been in: add previously + // added backend to ambig set + const t_string2registry::const_iterator iFind( + m_mediaType2backend.find( + /* media-type of pr. added backend */ + ins.first->second ) ); + OSL_ASSERT( + iFind != m_mediaType2backend.end() ); + if (iFind != m_mediaType2backend.end()) + m_ambiguousBackends.insert( iFind->second ); + } + } + if (ambig) { + m_ambiguousBackends.insert( xBackend ); + // mark filter to be removed later from filters map: + ambiguousFilters.insert( token ); + } + } + while (nIndex >= 0); + } + } +#if OSL_DEBUG_LEVEL > 0 + else { + ::rtl::OUStringBuffer buf; + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM( + "more than one PackageRegistryBackend for " + "media-type=\"") ); + buf.append( mediaType ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" => ") ); + buf.append( Reference<lang::XServiceInfo>( + xBackend, UNO_QUERY_THROW )-> + getImplementationName() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") ); + OSL_ENSURE( 0, ::rtl::OUStringToOString( + buf.makeStringAndClear(), + RTL_TEXTENCODING_UTF8 ) ); + } +#endif + } + + // cut out ambiguous filters: + t_stringset::const_iterator iPos( ambiguousFilters.begin() ); + const t_stringset::const_iterator iEnd( ambiguousFilters.end() ); + for ( ; iPos != iEnd; ++iPos ) { + m_filter2mediaType.erase( *iPos ); + } +} + +//______________________________________________________________________________ +Reference<deployment::XPackageRegistry> PackageRegistryImpl::create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + PackageRegistryImpl * that = new PackageRegistryImpl; + Reference<deployment::XPackageRegistry> xRet(that); + + // auto-detect all registered package registries: + Reference<container::XEnumeration> xEnum( + Reference<container::XContentEnumerationAccess>( + xComponentContext->getServiceManager(), + UNO_QUERY_THROW )->createContentEnumeration( + OUSTR("com.sun.star.deployment.PackageRegistryBackend") ) ); + if (xEnum.is()) + { + while (xEnum->hasMoreElements()) + { + Any element( xEnum->nextElement() ); + Sequence<Any> registryArgs( + cachePath.getLength() == 0 ? 1 : 3 ); + registryArgs[ 0 ] <<= context; + if (cachePath.getLength() > 0) + { + Reference<lang::XServiceInfo> xServiceInfo( + element, UNO_QUERY_THROW ); + OUString registryCachePath( + makeURL( cachePath, + ::rtl::Uri::encode( + xServiceInfo->getImplementationName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + registryArgs[ 1 ] <<= registryCachePath; + registryArgs[ 2 ] <<= readOnly; + if (! readOnly) + create_folder( 0, registryCachePath, + Reference<XCommandEnvironment>() ); + } + + Reference<deployment::XPackageRegistry> xBackend; + Reference<lang::XSingleComponentFactory> xFac( element, UNO_QUERY ); + if (xFac.is()) { + xBackend.set( + xFac->createInstanceWithArgumentsAndContext( + registryArgs, xComponentContext ), UNO_QUERY ); + } + else { + Reference<lang::XSingleServiceFactory> xSingleServiceFac( + element, UNO_QUERY_THROW ); + xBackend.set( + xSingleServiceFac->createInstanceWithArguments( + registryArgs ), UNO_QUERY ); + } + if (! xBackend.is()) { + throw DeploymentException( + OUSTR("cannot instantiate PackageRegistryBackend service: ") + + Reference<lang::XServiceInfo>( + element, UNO_QUERY_THROW )->getImplementationName(), + static_cast<OWeakObject *>(that) ); + } + + that->insertBackend( xBackend ); + } + } + + // Insert bundle back-end. + // Always register as last, because we want to add extensions also as folders + // and as a default we accept every folder, which was not recognized by the other + // backends. + Reference<deployment::XPackageRegistry> extensionBackend = + ::dp_registry::backend::bundle::create( + that, context, cachePath, readOnly, xComponentContext); + that->insertBackend(extensionBackend); + + Reference<lang::XServiceInfo> xServiceInfo( + extensionBackend, UNO_QUERY_THROW ); + + OSL_ASSERT(xServiceInfo.is()); + OUString registryCachePath( + makeURL( cachePath, + ::rtl::Uri::encode( + xServiceInfo->getImplementationName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + create_folder( 0, registryCachePath, Reference<XCommandEnvironment>()); + + +#if OSL_DEBUG_LEVEL > 1 + // dump tables: + { + t_registryset allBackends; + dp_misc::TRACE("> [dp_registry.cxx] media-type detection:\n\n" ); + for ( t_string2string::const_iterator iPos( + that->m_filter2mediaType.begin() ); + iPos != that->m_filter2mediaType.end(); ++iPos ) + { + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("extension \"") ); + buf.append( iPos->first ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\" maps to media-type \"") ); + buf.append( iPos->second ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\" maps to backend ") ); + const Reference<deployment::XPackageRegistry> xBackend( + that->m_mediaType2backend.find( iPos->second )->second ); + allBackends.insert( xBackend ); + buf.append( Reference<lang::XServiceInfo>( + xBackend, UNO_QUERY_THROW ) + ->getImplementationName() ); + dp_misc::writeConsole( buf.makeStringAndClear() + OUSTR("\n")); + } + dp_misc::TRACE( "> [dp_registry.cxx] ambiguous backends:\n\n" ); + for ( t_registryset::const_iterator iPos( + that->m_ambiguousBackends.begin() ); + iPos != that->m_ambiguousBackends.end(); ++iPos ) + { + ::rtl::OUStringBuffer buf; + buf.append( + Reference<lang::XServiceInfo>( + *iPos, UNO_QUERY_THROW )->getImplementationName() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + const Sequence< Reference<deployment::XPackageTypeInfo> > types( + (*iPos)->getSupportedPackageTypes() ); + for ( sal_Int32 pos = 0; pos < types.getLength(); ++pos ) { + Reference<deployment::XPackageTypeInfo> const & xInfo = + types[ pos ]; + buf.append( xInfo->getMediaType() ); + const OUString filter( xInfo->getFileFilter() ); + if (filter.getLength() > 0) { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" (") ); + buf.append( filter ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") ); + } + if (pos < (types.getLength() - 1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + dp_misc::TRACE(buf.makeStringAndClear() + OUSTR("\n\n")); + } + allBackends.insert( that->m_ambiguousBackends.begin(), + that->m_ambiguousBackends.end() ); + OSL_ASSERT( allBackends == that->m_allBackends ); + } +#endif + + return xRet; +} + +// XUpdatable: broadcast to backends +//______________________________________________________________________________ +void PackageRegistryImpl::update() throw (RuntimeException) +{ + check(); + t_registryset::const_iterator iPos( m_allBackends.begin() ); + const t_registryset::const_iterator iEnd( m_allBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) { + const Reference<util::XUpdatable> xUpdatable( *iPos, UNO_QUERY ); + if (xUpdatable.is()) + xUpdatable->update(); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageRegistryImpl::bindPackage( + OUString const & url, OUString const & mediaType_, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, deployment::InvalidRemovedParameterException, + CommandFailedException, + lang::IllegalArgumentException, RuntimeException) +{ + check(); + OUString mediaType(mediaType_); + if (mediaType.getLength() == 0) + { + ::ucbhelper::Content ucbContent; + if (create_ucb_content( + &ucbContent, url, xCmdEnv, false /* no throw */ ) + && !ucbContent.isFolder()) + { + OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + for (;;) + { + const t_string2string::const_iterator iFind( + m_filter2mediaType.find(title) ); + if (iFind != m_filter2mediaType.end()) { + mediaType = iFind->second; + break; + } + sal_Int32 point = title.indexOf( '.', 1 /* consume . */ ); + if (point < 0) + break; + title = title.copy(point); + } + } + } + if (mediaType.getLength() == 0) + { + // try ambiguous backends: + t_registryset::const_iterator iPos( m_ambiguousBackends.begin() ); + const t_registryset::const_iterator iEnd( m_ambiguousBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + try { + return (*iPos)->bindPackage( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } + catch (lang::IllegalArgumentException &) { + } + } + throw lang::IllegalArgumentException( + getResourceString(RID_STR_CANNOT_DETECT_MEDIA_TYPE) + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + else + { + // get backend by media-type: + t_string2registry::const_iterator iFind( + m_mediaType2backend.find( normalizeMediaType(mediaType) ) ); + if (iFind == m_mediaType2backend.end()) { + // xxx todo: more sophisticated media-type argument parsing... + sal_Int32 q = mediaType.indexOf( ';' ); + if (q >= 0) { + iFind = m_mediaType2backend.find( + normalizeMediaType( + // cut parameters: + mediaType.copy( 0, q ) ) ); + } + } + if (iFind == m_mediaType2backend.end()) { + throw lang::IllegalArgumentException( + getResourceString(RID_STR_UNSUPPORTED_MEDIA_TYPE) + mediaType, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + return iFind->second->bindPackage( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +PackageRegistryImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return comphelper::containerToSequence(m_typesInfos); +} +} // anon namespace + +//============================================================================== +Reference<deployment::XPackageRegistry> SAL_CALL create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + return PackageRegistryImpl::create( + context, cachePath, readOnly, xComponentContext ); +} + +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/dp_registry.src b/desktop/source/deployment/registry/dp_registry.src new file mode 100644 index 000000000000..68a52621741f --- /dev/null +++ b/desktop/source/deployment/registry/dp_registry.src @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_registry.hrc" + +String RID_STR_REGISTERING_PACKAGE +{ + Text [ en-US ] = "Enabling: "; +}; + +String RID_STR_REVOKING_PACKAGE +{ + Text [ en-US ] = "Disabling: "; +}; + +String RID_STR_CANNOT_DETECT_MEDIA_TYPE +{ + Text [ en-US ] = "Cannot detect media-type: "; +}; + +String RID_STR_UNSUPPORTED_MEDIA_TYPE +{ + Text [ en-US ] = "This media-type is not supported: "; +}; + +String RID_STR_ERROR_WHILE_REGISTERING +{ + Text [ en-US ] = "An error occurred while enabling: "; +}; + +String RID_STR_ERROR_WHILE_REVOKING +{ + Text [ en-US ] = "An error occurred while disabling: "; +}; + diff --git a/desktop/source/deployment/registry/executable/dp_executable.cxx b/desktop/source/deployment/registry/executable/dp_executable.cxx new file mode 100644 index 000000000000..968ee7297b0f --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executable.cxx @@ -0,0 +1,331 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_interact.h" +#include "rtl/string.hxx" +#include "osl/file.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "cppuhelper/implbase1.hxx" +#include "dp_executablebackenddb.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace dp_misc; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace executable { +namespace { + +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class ExecutablePackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + bool getFileAttributes(sal_uInt64& out_Attributes); + bool isUrlTargetInExtension(); + public: + inline ExecutablePackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier) + {} + }; + friend class ExecutablePackageImpl; + + typedef ::std::hash_map< OUString, Reference<XInterface>, + ::rtl::OUStringHash > t_string2object; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url); + bool isRegisteredInDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + Reference<deployment::XPackageTypeInfo> m_xExecutableTypeInfo; + std::auto_ptr<ExecutableBackendDb> m_backendDb; +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; +}; + + +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xExecutableTypeInfo(new Package::TypeInfo( + OUSTR("application/vnd.sun.star.executable"), + OUSTR(""), + OUSTR("Executable"), + RID_IMG_COMPONENT, + RID_IMG_COMPONENT_HC ) ) +{ + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ExecutableBackendDb(getComponentContext(), dbFile)); + } +} + +void BackendImpl::addDataToDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url); +} + +bool BackendImpl::isRegisteredInDb(OUString const & url) +{ + bool ret = false; + if (m_backendDb.get()) + ret = m_backendDb->getEntry(url); + return ret; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +// XPackageRegistry +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return Sequence<Reference<deployment::XPackageTypeInfo> >( + & m_xExecutableTypeInfo, 1); +} + +// PackageRegistryBackend +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (mediaType.getLength() == 0) + { + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + dp_misc::StrTitle::get() ).get<OUString>(); + } + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.executable")) + { + return new BackendImpl::ExecutablePackageImpl( + this, url, name, m_xExecutableTypeInfo, bRemoved, + identifier); + } + } + } + return Reference<deployment::XPackage>(); +} + +//############################################################################## + + +// Package +BackendImpl * BackendImpl::ExecutablePackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<ExecutablePackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::ExecutablePackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<dp_misc::AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + bool registered = getMyBackend()->isRegisteredInDb(getURL()); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + sal_True /* IsPresent */, + beans::Ambiguous<sal_Bool>( + registered, sal_False /* IsAmbiguous */ ) ); +} + +void BackendImpl::ExecutablePackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /*startup*/, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & /*xCmdEnv*/ ) +{ + checkAborted(abortChannel); + if (doRegisterPackage) + { + if (!isUrlTargetInExtension()) + { + OSL_ASSERT(0); + return; + } + sal_uInt64 attributes = 0; + //Setting the executable attribut does not affect executables on Windows + if (getFileAttributes(attributes)) + { + if(getMyBackend()->m_context.equals(OUSTR("user"))) + attributes |= osl_File_Attribute_OwnExe; + else if (getMyBackend()->m_context.equals(OUSTR("shared"))) + attributes |= (osl_File_Attribute_OwnExe | osl_File_Attribute_GrpExe + | osl_File_Attribute_OthExe); + else if (!getMyBackend()->m_context.equals(OUSTR("bundled"))) + //Bundled extension are required to be in the properly + //installed. That is an executable must have the right flags + OSL_ASSERT(0); + + //This won't have affect on Windows + osl::File::setAttributes( + dp_misc::expandUnoRcUrl(m_url), attributes); + } + getMyBackend()->addDataToDb(getURL()); + } + else + { + getMyBackend()->deleteDataFromDb(getURL()); + } +} + +//We currently cannot check if this XPackage represents a content of a particular extension +//But we can check if we are within $UNO_USER_PACKAGES_CACHE etc. +//Done for security reasons. For example an extension manifest could contain a path to +//an executable outside the extension. +bool BackendImpl::ExecutablePackageImpl::isUrlTargetInExtension() +{ + bool bSuccess = false; + OUString sExtensionDir; + if(getMyBackend()->m_context.equals(OUSTR("user"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_USER_PACKAGES_CACHE")); + else if (getMyBackend()->m_context.equals(OUSTR("shared"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_SHARED_PACKAGES_CACHE")); + else if (getMyBackend()->m_context.equals(OUSTR("bundled"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$BUNDLED_EXTENSIONS")); + else + OSL_ASSERT(0); + //remove file ellipses + if (osl::File::E_None == osl::File::getAbsoluteFileURL(OUString(), sExtensionDir, sExtensionDir)) + { + OUString sFile; + if (osl::File::E_None == osl::File::getAbsoluteFileURL( + OUString(), dp_misc::expandUnoRcUrl(m_url), sFile)) + { + if (sal_True == sFile.match(sExtensionDir, 0)) + bSuccess = true; + } + } + return bSuccess; +} + +bool BackendImpl::ExecutablePackageImpl::getFileAttributes(sal_uInt64& out_Attributes) +{ + bool bSuccess = false; + const OUString url(dp_misc::expandUnoRcUrl(m_url)); + osl::DirectoryItem item; + if (osl::FileBase::E_None == osl::DirectoryItem::get(url, item)) + { + osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes); + if( osl::FileBase::E_None == item.getFileStatus(aStatus)) + { + out_Attributes = aStatus.getAttributes(); + bSuccess = true; + } + } + return bSuccess; +} + +//############################################################################## + + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.executable.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace component +} // namespace backend +} // namespace dp_registry + + diff --git a/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx b/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx new file mode 100644 index 000000000000..ff1044910985 --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "dp_misc.h" +#include "dp_executablebackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/executable-registry/2010" +#define NS_PREFIX "exe" +#define ROOT_ELEMENT_NAME "executable-backend-db" +#define ENTRY_NAME "executable" + +namespace dp_registry { +namespace backend { +namespace executable { + +ExecutableBackendDb::ExecutableBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):RegisteredDb(xContext, url) +{ + +} + +OUString ExecutableBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ExecutableBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ExecutableBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ExecutableBackendDb::getKeyElementName() +{ + return OUSTR(ENTRY_NAME); +} + + +} // namespace executable +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx b/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx new file mode 100644 index 000000000000..80cd33771a34 --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_EXECUTABLEBACKENDDB_HXX +#define INCLUDED_DP_EXECUTABLEBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace executable { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + The format looks like this: + +<?xml version="1.0"?> + */ +class ExecutableBackendDb: public dp_registry::backend::RegisteredDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + + ExecutableBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/executable/makefile.mk b/desktop/source/deployment/registry/executable/makefile.mk new file mode 100644 index 000000000000..81b2baa44e5d --- /dev/null +++ b/desktop/source/deployment/registry/executable/makefile.mk @@ -0,0 +1,44 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_executable +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_executable.obj \ + $(SLO)$/dp_executablebackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/help/dp_help.cxx b/desktop/source/deployment/registry/help/dp_help.cxx new file mode 100644 index 000000000000..5a5efe825cfb --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.cxx @@ -0,0 +1,658 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_help.hrc" +#include "dp_backend.h" +#include "dp_helpbackenddb.hxx" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "osl/file.hxx" +#include "rtl/bootstrap.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "unotools/pathoptions.hxx" + +#include <l10ntools/compilehelp.hxx> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/util/XMacroExpander.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/XVndSunStarExpandUrl.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include "boost/optional.hpp" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace help { +namespace { + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + +// HelpBackendDb::Data m_dbData; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + bool extensionContainsCompiledHelp(); + public: + PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier); + + //XPackage + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, css::uno::RuntimeException); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void implProcessHelp( Reference< deployment::XPackage > xPackage, bool doRegisterPackage, + bool compiledHelp, Reference<ucb::XCommandEnvironment> const & xCmdEnv); + void implCollectXhpFiles( const rtl::OUString& aDir, + std::vector< rtl::OUString >& o_rXhpFileVector ); + + void addDataToDb(OUString const & url, HelpBackendDb::Data const & data); + ::boost::optional<HelpBackendDb::Data> readDataFromDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + Reference< ucb::XSimpleFileAccess > getFileAccess( void ); + Reference< ucb::XSimpleFileAccess > m_xSFA; + + const Reference<deployment::XPackageTypeInfo> m_xHelpTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + std::auto_ptr<HelpBackendDb> m_backendDb; + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xHelpTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.help"), + rtl::OUString(), + getResourceString(RID_STR_HELP), + RID_IMG_HELP, RID_IMG_HELP_HC ) ), + m_typeInfos( 1 ) +{ + m_typeInfos[ 0 ] = m_xHelpTypeInfo; + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new HelpBackendDb(getComponentContext(), dbFile)); + + //clean up data folders which are no longer used. + //This must not be done in the same process where the help files + //are still registers. Only after revoking and restarting OOo the folders + //can be removed. This works now, because the extension manager is a singleton + //and the backends are only create once per process. + ::std::list<OUString> folders = m_backendDb->getAllDataUrls(); + deleteUnusedFolders(OUString(), folders); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + // we don't support auto detection: + if (mediaType_.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType_, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.help")) + { + return new PackageImpl( + this, url, name, m_xHelpTypeInfo, bRemoved, + identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType_, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +void BackendImpl::addDataToDb( + OUString const & url, HelpBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +::boost::optional<HelpBackendDb::Data> BackendImpl::readDataFromDb( + OUString const & url) +{ + ::boost::optional<HelpBackendDb::Data> data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +//############################################################################## +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name, xPackageType, bRemoved, + identifier) +{ +// if (bRemoved) +// { +// ::boost::optional<HelpBackendDb::Data> opt = +// getMyBackend()->readDataFromDb(url); +// if (opt) +// m_dbData = *opt; +// } +} + +// Package +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + + +bool BackendImpl::PackageImpl::extensionContainsCompiledHelp() +{ + bool bCompiled = true; + rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl(getURL()); + + ::osl::Directory helpFolder(aExpandedHelpURL); + if ( helpFolder.open() == ::osl::File::E_None) + { + //iterate over the contents of the help folder + //We assume that all folders withing the help folder contain language specific + //help files. If just one of them does not contain compiled help then this + //function returns false. + ::osl::DirectoryItem item; + ::osl::File::RC errorNext = ::osl::File::E_None; + while ((errorNext = helpFolder.getNextItem(item)) == ::osl::File::E_None) + { + //No find the language folders + ::osl::FileStatus stat(FileStatusMask_Type | FileStatusMask_FileName |FileStatusMask_FileURL); + if (item.getFileStatus(stat) == ::osl::File::E_None) + { + if (stat.getFileType() != ::osl::FileStatus::Directory) + continue; + + //look if there is the folder help.idxl in the language folder + OUString compUrl(stat.getFileURL() + OUSTR("/help.idxl")); + ::osl::Directory compiledFolder(compUrl); + if (compiledFolder.open() != ::osl::File::E_None) + { + bCompiled = false; + break; + } + } + else + { + //Error + OSL_ASSERT(0); + bCompiled = false; + break; + } + } + if (errorNext != ::osl::File::E_NOENT + && errorNext != ::osl::File::E_None) + { + //Error + OSL_ASSERT(0); + bCompiled = false; + } + } + return bCompiled; +} +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + + bool bReg = false; + if (that->readDataFromDb(getURL())) + bReg = true; + + return beans::Optional< beans::Ambiguous<sal_Bool> >( true, beans::Ambiguous<sal_Bool>( bReg, false ) ); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /* startup */, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + (void)doRegisterPackage; + (void)abortChannel; + (void)xCmdEnv; + + BackendImpl* that = getMyBackend(); + Reference< deployment::XPackage > xThisPackage( this ); + that->implProcessHelp( xThisPackage, doRegisterPackage, + extensionContainsCompiledHelp(), xCmdEnv); +} + +beans::Optional< OUString > BackendImpl::PackageImpl::getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::boost::optional<HelpBackendDb::Data> data = + getMyBackend()->readDataFromDb(getURL()); + + if (data) + return beans::Optional<OUString>(true, data->dataUrl); + + return beans::Optional<OUString>(true, OUString()); +} + + +//############################################################################## + +static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) ); +static rtl::OUString aHelpStr( rtl::OUString::createFromAscii( "help" ) ); + + +void BackendImpl::implProcessHelp +( Reference< deployment::XPackage > xPackage, bool doRegisterPackage, bool compiledHelp, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + OSL_ASSERT(xPackage.is()); + if (doRegisterPackage) + { + HelpBackendDb::Data data; + + if (compiledHelp) + { + data.dataUrl = xPackage->getURL(); + } + else + { + const OUString sHelpFolder = createFolder(OUString(), xCmdEnv); + data.dataUrl = sHelpFolder; + + Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess(); + rtl::OUString aHelpURL = xPackage->getURL(); + rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl( aHelpURL ); + rtl::OUString aName = xPackage->getName(); + if( !xSFA->isFolder( aExpandedHelpURL ) ) + { + rtl::OUString aErrStr = getResourceString( RID_STR_HELPPROCESSING_GENERAL_ERROR ); + aErrStr += rtl::OUString::createFromAscii( "No help folder" ); + OWeakObject* oWeakThis = static_cast<OWeakObject *>(this); + throw deployment::DeploymentException( rtl::OUString(), oWeakThis, + makeAny( uno::Exception( aErrStr, oWeakThis ) ) ); + } + + Reference<XComponentContext> const & xContext = getComponentContext(); + Reference< script::XInvocation > xInvocation; + if( xContext.is() ) + { + try + { + xInvocation = Reference< script::XInvocation >( + xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii( + "com.sun.star.help.HelpIndexer" ), xContext ) , UNO_QUERY ); + } + catch (Exception &) + { + // i98680: Survive missing lucene + } + } + + // Scan languages + Sequence< rtl::OUString > aLanguageFolderSeq = xSFA->getFolderContents( aExpandedHelpURL, true ); + sal_Int32 nLangCount = aLanguageFolderSeq.getLength(); + const rtl::OUString* pSeq = aLanguageFolderSeq.getConstArray(); + for( sal_Int32 iLang = 0 ; iLang < nLangCount ; ++iLang ) + { + rtl::OUString aLangURL = pSeq[iLang]; + if( xSFA->isFolder( aLangURL ) ) + { + std::vector< rtl::OUString > aXhpFileVector; + + // calculate jar file URL + sal_Int32 indexStartSegment = aLangURL.lastIndexOf('/'); + // for example "/en" + OUString langFolderURLSegment( + aLangURL.copy( + indexStartSegment + 1, aLangURL.getLength() - indexStartSegment - 1)); + + //create the folder in the "temporary folder" + ::ucbhelper::Content langFolderContent; + const OUString langFolderDest = makeURL(sHelpFolder, langFolderURLSegment); + const OUString langFolderDestExpanded = ::dp_misc::expandUnoRcUrl(langFolderDest); + ::dp_misc::create_folder( + &langFolderContent, + langFolderDest, xCmdEnv); + + rtl::OUString aJarFile( + makeURL(sHelpFolder, langFolderURLSegment + aSlash + aHelpStr + + OUSTR(".jar"))); + aJarFile = ::dp_misc::expandUnoRcUrl(aJarFile); + + rtl::OUString aEncodedJarFilePath = rtl::Uri::encode( + aJarFile, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + rtl::OUString aDestBasePath = rtl::OUString::createFromAscii( "vnd.sun.star.pkg://" ); + aDestBasePath += aEncodedJarFilePath; + aDestBasePath += rtl::OUString::createFromAscii( "/" ); + + sal_Int32 nLenLangFolderURL = aLangURL.getLength() + 1; + + Sequence< rtl::OUString > aSubLangSeq = xSFA->getFolderContents( aLangURL, true ); + sal_Int32 nSubLangCount = aSubLangSeq.getLength(); + const rtl::OUString* pSubLangSeq = aSubLangSeq.getConstArray(); + for( sal_Int32 iSubLang = 0 ; iSubLang < nSubLangCount ; ++iSubLang ) + { + rtl::OUString aSubFolderURL = pSubLangSeq[iSubLang]; + if( !xSFA->isFolder( aSubFolderURL ) ) + continue; + + implCollectXhpFiles( aSubFolderURL, aXhpFileVector ); + + // Copy to package (later: move?) + rtl::OUString aDestPath = aDestBasePath; + rtl::OUString aPureFolderName = aSubFolderURL.copy( nLenLangFolderURL ); + aDestPath += aPureFolderName; + xSFA->copy( aSubFolderURL, aDestPath ); + } + + // Call compiler + sal_Int32 nXhpFileCount = aXhpFileVector.size(); + rtl::OUString* pXhpFiles = new rtl::OUString[nXhpFileCount]; + for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp ) + { + rtl::OUString aXhpFile = aXhpFileVector[iXhp]; + rtl::OUString aXhpRelFile = aXhpFile.copy( nLenLangFolderURL ); + pXhpFiles[iXhp] = aXhpRelFile; + } + + rtl::OUString aOfficeHelpPath( SvtPathOptions().GetHelpPath() ); + rtl::OUString aOfficeHelpPathFileURL; + ::osl::File::getFileURLFromSystemPath( aOfficeHelpPath, aOfficeHelpPathFileURL ); + + HelpProcessingErrorInfo aErrorInfo; + bool bSuccess = compileExtensionHelp( + aOfficeHelpPathFileURL, aHelpStr, aLangURL, + nXhpFileCount, pXhpFiles, + langFolderDestExpanded, aErrorInfo ); + + if( bSuccess && xInvocation.is() ) + { + Sequence<uno::Any> aParamsSeq( 6 ); + + aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) ); + + rtl::OUString aLang; + sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' ); + if( nLastSlash != -1 ) + aLang = aLangURL.copy( nLastSlash + 1 ); + else + aLang = rtl::OUString::createFromAscii( "en" ); + aParamsSeq[1] = uno::makeAny( aLang ); + + aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) ); + aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) ); + + aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) ); + rtl::OUString aSystemPath; + osl::FileBase::getSystemPathFromFileURL( + langFolderDestExpanded, aSystemPath ); + aParamsSeq[5] = uno::makeAny( aSystemPath ); + + Sequence< sal_Int16 > aOutParamIndex; + Sequence< uno::Any > aOutParam; + uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ), + aParamsSeq, aOutParamIndex, aOutParam ); + } + + if( !bSuccess ) + { + USHORT nErrStrId = 0; + switch( aErrorInfo.m_eErrorClass ) + { + case HELPPROCESSING_GENERAL_ERROR: + case HELPPROCESSING_INTERNAL_ERROR: nErrStrId = RID_STR_HELPPROCESSING_GENERAL_ERROR; break; + case HELPPROCESSING_XMLPARSING_ERROR: nErrStrId = RID_STR_HELPPROCESSING_XMLPARSING_ERROR; break; + default: ; + }; + + rtl::OUString aErrStr; + if( nErrStrId != 0 ) + { + aErrStr = getResourceString( nErrStrId ); + + // Remoce CR/LF + rtl::OUString aErrMsg( aErrorInfo.m_aErrorMsg ); + sal_Unicode nCR = 13, nLF = 10; + sal_Int32 nSearchCR = aErrMsg.indexOf( nCR ); + sal_Int32 nSearchLF = aErrMsg.indexOf( nLF ); + sal_Int32 nCopy; + if( nSearchCR != -1 || nSearchLF != -1 ) + { + if( nSearchCR == -1 ) + nCopy = nSearchLF; + else if( nSearchLF == -1 ) + nCopy = nSearchCR; + else + nCopy = ( nSearchCR < nSearchLF ) ? nSearchCR : nSearchLF; + + aErrMsg = aErrMsg.copy( 0, nCopy ); + } + aErrStr += aErrMsg; + if( nErrStrId == RID_STR_HELPPROCESSING_XMLPARSING_ERROR && aErrorInfo.m_aXMLParsingFile.getLength() ) + { + aErrStr += rtl::OUString::createFromAscii( " in " ); + + rtl::OUString aDecodedFile = rtl::Uri::decode( aErrorInfo.m_aXMLParsingFile, + rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + aErrStr += aDecodedFile; + if( aErrorInfo.m_nXMLParsingLine != -1 ) + { + aErrStr += rtl::OUString::createFromAscii( ", line " ); + aErrStr += ::rtl::OUString::valueOf( aErrorInfo.m_nXMLParsingLine ); + } + } + } + + OWeakObject* oWeakThis = static_cast<OWeakObject *>(this); + throw deployment::DeploymentException( rtl::OUString(), oWeakThis, + makeAny( uno::Exception( aErrStr, oWeakThis ) ) ); + } + } + } + } + //Writing the data entry replaces writing the flag file. If we got to this + //point the registration was successful. + addDataToDb(xPackage->getURL(), data); + } //if (doRegisterPackage) + else + { + deleteDataFromDb(xPackage->getURL()); + } +} + + +void BackendImpl::implCollectXhpFiles( const rtl::OUString& aDir, + std::vector< rtl::OUString >& o_rXhpFileVector ) +{ + Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess(); + + // Scan xhp files recursively + Sequence< rtl::OUString > aSeq = xSFA->getFolderContents( aDir, true ); + sal_Int32 nCount = aSeq.getLength(); + const rtl::OUString* pSeq = aSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nCount ; ++i ) + { + rtl::OUString aURL = pSeq[i]; + if( xSFA->isFolder( aURL ) ) + { + implCollectXhpFiles( aURL, o_rXhpFileVector ); + } + else + { + sal_Int32 nLastDot = aURL.lastIndexOf( '.' ); + if( nLastDot != -1 ) + { + rtl::OUString aExt = aURL.copy( nLastDot + 1 ); + if( aExt.equalsIgnoreAsciiCase( rtl::OUString::createFromAscii( "xhp" ) ) ) + o_rXhpFileVector.push_back( aURL ); + } + } + } +} + +Reference< ucb::XSimpleFileAccess > BackendImpl::getFileAccess( void ) +{ + if( !m_xSFA.is() ) + { + Reference<XComponentContext> const & xContext = getComponentContext(); + if( xContext.is() ) + { + m_xSFA = Reference< ucb::XSimpleFileAccess >( + xContext->getServiceManager()->createInstanceWithContext( + rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), + xContext ), UNO_QUERY ); + } + if( !m_xSFA.is() ) + { + throw RuntimeException( + ::rtl::OUString::createFromAscii( + "dp_registry::backend::help::BackendImpl::getFileAccess(), " + "could not instatiate SimpleFileAccess." ), + Reference< XInterface >() ); + } + } + return m_xSFA; +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.help.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace help +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/help/dp_help.hrc b/desktop/source/deployment/registry/help/dp_help.hrc new file mode 100644 index 000000000000..c1e10547ccdd --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_HELP_HRC +#define INCLUDED_DP_HELP_HRC + +#include "deployment.hrc" + +#define RID_STR_HELP (RID_DEPLOYMENT_HELP_START+2) + +#define RID_STR_HELPPROCESSING_GENERAL_ERROR (RID_DEPLOYMENT_HELP_START+3) +#define RID_STR_HELPPROCESSING_XMLPARSING_ERROR (RID_DEPLOYMENT_HELP_START+4) + + +#endif diff --git a/desktop/source/deployment/registry/help/dp_help.src b/desktop/source/deployment/registry/help/dp_help.src new file mode 100644 index 000000000000..6b6a3f9a6508 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.src @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_help.hrc" + +String RID_STR_HELP +{ + Text [ en-US ] = "Help"; +}; + +String RID_STR_HELPPROCESSING_GENERAL_ERROR +{ + Text [ en-US ] = "The extension cannot be installed because:\n"; +}; + +String RID_STR_HELPPROCESSING_XMLPARSING_ERROR +{ + Text [ en-US ] = "The extension will not be installed because an error occurred in the Help files:\n"; +}; + diff --git a/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx b/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx new file mode 100644 index 000000000000..8ec9a39d5050 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx @@ -0,0 +1,175 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_helpbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/help-registry/2010" +#define NS_PREFIX "help" +#define ROOT_ELEMENT_NAME "help-backend-db" +#define KEY_ELEMENT_NAME "help" + +namespace dp_registry { +namespace backend { +namespace help { + +HelpBackendDb::HelpBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString HelpBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString HelpBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString HelpBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString HelpBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + +void HelpBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> helpNode + = writeKeyElement(url); + + writeSimpleElement(OUSTR("data-url"), data.dataUrl, helpNode); + save(); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in help backend db: ") + + m_urlDb, 0, exc); + } +} + + +::boost::optional<HelpBackendDb::Data> +HelpBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + HelpBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + retData.dataUrl = readSimpleElement(OUSTR("data-url"), aNode); + } + else + { + return ::boost::optional<Data>(); + } + return ::boost::optional<Data>(retData); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in help backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> HelpBackendDb::getAllDataUrls() +{ + try + { + ::std::list<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + OUString sExpression( + sPrefix + OUSTR(":help/") + sPrefix + OUSTR(":data-url/text()")); + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, sExpression); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in help backend db: ") + + m_urlDb, 0, exc); + } +} + + +} // namespace help +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx b/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx new file mode 100644 index 000000000000..c7b730fd1b99 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_HELPBACKENDDB_HXX +#define INCLUDED_DP_HELPBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include <list> +#include "boost/optional.hpp" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace help { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class HelpBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* the URL to the folder containing the compiled help files, etc. + */ + ::rtl::OUString dataUrl; + + }; + +public: + + HelpBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + ::boost::optional<Data> getEntry(::rtl::OUString const & url); + ::std::list< ::rtl::OUString> getAllDataUrls(); + +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/help/makefile.mk b/desktop/source/deployment/registry/help/makefile.mk new file mode 100644 index 000000000000..d4934f71a46f --- /dev/null +++ b/desktop/source/deployment/registry/help/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_help +ENABLE_EXCEPTIONS = TRUE + +INCPRE += ..$/..$/inc + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_help.src + +SLOFILES = \ + $(SLO)$/dp_help.obj \ + $(SLO)$/dp_helpbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/inc/dp_backend.h b/desktop/source/deployment/registry/inc/dp_backend.h new file mode 100644 index 000000000000..3d3bf7cf912c --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_backend.h @@ -0,0 +1,379 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_REGISTRY_H +#define INCLUDED_DP_REGISTRY_H + +#include "dp_misc.h" +#include "dp_resource.h" +#include "dp_interact.h" +#include "rtl/ref.hxx" +#include "cppuhelper/weakref.hxx" +#include "cppuhelper/implbase1.hxx" +#include "cppuhelper/compbase1.hxx" +#include "cppuhelper/compbase2.hxx" +#include "tools/inetmime.hxx" +#include "com/sun/star/lang/XEventListener.hpp" +#include "com/sun/star/deployment/XPackageRegistry.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "com/sun/star/deployment/InvalidRemovedParameterException.hpp" +#include <memory> +#include <hash_map> +#include <list> +#include "dp_registry.hrc" + +namespace dp_registry +{ +namespace backend +{ + +namespace css = ::com::sun::star; + +class PackageRegistryBackend; + +char const* const BACKEND_SERVICE_NAME = +"com.sun.star.deployment.PackageRegistryBackend"; + +typedef ::cppu::WeakComponentImplHelper1< + css::deployment::XPackage > t_PackageBase; + +//============================================================================== +class Package : protected ::dp_misc::MutexHolder, public t_PackageBase +{ + PackageRegistryBackend * getMyBackend() const; + void processPackage_impl( + bool registerPackage, + bool startup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + +protected: + ::rtl::Reference<PackageRegistryBackend> m_myBackend; + const ::rtl::OUString m_url; + ::rtl::OUString m_name; + ::rtl::OUString m_displayName; + const css::uno::Reference<css::deployment::XPackageTypeInfo> m_xPackageType; + const bool m_bRemoved; + //Only set if m_bRemoved = true; + const ::rtl::OUString m_identifier; + + void check() const; + void fireModified(); + virtual void SAL_CALL disposing(); + + void checkAborted( + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel ); + + // @@@ to be implemented by specific backend: + virtual css::beans::Optional< css::beans::Ambiguous<sal_Bool> > + isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + + virtual ~Package(); + Package( ::rtl::Reference<PackageRegistryBackend> const & myBackend, + ::rtl::OUString const & url, + ::rtl::OUString const & name, + ::rtl::OUString const & displayName, + css::uno::Reference<css::deployment::XPackageTypeInfo> const & + xPackageType, + bool bRemoved, + ::rtl::OUString const & identifier); + +public: + + class TypeInfo : + public ::cppu::WeakImplHelper1<css::deployment::XPackageTypeInfo> + { + const ::rtl::OUString m_mediaType; + const ::rtl::OUString m_fileFilter; + const ::rtl::OUString m_shortDescr; + const sal_uInt16 m_smallIcon, m_smallIcon_HC; + public: + virtual ~TypeInfo(); + TypeInfo( ::rtl::OUString const & mediaType, + ::rtl::OUString const & fileFilter, + ::rtl::OUString const & shortDescr, + sal_uInt16 smallIcon, sal_uInt16 smallIcon_HC ) + : m_mediaType(mediaType), m_fileFilter(fileFilter), + m_shortDescr(shortDescr), + m_smallIcon(smallIcon), m_smallIcon_HC(smallIcon_HC) + {} + // XPackageTypeInfo + virtual ::rtl::OUString SAL_CALL getMediaType() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getShortDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getFileFilter() + throw (css::uno::RuntimeException); + virtual css::uno::Any SAL_CALL getIcon( sal_Bool highContrast, + sal_Bool smallIcon ) + throw (css::uno::RuntimeException); + }; + + // XComponent + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException); + virtual void SAL_CALL addEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XPackage + virtual css::uno::Reference<css::task::XAbortChannel> SAL_CALL + createAbortChannel() throw (css::uno::RuntimeException); + virtual css::beans::Optional< css::beans::Ambiguous<sal_Bool> > + SAL_CALL isRegistered( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException); + + virtual ::sal_Int32 SAL_CALL checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >& xAbortChannel, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + sal_Bool noLicenseChecking) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::uno::RuntimeException); + + virtual void SAL_CALL registerPackage( + sal_Bool startup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, css::uno::RuntimeException); + virtual void SAL_CALL revokePackage( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + virtual sal_Bool SAL_CALL isBundle() + throw (css::uno::RuntimeException); + virtual css::uno::Sequence< css::uno::Reference<css::deployment::XPackage> > + SAL_CALL getBundle( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getName() + throw (css::uno::RuntimeException); + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getIdentifier() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getVersion() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getURL() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDisplayName() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL + getUpdateInformationURLs() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::beans::StringPair SAL_CALL getPublisherInfo() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL + getIcon( sal_Bool bHighContrast ) + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Reference<css::deployment::XPackageTypeInfo> SAL_CALL + getPackageType() throw (css::uno::RuntimeException); + virtual void SAL_CALL exportTo( + ::rtl::OUString const & destFolderURL, + ::rtl::OUString const & newTitle, + sal_Int32 nameClashAction, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getRepositoryName() + throw (css::uno::RuntimeException); + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual sal_Bool SAL_CALL isRemoved() + throw (css::uno::RuntimeException); + +}; + +typedef ::cppu::WeakComponentImplHelper2< + css::lang::XEventListener, + css::deployment::XPackageRegistry > t_BackendBase; + +//============================================================================== +class PackageRegistryBackend + : protected ::dp_misc::MutexHolder, public t_BackendBase +{ + //The map held originally WeakReferences. The map entries are removed in the disposing + //function, which is called when the XPackages are destructed or they are + //explicitely disposed. The latter happens, for example, when a extension is + //removed (see dp_manager.cxx). However, because of how the help systems work, now + // XPackageManager::getDeployedPackages is called often. This results in a lot + //of bindPackage calls which are costly. Therefore we keep hard references in + //the map now. + typedef ::std::hash_map< + ::rtl::OUString, css::uno::Reference<css::deployment::XPackage>, + ::rtl::OUStringHash > t_string2ref; + t_string2ref m_bound; + +protected: + ::rtl::OUString m_cachePath; + css::uno::Reference<css::uno::XComponentContext> m_xComponentContext; + + ::rtl::OUString m_context; + // currently only for library containers: + enum context { + CONTEXT_UNKNOWN, + CONTEXT_USER, CONTEXT_SHARED,CONTEXT_BUNDLED, CONTEXT_TMP, + CONTEXT_DOCUMENT + } m_eContext; + bool m_readOnly; + + struct StrCannotDetectMediaType : public ::dp_misc::StaticResourceString< + StrCannotDetectMediaType, RID_STR_CANNOT_DETECT_MEDIA_TYPE> {}; + struct StrUnsupportedMediaType : public ::dp_misc::StaticResourceString< + StrUnsupportedMediaType, RID_STR_UNSUPPORTED_MEDIA_TYPE> {}; + + // @@@ to be implemented by specific backend: + virtual css::uno::Reference<css::deployment::XPackage> bindPackage_( + ::rtl::OUString const & url, ::rtl::OUString const & mediaType, + sal_Bool bRemoved, ::rtl::OUString const & identifier, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + + void check(); + virtual void SAL_CALL disposing(); + + virtual ~PackageRegistryBackend(); + PackageRegistryBackend( + css::uno::Sequence<css::uno::Any> const & args, + css::uno::Reference<css::uno::XComponentContext> const & xContext ); + + /* creates a folder with a unique name. + If url is empty then it is created in the the backend folder, otherwise + at a location relative to that folder specified by url. + */ + ::rtl::OUString createFolder( + ::rtl::OUString const & relUrl, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + /* deletes folders and files. + + All folder all files which end with ".tmp" or ".tmp_" and which are + not used are deleted. + */ + void deleteUnusedFolders( + ::rtl::OUString const & relUrl, + ::std::list< ::rtl::OUString> const & usedFolders); + /* deletes one folder with a "temporary" name and the corresponding + tmp file, which was used to derive the folder name. + */ + static void deleteTempFolder( + ::rtl::OUString const & folderUrl); + + +public: + struct StrRegisteringPackage : public ::dp_misc::StaticResourceString< + StrRegisteringPackage, RID_STR_REGISTERING_PACKAGE> {}; + struct StrRevokingPackage : public ::dp_misc::StaticResourceString< + StrRevokingPackage, RID_STR_REVOKING_PACKAGE> {}; + + inline css::uno::Reference<css::uno::XComponentContext> const & + getComponentContext() const { return m_xComponentContext; } + + inline ::rtl::OUString const & getCachePath() const { return m_cachePath; } + inline bool transientMode() const { return m_cachePath.getLength() == 0; } + + inline ::rtl::OUString getContext() const {return m_context; } + + // XEventListener + virtual void SAL_CALL disposing( css::lang::EventObject const & evt ) + throw (css::uno::RuntimeException); + + // XPackageRegistry + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL bindPackage( + ::rtl::OUString const & url, ::rtl::OUString const & mediaType, + sal_Bool bRemoved, ::rtl::OUString const & identifier, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::InvalidRemovedParameterException, + css::ucb::CommandFailedException, + css::lang::IllegalArgumentException, css::uno::RuntimeException); +}; + +} +} + +#endif + diff --git a/desktop/source/deployment/registry/inc/dp_backenddb.hxx b/desktop/source/deployment/registry/inc/dp_backenddb.hxx new file mode 100644 index 000000000000..a0e477979f8c --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_backenddb.hxx @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_BACKENDDB_HXX +#define INCLUDED_DP_BACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include <list> +#include <vector> + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { + +class BackendDb +{ +private: + + css::uno::Reference<css::xml::dom::XDocument> m_doc; + css::uno::Reference<css::xml::xpath::XXPathAPI> m_xpathApi; + + BackendDb(BackendDb const &); + BackendDb & operator = (BackendDb const &); + +protected: + const css::uno::Reference<css::uno::XComponentContext> m_xContext; + ::rtl::OUString m_urlDb; + +protected: + + /* caller must make sure that only one thread accesses the function + */ + css::uno::Reference<css::xml::dom::XDocument> getDocument(); + + /* the namespace prefix is "reg" (without quotes) + */ + css::uno::Reference<css::xml::xpath::XXPathAPI> getXPathAPI(); + void save(); + void removeElement(::rtl::OUString const & sXPathExpression); + + css::uno::Reference<css::xml::dom::XNode> getKeyElement( + ::rtl::OUString const & url); + + void writeSimpleList( + ::std::list< ::rtl::OUString> const & list, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sMemberTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + void writeVectorOfPair( + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > const & vecPairs, + ::rtl::OUString const & sVectorTagName, + ::rtl::OUString const & sPairTagName, + ::rtl::OUString const & sFirstTagName, + ::rtl::OUString const & sSecondTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + void writeSimpleElement( + ::rtl::OUString const & sElementName, ::rtl::OUString const & value, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + css::uno::Reference<css::xml::dom::XNode> writeKeyElement( + ::rtl::OUString const & url); + + ::rtl::OUString readSimpleElement( + ::rtl::OUString const & sElementName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > + readVectorOfPair( + css::uno::Reference<css::xml::dom::XNode> const & parent, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sPairTagName, + ::rtl::OUString const & sFirstTagName, + ::rtl::OUString const & sSecondTagName); + + ::std::list< ::rtl::OUString> readList( + css::uno::Reference<css::xml::dom::XNode> const & parent, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sMemberTagName); + + /* returns the values of one particulary child element of all key elements. + */ + ::std::list< ::rtl::OUString> getOneChildFromAllEntries( + ::rtl::OUString const & sElementName); + + + /* returns the namespace which is to be written as xmlns attribute + into the root element. + */ + virtual ::rtl::OUString getDbNSName()=0; + /* return the namespace prefix which is to be registered with the XPath API. + + The prefix can then be used in XPath expressions. + */ + virtual ::rtl::OUString getNSPrefix()=0; + /* returns the name of the root element without any namespace prefix. + */ + virtual ::rtl::OUString getRootElementName()=0; + /* returns the name of xml element for each entry + */ + virtual ::rtl::OUString getKeyElementName()=0; + + + +public: + BackendDb(css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + virtual ~BackendDb() {}; + + void removeEntry(::rtl::OUString const & url); +}; + +class RegisteredDb: public BackendDb +{ + +public: + RegisteredDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + virtual ~RegisteredDb() {}; + + + virtual void addEntry(::rtl::OUString const & url); + virtual bool getEntry(::rtl::OUString const & url); + +}; + + +} +} +#endif + diff --git a/desktop/source/deployment/registry/inc/dp_registry.hrc b/desktop/source/deployment/registry/inc/dp_registry.hrc new file mode 100644 index 000000000000..4a3b1d0b1a4a --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_registry.hrc @@ -0,0 +1,40 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_REGISTRY_HRC +#define INCLUDED_DP_REGISTRY_HRC + +#include "deployment.hrc" + +#define RID_STR_CANNOT_DETECT_MEDIA_TYPE (RID_DEPLOYMENT_REGISTRY_START+0) +#define RID_STR_UNSUPPORTED_MEDIA_TYPE (RID_DEPLOYMENT_REGISTRY_START+1) +#define RID_STR_ERROR_WHILE_REGISTERING (RID_DEPLOYMENT_REGISTRY_START+2) +#define RID_STR_ERROR_WHILE_REVOKING (RID_DEPLOYMENT_REGISTRY_START+3) +#define RID_STR_REGISTERING_PACKAGE (RID_DEPLOYMENT_REGISTRY_START+4) +#define RID_STR_REVOKING_PACKAGE (RID_DEPLOYMENT_REGISTRY_START+5) + +#endif diff --git a/desktop/source/deployment/registry/makefile.mk b/desktop/source/deployment/registry/makefile.mk new file mode 100644 index 000000000000..e45cec272ca7 --- /dev/null +++ b/desktop/source/deployment/registry/makefile.mk @@ -0,0 +1,49 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_registry.src + +INCPRE += inc + +SLOFILES = \ + $(SLO)$/dp_backend.obj \ + $(SLO)$/dp_registry.obj \ + $(SLO)$/dp_backenddb.obj + +.INCLUDE : ..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/package/dp_extbackenddb.cxx b/desktop/source/deployment/registry/package/dp_extbackenddb.cxx new file mode 100644 index 000000000000..2e92a907f8fb --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_extbackenddb.cxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_extbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/extension-registry/2010" +#define NS_PREFIX "ext" +#define ROOT_ELEMENT_NAME "extension-backend-db" +#define KEY_ELEMENT_NAME "extension" + +namespace dp_registry { +namespace backend { +namespace bundle { + +ExtensionBackendDb::ExtensionBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ExtensionBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ExtensionBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ExtensionBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ExtensionBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + +void ExtensionBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> extensionNodeNode = writeKeyElement(url); + writeVectorOfPair( + data.items, + OUSTR("extension-items"), + OUSTR("item"), + OUSTR("url"), + OUSTR("media-type"), + extensionNodeNode); + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +ExtensionBackendDb::Data ExtensionBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ExtensionBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + + if (aNode.is()) + { + retData.items = + readVectorOfPair( + aNode, + OUSTR("extension-items"), + OUSTR("item"), + OUSTR("url"), + OUSTR("media-type")); + } + return retData; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/package/dp_extbackenddb.hxx b/desktop/source/deployment/registry/package/dp_extbackenddb.hxx new file mode 100644 index 000000000000..d09fd0891a32 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_extbackenddb.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#if ! defined INCLUDED_DP_EXTBACKENDDB_HXX +#define INCLUDED_DP_EXTBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "rtl/string.hxx" +#include <vector> +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { +namespace bundle { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ExtensionBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + virtual ::rtl::OUString getNSPrefix(); + virtual ::rtl::OUString getRootElementName(); + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* every element consists of a pair of the url to the item (jar,rdb, etc) + and the media type + */ + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> > items; + typedef ::std::vector< + ::std::pair< ::rtl::OUString, ::rtl::OUString> >::const_iterator ITC_ITEMS; + + }; + +public: + + ExtensionBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + Data getEntry(::rtl::OUString const & url); + +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/package/dp_package.cxx b/desktop/source/deployment/registry/package/dp_package.cxx new file mode 100644 index 000000000000..feb55d0af3bf --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.cxx @@ -0,0 +1,1645 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_package.hrc" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_interact.h" +#include "dp_dependencies.hxx" +#include "dp_platform.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_identifier.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "ucbhelper/content.hxx" +#include "svl/inettype.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/makesequence.hxx" +#include "comphelper/sequence.hxx" +#include "com/sun/star/lang/WrappedTargetException.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/beans/UnknownPropertyException.hpp" +#include "com/sun/star/graphic/XGraphic.hpp" +#include "com/sun/star/graphic/XGraphicProvider.hpp" +#include "com/sun/star/io/XOutputStream.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/task/InteractionClassification.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" +#include "com/sun/star/ucb/XInteractionReplaceExistingData.hpp" +#include "com/sun/star/ucb/NameClashResolveRequest.hpp" +#include "com/sun/star/ucb/XContentAccess.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/ucb/UnsupportedCommandException.hpp" +#include "com/sun/star/sdbc/XResultSet.hpp" +#include "com/sun/star/sdbc/XRow.hpp" +#include "com/sun/star/packages/manifest/XManifestReader.hpp" +#include "com/sun/star/packages/manifest/XManifestWriter.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/PlatformException.hpp" +#include "com/sun/star/deployment/Prerequisites.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "boost/optional.hpp" +#include <vector> +#include <stdio.h> + +#include "dp_extbackenddb.hxx" +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace css = ::com::sun::star; + +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace bundle { +namespace { + +typedef cppu::ImplInheritanceHelper1<PackageRegistryBackend, + lang::XServiceInfo> ImplBaseT; + +//============================================================================== +class BackendImpl : public ImplBaseT +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + /** constains the old tooltip description for the Extension Manager GUI in OOo v.2.x + We keep it for backward compatibility. + */ + OUString m_oldDescription; + OUString m_url_expanded; + const bool m_legacyBundle; + Sequence< Reference<deployment::XPackage> > m_bundle; + Sequence< Reference<deployment::XPackage> > * m_pBundle; + + ExtensionBackendDb::Data m_dbData; + + Reference<deployment::XPackage> bindBundleItem( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, //that is, useing data base information + OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool notifyDetectionError = true ); + + typedef ::std::vector< Reference<deployment::XPackage> > t_packagevec; + void scanBundle( + t_packagevec & bundle, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + void scanLegacyBundle( + t_packagevec & bundle, + OUString const & url, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool skip_registration = false ); + ::std::vector<Reference<deployment::XPackage> > getPackagesFromDb( + Reference<ucb::XCommandEnvironment> const & xCmdEnv); + bool checkPlatform( + Reference<ucb::XCommandEnvironment > const & environment); + + bool checkDependencies( + Reference<ucb::XCommandEnvironment > const & + environment, + DescriptionInfoset const & description); + // throws css::uno::RuntimeException, + // css::deployment::DeploymentException + + ::sal_Bool checkLicense( + Reference< ucb::XCommandEnvironment > const & xCmdEnv, + DescriptionInfoset const & description, bool bNoLicenseChecking) + throw (deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + // @throws DeploymentException + OUString getTextFromURL( + const Reference< ucb::XCommandEnvironment >& xCmdEnv, + const OUString& licenseUrl); + + DescriptionInfoset getDescriptionInfoset(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + + + + public: + PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool legacyBundle, + bool bRemoved, + OUString const & identifier); + + // XPackage + virtual sal_Bool SAL_CALL isBundle() throw (RuntimeException); + + virtual Sequence< Reference<deployment::XPackage> > SAL_CALL getBundle( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, RuntimeException); + virtual OUString SAL_CALL getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual void SAL_CALL exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::ExtensionRemovedException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + + virtual ::sal_Int32 SAL_CALL checkPrerequisites( + const Reference< task::XAbortChannel >& xAbortChannel, + const Reference< ucb::XCommandEnvironment >& xCmdEnv, + ::sal_Bool noLicenseChecking) + throw (deployment::ExtensionRemovedException, + deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + + virtual ::sal_Bool SAL_CALL checkDependencies( + const Reference< ucb::XCommandEnvironment >& xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + ucb::CommandFailedException, + RuntimeException); + + virtual beans::Optional<OUString> SAL_CALL getIdentifier() + throw (RuntimeException); + + virtual OUString SAL_CALL getVersion() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual Sequence<OUString> SAL_CALL getUpdateInformationURLs() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual beans::StringPair SAL_CALL getPublisherInfo() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual OUString SAL_CALL getDisplayName() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual Reference< graphic::XGraphic > SAL_CALL + getIcon( ::sal_Bool bHighContrast ) + throw (deployment::ExtensionRemovedException, + RuntimeException); + }; + friend class PackageImpl; + + Reference<deployment::XPackageRegistry> m_xRootRegistry; + const Reference<deployment::XPackageTypeInfo> m_xBundleTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xLegacyBundleTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + std::auto_ptr<ExtensionBackendDb> m_backendDb; + + void addDataToDb(OUString const & url, ExtensionBackendDb::Data const & data); + ExtensionBackendDb::Data readDataFromDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + +public: + BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext, + Reference<deployment::XPackageRegistry> const & xRootRegistry ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); + virtual sal_Bool SAL_CALL supportsService( OUString const& name ) + throw (RuntimeException); + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() + throw (RuntimeException); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using ImplBaseT::disposing; +}; + +//Used to find a XPackage with a particular URL +class XPackage_eq : public std::unary_function<Reference<deployment::XPackage>, bool> +{ + OUString m_URL; +public: + explicit XPackage_eq(const OUString & s) : m_URL(s) {} + bool operator() (const Reference<deployment::XPackage> & p) const + { + return m_URL.equals(p->getURL()); + } +}; + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext, + Reference<deployment::XPackageRegistry> const & xRootRegistry ) + : ImplBaseT( args, xComponentContext ), + m_xRootRegistry( xRootRegistry ), + m_xBundleTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.package-bundle"), + OUSTR("*.oxt;*.uno.pkg"), + getResourceString(RID_STR_PACKAGE_BUNDLE), + RID_IMG_DEF_PACKAGE_BUNDLE, + RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ), + m_xLegacyBundleTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.legacy-package-bundle"), + OUSTR("*.zip"), + m_xBundleTypeInfo->getShortDescription(), + RID_IMG_DEF_PACKAGE_BUNDLE, + RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ), + m_typeInfos(2) +{ + m_typeInfos[ 0 ] = m_xBundleTypeInfo; + m_typeInfos[ 1 ] = m_xLegacyBundleTypeInfo; + + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), getImplementationName()); + dbFile = makeURL(dbFile, OUSTR("backenddb.xml")); + m_backendDb.reset( + new ExtensionBackendDb(getComponentContext(), dbFile)); + } +} + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + m_xRootRegistry.clear(); + PackageRegistryBackend::disposing(); +} + +// XServiceInfo +OUString BackendImpl::getImplementationName() throw (RuntimeException) +{ + return OUSTR("com.sun.star.comp.deployment.bundle.PackageRegistryBackend"); +} + +sal_Bool BackendImpl::supportsService( OUString const& name ) + throw (RuntimeException) +{ + return getSupportedServiceNames()[0].equals(name); +} + +Sequence<OUString> BackendImpl::getSupportedServiceNames() + throw (RuntimeException) +{ + return comphelper::makeSequence( + OUString::createFromAscii(BACKEND_SERVICE_NAME) ); +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + + + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) + { + if (ucbContent.isFolder()) + { + //Every .oxt, uno.pkg file must contain a META-INF folder + ::ucbhelper::Content metaInfContent; + if (create_ucb_content( + &metaInfContent, makeURL( url, OUSTR("META-INF") ), + xCmdEnv, false /* no throw */ )) + { + mediaType = OUSTR("application/vnd.sun.star.package-bundle"); + } + //No support of legacy bundles, because every folder could be one. + } + else + { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".oxt") ) || + title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".uno.pkg") )) + mediaType = OUSTR("application/vnd.sun.star.package-bundle"); + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".zip") )) + mediaType = + OUSTR("application/vnd.sun.star.legacy-package-bundle"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + + //In case a XPackage is created for a removed extension, we cannot + //obtain the name + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.package-bundle")) { + return new PackageImpl( + this, url, name, m_xBundleTypeInfo, false, bRemoved, + identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.legacy-package-bundle")) { + return new PackageImpl( + this, url, name, m_xLegacyBundleTypeInfo, true, bRemoved, + identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +void BackendImpl::addDataToDb( + OUString const & url, ExtensionBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +ExtensionBackendDb::Data BackendImpl::readDataFromDb( + OUString const & url) +{ + ExtensionBackendDb::Data data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + + +//############################################################################## + +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool legacyBundle, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_url_expanded( expandUnoRcUrl( url ) ), + m_legacyBundle( legacyBundle ), + m_pBundle( 0 ) +{ + if (bRemoved) + m_dbData = getMyBackend()->readDataFromDb(url); +} + +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +void BackendImpl::PackageImpl::disposing() +{ + sal_Int32 len = m_bundle.getLength(); + Reference<deployment::XPackage> const * p = m_bundle.getConstArray(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + try_dispose( p[ pos ] ); + m_bundle.realloc( 0 ); + + Package::disposing(); +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + //In case the object was created for a removed extension (m_bRemoved = true) + //but the extension is not registered, then bundle will be empty. Then + //the return value will be Optional<...>.IsPresent= false. Althoug this is + //not true, this does not matter. Then registerPackage or revokePackage + //would never be called for the items. But since the extension is removed + //and not registered anyway, this does not matter. + const Sequence< Reference<deployment::XPackage> > bundle( + getBundle( abortChannel.get(), xCmdEnv ) ); + + bool reg = false; + bool present = false; + bool ambig = false; + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + beans::Optional< beans::Ambiguous<sal_Bool> > option( + xPackage->isRegistered( xSubAbortChannel, xCmdEnv ) ); + + //present = true if at least one bundle item has this value. + //reg = true if all bundle items have an option value (option.IsPresent == 1) + //and all have value of true (option.Value.Value == true) + //If not, then the bundle has the status of not registered and ambiguous. + if (option.IsPresent) + { + beans::Ambiguous<sal_Bool> const & status = option.Value; + if (present) + { + //we never come here in the first iteration + if (reg != (status.Value != sal_False)) { + + ambig = true; + reg = false; + break; + } + } + else + { + //we always come here in the first iteration + reg = status.Value; + present = true; + } + } + } + return beans::Optional< beans::Ambiguous<sal_Bool> >( + present, beans::Ambiguous<sal_Bool>(reg, ambig) ); +} + +OUString BackendImpl::PackageImpl::getTextFromURL( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + const OUString& licenseUrl) +{ + try + { + ::ucbhelper::Content descContent(licenseUrl, xCmdEnv); + ::rtl::ByteSequence seq = dp_misc::readFile(descContent); + return OUString( reinterpret_cast<sal_Char const *>( + seq.getConstArray()), seq.getLength(), RTL_TEXTENCODING_UTF8); + } + catch (css::uno::Exception&) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Could not read file ") + licenseUrl, 0, exc); + } + +} + +DescriptionInfoset BackendImpl::PackageImpl::getDescriptionInfoset() +{ + return dp_misc::getDescriptionInfoset(m_url_expanded); +} + +bool BackendImpl::PackageImpl::checkPlatform( + css::uno::Reference< css::ucb::XCommandEnvironment > const & environment) +{ + bool ret = false; + DescriptionInfoset info(getDescriptionInfoset()); + Sequence<OUString> platforms(info.getSupportedPlaforms()); + if (hasValidPlatform(platforms)) + { + ret = true; + } + else + { + ret = false; + rtl::OUString msg( + RTL_CONSTASCII_USTRINGPARAM("unsupported platform")); + Any e( + css::deployment::PlatformException( + msg, static_cast<OWeakObject *>(this), this)); + if (!interactContinuation( + e, cppu::UnoType< css::task::XInteractionApprove >::get(), + environment, NULL, NULL)) + { + throw css::deployment::DeploymentException( + msg, static_cast<OWeakObject *>(this), e); + } + } + return ret; +} + + +bool BackendImpl::PackageImpl::checkDependencies( + css::uno::Reference< css::ucb::XCommandEnvironment > const & environment, + DescriptionInfoset const & description) +{ + css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > + unsatisfied(dp_misc::Dependencies::check(description)); + + if (unsatisfied.getLength() == 0) { + return true; + } else { + rtl::OUString msg( + RTL_CONSTASCII_USTRINGPARAM("unsatisfied dependencies")); + Any e( + css::deployment::DependencyException( + msg, static_cast<OWeakObject *>(this), unsatisfied)); + if (!interactContinuation( + e, cppu::UnoType< css::task::XInteractionApprove >::get(), + environment, NULL, NULL)) + { + throw css::deployment::DeploymentException( + msg, static_cast<OWeakObject *>(this), e); + } + return false; + } +} + +::sal_Bool BackendImpl::PackageImpl::checkLicense( + css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv, + DescriptionInfoset const & info, bool alreadyInstalled) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + try + { + ::boost::optional<SimpleLicenseAttributes> simplLicAttr + = info.getSimpleLicenseAttributes(); + if (! simplLicAttr) + return true; + OUString sLic = info.getLocalizedLicenseURL(); + //If we do not get a localized licence then there is an error in the description.xml + //This should be handled by using a validating parser. Therefore we assume that no + //license is available. + if (sLic.getLength() == 0) + throw css::deployment::DeploymentException( + OUSTR("Could not obtain path to license. Possible error in description.xml"), 0, Any()); + OUString sHref = m_url_expanded + OUSTR("/") + sLic; + OUString sLicense = getTextFromURL(xCmdEnv, sHref); + ////determine who has to agree to the license + //check correct value for attribute + if ( ! (simplLicAttr->acceptBy.equals(OUSTR("user")) || simplLicAttr->acceptBy.equals(OUSTR("admin")))) + throw css::deployment::DeploymentException( + OUSTR("Could not obtain attribute simple-lincense@accept-by or it has no valid value"), 0, Any()); + + + //Only use interaction if there is no version of this extension already installed + //and the suppress-on-update flag is not set for the new extension + // alreadyInstalled | bSuppressOnUpdate | show license + //---------------------------------------- + // 0 | 0 | 1 + // 0 | 1 | 1 + // 1 | 0 | 1 + // 1 | 1 | 0 + + if ( !(alreadyInstalled && simplLicAttr->suppressOnUpdate)) + { + css::deployment::LicenseException licExc( + OUString(), 0, getDisplayName(), sLicense, + simplLicAttr->acceptBy); + bool approve = false; + bool abort = false; + if (! interactContinuation( + Any(licExc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort )) + throw css::deployment::DeploymentException( + OUSTR("Could not interact with user."), 0, Any()); + + if (approve == true) + return true; + else + return false; + //throw css::deployment::DeploymentException( + // OUSTR("Extension Manager: User declined the license."), + // static_cast<OWeakObject*>(this), + // Any( css::deployment::LicenseException(OUSTR("User declined the license."), 0, m_name, sLicense))); + } + return true; + } catch (css::ucb::CommandFailedException&) { + throw; + } catch (css::ucb::CommandAbortedException&) { + throw; + } catch (css::deployment::DeploymentException&) { + throw; + } catch (css::uno::RuntimeException&) { + throw; + } catch (css::uno::Exception&) { + Any anyExc = cppu::getCaughtException(); + throw css::deployment::DeploymentException(OUSTR("Unexpected exception"), 0, anyExc); + } +} + +::sal_Int32 BackendImpl::PackageImpl::checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >&, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + sal_Bool alreadyInstalled) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + DescriptionInfoset info = getDescriptionInfoset(); + if (!info.hasDescription()) + return 0; + + //always return LICENSE as long as the user did not accept the license + //so that XExtensonManager::checkPrerequisitesAndEnable will again + //check the license + if (!checkPlatform(xCmdEnv)) + return deployment::Prerequisites::PLATFORM | + deployment::Prerequisites::LICENSE; + else if(!checkDependencies(xCmdEnv, info)) + return deployment::Prerequisites::DEPENDENCIES | + deployment::Prerequisites::LICENSE; + else if(!checkLicense(xCmdEnv, info, alreadyInstalled)) + return deployment::Prerequisites::LICENSE; + else + return 0; +} + +::sal_Bool BackendImpl::PackageImpl::checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + ucb::CommandFailedException, + RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + DescriptionInfoset info = getDescriptionInfoset(); + if (!info.hasDescription()) + return sal_True; + + return checkDependencies(xCmdEnv, info); +} + +beans::Optional<OUString> BackendImpl::PackageImpl::getIdentifier() + throw (RuntimeException) +{ + OUString identifier; + if (m_bRemoved) + identifier = m_identifier; + else + identifier = dp_misc::generateIdentifier( + getDescriptionInfoset().getIdentifier(), m_name); + + return beans::Optional<OUString>( + true, identifier); +} + +OUString BackendImpl::PackageImpl::getVersion() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return getDescriptionInfoset().getVersion(); +} + +Sequence<OUString> BackendImpl::PackageImpl::getUpdateInformationURLs() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return getDescriptionInfoset().getUpdateInformationUrls(); +} + +beans::StringPair BackendImpl::PackageImpl::getPublisherInfo() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + ::std::pair< OUString, OUString > aInfo = getDescriptionInfoset().getLocalizedPublisherNameAndURL(); + beans::StringPair aStrPair( aInfo.first, aInfo.second ); + return aStrPair; +} + +//______________________________________________________________________________ +uno::Reference< graphic::XGraphic > BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast ) + throw (deployment::ExtensionRemovedException, RuntimeException ) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + uno::Reference< graphic::XGraphic > xGraphic; + + OUString aIconURL = getDescriptionInfoset().getIconURL( bHighContrast ); + if ( aIconURL.getLength() ) + { + OUString aFullIconURL = m_url_expanded + OUSTR("/") + aIconURL; + + uno::Reference< XComponentContext > xContext( getMyBackend()->getComponentContext() ); + uno::Reference< graphic::XGraphicProvider > xGraphProvider( + xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.graphic.GraphicProvider" ), xContext ), + uno::UNO_QUERY ); + + if ( xGraphProvider.is() ) + { + uno::Sequence< beans::PropertyValue > aMediaProps( 1 ); + aMediaProps[0].Name = OUSTR( "URL" ); + aMediaProps[0].Value <<= aFullIconURL; + + xGraphic = xGraphProvider->queryGraphic( aMediaProps ); + } + } + + return xGraphic; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + const Sequence< Reference<deployment::XPackage> > bundle( + getBundle( abortChannel.get(), xCmdEnv ) ); + + if (doRegisterPackage) + { + ExtensionBackendDb::Data data; + const sal_Int32 len = bundle.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + checkAborted(abortChannel); + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + try { + xPackage->registerPackage( startup, xSubAbortChannel, xCmdEnv ); + } + catch (Exception &) + { + //We even try a rollback if the user cancelled the action (CommandAbortedException) + //in order to prevent invalid database entries. + Any exc( ::cppu::getCaughtException() ); + // try to handle exception, notify: + bool approve = false, abort = false; + if (! interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item registration error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, + &approve, &abort )) { + OSL_ASSERT( !approve && !abort ); + if (m_legacyBundle) // default for legacy packages: ignore + continue; + // no selection at all, so rethrow; + // no C++ rethrow after getCaughtException(), + // see cppuhelper/exc_hlp.hxx: + ::cppu::throwException(exc); + } + if (approve && !abort) // ignore error, just continue + continue; + + { + ProgressLevel progress( + xCmdEnv, OUSTR("rollback...") ); + // try rollback + for ( ; pos--; ) + { + try { + bundle[ pos ]->revokePackage( + xSubAbortChannel, xCmdEnv ); + } + catch (Exception &) + { + OSL_ENSURE( 0, ::rtl::OUStringToOString( + ::comphelper::anyToString( + ::cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + // ignore any errors of rollback + } + } + progress.update( OUSTR("rollback finished.") ); + } + + deployment::DeploymentException dpExc; + if (exc >>= dpExc) { + throw ucb::CommandFailedException( + dpExc.Message, dpExc.Context, dpExc.Cause ); + } + else { + // rethrow CommandFailedException + ::cppu::throwException(exc); + } + } + data.items.push_back( + ::std::make_pair(xPackage->getURL(), + xPackage->getPackageType()->getMediaType())); + } + getMyBackend()->addDataToDb(getURL(), data); + } + else + { + // revoke in reverse order: + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + checkAborted(abortChannel); + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + try { + bundle[ pos ]->revokePackage( xSubAbortChannel, xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandAbortedException &) { + throw; + } + catch (Exception &) { + // CommandFailedException, DeploymentException: + Any exc( ::cppu::getCaughtException() ); + // try to handle exception, notify: + bool approve = false, abort = false; + if (! interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item revocation error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, + &approve, &abort )) { + OSL_ASSERT( !approve && !abort ); + if (m_legacyBundle) // default for legacy packages: ignore + continue; + // no selection at all, so rethrow + // no C++ rethrow after getCaughtException(), + // see cppuhelper/exc_hlp.hxx: + ::cppu::throwException(exc); + } + // ignore errors when revoking, although abort may have been + // selected + } + } + getMyBackend()->deleteDataFromDb(getURL()); + } +} + +//______________________________________________________________________________ +OUString BackendImpl::PackageImpl::getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + const OUString sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL()); + OUString sDescription; + if (sRelativeURL.getLength()) + { + OUString sURL = m_url_expanded + OUSTR("/") + sRelativeURL; + sDescription = getTextFromURL( + css::uno::Reference< css::ucb::XCommandEnvironment >(), sURL); + + } + if (sDescription.getLength()) + return sDescription; + else if(m_oldDescription.getLength()) + return m_oldDescription; + else + return OUString(); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (ucb::CommandFailedException, + deployment::ExtensionRemovedException, + ucb::CommandAbortedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::ucbhelper::Content sourceContent( m_url_expanded, xCmdEnv ); + OUString title(newTitle); + if (title.getLength() == 0) + sourceContent.getPropertyValue( StrTitle::get() ) >>= title; + OUString destURL( makeURL( destFolderURL, ::rtl::Uri::encode( + title, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + + if (nameClashAction == ucb::NameClash::ASK) + { + if (create_ucb_content( + 0, destURL, xCmdEnv, false /* no throw */ )) { + bool replace = false, abort = false; + if (! interactContinuation( + Any( ucb::NameClashResolveRequest( + OUSTR("file already exists: ") + title, + static_cast<OWeakObject *>(this), + task::InteractionClassification_QUERY, + destFolderURL, title, OUString() ) ), + ucb::XInteractionReplaceExistingData::static_type(), xCmdEnv, + &replace, &abort ) || !replace) { + return; + } + } + } + else if (nameClashAction != ucb::NameClash::OVERWRITE) { + throw ucb::CommandFailedException( + OUSTR("unsupported nameClashAction!"), + static_cast<OWeakObject *>(this), Any() ); + } + erase_path( destURL, xCmdEnv ); + + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); + buf.append( ::rtl::Uri::encode( destURL, + rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + buf.append( static_cast<sal_Unicode>('/') ); + OUString destFolder( buf.makeStringAndClear() ); + + ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv ); + { + // transfer every item of folder into zip: + Reference<sdbc::XResultSet> xResultSet( + sourceContent.createCursor( + Sequence<OUString>(), + ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); + ProgressLevel progress( xCmdEnv, OUString() ); + while (xResultSet->next()) + { + ::ucbhelper::Content subContent( + Reference<ucb::XContentAccess>( + xResultSet, UNO_QUERY_THROW )->queryContent(), xCmdEnv ); + if (! destFolderContent.transferContent( + subContent, ::ucbhelper::InsertOperation_COPY, + OUString(), ucb::NameClash::OVERWRITE )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), + static_cast<OWeakObject *>(this) ); + progress.update( Any() ); // animating progress bar + } + } + + // assure META-INF folder: + ::ucbhelper::Content metainfFolderContent; + create_folder( &metainfFolderContent, + makeURL( destFolderContent.getURL(), OUSTR("META-INF") ), + xCmdEnv ); + + if (m_legacyBundle) + { + // easy to migrate legacy bundles to new format: + // just export them once using a .oxt name! + // set detected media-types of any bundle item: + + // collect all manifest entries: + Sequence< Reference<deployment::XPackage> > bundle; + try { + bundle = getBundle( Reference<task::XAbortChannel>(), xCmdEnv ); + } + // xxx todo: think about exception specs: + catch (deployment::DeploymentException &) { + OSL_ENSURE( 0, ::rtl::OUStringToOString( + ::comphelper::anyToString( + ::cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (lang::IllegalArgumentException & exc) { + (void) exc; + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + ::std::vector< Sequence<beans::PropertyValue> > manifest; + manifest.reserve( bundle.getLength() ); + sal_Int32 baseURLlen = m_url_expanded.getLength(); + Reference<deployment::XPackage> const *pbundle = bundle.getConstArray(); + const OUString strMediaType = OUSTR("MediaType"); + const OUString strFullPath = OUSTR("FullPath"); + const OUString strIsFolder = OUSTR("IsFolder"); + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + Reference<deployment::XPackage> const & xPackage = pbundle[ pos ]; + OUString url_( expandUnoRcUrl( xPackage->getURL() ) ); + OSL_ASSERT( url_.getLength() >= baseURLlen ); + OUString fullPath; + if (url_.getLength() > baseURLlen) + fullPath = url_.copy( baseURLlen + 1 ); + ::ucbhelper::Content ucbContent( url_, xCmdEnv ); + if (ucbContent.getPropertyValue(strIsFolder).get<bool>()) + fullPath += OUSTR("/"); + Sequence<beans::PropertyValue> attribs( 2 ); + beans::PropertyValue * pattribs = attribs.getArray(); + pattribs[ 0 ].Name = strFullPath; + pattribs[ 0 ].Value <<= fullPath; + pattribs[ 1 ].Name = strMediaType; + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OUString mediaType; + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + mediaType = xPackageType->getMediaType(); + else + mediaType = OUSTR("unknown"); + pattribs[ 1 ].Value <<= mediaType; + manifest.push_back( attribs ); + } + + // write into pipe: + Reference<XComponentContext> xContext( + getMyBackend()->getComponentContext() ); + Reference<packages::manifest::XManifestWriter> xManifestWriter( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.packages.manifest.ManifestWriter"), + xContext ), UNO_QUERY_THROW ); + Reference<io::XOutputStream> xPipe( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.io.Pipe"), xContext ), UNO_QUERY_THROW ); + xManifestWriter->writeManifestSequence( + xPipe, comphelper::containerToSequence(manifest) ); + + // write buffered pipe data to content: + ::ucbhelper::Content manifestContent( + makeURL( metainfFolderContent.getURL(), OUSTR("manifest.xml") ), + xCmdEnv ); + manifestContent.writeStream( + Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ), + true /* replace existing */ ); + } + else + { + // overwrite manifest.xml: + ::ucbhelper::Content manifestContent; + if ( ! create_ucb_content( + &manifestContent, + makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ), + xCmdEnv, false ) ) + { + OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" ); + return; + } + + if (! metainfFolderContent.transferContent( + manifestContent, ::ucbhelper::InsertOperation_COPY, + OUString(), ucb::NameClash::OVERWRITE )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), + static_cast<OWeakObject *>(this) ); + } + + // xxx todo: maybe obsolete in the future + try { + destFolderContent.executeCommand( OUSTR("flush"), Any() ); + } + catch (ucb::UnsupportedCommandException &) { + } +} + +//______________________________________________________________________________ +sal_Bool BackendImpl::PackageImpl::isBundle() throw (RuntimeException) +{ + return true; +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > BackendImpl::PackageImpl::getBundle( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + ucb::CommandFailedException, ucb::CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + Sequence< Reference<deployment::XPackage> > * pBundle = m_pBundle; + if (pBundle == 0) + { + t_packagevec bundle; + if (m_bRemoved) + { + bundle = getPackagesFromDb(xCmdEnv); + } + else + { + try { + if (m_legacyBundle) + { + // .zip legacy packages allow script.xlb, dialog.xlb in bundle + // root folder: + OUString mediaType; + // probe for script.xlb: + if (create_ucb_content( + 0, makeURL( m_url_expanded, OUSTR("script.xlb") ), + xCmdEnv, false /* no throw */ )) { + mediaType = OUSTR("application/vnd.sun.star.basic-library"); + } + // probe for dialog.xlb: + else if (create_ucb_content( + 0, makeURL( m_url_expanded, OUSTR("dialog.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star." + "dialog-library"); + + if (mediaType.getLength() > 0) { + const Reference<deployment::XPackage> xPackage( + bindBundleItem( getURL(), mediaType, false, OUString(), + xCmdEnv ) ); + if (xPackage.is()) + bundle.push_back( xPackage ); + // continue scanning: + } + scanLegacyBundle( bundle, getURL(), + AbortChannel::get(xAbortChannel), xCmdEnv ); + } + else + { + // .oxt: + scanBundle( bundle, AbortChannel::get(xAbortChannel), xCmdEnv ); + } + + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandFailedException &) { + throw; + } + catch (ucb::CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("error scanning bundle: ") + getURL(), + static_cast<OWeakObject *>(this), exc ); + } + } + + // sort: schema before config data, typelibs before components: + Sequence< Reference<deployment::XPackage> > ret( bundle.size() ); + Reference<deployment::XPackage> * pret = ret.getArray(); + sal_Int32 lower_end = 0; + sal_Int32 upper_end = ret.getLength(); + t_packagevec::const_iterator iPos( bundle.begin() ); + t_packagevec::const_iterator const iEnd( bundle.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + const Reference<deployment::XPackageTypeInfo> xPackageType( + (*iPos)->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) { + const OUString mediaType( xPackageType->getMediaType() ); + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( + mediaType, type, subType, ¶ms ) && + type.EqualsIgnoreCaseAscii("application") && + (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.uno-component") || + subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-data"))) + { + --upper_end; + pret[ upper_end ] = *iPos; + continue; + } + } + pret[ lower_end ] = *iPos; + ++lower_end; + } + OSL_ASSERT( lower_end == upper_end ); + + const ::osl::MutexGuard guard( getMutex() ); + pBundle = m_pBundle; + if (pBundle == 0) { + m_bundle = ret; + pBundle = &m_bundle; + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + m_pBundle = pBundle; + } + } + else { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return *pBundle; +} + +inline bool isBundle_( OUString const & mediaType ) +{ + // xxx todo: additional parsing? + return mediaType.getLength() > 0 && + (mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.package-bundle") ) || + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.legacy-package-bundle") )); +} + +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::PackageImpl::bindBundleItem( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool notifyDetectionError ) +{ + // ignore any nested bundles: + if (isBundle_(mediaType)) + return Reference<deployment::XPackage>(); + + Reference<deployment::XPackage>xPackage; + try { + xPackage.set( getMyBackend()->m_xRootRegistry->bindPackage( + url, mediaType, bRemoved, identifier, xCmdEnv ) ); + OSL_ASSERT( xPackage.is() ); + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandFailedException &) { + // ignore already handled error + } + catch (Exception &) { + const Any exc( ::cppu::getCaughtException() ); + if (notifyDetectionError || + !exc.isExtractableTo( + ::getCppuType( reinterpret_cast< + lang::IllegalArgumentException const *>(0) ) )) + { + interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, 0, 0 ); + } + } + + if (xPackage.is()) { + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + // ignore any nested bundles: + if (xPackageType.is() && isBundle_( xPackageType->getMediaType() )) + xPackage.clear(); + } + return xPackage; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::scanBundle( + t_packagevec & bundle, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + OSL_ASSERT( !m_legacyBundle ); + + ::ucbhelper::Content manifestContent; + if (! create_ucb_content( + &manifestContent, + makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ), + xCmdEnv, false /* no throw */ )) + { + OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" ); + return; + } + + + const lang::Locale officeLocale = getOfficeLocale(); + OUString descrFile; + lang::Locale descrFileLocale; + + const Reference<XComponentContext> xContext( + getMyBackend()->getComponentContext() ); + Reference<packages::manifest::XManifestReader> xManifestReader( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.packages.manifest.ManifestReader"), + xContext ), UNO_QUERY_THROW ); + const Sequence< Sequence<beans::PropertyValue> > manifestSeq( + xManifestReader->readManifestSequence( manifestContent.openStream() ) ); + const OUString packageRootURL( getURL() ); + for ( sal_Int32 pos = manifestSeq.getLength(); pos--; ) + { + OUString fullPath, mediaType; + Sequence<beans::PropertyValue> const & attribs = manifestSeq[ pos ]; + for ( sal_Int32 i = attribs.getLength(); i--; ) + { + if (fullPath.getLength() > 0 && mediaType.getLength() > 0) + break; + if (attribs[i].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("FullPath") )) + attribs[i].Value >>= fullPath; + else if (attribs[i].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("MediaType") )) + attribs[i].Value >>= mediaType; + } + + if (fullPath.getLength() == 0 || mediaType.getLength() == 0 || + mediaType.equalsAsciiL( // opt: exclude common text/xml + RTL_CONSTASCII_STRINGPARAM("text/xml") )) + continue; + + String type, subType; + INetContentTypeParameterList params; + if (! INetContentTypes::parse( mediaType, type, subType, ¶ms )) + continue; + + INetContentTypeParameter const * param = params.find( + ByteString("platform") ); + if (param != 0 && !platform_fits( param->m_sValue )) + continue; + const OUString url( makeURL( packageRootURL, fullPath ) ); + + // check for bundle description: + if (type.EqualsIgnoreCaseAscii("application") && + subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.package-bundle-description")) + { + // check locale: + param = params.find( ByteString("locale") ); + if (param == 0) { + if (descrFile.getLength() == 0) + descrFile = url; + } + else { + // match best locale: + lang::Locale locale( toLocale(param->m_sValue) ); + if (locale.Language == officeLocale.Language) + { + if (descrFileLocale.Country == officeLocale.Country + && locale.Country != officeLocale.Country) + continue; + if (descrFileLocale.Variant == officeLocale.Variant + && locale.Variant != officeLocale.Variant) + continue; + descrFile = url; + descrFileLocale = locale; + } + } + continue; + } + + checkAborted( abortChannel ); + + //We make sure that we only create one XPackage for a particular URL. + //Sometime programmers insert the same URL several times in the manifest + //which may lead to DisposedExceptions. + if (bundle.end() == std::find_if(bundle.begin(), bundle.end(), XPackage_eq(url))) + { + const Reference<deployment::XPackage> xPackage( + bindBundleItem( url, mediaType, false, OUString(), xCmdEnv ) ); + if (xPackage.is()) + bundle.push_back( xPackage ); + } + else + { + fprintf(stderr, "manifest.xml contains a duplicate entry!\n"); + } + } + + if (descrFile.getLength() > 0) + { + ::ucbhelper::Content descrFileContent; + if (create_ucb_content( &descrFileContent, descrFile, + xCmdEnv, false /* no throw */ )) + { + // patch description: + ::rtl::ByteSequence bytes( readFile( descrFileContent ) ); + ::rtl::OUStringBuffer buf; + if ( bytes.getLength() ) + { + buf.append( OUString( reinterpret_cast<sal_Char const *>( + bytes.getConstArray() ), + bytes.getLength(), RTL_TEXTENCODING_UTF8 ) ); + } + else + { + buf.append( Package::getDescription() ); + } + m_oldDescription = buf.makeStringAndClear(); + } + } +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::scanLegacyBundle( + t_packagevec & bundle, + OUString const & url, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool skip_registration ) +{ + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + + // check for platform pathes: + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".plt") ) && + !platform_fits( title.copy( 0, title.getLength() - 4 ) )) { + return; + } + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("skip_registration") )) + skip_registration = true; + + OUString ar [] = { StrTitle::get(), OUSTR("IsFolder") }; + Reference<sdbc::XResultSet> xResultSet( + ucbContent.createCursor( + Sequence<OUString>( ar, ARLEN(ar) ), + ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); + while (xResultSet->next()) + { + checkAborted( abortChannel ); + + const Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW ); + const OUString title_enc( ::rtl::Uri::encode( + xRow->getString( 1 /* Title */ ), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + const OUString path( makeURL( url, title_enc ) ); + + OUString mediaType; + const Reference<deployment::XPackage> xPackage( + bindBundleItem( path, OUString() /* detect */, false, OUString(), + xCmdEnv, false /* ignore detection errors */ ) ); + if (xPackage.is()) { + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + mediaType = xPackageType->getMediaType(); + + if (skip_registration && + // xxx todo: additional parsing? + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-component") )) + continue; + + bundle.push_back( xPackage ); + } + + if (mediaType.getLength() == 0 || + // script.xlb, dialog.xlb can be met everywhere: + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.basic-library") ) || + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.dialog-library") )) + { + if (xRow->getBoolean( 2 /* IsFolder */ )) { // recurse into folder: + scanLegacyBundle( + bundle, path, abortChannel, xCmdEnv, skip_registration ); + } + } + } +} + +OUString BackendImpl::PackageImpl::getDisplayName() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + OUString sName = getDescriptionInfoset().getLocalizedDisplayName(); + if (sName.getLength() == 0) + return m_displayName; + else + return sName; +} + +::std::vector<Reference<deployment::XPackage> > +BackendImpl::PackageImpl::getPackagesFromDb( + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + ::std::vector<Reference<deployment::XPackage> > retVector; + + typedef ::std::vector< ::std::pair<OUString, OUString> >::const_iterator ITC; + for (ITC i = m_dbData.items.begin(); i != m_dbData.items.end(); i++) + { + Reference<deployment::XPackage> xExtension = + bindBundleItem(i->first, i->second, true, m_identifier, xCmdEnv); + OSL_ASSERT(xExtension.is()); + retVector.push_back(xExtension); + } + + return retVector; +} + +} // anon namespace + +//============================================================================== +Reference<deployment::XPackageRegistry> create( + Reference<deployment::XPackageRegistry> const & xRootRegistry, + OUString const & context, OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + Sequence<Any> args( + cachePath.getLength() == 0 ? 1 : 3 ); + args[ 0 ] <<= context; + if (cachePath.getLength() > 0) { + args[ 1 ] <<= cachePath; + args[ 2 ] <<= readOnly; + } + return new BackendImpl( args, xComponentContext, xRootRegistry ); +} + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/package/dp_package.hrc b/desktop/source/deployment/registry/package/dp_package.hrc new file mode 100644 index 000000000000..3a840b64f0b6 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.hrc @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_PACKAGE_HRC +#define INCLUDED_DP_PACKAGE_HRC + +#include "deployment.hrc" + +#define RID_STR_PACKAGE_BUNDLE (RID_DEPLOYMENT_BUNDLE_START+10) + +#endif diff --git a/desktop/source/deployment/registry/package/dp_package.src b/desktop/source/deployment/registry/package/dp_package.src new file mode 100644 index 000000000000..57307040bba4 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.src @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_package.hrc" + +String RID_STR_PACKAGE_BUNDLE +{ + Text [ en-US ] = "Extension"; +}; + diff --git a/desktop/source/deployment/registry/package/makefile.mk b/desktop/source/deployment/registry/package/makefile.mk new file mode 100644 index 000000000000..203ce176d289 --- /dev/null +++ b/desktop/source/deployment/registry/package/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_package +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_package.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_package.obj \ + $(SLO)$/dp_extbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/script/dp_lib_container.cxx b/desktop/source/deployment/registry/script/dp_lib_container.cxx new file mode 100644 index 000000000000..be6170cdf5d8 --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_lib_container.cxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_script.hrc" +#include "dp_resource.h" +#include "dp_xml.h" +#include "dp_lib_container.h" +#include "ucbhelper/content.hxx" + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace script { + +namespace { +struct StrCannotDetermineLibName : public StaticResourceString< + StrCannotDetermineLibName, RID_STR_CANNOT_DETERMINE_LIBNAME> {}; +} + +//______________________________________________________________________________ +OUString LibraryContainer::get_libname( + OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv, + Reference<XComponentContext> const & xContext ) +{ + ::xmlscript::LibDescriptor import; + ::ucbhelper::Content ucb_content( url, xCmdEnv ); + xml_parse( ::xmlscript::importLibrary( import ), ucb_content, xContext ); + + if (import.aName.getLength() == 0) { + throw Exception( StrCannotDetermineLibName::get(), + Reference<XInterface>() ); + } + return import.aName; +} + +} +} +} + diff --git a/desktop/source/deployment/registry/script/dp_lib_container.h b/desktop/source/deployment/registry/script/dp_lib_container.h new file mode 100644 index 000000000000..3e7cbf54cbae --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_lib_container.h @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_LIB_CONTAINER_H +#define INCLUDED_DP_LIB_CONTAINER_H + +#include "rtl/ustring.hxx" +#include "xmlscript/xmllib_imexp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" + + +namespace css = ::com::sun::star; + +namespace dp_registry { +namespace backend { +namespace script { + +//============================================================================== +class LibraryContainer +{ +public: + static ::rtl::OUString get_libname( + ::rtl::OUString const & url, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + css::uno::Reference<css::uno::XComponentContext> const & xContext ); +}; + +} +} +} + +#endif diff --git a/desktop/source/deployment/registry/script/dp_script.cxx b/desktop/source/deployment/registry/script/dp_script.cxx new file mode 100644 index 000000000000..edeae256cbaf --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.cxx @@ -0,0 +1,499 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_script.hrc" +#include "dp_lib_container.h" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/util/XUpdatable.hpp" +#include "com/sun/star/script/XLibraryContainer3.hpp" +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/util/XMacroExpander.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <memory> +#include "dp_scriptbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; +namespace css = ::com::sun::star; + +namespace dp_registry { +namespace backend { +namespace script { +namespace { + +typedef ::cppu::ImplInheritanceHelper1< + ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper; + +//============================================================================== +class BackendImpl : public t_helper +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const OUString m_scriptURL; + const OUString m_dialogURL; + OUString m_dialogName; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, + Reference<XCommandEnvironment> const &xCmdEnv, + OUString const & scriptURL, OUString const & dialogURL, + bool bRemoved, OUString const & identifier); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + bool isRegisteredInDb(OUString const & url); + + + +// Reference< ucb::XSimpleFileAccess > getFileAccess( void ); +// Reference< ucb::XSimpleFileAccess > m_xSFA; + + const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + std::auto_ptr<ScriptBackendDb> m_backendDb; +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XUpdatable + virtual void SAL_CALL update() throw (RuntimeException); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, + Reference<XCommandEnvironment> const &xCmdEnv, + OUString const & scriptURL, OUString const & dialogURL, bool bRemoved, + OUString const & identifier) + : Package( myBackend.get(), url, + OUString(), OUString(), // will be late-initialized + scriptURL.getLength() > 0 ? myBackend->m_xBasicLibTypeInfo + : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier), + m_scriptURL( scriptURL ), + m_dialogURL( dialogURL ) +{ + // name, displayName: + if (dialogURL.getLength() > 0) { + m_dialogName = LibraryContainer::get_libname( + dialogURL, xCmdEnv, myBackend->getComponentContext() ); + } + if (scriptURL.getLength() > 0) { + m_name = LibraryContainer::get_libname( + scriptURL, xCmdEnv, myBackend->getComponentContext() ); + } + else + m_name = m_dialogName; + m_displayName = m_name; +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : t_helper( args, xComponentContext ), + m_xBasicLibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.basic-library"), + OUString() /* no file filter */, + getResourceString(RID_STR_BASIC_LIB), + RID_IMG_SCRIPTLIB, RID_IMG_SCRIPTLIB_HC ) ), + m_xDialogLibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.dialog-library"), + OUString() /* no file filter */, + getResourceString(RID_STR_DIALOG_LIB), + RID_IMG_DIALOGLIB, RID_IMG_DIALOGLIB_HC ) ), + m_typeInfos( 2 ) +{ + m_typeInfos[ 0 ] = m_xBasicLibTypeInfo; + m_typeInfos[ 1 ] = m_xDialogLibTypeInfo; + + OSL_ASSERT( ! transientMode() ); + + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ScriptBackendDb(getComponentContext(), dbFile)); + } + +} +void BackendImpl::addDataToDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url); +} + +bool BackendImpl::isRegisteredInDb(OUString const & url) +{ + bool registered = false; + if (m_backendDb.get()) + registered = m_backendDb->getEntry(url); + return registered; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +// XUpdatable +//______________________________________________________________________________ +void BackendImpl::update() throw (RuntimeException) +{ + // Nothing to do here after fixing i70283!? +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv ) && + ucbContent.isFolder()) + { + // probe for script.xlb: + if (create_ucb_content( + 0, makeURL( url, OUSTR("script.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star.basic-library"); + // probe for dialog.xlb: + else if (create_ucb_content( + 0, makeURL( url, OUSTR("dialog.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star.dialog-library"); + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) ); + if (! create_ucb_content( + 0, dialogURL, xCmdEnv, false /* no throw */ )) { + dialogURL = OUString(); + } + + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.basic-library")) + { + OUString scriptURL( makeURL( url, OUSTR("script.xlb"))); + if (! create_ucb_content( + 0, scriptURL, xCmdEnv, false /* no throw */ )) { + scriptURL = OUString(); + } + + return new PackageImpl( + this, url, xCmdEnv, scriptURL, + dialogURL, bRemoved, identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.dialog-library")) { + return new PackageImpl( + this, url, xCmdEnv, + OUString() /* no script lib */, + dialogURL, + bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +// Package +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + (void)xCmdEnv; + + BackendImpl * that = getMyBackend(); + Reference< deployment::XPackage > xThisPackage( this ); + + bool registered = that->isRegisteredInDb(getURL()); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) ); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + (void)xCmdEnv; + + BackendImpl * that = getMyBackend(); + + Reference< deployment::XPackage > xThisPackage( this ); + Reference<XComponentContext> const & xComponentContext = that->getComponentContext(); + + bool bScript = (m_scriptURL.getLength() > 0); + Reference<css::script::XLibraryContainer3> xScriptLibs; + + bool bDialog = (m_dialogURL.getLength() > 0); + Reference<css::script::XLibraryContainer3> xDialogLibs; + + bool bRunning = office_is_running(); + if( bRunning ) + { + if( bScript ) + { + xScriptLibs.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"), + xComponentContext ), UNO_QUERY_THROW ); + } + + if( bDialog ) + { + xDialogLibs.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"), + xComponentContext ), UNO_QUERY_THROW ); + } + } + bool bRegistered = getMyBackend()->isRegisteredInDb(getURL()); + if( !doRegisterPackage ) + { + //We cannot just call removeLibrary(name) because this could remove a + //script which was added by an extension in a different repository. For + //example, extension foo is contained in the bundled repository and then + //the user adds it it to the user repository. The extension manager will + //then register the new script and revoke the script from the bundled + //extension. removeLibrary(name) would now remove the script from the + //user repository. That is, the script of the newly added user extension does + //not work anymore. Therefore we must check if the currently active + //script comes in fact from the currently processed extension. + + if (bRegistered) + { + //we also prevent and live deployment at startup + if (!isRemoved() && !startup) + { + if (bScript && xScriptLibs.is() && xScriptLibs->hasByName(m_name)) + { + const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); + if (sScriptUrl.equals(m_scriptURL)) + xScriptLibs->removeLibrary(m_name); + } + + if (bDialog && xDialogLibs.is() && xDialogLibs->hasByName(m_dialogName)) + { + const OUString sDialogUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); + if (sDialogUrl.equals(m_dialogURL)) + xDialogLibs->removeLibrary(m_dialogName); + } + } + getMyBackend()->deleteDataFromDb(getURL()); + return; + } + } + if (bRegistered) + return; // Already registered + + // Update LibraryContainer + bool bScriptSuccess = false; + const bool bReadOnly = false; + + bool bDialogSuccess = false; + if (!startup) + { + //If there is a bundled extension, and the user installes the same extension + //then the script from the bundled extension must be removed. If this does not work + //then live deployment does not work for scripts. + if (bScript && xScriptLibs.is()) + { + bool bCanAdd = true; + if (xScriptLibs->hasByName(m_name)) + { + const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); + //We assume here that library names in extensions are unique, which may not be the case + //ToDo: If the script exist in another extension, then both extensions must have the + //same id + if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) + { + xScriptLibs->removeLibrary(m_name); + bCanAdd = true; + } + else + { + bCanAdd = false; + } + } + + if (bCanAdd) + { + xScriptLibs->createLibraryLink( m_name, m_scriptURL, bReadOnly ); + bScriptSuccess = xScriptLibs->hasByName( m_name ); + } + } + + + if (bDialog && xDialogLibs.is()) + { + bool bCanAdd = true; + if (xDialogLibs->hasByName(m_dialogName)) + { + const OUString sOriginalUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); + //We assume here that library names in extensions are unique, which may not be the case + //ToDo: If the script exist in another extension, then both extensions must have the + //same id + if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) + { + xDialogLibs->removeLibrary(m_dialogName); + bCanAdd = true; + } + else + { + bCanAdd = false; + } + } + + if (bCanAdd) + { + xDialogLibs->createLibraryLink( m_dialogName, m_dialogURL, bReadOnly ); + bDialogSuccess = xDialogLibs->hasByName(m_dialogName); + } + } + } + bool bSuccess = bScript || bDialog; // Something must have happened + if( bRunning && !startup) + if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) ) + bSuccess = false; + + if (bSuccess) + getMyBackend()->addDataToDb(getURL()); +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.script.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace script +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/script/dp_script.hrc b/desktop/source/deployment/registry/script/dp_script.hrc new file mode 100644 index 000000000000..8ddfa6f51ffc --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SCRIPT_HRC +#define INCLUDED_DP_SCRIPT_HRC + +#include "deployment.hrc" + +#define RID_STR_BASIC_LIB (RID_DEPLOYMENT_SCRIPT_START+10) +#define RID_STR_DIALOG_LIB (RID_DEPLOYMENT_SCRIPT_START+11) + +#define RID_STR_LIBNAME_ALREADY_EXISTS (RID_DEPLOYMENT_SCRIPT_START+15) +#define RID_STR_CANNOT_DETERMINE_LIBNAME (RID_DEPLOYMENT_SCRIPT_START+16) + +#endif diff --git a/desktop/source/deployment/registry/script/dp_script.src b/desktop/source/deployment/registry/script/dp_script.src new file mode 100644 index 000000000000..117f4eac945a --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.src @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_script.hrc" + +String RID_STR_BASIC_LIB +{ + Text [ en-US ] = "%PRODUCTNAME Basic Library"; +}; + +String RID_STR_DIALOG_LIB +{ + Text [ en-US ] = "Dialog Library"; +}; + +String RID_STR_CANNOT_DETERMINE_LIBNAME +{ + Text [ en-US ] = "The library name could not be determined."; +}; + +String RID_STR_LIBNAME_ALREADY_EXISTS +{ + Text [ en-US ] = "This library name already exists. Please choose a different name."; +}; + diff --git a/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx b/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx new file mode 100644 index 000000000000..9a84a7286027 --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocument.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" +#include "dp_scriptbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/script-registry/2010" +#define NS_PREFIX "script" +#define ROOT_ELEMENT_NAME "script-backend-db" +#define KEY_ELEMENT_NAME "script" + +namespace dp_registry { +namespace backend { +namespace script { + +ScriptBackendDb::ScriptBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):RegisteredDb(xContext, url) +{ + +} + +OUString ScriptBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ScriptBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ScriptBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ScriptBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + + +} // namespace executable +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx b/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx new file mode 100644 index 000000000000..7feaeba5568b --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SCRIPTBACKENDDB_HXX +#define INCLUDED_DP_SCRIPTBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "dp_backenddb.hxx" +#include "boost/optional.hpp" +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace script { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ScriptBackendDb: public dp_registry::backend::RegisteredDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + + +public: + + ScriptBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); +}; + + + +} +} +} +#endif + diff --git a/desktop/source/deployment/registry/script/makefile.mk b/desktop/source/deployment/registry/script/makefile.mk new file mode 100644 index 000000000000..708def358021 --- /dev/null +++ b/desktop/source/deployment/registry/script/makefile.mk @@ -0,0 +1,49 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_script +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_script.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_script.obj \ + $(SLO)$/dp_lib_container.obj \ + $(SLO)$/dp_scriptbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx b/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx new file mode 100644 index 000000000000..bf35aa2f50a5 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" +#include "dp_misc.h" +#include "dp_parceldesc.hxx" + + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using ::rtl::OUString; + +namespace css = ::com::sun::star; +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + + +// XDocumentHandler +void SAL_CALL +ParcelDescDocHandler::startDocument() +throw ( xml::sax::SAXException, RuntimeException ) +{ + m_bIsParsed = false; +} + +void SAL_CALL +ParcelDescDocHandler::endDocument() +throw ( xml::sax::SAXException, RuntimeException ) +{ + m_bIsParsed = true; +} + +void SAL_CALL +ParcelDescDocHandler::characters( const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::ignorableWhitespace( const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::processingInstruction( + const OUString &, const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::setDocumentLocator( + const Reference< xml::sax::XLocator >& ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::startElement( const OUString& aName, + const Reference< xml::sax::XAttributeList > & xAttribs ) + throw ( xml::sax::SAXException, + RuntimeException ) +{ + + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::startElement() for ") + + aName + OUSTR("\n")); + if ( !skipIndex ) + { + if ( aName.equals( OUString::createFromAscii( "parcel" ) ) ) + { + m_sLang = xAttribs->getValueByName( OUString::createFromAscii( "language" ) ); + } + ++skipIndex; + } + else + { + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::startElement() skipping for ") + + aName + OUSTR("\n")); + } + +} + +void SAL_CALL ParcelDescDocHandler::endElement( const OUString & aName ) + throw ( xml::sax::SAXException, RuntimeException ) +{ + if ( skipIndex ) + { + --skipIndex; + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::endElement() skipping for ") + + aName + OUSTR("\n")); + } +} + + +} +} +} + diff --git a/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx b/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx new file mode 100644 index 000000000000..a23e9f865894 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <cppuhelper/implbase1.hxx> + +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> + +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +namespace css = ::com::sun::star; +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + +typedef ::cppu::WeakImplHelper1< css::xml::sax::XDocumentHandler > t_DocHandlerImpl; + +class ParcelDescDocHandler : public t_DocHandlerImpl +{ +private: + bool m_bIsParsed; + ::rtl::OUString m_sLang; + sal_Int32 skipIndex; +public: + ParcelDescDocHandler():m_bIsParsed( false ), skipIndex( 0 ){} + ::rtl::OUString getParcelLanguage() { return m_sLang; } + bool isParsed() { return m_bIsParsed; } + // XDocumentHandler + virtual void SAL_CALL startDocument() + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL endDocument() + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttribs ) + throw ( css::xml::sax::SAXException, + css::uno::RuntimeException ); + + virtual void SAL_CALL endElement( const ::rtl::OUString & aName ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL characters( const ::rtl::OUString & aChars ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString & aWhitespaces ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL processingInstruction( + const ::rtl::OUString & aTarget, const ::rtl::OUString & aData ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL setDocumentLocator( + const css::uno::Reference< css::xml::sax::XLocator >& xLocator ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); +}; +} +} +} diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx b/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx new file mode 100644 index 000000000000..8a4ee1b45fbc --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx @@ -0,0 +1,408 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" +#include "dp_sfwk.hrc" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_parceldesc.hxx" +#include "rtl/uri.hxx" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/script/provider/XScriptProviderFactory.hpp> +#include <memory> + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::script; + +using ::rtl::OUString; +namespace css = ::com::sun::star; + +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + Reference< container::XNameContainer > m_xNameCntrPkgHandler; + OUString m_descr; + + void initPackageHandler(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, OUString const & libType, bool bRemoved, + OUString const & identifier); + // XPackage + virtual OUString SAL_CALL getDescription() throw (RuntimeException); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + const Reference<deployment::XPackageTypeInfo> m_xTypeInfo; + +public: + BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +OUString BackendImpl::PackageImpl::getDescription() throw (RuntimeException) +{ + if (m_descr.getLength() == 0) + return Package::getDescription(); + else + return m_descr; +} + +//______________________________________________________________________________ +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, OUString const & libType, bool bRemoved, + OUString const & identifier) + : Package( myBackend.get(), url, OUString(), OUString(), + myBackend->m_xTypeInfo, bRemoved, identifier), + m_descr(libType) +{ + initPackageHandler(); + + sal_Int32 segmEnd = url.getLength(); + if (url.getLength() > 0 && url[ url.getLength() - 1 ] == '/') + --segmEnd; + sal_Int32 segmStart = (url.lastIndexOf( '/', segmEnd ) + 1); + if (segmStart < 0) + segmStart = 0; + // name and display name default the same: + m_displayName = ::rtl::Uri::decode( + url.copy( segmStart, segmEnd - segmStart ), + rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + m_name = m_displayName; + + dp_misc::TRACE(OUSTR("PakageImpl displayName is ") + m_displayName); +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.framework-script"), + OUString() /* no file filter */, + OUSTR("Scripting Framework Script Library"), + RID_IMG_SCRIPTLIB, RID_IMG_SCRIPTLIB_HC ) ) +{ + if (! transientMode()) + { +/* + if (office_is_running()) + { + Reference<XComponentContext> xContext( getComponentContext() ); + m_xScriptLibs.set( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star." + "script.ApplicationScriptLibraryContainer"), + xContext ), UNO_QUERY_THROW ); + m_xDialogLibs.set( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star." + "script.ApplicationDialogLibraryContainer"), + xContext ), UNO_QUERY_THROW ); + } + else + { + OUString basic_path( + m_eContext == CONTEXT_USER + ? OUSTR("vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + SAL_CONFIGFILE("bootstrap") + ":UserInstallation}/user/basic") + : OUSTR("vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + SAL_CONFIGFILE("bootstrap") + ":BaseInstallation}/share/basic") ); + m_basic_script_libs.reset( + new LibraryContainer( + makeURL( basic_path, OUSTR("script.xlc") ), + getMutex(), + getComponentContext() ) ); + m_dialog_libs.reset( + new LibraryContainer( + makeURL( basic_path, OUSTR("dialog.xlc") ), + getMutex(), + getComponentContext() ) ); + } +*/ + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return Sequence< Reference<deployment::XPackageTypeInfo> >(&m_xTypeInfo, 1); +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv ) && + ucbContent.isFolder()) + { + // probe for parcel-descriptor.xml: + if (create_ucb_content( + 0, makeURL( url, OUSTR("parcel-descriptor.xml") ), + xCmdEnv, false /* no throw */ )) + { + mediaType = OUSTR("application/vnd.sun.star.framework-script"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.framework-script")) + { + OUString lang = OUString::createFromAscii("Script"); + OUString sParcelDescURL = makeURL( + url, OUSTR("parcel-descriptor.xml") ); + + ::ucbhelper::Content ucb_content; + + if (create_ucb_content( &ucb_content, sParcelDescURL, + xCmdEnv, false /* no throw */ )) + { + ParcelDescDocHandler* pHandler = + new ParcelDescDocHandler(); + Reference< xml::sax::XDocumentHandler > + xDocHandler = pHandler; + + Reference<XComponentContext> + xContext( getComponentContext() ); + + Reference< xml::sax::XParser > xParser( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.sax.Parser"), xContext ), + UNO_QUERY_THROW ); + + xParser->setDocumentHandler( xDocHandler ); + xml::sax::InputSource source; + source.aInputStream = ucb_content.openStream(); + source.sSystemId = ucb_content.getURL(); + xParser->parseStream( source ); + + if ( pHandler->isParsed() ) + { + lang = pHandler->getParcelLanguage(); + } + } + + OUString sfwkLibType = getResourceString( RID_STR_SFWK_LIB ); + // replace %MACRONAME placeholder with language name + OUString MACRONAME( OUSTR("%MACROLANG" ) ); + sal_Int32 startOfReplace = sfwkLibType.indexOf( MACRONAME ); + sal_Int32 charsToReplace = MACRONAME.getLength(); + sfwkLibType = sfwkLibType.replaceAt( startOfReplace, charsToReplace, lang ); + dp_misc::TRACE("******************************\n"); + dp_misc::TRACE(OUSTR(" BackEnd detected lang = ") + lang + OUSTR("\n")); + dp_misc::TRACE(OUSTR(" for url ") + sParcelDescURL + OUSTR("\n") ); + dp_misc::TRACE("******************************\n"); + return new PackageImpl( this, url, sfwkLibType, bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +void BackendImpl::PackageImpl:: initPackageHandler() +{ + if (m_xNameCntrPkgHandler.is()) + return; + + BackendImpl * that = getMyBackend(); + Any aContext; + + if ( that->m_eContext == CONTEXT_USER ) + { + aContext <<= OUSTR("user"); + } + else if ( that->m_eContext == CONTEXT_SHARED ) + { + aContext <<= OUSTR("share"); + } + else if ( that->m_eContext == CONTEXT_BUNDLED ) + { + aContext <<= OUSTR("bundled"); + } + else + { + OSL_ASSERT( 0 ); + // NOT supported at the momemtn // TODO + } + + Reference< provider::XScriptProviderFactory > xFac( + that->getComponentContext()->getValueByName( + OUSTR( "/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory") ), UNO_QUERY ); + + if ( xFac.is() ) + { + Reference< container::XNameContainer > xName( xFac->createScriptProvider( aContext ), UNO_QUERY ); + if ( xName.is() ) + { + m_xNameCntrPkgHandler.set( xName ); + } + } + // TODO what happens if above fails?? +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + m_xNameCntrPkgHandler.is() && m_xNameCntrPkgHandler->hasByName( + m_url ), + false /* IsAmbiguous */ ) ); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /* startup */, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + if ( !m_xNameCntrPkgHandler.is() ) + { + dp_misc::TRACE("no package handler!!!!\n"); + throw RuntimeException( OUSTR("No package Handler " ), + Reference< XInterface >() ); + } + + if (doRegisterPackage) + { + // will throw if it fails + m_xNameCntrPkgHandler->insertByName( m_url, makeAny( Reference< XPackage >(this) ) ); + + } + else // revokePackage() + { + m_xNameCntrPkgHandler->removeByName( m_url ); + } +} + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.sfwk.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace sfwk +} // namespace backend +} // namespace dp_registry + diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc b/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc new file mode 100644 index 000000000000..0eb619e839e3 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SFWK_HRC +#define INCLUDED_DP_SFWK_HRC + +#include "deployment.hrc" + +#define RID_STR_SFWK_LIB (RID_DEPLOYMENT_SCRIPT_START+20) + +#endif diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.src b/desktop/source/deployment/registry/sfwk/dp_sfwk.src new file mode 100644 index 000000000000..c8d37ce067ac --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.src @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_sfwk.hrc" + +String RID_STR_SFWK_LIB +{ + Text [ en-US ] = "%MACROLANG Library"; +}; + + diff --git a/desktop/source/deployment/registry/sfwk/makefile.mk b/desktop/source/deployment/registry/sfwk/makefile.mk new file mode 100644 index 000000000000..a052296d5c21 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_sfwk +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk +SRS1NAME = $(TARGET) + +SRC1FILES = \ + dp_sfwk.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_parceldesc.obj \ + $(SLO)$/dp_sfwk.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + |