diff --git a/src/service/usServiceReferenceBasePrivate.cpp b/src/service/usServiceReferenceBasePrivate.cpp index 164c966723..f78a4fd545 100644 --- a/src/service/usServiceReferenceBasePrivate.cpp +++ b/src/service/usServiceReferenceBasePrivate.cpp @@ -1,320 +1,324 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usServiceReferenceBasePrivate.h" #include "usServiceFactory.h" #include "usServiceException.h" #include "usServiceRegistry_p.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" #include #include +#ifdef _MSC_VER +#pragma warning(disable:4503) // decorated name length exceeded, name was truncated +#endif + US_BEGIN_NAMESPACE typedef ServiceRegistrationBasePrivate::MutexLocker MutexLocker; ServiceReferenceBasePrivate::ServiceReferenceBasePrivate(ServiceRegistrationBasePrivate* reg) : ref(1), registration(reg) { if(registration) registration->ref.Ref(); } ServiceReferenceBasePrivate::~ServiceReferenceBasePrivate() { if (registration && !registration->ref.Deref()) delete registration; } InterfaceMap ServiceReferenceBasePrivate::GetServiceFromFactory(Module* module, ServiceFactory* factory, bool isModuleScope) { assert(factory && "Factory service pointer is NULL"); InterfaceMap s; try { InterfaceMap smap = factory->GetService(module, ServiceRegistrationBase(registration)); if (smap.empty()) { US_WARN << "ServiceFactory produced null"; return smap; } const std::vector& classes = ref_any_cast >(registration->properties.Value(ServiceConstants::OBJECTCLASS())); for (std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { if (smap.find(*i) == smap.end() && *i != "org.cppmicroservices.factory") { US_WARN << "ServiceFactory produced an object " "that did not implement: " << (*i); smap.clear(); return smap; } } s = smap; if (isModuleScope) { registration->moduleServiceInstance.insert(std::make_pair(module, smap)); } else { registration->prototypeServiceInstances[module].push_back(smap); } } catch (...) { US_WARN << "ServiceFactory threw an exception"; s.clear(); } return s; } InterfaceMap ServiceReferenceBasePrivate::GetPrototypeService(Module* module) { InterfaceMap s; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* factory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); s = GetServiceFromFactory(module, factory, false); } } return s; } void* ServiceReferenceBasePrivate::GetService(Module* module) { void* s = NULL; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { const InterfaceMap im = GetServiceFromFactory(module, serviceFactory, true); s = im.find(interfaceId)->second; } else { s = registration->GetService(interfaceId); } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module][interfaceId]; } else { s = registration->GetService(interfaceId); } } if (s) { registration->dependents[module] = count + 1; } } } return s; } InterfaceMap ServiceReferenceBasePrivate::GetServiceInterfaceMap(Module* module) { InterfaceMap s; { MutexLocker lock(registration->propsLock); if (registration->available) { ServiceFactory* serviceFactory = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); const int count = registration->dependents[module]; if (count == 0) { if (serviceFactory) { s = GetServiceFromFactory(module, serviceFactory, true); } else { s = registration->service; } } else { if (serviceFactory) { // return the already produced instance s = registration->moduleServiceInstance[module]; } else { s = registration->service; } } if (!s.empty()) { registration->dependents[module] = count + 1; } } } return s; } bool ServiceReferenceBasePrivate::UngetPrototypeService(Module* module, const InterfaceMap& service) { MutexLocker lock(registration->propsLock); ServiceRegistrationBasePrivate::ModuleToServicesMap::iterator iter = registration->prototypeServiceInstances.find(module); if (iter == registration->prototypeServiceInstances.end()) { return false; } std::list& prototypeServiceMaps = iter->second; for (std::list::iterator imIter = prototypeServiceMaps.begin(); imIter != prototypeServiceMaps.end(); ++imIter) { if (service == *imIter) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), service); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } prototypeServiceMaps.erase(imIter); if (prototypeServiceMaps.empty()) { registration->prototypeServiceInstances.erase(iter); } return true; } } return false; } bool ServiceReferenceBasePrivate::UngetService(Module* module, bool checkRefCounter) { MutexLocker lock(registration->propsLock); bool hadReferences = false; bool removeService = false; int count= registration->dependents[module]; if (count > 0) { hadReferences = true; } if(checkRefCounter) { if (count > 1) { registration->dependents[module] = count - 1; } else if(count == 1) { removeService = true; } } else { removeService = true; } if (removeService) { InterfaceMap sfi = registration->moduleServiceInstance[module]; registration->moduleServiceInstance.erase(module); if (!sfi.empty()) { try { ServiceFactory* sf = reinterpret_cast( registration->GetService("org.cppmicroservices.factory")); sf->UngetService(module, ServiceRegistrationBase(registration), sfi); } catch (const std::exception& /*e*/) { US_WARN << "ServiceFactory threw an exception"; } } registration->dependents.erase(module); } return hadReferences && removeService; } const ServicePropertiesImpl& ServiceReferenceBasePrivate::GetProperties() const { return registration->properties; } Any ServiceReferenceBasePrivate::GetProperty(const std::string& key, bool lock) const { if (lock) { MutexLocker lock(registration->propsLock); return registration->properties.Value(key); } else { return registration->properties.Value(key); } } bool ServiceReferenceBasePrivate::IsConvertibleTo(const std::string& interfaceId) const { return registration->service.find(interfaceId) != registration->service.end(); } US_END_NAMESPACE diff --git a/src/util/usLDAPProp.cpp b/src/util/usLDAPProp.cpp index ff2c835961..2340dc702d 100644 --- a/src/util/usLDAPProp.cpp +++ b/src/util/usLDAPProp.cpp @@ -1,117 +1,136 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usLDAPProp.h" +#include + US_BEGIN_NAMESPACE LDAPPropExpr::LDAPPropExpr(const std::string& expr) : m_ldapExpr(expr) {} LDAPPropExpr& LDAPPropExpr::operator!() { + if (m_ldapExpr.empty()) return *this; + m_ldapExpr = "(!" + m_ldapExpr + ")"; return *this; } LDAPPropExpr::operator std::string() const { return m_ldapExpr; } +bool LDAPPropExpr::IsNull() const +{ + return m_ldapExpr.empty(); +} + LDAPProp::LDAPProp(const std::string& property) : m_property(property) -{} +{ + if (m_property.empty()) throw std::invalid_argument("property must not be empty"); +} LDAPPropExpr LDAPProp::operator==(const std::string& s) const { + if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "=" + s + ")"); } LDAPPropExpr LDAPProp::operator==(const us::Any& any) const { return operator==(any.ToString()); } LDAPProp::operator LDAPPropExpr () const { return LDAPPropExpr("(" + m_property + "=*)"); } LDAPPropExpr LDAPProp::operator!() const { return LDAPPropExpr("(!(" + m_property + "=*))"); } LDAPPropExpr LDAPProp::operator!=(const std::string& s) const { + if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(!(" + m_property + "=" + s + "))"); } LDAPPropExpr LDAPProp::operator!=(const us::Any& any) const { return operator!=(any.ToString()); } LDAPPropExpr LDAPProp::operator>=(const std::string& s) const { + if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + ">=" + s + ")"); } LDAPPropExpr LDAPProp::operator>=(const us::Any& any) const { return operator>=(any.ToString()); } LDAPPropExpr LDAPProp::operator<=(const std::string& s) const { + if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "<=" + s + ")"); } LDAPPropExpr LDAPProp::operator<=(const us::Any& any) const { return operator<=(any.ToString()); } LDAPPropExpr LDAPProp::Approx(const std::string& s) const { + if (s.empty()) return LDAPPropExpr(s); return LDAPPropExpr("(" + m_property + "~=" + s + ")"); } LDAPPropExpr LDAPProp::Approx(const us::Any& any) const { return Approx(any.ToString()); } - US_END_NAMESPACE us::LDAPPropExpr operator&&(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right) { + if (left.IsNull()) return right; + if (right.IsNull()) return left; return us::LDAPPropExpr("(&" + static_cast(left) + static_cast(right) + ")"); } us::LDAPPropExpr operator||(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right) { + if (left.IsNull()) return right; + if (right.IsNull()) return left; return us::LDAPPropExpr("(|" + static_cast(left) + static_cast(right) + ")"); } diff --git a/src/util/usLDAPProp.h b/src/util/usLDAPProp.h index e63d27a9ff..c7831b5cd1 100644 --- a/src/util/usLDAPProp.h +++ b/src/util/usLDAPProp.h @@ -1,233 +1,235 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USLDAPPROP_H #define USLDAPPROP_H #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4251) #endif US_BEGIN_NAMESPACE /// \cond class US_EXPORT LDAPPropExpr { public: explicit LDAPPropExpr(const std::string& expr); LDAPPropExpr& operator!(); operator std::string() const; + bool IsNull() const; + private: LDAPPropExpr& operator=(const LDAPPropExpr&); std::string m_ldapExpr; }; /// \endcond /** * \ingroup MicroServicesUtils * * A fluent API for creating LDAP filter strings. * * Examples for creating LDAPFilter objects: * \code * // This creates the filter "(&(name=Ben)(!(count=1)))" * LDAPFilter filter(LDAPProp("name") == "Ben" && !(LDAPProp("count") == 1)); * * // This creates the filter "(|(presence=*)(!(absence=*)))" * LDAPFilter filter(LDAPProp("presence") || !LDAPProp("absence")); * * // This creates the filter "(&(ge>=-3)(approx~=hi))" * LDAPFilter filter(LDAPProp("ge") >= -3 && LDAPProp("approx").Approx("hi")); * \endcode * * \sa LDAPFilter */ class US_EXPORT LDAPProp { public: /** * Create a LDAPProp instance for the named LDAP property. * * @param property The name of the LDAP property. */ LDAPProp(const std::string& property); /** * LDAP equality '=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator==(const std::string& s) const; LDAPPropExpr operator==(const us::Any& s) const; template LDAPPropExpr operator==(const T& s) const { std::stringstream ss; ss << s; return LDAPPropExpr("(" + m_property + "=" + ss.str() + ")"); } /// @} operator LDAPPropExpr () const; /** * States the absence of the LDAP property. * * @return A LDAP expression object. */ LDAPPropExpr operator!() const; /** * Convenience operator for LDAP inequality. * * Writing either * \code * LDAPProp("attr") != "val" * \endcode * or * \code * !(LDAPProp("attr") == "val") * \endcode * leads to the same string "(!(attr=val))". * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator!=(const std::string& s) const; LDAPPropExpr operator!=(const us::Any& s) const; template LDAPPropExpr operator!=(const T& s) const { std::stringstream ss; ss << s; return operator!=(ss.str()); } /// @} /** * LDAP greater or equal '>=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator>=(const std::string& s) const; LDAPPropExpr operator>=(const us::Any& s) const; template LDAPPropExpr operator>=(const T& s) const { std::stringstream ss; ss << s; return operator>=(ss.str()); } /// @} /** * LDAP less or equal '<=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr operator<=(const std::string& s) const; LDAPPropExpr operator<=(const us::Any& s) const; template LDAPPropExpr operator<=(const T& s) const { std::stringstream ss; ss << s; return operator<=(ss.str()); } /// @} /** * LDAP approximation '~=' * * @param s A type convertible to std::string. * @return A LDAP expression object. * * @{ */ LDAPPropExpr Approx(const std::string& s) const; LDAPPropExpr Approx(const us::Any& s) const; template LDAPPropExpr Approx(const T& s) const { std::stringstream ss; ss << s; return Approx(ss.str()); } /// @} private: LDAPProp& operator=(const LDAPProp&); std::string m_property; }; US_END_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif /** * \ingroup MicroServicesUtils * * LDAP logical and '&' * * @param left A LDAP expression. * @param right A LDAP expression. * @return A LDAP expression */ US_EXPORT us::LDAPPropExpr operator&&(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right); /** * \ingroup MicroServicesUtils * * LDAP logical or '|' * * @param left A LDAP expression. * @param right A LDAP expression. * @return A LDAP expression */ US_EXPORT us::LDAPPropExpr operator||(const us::LDAPPropExpr& left, const us::LDAPPropExpr& right); #endif // USLDAPPROP_H diff --git a/test/usLDAPFilterTest.cpp b/test/usLDAPFilterTest.cpp index 5bdce68814..e86ac4451b 100644 --- a/test/usLDAPFilterTest.cpp +++ b/test/usLDAPFilterTest.cpp @@ -1,163 +1,169 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include "usTestingMacros.h" #include US_USE_NAMESPACE int TestParsing() { // WELL FORMED Expr try { US_TEST_OUTPUT(<< "Parsing (cn=Babs Jensen)") LDAPFilter ldap( "(cn=Babs Jensen)" ); US_TEST_OUTPUT(<< "Parsing (!(cn=Tim Howes))") ldap = LDAPFilter( "(!(cn=Tim Howes))" ); US_TEST_OUTPUT(<< "Parsing " << std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))") ldap = LDAPFilter( std::string("(&(") + ServiceConstants::OBJECTCLASS() + "=Person)(|(sn=Jensen)(cn=Babs J*)))" ); US_TEST_OUTPUT(<< "Parsing (o=univ*of*mich*)") ldap = LDAPFilter( "(o=univ*of*mich*)" ); } catch (const std::invalid_argument& e) { US_TEST_OUTPUT(<< e.what()); return EXIT_FAILURE; } // MALFORMED Expr try { US_TEST_OUTPUT( << "Parsing malformed expr: cn=Babs Jensen)") LDAPFilter ldap( "cn=Babs Jensen)" ); return EXIT_FAILURE; } catch (const std::invalid_argument&) { } return EXIT_SUCCESS; } int TestEvaluate() { // EVALUATE try { LDAPFilter ldap( "(Cn=Babs Jensen)" ); ServiceProperties props; bool eval = false; // Several values props["cn"] = std::string("Babs Jensen"); props["unused"] = std::string("Jansen"); US_TEST_OUTPUT(<< "Evaluating expr: " << ldap.ToString()) eval = ldap.Match(props); if (!eval) { return EXIT_FAILURE; } // WILDCARD ldap = LDAPFilter( "(cn=Babs *)" ); props.clear(); props["cn"] = std::string("Babs Jensen"); US_TEST_OUTPUT(<< "Evaluating wildcard expr: " << ldap.ToString()) eval = ldap.Match(props); if ( !eval ) { return EXIT_FAILURE; } // NOT FOUND ldap = LDAPFilter( "(cn=Babs *)" ); props.clear(); props["unused"] = std::string("New"); US_TEST_OUTPUT(<< "Expr not found test: " << ldap.ToString()) eval = ldap.Match(props); if ( eval ) { return EXIT_FAILURE; } // std::vector with integer values ldap = LDAPFilter( " ( |(cn=Babs *)(sn=1) )" ); props.clear(); std::vector list; list.push_back(std::string("Babs Jensen")); list.push_back(std::string("1")); props["sn"] = list; US_TEST_OUTPUT(<< "Evaluating vector expr: " << ldap.ToString()) eval = ldap.Match(props); if (!eval) { return EXIT_FAILURE; } // wrong case ldap = LDAPFilter( "(cN=Babs *)" ); props.clear(); props["cn"] = std::string("Babs Jensen"); US_TEST_OUTPUT(<< "Evaluating case sensitive expr: " << ldap.ToString()) eval = ldap.MatchCase(props); if (eval) { return EXIT_FAILURE; } } catch (const std::invalid_argument& e) { US_TEST_OUTPUT( << e.what() ) return EXIT_FAILURE; } return EXIT_SUCCESS; } void TestLDAPExpressions() { LDAPFilter filter( LDAPProp("bla") == "jo" && !(LDAPProp("ha") == 1) && (LDAPProp("presence") || !LDAPProp("absence")) && LDAPProp("le") <= 4.1 && LDAPProp("ge") >= -3 && LDAPProp("approx").Approx("Approx") ); const std::string filterStr = "(&(&(&(&(&(bla=jo)(!(ha=1)))(|(presence=*)(!(absence=*))))(le<=4.1))(ge>=-3))(approx~=Approx))"; US_TEST_CONDITION(filter.ToString() == filterStr, "test generated filter string") + + std::string emptyValue; + std::string someValue = "some"; + std::string filter1 = LDAPProp("key2") == someValue && LDAPProp("key3"); + std::string filter2 = LDAPProp("key2") == someValue && (LDAPProp("key1") == emptyValue || LDAPProp("key3")); + US_TEST_CONDITION(filter1 == filter2, "test null expressions") } int usLDAPFilterTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("LDAPFilterTest"); TestLDAPExpressions(); US_TEST_CONDITION(TestParsing() == EXIT_SUCCESS, "Parsing LDAP expressions: ") US_TEST_CONDITION(TestEvaluate() == EXIT_SUCCESS, "Evaluating LDAP expressions: ") US_TEST_END() }