merge the formfield patch from ooo-build
[ooovba.git] / desktop / source / deployment / registry / dp_registry.cxx
blob543bb4fd6cb1f037b84b2d30abac80970b5fcac8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dp_registry.cxx,v $
10 * $Revision: 1.12.86.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_desktop.hxx"
34 #include "dp_registry.hrc"
35 #include "dp_misc.h"
36 #include "dp_resource.h"
37 #include "dp_interact.h"
38 #include "dp_ucb.h"
39 #include "osl/diagnose.h"
40 #include "rtl/ustrbuf.hxx"
41 #include "rtl/uri.hxx"
42 #include "cppuhelper/compbase2.hxx"
43 #include "cppuhelper/exc_hlp.hxx"
44 #include "comphelper/sequence.hxx"
45 #include "ucbhelper/content.hxx"
46 #include "com/sun/star/uno/DeploymentException.hpp"
47 #include "com/sun/star/lang/DisposedException.hpp"
48 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
49 #include "com/sun/star/lang/XServiceInfo.hpp"
50 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
51 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
52 #include "com/sun/star/util/XUpdatable.hpp"
53 #include "com/sun/star/container/XContentEnumerationAccess.hpp"
54 #include "com/sun/star/deployment/PackageRegistryBackend.hpp"
55 #include <hash_map>
56 #include <set>
57 #include <hash_set>
58 #include <memory>
60 using namespace ::dp_misc;
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::ucb;
64 using ::rtl::OUString;
67 namespace dp_registry {
69 namespace backend {
70 namespace bundle {
71 Reference<deployment::XPackageRegistry> create(
72 Reference<deployment::XPackageRegistry> const & xRootRegistry,
73 OUString const & context, OUString const & cachePath, bool readOnly,
74 Reference<XComponentContext> const & xComponentContext );
78 namespace {
80 typedef ::cppu::WeakComponentImplHelper2<
81 deployment::XPackageRegistry, util::XUpdatable > t_helper;
83 //==============================================================================
84 class PackageRegistryImpl : private MutexHolder, public t_helper
86 struct ci_string_hash {
87 ::std::size_t operator () ( OUString const & str ) const {
88 return str.toAsciiLowerCase().hashCode();
91 struct ci_string_equals {
92 bool operator () ( OUString const & str1, OUString const & str2 ) const{
93 return str1.equalsIgnoreAsciiCase( str2 );
96 typedef ::std::hash_map<
97 OUString, Reference<deployment::XPackageRegistry>,
98 ci_string_hash, ci_string_equals > t_string2registry;
99 typedef ::std::hash_map<
100 OUString, OUString,
101 ci_string_hash, ci_string_equals > t_string2string;
102 typedef ::std::set<
103 Reference<deployment::XPackageRegistry> > t_registryset;
105 t_string2registry m_mediaType2backend;
106 t_string2string m_filter2mediaType;
107 t_registryset m_ambiguousBackends;
108 t_registryset m_allBackends;
109 ::std::vector< Reference<deployment::XPackageTypeInfo> > m_typesInfos;
111 void insertBackend(
112 Reference<deployment::XPackageRegistry> const & xBackend );
114 protected:
115 inline void check();
116 virtual void SAL_CALL disposing();
118 virtual ~PackageRegistryImpl();
119 PackageRegistryImpl() : t_helper( getMutex() ) {}
121 public:
122 static Reference<deployment::XPackageRegistry> create(
123 OUString const & context,
124 OUString const & cachePath, bool readOnly,
125 Reference<XComponentContext> const & xComponentContext );
127 // XUpdatable
128 virtual void SAL_CALL update() throw (RuntimeException);
130 // XPackageRegistry
131 virtual Reference<deployment::XPackage> SAL_CALL bindPackage(
132 OUString const & url, OUString const & mediaType,
133 Reference<XCommandEnvironment> const & xCmdEnv )
134 throw (deployment::DeploymentException, CommandFailedException,
135 lang::IllegalArgumentException, RuntimeException);
136 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
137 getSupportedPackageTypes() throw (RuntimeException);
140 //______________________________________________________________________________
141 inline void PackageRegistryImpl::check()
143 ::osl::MutexGuard guard( getMutex() );
144 if (rBHelper.bInDispose || rBHelper.bDisposed) {
145 throw lang::DisposedException(
146 OUSTR("PackageRegistry instance has already been disposed!"),
147 static_cast<OWeakObject *>(this) );
151 //______________________________________________________________________________
152 void PackageRegistryImpl::disposing()
154 // dispose all backends:
155 t_registryset::const_iterator iPos( m_allBackends.begin() );
156 t_registryset::const_iterator const iEnd( m_allBackends.end() );
157 for ( ; iPos != iEnd; ++iPos ) {
158 try_dispose( *iPos );
160 m_mediaType2backend = t_string2registry();
161 m_ambiguousBackends = t_registryset();
162 m_allBackends = t_registryset();
164 t_helper::disposing();
167 //______________________________________________________________________________
168 PackageRegistryImpl::~PackageRegistryImpl()
172 //______________________________________________________________________________
173 OUString normalizeMediaType( OUString const & mediaType )
175 ::rtl::OUStringBuffer buf;
176 sal_Int32 index = 0;
177 for (;;) {
178 buf.append( mediaType.getToken( 0, '/', index ).trim() );
179 if (index < 0)
180 break;
181 buf.append( static_cast< sal_Unicode >('/') );
183 return buf.makeStringAndClear();
186 //______________________________________________________________________________
187 void PackageRegistryImpl::insertBackend(
188 Reference<deployment::XPackageRegistry> const & xBackend )
190 m_allBackends.insert( xBackend );
191 typedef ::std::hash_set<OUString, ::rtl::OUStringHash> t_stringset;
192 t_stringset ambiguousFilters;
194 const Sequence< Reference<deployment::XPackageTypeInfo> > packageTypes(
195 xBackend->getSupportedPackageTypes() );
196 for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos )
198 Reference<deployment::XPackageTypeInfo> const & xPackageType =
199 packageTypes[ pos ];
200 m_typesInfos.push_back( xPackageType );
202 const OUString mediaType( normalizeMediaType(
203 xPackageType->getMediaType() ) );
204 ::std::pair<t_string2registry::iterator, bool> mb_insertion(
205 m_mediaType2backend.insert( t_string2registry::value_type(
206 mediaType, xBackend ) ) );
207 if (mb_insertion.second) {
208 // add parameterless media-type, too:
209 sal_Int32 semi = mediaType.indexOf( ';' );
210 if (semi >= 0) {
211 m_mediaType2backend.insert(
212 t_string2registry::value_type(
213 mediaType.copy( 0, semi ), xBackend ) );
215 const OUString fileFilter( xPackageType->getFileFilter() );
216 if (fileFilter.getLength() == 0 ||
217 fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*.*") ) ||
218 fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*") ))
220 m_ambiguousBackends.insert( xBackend );
222 else
224 sal_Int32 nIndex = 0;
225 do {
226 OUString token( fileFilter.getToken( 0, ';', nIndex ) );
227 if (token.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("*.") ))
228 token = token.copy( 1 );
229 if (token.getLength() == 0)
230 continue;
231 // mark any further wildcards ambig:
232 bool ambig = (token.indexOf('*') >= 0 ||
233 token.indexOf('?') >= 0);
234 if (! ambig) {
235 ::std::pair<t_string2string::iterator, bool> ins(
236 m_filter2mediaType.insert(
237 t_string2string::value_type(
238 token, mediaType ) ) );
239 ambig = !ins.second;
240 if (ambig) {
241 // filter has already been in: add previously
242 // added backend to ambig set
243 const t_string2registry::const_iterator iFind(
244 m_mediaType2backend.find(
245 /* media-type of pr. added backend */
246 ins.first->second ) );
247 OSL_ASSERT(
248 iFind != m_mediaType2backend.end() );
249 if (iFind != m_mediaType2backend.end())
250 m_ambiguousBackends.insert( iFind->second );
253 if (ambig) {
254 m_ambiguousBackends.insert( xBackend );
255 // mark filter to be removed later from filters map:
256 ambiguousFilters.insert( token );
259 while (nIndex >= 0);
262 #if OSL_DEBUG_LEVEL > 0
263 else {
264 ::rtl::OUStringBuffer buf;
265 buf.appendAscii(
266 RTL_CONSTASCII_STRINGPARAM(
267 "more than one PackageRegistryBackend for "
268 "media-type=\"") );
269 buf.append( mediaType );
270 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" => ") );
271 buf.append( Reference<lang::XServiceInfo>(
272 xBackend, UNO_QUERY_THROW )->
273 getImplementationName() );
274 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
275 OSL_ENSURE( 0, ::rtl::OUStringToOString(
276 buf.makeStringAndClear(),
277 RTL_TEXTENCODING_UTF8 ) );
279 #endif
282 // cut out ambiguous filters:
283 t_stringset::const_iterator iPos( ambiguousFilters.begin() );
284 const t_stringset::const_iterator iEnd( ambiguousFilters.end() );
285 for ( ; iPos != iEnd; ++iPos ) {
286 m_filter2mediaType.erase( *iPos );
290 //______________________________________________________________________________
291 Reference<deployment::XPackageRegistry> PackageRegistryImpl::create(
292 OUString const & context,
293 OUString const & cachePath, bool readOnly,
294 Reference<XComponentContext> const & xComponentContext )
296 PackageRegistryImpl * that = new PackageRegistryImpl;
297 Reference<deployment::XPackageRegistry> xRet(that);
299 // auto-detect all registered package registries:
300 Reference<container::XEnumeration> xEnum(
301 Reference<container::XContentEnumerationAccess>(
302 xComponentContext->getServiceManager(),
303 UNO_QUERY_THROW )->createContentEnumeration(
304 OUSTR("com.sun.star.deployment.PackageRegistryBackend") ) );
305 if (xEnum.is())
307 while (xEnum->hasMoreElements())
309 Any element( xEnum->nextElement() );
310 Sequence<Any> registryArgs(
311 cachePath.getLength() == 0 ? 1 : 3 );
312 registryArgs[ 0 ] <<= context;
313 if (cachePath.getLength() > 0)
315 Reference<lang::XServiceInfo> xServiceInfo(
316 element, UNO_QUERY_THROW );
317 OUString registryCachePath(
318 makeURL( cachePath,
319 ::rtl::Uri::encode(
320 xServiceInfo->getImplementationName(),
321 rtl_UriCharClassPchar,
322 rtl_UriEncodeIgnoreEscapes,
323 RTL_TEXTENCODING_UTF8 ) ) );
324 registryArgs[ 1 ] <<= registryCachePath;
325 registryArgs[ 2 ] <<= readOnly;
326 if (! readOnly)
327 create_folder( 0, registryCachePath,
328 Reference<XCommandEnvironment>() );
331 Reference<deployment::XPackageRegistry> xBackend;
332 Reference<lang::XSingleComponentFactory> xFac( element, UNO_QUERY );
333 if (xFac.is()) {
334 xBackend.set(
335 xFac->createInstanceWithArgumentsAndContext(
336 registryArgs, xComponentContext ), UNO_QUERY );
338 else {
339 Reference<lang::XSingleServiceFactory> xSingleServiceFac(
340 element, UNO_QUERY_THROW );
341 xBackend.set(
342 xSingleServiceFac->createInstanceWithArguments(
343 registryArgs ), UNO_QUERY );
345 if (! xBackend.is()) {
346 throw DeploymentException(
347 OUSTR("cannot instantiate PackageRegistryBackend service: ")
348 + Reference<lang::XServiceInfo>(
349 element, UNO_QUERY_THROW )->getImplementationName(),
350 static_cast<OWeakObject *>(that) );
353 that->insertBackend( xBackend );
357 // insert bundle be:
358 that->insertBackend(
359 ::dp_registry::backend::bundle::create(
360 that, context, cachePath, readOnly, xComponentContext ) );
362 #if OSL_DEBUG_LEVEL > 1
363 // dump tables:
365 t_registryset allBackends;
366 dp_misc::TRACE("> [dp_registry.cxx] media-type detection:\n\n" );
367 for ( t_string2string::const_iterator iPos(
368 that->m_filter2mediaType.begin() );
369 iPos != that->m_filter2mediaType.end(); ++iPos )
371 ::rtl::OUStringBuffer buf;
372 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("extension \"") );
373 buf.append( iPos->first );
374 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
375 "\" maps to media-type \"") );
376 buf.append( iPos->second );
377 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
378 "\" maps to backend ") );
379 const Reference<deployment::XPackageRegistry> xBackend(
380 that->m_mediaType2backend.find( iPos->second )->second );
381 allBackends.insert( xBackend );
382 buf.append( Reference<lang::XServiceInfo>(
383 xBackend, UNO_QUERY_THROW )
384 ->getImplementationName() );
385 dp_misc::writeConsole( buf.makeStringAndClear() + OUSTR("\n"));
387 dp_misc::TRACE( "> [dp_registry.cxx] ambiguous backends:\n\n" );
388 for ( t_registryset::const_iterator iPos(
389 that->m_ambiguousBackends.begin() );
390 iPos != that->m_ambiguousBackends.end(); ++iPos )
392 ::rtl::OUStringBuffer buf;
393 buf.append(
394 Reference<lang::XServiceInfo>(
395 *iPos, UNO_QUERY_THROW )->getImplementationName() );
396 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
397 const Sequence< Reference<deployment::XPackageTypeInfo> > types(
398 (*iPos)->getSupportedPackageTypes() );
399 for ( sal_Int32 pos = 0; pos < types.getLength(); ++pos ) {
400 Reference<deployment::XPackageTypeInfo> const & xInfo =
401 types[ pos ];
402 buf.append( xInfo->getMediaType() );
403 const OUString filter( xInfo->getFileFilter() );
404 if (filter.getLength() > 0) {
405 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" (") );
406 buf.append( filter );
407 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") );
409 if (pos < (types.getLength() - 1))
410 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
412 dp_misc::TRACE(buf.makeStringAndClear() + OUSTR("\n\n"));
414 allBackends.insert( that->m_ambiguousBackends.begin(),
415 that->m_ambiguousBackends.end() );
416 OSL_ASSERT( allBackends == that->m_allBackends );
418 #endif
420 return xRet;
423 // XUpdatable: broadcast to backends
424 //______________________________________________________________________________
425 void PackageRegistryImpl::update() throw (RuntimeException)
427 check();
428 t_registryset::const_iterator iPos( m_allBackends.begin() );
429 const t_registryset::const_iterator iEnd( m_allBackends.end() );
430 for ( ; iPos != iEnd; ++iPos ) {
431 const Reference<util::XUpdatable> xUpdatable( *iPos, UNO_QUERY );
432 if (xUpdatable.is())
433 xUpdatable->update();
437 // XPackageRegistry
438 //______________________________________________________________________________
439 Reference<deployment::XPackage> PackageRegistryImpl::bindPackage(
440 OUString const & url, OUString const & mediaType_,
441 Reference<XCommandEnvironment> const & xCmdEnv )
442 throw (deployment::DeploymentException, CommandFailedException,
443 lang::IllegalArgumentException, RuntimeException)
445 check();
446 OUString mediaType(mediaType_);
447 if (mediaType.getLength() == 0)
449 ::ucbhelper::Content ucbContent;
450 if (create_ucb_content(
451 &ucbContent, url, xCmdEnv, false /* no throw */ ))
453 OUString title( ucbContent.getPropertyValue(
454 StrTitle::get() ).get<OUString>() );
455 for (;;)
457 const t_string2string::const_iterator iFind(
458 m_filter2mediaType.find(title) );
459 if (iFind != m_filter2mediaType.end()) {
460 mediaType = iFind->second;
461 break;
463 sal_Int32 point = title.indexOf( '.', 1 /* consume . */ );
464 if (point < 0)
465 break;
466 title = title.copy(point);
470 if (mediaType.getLength() == 0)
472 // try ambiguous backends:
473 t_registryset::const_iterator iPos( m_ambiguousBackends.begin() );
474 const t_registryset::const_iterator iEnd( m_ambiguousBackends.end() );
475 for ( ; iPos != iEnd; ++iPos )
477 try {
478 return (*iPos)->bindPackage( url, mediaType, xCmdEnv );
480 catch (lang::IllegalArgumentException &) {
483 throw lang::IllegalArgumentException(
484 getResourceString(RID_STR_CANNOT_DETECT_MEDIA_TYPE) + url,
485 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
487 else
489 // get backend by media-type:
490 t_string2registry::const_iterator iFind(
491 m_mediaType2backend.find( normalizeMediaType(mediaType) ) );
492 if (iFind == m_mediaType2backend.end()) {
493 // xxx todo: more sophisticated media-type argument parsing...
494 sal_Int32 q = mediaType.indexOf( ';' );
495 if (q >= 0) {
496 iFind = m_mediaType2backend.find(
497 normalizeMediaType(
498 // cut parameters:
499 mediaType.copy( 0, q ) ) );
502 if (iFind == m_mediaType2backend.end()) {
503 throw lang::IllegalArgumentException(
504 getResourceString(RID_STR_UNSUPPORTED_MEDIA_TYPE) + mediaType,
505 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
507 return iFind->second->bindPackage( url, mediaType, xCmdEnv );
511 //______________________________________________________________________________
512 Sequence< Reference<deployment::XPackageTypeInfo> >
513 PackageRegistryImpl::getSupportedPackageTypes() throw (RuntimeException)
515 return comphelper::containerToSequence(m_typesInfos);
518 } // anon namespace
520 //==============================================================================
521 Reference<deployment::XPackageRegistry> SAL_CALL create(
522 OUString const & context,
523 OUString const & cachePath, bool readOnly,
524 Reference<XComponentContext> const & xComponentContext )
526 return PackageRegistryImpl::create(
527 context, cachePath, readOnly, xComponentContext );
530 } // namespace dp_registry