1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
36 #include "dp_resource.h"
37 #include "dp_interact.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"
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
{
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
);
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
<
101 ci_string_hash
, ci_string_equals
> t_string2string
;
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
;
112 Reference
<deployment::XPackageRegistry
> const & xBackend
);
116 virtual void SAL_CALL
disposing();
118 virtual ~PackageRegistryImpl();
119 PackageRegistryImpl() : t_helper( getMutex() ) {}
122 static Reference
<deployment::XPackageRegistry
> create(
123 OUString
const & context
,
124 OUString
const & cachePath
, bool readOnly
,
125 Reference
<XComponentContext
> const & xComponentContext
);
128 virtual void SAL_CALL
update() throw (RuntimeException
);
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
;
178 buf
.append( mediaType
.getToken( 0, '/', index
).trim() );
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
=
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( ';' );
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
);
224 sal_Int32 nIndex
= 0;
226 OUString
token( fileFilter
.getToken( 0, ';', nIndex
) );
227 if (token
.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("*.") ))
228 token
= token
.copy( 1 );
229 if (token
.getLength() == 0)
231 // mark any further wildcards ambig:
232 bool ambig
= (token
.indexOf('*') >= 0 ||
233 token
.indexOf('?') >= 0);
235 ::std::pair
<t_string2string::iterator
, bool> ins(
236 m_filter2mediaType
.insert(
237 t_string2string::value_type(
238 token
, mediaType
) ) );
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
) );
248 iFind
!= m_mediaType2backend
.end() );
249 if (iFind
!= m_mediaType2backend
.end())
250 m_ambiguousBackends
.insert( iFind
->second
);
254 m_ambiguousBackends
.insert( xBackend
);
255 // mark filter to be removed later from filters map:
256 ambiguousFilters
.insert( token
);
262 #if OSL_DEBUG_LEVEL > 0
264 ::rtl::OUStringBuffer buf
;
266 RTL_CONSTASCII_STRINGPARAM(
267 "more than one PackageRegistryBackend for "
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
) );
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") ) );
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(
320 xServiceInfo
->getImplementationName(),
321 rtl_UriCharClassPchar
,
322 rtl_UriEncodeIgnoreEscapes
,
323 RTL_TEXTENCODING_UTF8
) ) );
324 registryArgs
[ 1 ] <<= registryCachePath
;
325 registryArgs
[ 2 ] <<= readOnly
;
327 create_folder( 0, registryCachePath
,
328 Reference
<XCommandEnvironment
>() );
331 Reference
<deployment::XPackageRegistry
> xBackend
;
332 Reference
<lang::XSingleComponentFactory
> xFac( element
, UNO_QUERY
);
335 xFac
->createInstanceWithArgumentsAndContext(
336 registryArgs
, xComponentContext
), UNO_QUERY
);
339 Reference
<lang::XSingleServiceFactory
> xSingleServiceFac(
340 element
, UNO_QUERY_THROW
);
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
);
359 ::dp_registry::backend::bundle::create(
360 that
, context
, cachePath
, readOnly
, xComponentContext
) );
362 #if OSL_DEBUG_LEVEL > 1
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
;
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
=
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
);
423 // XUpdatable: broadcast to backends
424 //______________________________________________________________________________
425 void PackageRegistryImpl::update() throw (RuntimeException
)
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
);
433 xUpdatable
->update();
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
)
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
>() );
457 const t_string2string::const_iterator
iFind(
458 m_filter2mediaType
.find(title
) );
459 if (iFind
!= m_filter2mediaType
.end()) {
460 mediaType
= iFind
->second
;
463 sal_Int32 point
= title
.indexOf( '.', 1 /* consume . */ );
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
)
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) );
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( ';' );
496 iFind
= m_mediaType2backend
.find(
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
);
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