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 { 223 OSL_ASSERT(thisIs(IS_ANY)); 224 osl::MutexGuard g(lock); 225 checkLocalizedPropertyAccess(); 226 css::uno::Any res(Access::queryInterface(aType)); 227 if (res.hasValue()) { 228 return res; 229 } 230 res = cppu::queryInterface( 231 aType, static_cast< css::util::XChangesNotifier * >(this)); 232 if (res.hasValue()) { 233 return res; 234 } 235 if (!res.hasValue() && update_) { 236 res = cppu::queryInterface( 237 aType, static_cast< css::util::XChangesBatch * >(this)); 238 } 239 return res; 240 } 241 242 void RootAccess::addChangesListener( 243 css::uno::Reference< css::util::XChangesListener > const & aListener) 244 { 245 OSL_ASSERT(thisIs(IS_ANY)); 246 { 247 osl::MutexGuard g(lock); 248 checkLocalizedPropertyAccess(); 249 if (!aListener.is()) { 250 throw css::uno::RuntimeException( 251 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")), 252 static_cast< cppu::OWeakObject * >(this)); 253 } 254 if (!isDisposed()) { 255 changesListeners_.insert(aListener); 256 return; 257 } 258 } 259 try { 260 aListener->disposing( 261 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); 262 } catch (css::lang::DisposedException &) {} 263 } 264 265 void RootAccess::removeChangesListener( 266 css::uno::Reference< css::util::XChangesListener > const & aListener) 267 { 268 OSL_ASSERT(thisIs(IS_ANY)); 269 osl::MutexGuard g(lock); 270 checkLocalizedPropertyAccess(); 271 ChangesListeners::iterator i(changesListeners_.find(aListener)); 272 if (i != changesListeners_.end()) { 273 changesListeners_.erase(i); 274 } 275 } 276 277 void RootAccess::commitChanges() 278 { 279 OSL_ASSERT(thisIs(IS_UPDATE)); 280 Broadcaster bc; 281 { 282 osl::MutexGuard g(lock); 283 checkLocalizedPropertyAccess(); 284 int finalizedLayer; 285 Modifications globalMods; 286 commitChildChanges( 287 ((getComponents().resolvePathRepresentation( 288 pathRepresentation_, 0, 0, &finalizedLayer) 289 == node_) && 290 finalizedLayer == Data::NO_LAYER), 291 &globalMods); 292 getComponents().writeModifications(); 293 getComponents().initGlobalBroadcaster(globalMods, this, &bc); 294 } 295 bc.send(); 296 } 297 298 sal_Bool RootAccess::hasPendingChanges() { 299 OSL_ASSERT(thisIs(IS_UPDATE)); 300 osl::MutexGuard g(lock); 301 checkLocalizedPropertyAccess(); 302 //TODO: Optimize: 303 std::vector< css::util::ElementChange > changes; 304 reportChildChanges(&changes); 305 return !changes.empty(); 306 } 307 308 css::util::ChangesSet RootAccess::getPendingChanges() 309 { 310 OSL_ASSERT(thisIs(IS_UPDATE)); 311 osl::MutexGuard g(lock); 312 checkLocalizedPropertyAccess(); 313 comphelper::SequenceAsVector< css::util::ElementChange > changes; 314 reportChildChanges(&changes); 315 return changes.getAsConstList(); 316 } 317 318 } 319