1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_configmgr.hxx" 25 #include "sal/config.h" 26 27 #include <vector> 28 29 #include "com/sun/star/lang/DisposedException.hpp" 30 #include "com/sun/star/lang/EventObject.hpp" 31 #include "com/sun/star/lang/WrappedTargetException.hpp" 32 #include "com/sun/star/uno/Any.hxx" 33 #include "com/sun/star/uno/Reference.hxx" 34 #include "com/sun/star/uno/RuntimeException.hpp" 35 #include "com/sun/star/uno/Type.hxx" 36 #include "com/sun/star/uno/XInterface.hpp" 37 #include "com/sun/star/util/ChangesEvent.hpp" 38 #include "com/sun/star/util/ChangesSet.hpp" 39 #include "com/sun/star/util/ElementChange.hpp" 40 #include "com/sun/star/util/XChangesBatch.hpp" 41 #include "com/sun/star/util/XChangesListener.hpp" 42 #include "com/sun/star/util/XChangesNotifier.hpp" 43 #include "comphelper/sequenceasvector.hxx" 44 #include "cppu/unotype.hxx" 45 #include "cppuhelper/queryinterface.hxx" 46 #include "cppuhelper/weak.hxx" 47 #include "osl/diagnose.h" 48 #include "osl/mutex.hxx" 49 #include "rtl/ref.hxx" 50 #include "rtl/ustring.h" 51 #include "rtl/ustring.hxx" 52 53 #include "broadcaster.hxx" 54 #include "childaccess.hxx" 55 #include "components.hxx" 56 #include "data.hxx" 57 #include "lock.hxx" 58 #include "modifications.hxx" 59 #include "node.hxx" 60 #include "path.hxx" 61 #include "rootaccess.hxx" 62 63 namespace configmgr { 64 65 namespace { 66 67 namespace css = com::sun::star; 68 69 } 70 71 RootAccess::RootAccess( 72 Components & components, rtl::OUString const & pathRepresentation, 73 rtl::OUString const & locale, bool update): 74 Access(components), pathRepresentation_(pathRepresentation), 75 locale_(locale), update_(update) 76 {} 77 78 Path RootAccess::getAbsolutePath() { 79 getNode(); 80 return path_; 81 } 82 83 void RootAccess::initBroadcaster( 84 Modifications::Node const & modifications, Broadcaster * broadcaster) 85 { 86 OSL_ASSERT(broadcaster != 0); 87 comphelper::SequenceAsVector< css::util::ElementChange > changes; 88 initBroadcasterAndChanges( 89 modifications, broadcaster, changesListeners_.empty() ? 0 : &changes); 90 if (!changes.empty()) { 91 css::util::ChangesSet set(changes.getAsConstList()); 92 for (ChangesListeners::iterator i(changesListeners_.begin()); 93 i != changesListeners_.end(); ++i) 94 { 95 cppu::OWeakObject* pSource = static_cast< cppu::OWeakObject * >(this); 96 css::uno::Reference< css::uno::XInterface > xBase( pSource, css::uno::UNO_QUERY ); 97 broadcaster->addChangesNotification( 98 *i, 99 css::util::ChangesEvent( 100 pSource, makeAny( xBase ), set)); 101 } 102 } 103 } 104 105 void RootAccess::acquire() throw () { 106 Access::acquire(); 107 } 108 109 void RootAccess::release() throw () { 110 Access::release(); 111 } 112 113 rtl::OUString RootAccess::getAbsolutePathRepresentation() { 114 getNode(); // turn pathRepresentation_ into canonic form 115 return pathRepresentation_; 116 } 117 118 rtl::OUString RootAccess::getLocale() const { 119 return locale_; 120 } 121 122 bool RootAccess::isUpdate() const { 123 return update_; 124 } 125 126 RootAccess::~RootAccess() { 127 osl::MutexGuard g(lock); 128 getComponents().removeRootAccess(this); 129 } 130 131 Path RootAccess::getRelativePath() { 132 return Path(); 133 } 134 135 rtl::OUString RootAccess::getRelativePathRepresentation() { 136 return rtl::OUString(); 137 } 138 139 rtl::Reference< Node > RootAccess::getNode() { 140 if (!node_.is()) { 141 rtl::OUString canonic; 142 int finalizedLayer; 143 node_ = getComponents().resolvePathRepresentation( 144 pathRepresentation_, &canonic, &path_, &finalizedLayer); 145 if (!node_.is()) { 146 throw css::uno::RuntimeException( 147 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cannot find ")) + 148 pathRepresentation_), 149 0); 150 // RootAccess::queryInterface indirectly calls 151 // RootAccess::getNode, so if this RootAccess were passed out in 152 // RuntimeException.Context, client code that called 153 // queryInterface on it would cause trouble; therefore, 154 // RuntimeException.Context is left null here 155 } 156 pathRepresentation_ = canonic; 157 OSL_ASSERT(!path_.empty()); 158 name_ = path_.back(); 159 finalized_ = finalizedLayer != Data::NO_LAYER; 160 } 161 return node_; 162 } 163 164 bool RootAccess::isFinalized() { 165 getNode(); 166 return finalized_; 167 } 168 169 rtl::OUString RootAccess::getNameInternal() { 170 getNode(); 171 return name_; 172 } 173 174 rtl::Reference< RootAccess > RootAccess::getRootAccess() { 175 return this; 176 } 177 178 rtl::Reference< Access > RootAccess::getParentAccess() { 179 return rtl::Reference< Access >(); 180 } 181 182 void RootAccess::addTypes(std::vector< css::uno::Type > * types) const { 183 OSL_ASSERT(types != 0); 184 types->push_back(cppu::UnoType< css::util::XChangesNotifier >::get()); 185 types->push_back(cppu::UnoType< css::util::XChangesBatch >::get()); 186 } 187 188 void RootAccess::addSupportedServiceNames( 189 std::vector< rtl::OUString > * services) 190 { 191 OSL_ASSERT(services != 0); 192 services->push_back( 193 rtl::OUString( 194 RTL_CONSTASCII_USTRINGPARAM( 195 "com.sun.star.configuration.AccessRootElement"))); 196 if (update_) { 197 services->push_back( 198 rtl::OUString( 199 RTL_CONSTASCII_USTRINGPARAM( 200 "com.sun.star.configuration.UpdateRootElement"))); 201 } 202 } 203 204 void RootAccess::initDisposeBroadcaster(Broadcaster * broadcaster) { 205 OSL_ASSERT(broadcaster != 0); 206 for (ChangesListeners::iterator i(changesListeners_.begin()); 207 i != changesListeners_.end(); ++i) 208 { 209 broadcaster->addDisposeNotification( 210 i->get(), 211 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); 212 } 213 Access::initDisposeBroadcaster(broadcaster); 214 } 215 216 void RootAccess::clearListeners() throw() { 217 changesListeners_.clear(); 218 Access::clearListeners(); 219 } 220 221 css::uno::Any RootAccess::queryInterface(css::uno::Type const & aType) 222 throw (css::uno::RuntimeException) 223 { 224 OSL_ASSERT(thisIs(IS_ANY)); 225 osl::MutexGuard g(lock); 226 checkLocalizedPropertyAccess(); 227 css::uno::Any res(Access::queryInterface(aType)); 228 if (res.hasValue()) { 229 return res; 230 } 231 res = cppu::queryInterface( 232 aType, static_cast< css::util::XChangesNotifier * >(this)); 233 if (res.hasValue()) { 234 return res; 235 } 236 if (!res.hasValue() && update_) { 237 res = cppu::queryInterface( 238 aType, static_cast< css::util::XChangesBatch * >(this)); 239 } 240 return res; 241 } 242 243 void RootAccess::addChangesListener( 244 css::uno::Reference< css::util::XChangesListener > const & aListener) 245 throw (css::uno::RuntimeException) 246 { 247 OSL_ASSERT(thisIs(IS_ANY)); 248 { 249 osl::MutexGuard g(lock); 250 checkLocalizedPropertyAccess(); 251 if (!aListener.is()) { 252 throw css::uno::RuntimeException( 253 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")), 254 static_cast< cppu::OWeakObject * >(this)); 255 } 256 if (!isDisposed()) { 257 changesListeners_.insert(aListener); 258 return; 259 } 260 } 261 try { 262 aListener->disposing( 263 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); 264 } catch (css::lang::DisposedException &) {} 265 } 266 267 void RootAccess::removeChangesListener( 268 css::uno::Reference< css::util::XChangesListener > const & aListener) 269 throw (css::uno::RuntimeException) 270 { 271 OSL_ASSERT(thisIs(IS_ANY)); 272 osl::MutexGuard g(lock); 273 checkLocalizedPropertyAccess(); 274 ChangesListeners::iterator i(changesListeners_.find(aListener)); 275 if (i != changesListeners_.end()) { 276 changesListeners_.erase(i); 277 } 278 } 279 280 void RootAccess::commitChanges() 281 throw (css::lang::WrappedTargetException, css::uno::RuntimeException) 282 { 283 OSL_ASSERT(thisIs(IS_UPDATE)); 284 Broadcaster bc; 285 { 286 osl::MutexGuard g(lock); 287 checkLocalizedPropertyAccess(); 288 int finalizedLayer; 289 Modifications globalMods; 290 commitChildChanges( 291 ((getComponents().resolvePathRepresentation( 292 pathRepresentation_, 0, 0, &finalizedLayer) 293 == node_) && 294 finalizedLayer == Data::NO_LAYER), 295 &globalMods); 296 getComponents().writeModifications(); 297 getComponents().initGlobalBroadcaster(globalMods, this, &bc); 298 } 299 bc.send(); 300 } 301 302 sal_Bool RootAccess::hasPendingChanges() throw (css::uno::RuntimeException) { 303 OSL_ASSERT(thisIs(IS_UPDATE)); 304 osl::MutexGuard g(lock); 305 checkLocalizedPropertyAccess(); 306 //TODO: Optimize: 307 std::vector< css::util::ElementChange > changes; 308 reportChildChanges(&changes); 309 return !changes.empty(); 310 } 311 312 css::util::ChangesSet RootAccess::getPendingChanges() 313 throw (css::uno::RuntimeException) 314 { 315 OSL_ASSERT(thisIs(IS_UPDATE)); 316 osl::MutexGuard g(lock); 317 checkLocalizedPropertyAccess(); 318 comphelper::SequenceAsVector< css::util::ElementChange > changes; 319 reportChildChanges(&changes); 320 return changes.getAsConstList(); 321 } 322 323 } 324