Improve property inheritance, first batch of SessionInitiators, rename providerId.
[shibboleth/sp.git] / shibsp / util / DOMPropertySet.cpp
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * DOMPropertySet.cpp
19  * 
20  * DOM-based property set implementation.
21  */
22
23 #include "internal.h"
24 #include "util/DOMPropertySet.h"
25
26 #include <algorithm>
27 #include <xmltooling/util/NDC.h>
28 #include <xmltooling/util/XMLConstants.h>
29
30 using namespace shibsp;
31 using namespace xmltooling;
32 using namespace log4cpp;
33 using namespace xercesc;
34 using namespace std;
35
36 DOMPropertySet::~DOMPropertySet()
37 {
38     for (map<string,pair<char*,const XMLCh*> >::iterator i=m_map.begin(); i!=m_map.end(); i++)
39         XMLString::release(&(i->second.first));
40     for_each(m_nested.begin(),m_nested.end(),cleanup_pair<string,DOMPropertySet>());
41 }
42
43 void DOMPropertySet::load(
44     const DOMElement* e,
45     Category& log,
46     DOMNodeFilter* filter,
47     const std::map<std::string,std::string>* remapper
48     )
49 {
50 #ifdef _DEBUG
51     NDC ndc("load");
52 #endif
53     m_root=e;
54
55     // Process each attribute as a property.
56     DOMNamedNodeMap* attrs=m_root->getAttributes();
57     for (XMLSize_t i=0; i<attrs->getLength(); i++) {
58         DOMNode* a=attrs->item(i);
59         if (!XMLString::compareString(a->getNamespaceURI(),xmlconstants::XMLNS_NS))
60             continue;
61         char* val=XMLString::transcode(a->getNodeValue());
62         if (val && *val) {
63             auto_ptr_char ns(a->getNamespaceURI());
64             auto_ptr_char name(a->getLocalName());
65             const char* realname=name.get();
66             map<string,string>::const_iterator remap;
67             if (remapper) {
68                 remap=remapper->find(realname);
69                 if (remap!=remapper->end()) {
70                     log.warn("remapping property (%s) to (%s)",realname,remap->second.c_str());
71                     realname=remap->second.c_str();
72                 }
73             }
74             if (ns.get()) {
75                 if (remapper && (remap=remapper->find(ns.get()))!=remapper->end())
76                     m_map[string("{") + remap->second.c_str() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
77                 else
78                     m_map[string("{") + ns.get() + '}' + realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
79                 log.debug("added property {%s}%s (%s)",ns.get(),realname,val);
80             }
81             else {
82                 m_map[realname]=pair<char*,const XMLCh*>(val,a->getNodeValue());
83                 log.debug("added property %s (%s)",realname,val);
84             }
85         }
86     }
87     
88     // Process non-excluded elements as nested sets.
89     DOMTreeWalker* walker=
90         static_cast<DOMDocumentTraversal*>(
91             m_root->getOwnerDocument())->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,filter,false
92             );
93     e=static_cast<DOMElement*>(walker->firstChild());
94     while (e) {
95         auto_ptr_char ns(e->getNamespaceURI());
96         auto_ptr_char name(e->getLocalName());
97         const char* realname=name.get();
98         map<string,string>::const_iterator remap;
99         if (remapper) {
100             remap=remapper->find(realname);
101             if (remap!=remapper->end()) {
102                 log.warn("remapping property set (%s) to (%s)",realname,remap->second.c_str());
103                 realname=remap->second.c_str();
104             }
105         }
106         string key;
107         if (ns.get()) {
108             if (remapper && (remap=remapper->find(ns.get()))!=remapper->end())
109                 key=string("{") + remap->second.c_str() + '}' + realname;
110             else
111                 key=string("{") + ns.get() + '}' + realname;
112         }
113         else
114             key=realname;
115         if (m_nested.find(key)!=m_nested.end())
116             log.warn("load() skipping duplicate property set: %s",key.c_str());
117         else {
118             DOMPropertySet* set=new DOMPropertySet();
119             set->load(e,log,filter,remapper);
120             m_nested[key]=set;
121             log.debug("added nested property set: %s",key.c_str());
122         }
123         e=static_cast<DOMElement*>(walker->nextSibling());
124     }
125     walker->release();
126 }
127
128 pair<bool,bool> DOMPropertySet::getBool(const char* name, const char* ns) const
129 {
130     map<string,pair<char*,const XMLCh*> >::const_iterator i;
131
132     if (ns)
133         i=m_map.find(string("{") + ns + '}' + name);
134     else
135         i=m_map.find(name);
136
137     if (i!=m_map.end())
138         return make_pair(true,(!strcmp(i->second.first,"true") || !strcmp(i->second.first,"1")));
139     else if (m_parent)
140         return m_parent->getBool(name,ns);
141     return make_pair(false,false);
142 }
143
144 pair<bool,const char*> DOMPropertySet::getString(const char* name, const char* ns) const
145 {
146     pair<bool,const char*> ret(false,NULL);
147     map<string,pair<char*,const XMLCh*> >::const_iterator i;
148
149     if (ns)
150         i=m_map.find(string("{") + ns + '}' + name);
151     else
152         i=m_map.find(name);
153
154     if (i!=m_map.end())
155         return make_pair(true,i->second.first);
156     else if (m_parent)
157         return m_parent->getString(name,ns);
158     return pair<bool,const char*>(false,NULL);
159 }
160
161 pair<bool,const XMLCh*> DOMPropertySet::getXMLString(const char* name, const char* ns) const
162 {
163     map<string,pair<char*,const XMLCh*> >::const_iterator i;
164
165     if (ns)
166         i=m_map.find(string("{") + ns + '}' + name);
167     else
168         i=m_map.find(name);
169
170     if (i!=m_map.end())
171         return make_pair(true,i->second.second);
172     else if (m_parent)
173         return m_parent->getXMLString(name,ns);
174     return pair<bool,const XMLCh*>(false,NULL);
175 }
176
177 pair<bool,unsigned int> DOMPropertySet::getUnsignedInt(const char* name, const char* ns) const
178 {
179     map<string,pair<char*,const XMLCh*> >::const_iterator i;
180
181     if (ns)
182         i=m_map.find(string("{") + ns + '}' + name);
183     else
184         i=m_map.find(name);
185
186     if (i!=m_map.end())
187         return pair<bool,unsigned int>(true,strtol(i->second.first,NULL,10));
188     else if (m_parent)
189         return m_parent->getUnsignedInt(name,ns);
190     return pair<bool,unsigned int>(false,0);
191 }
192
193 pair<bool,int> DOMPropertySet::getInt(const char* name, const char* ns) const
194 {
195     map<string,pair<char*,const XMLCh*> >::const_iterator i;
196
197     if (ns)
198         i=m_map.find(string("{") + ns + '}' + name);
199     else
200         i=m_map.find(name);
201
202     if (i!=m_map.end())
203         return pair<bool,int>(true,atoi(i->second.first));
204     else if (m_parent)
205         return m_parent->getInt(name,ns);
206     return pair<bool,int>(false,0);
207 }
208
209 const PropertySet* DOMPropertySet::getPropertySet(const char* name, const char* ns) const
210 {
211     map<string,DOMPropertySet*>::const_iterator i;
212
213     if (ns)
214         i=m_nested.find(string("{") + ns + '}' + name);
215     else
216         i=m_nested.find(name);
217
218     return (i!=m_nested.end()) ? i->second : (m_parent ? m_parent->getPropertySet(name,ns) : NULL);
219 }