First commit
[anna.git] / include / anna / ldap / Engine.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_ldap_Engine_hpp
38 #define anna_ldap_Engine_hpp
39
40 #include <map>
41 #include <string>
42
43 #include <anna/app/Component.hpp>
44
45 namespace anna {
46
47 namespace ldap {
48
49 class Session;
50
51 /**
52    Gestor general de conexiones realizadas a diversos servidores LDAP.
53
54    Optimiza la creacion, busqueda y liberacion de las sesiónes establecidas contra un
55    numero indeterminado de servidores LDAP.
56
57    El siguiente codigo muestra un ejemplo de implementacion:
58
59    \code
60
61       class MyEngine : public ldap::Engine {
62       public:
63          MyEngine () {;}
64
65       private:
66          anna::Recycler<MySession> a_sessions;
67
68          anna::ldap::Session* allocateSession (const int category) throw () { return a_sessions.create (); }
69
70          void releaseSession (anna::ldap::Session* session) throw () {
71             MySession* aux = static_cast <MySession*> (session);
72             a_sessions.release (aux);
73          }
74       };
75
76    \endcode
77 */
78 class Engine : public app::Component {
79 public:
80   /**
81    * Máscara de los niveles de depuración que pueden ser usados en el método #setDebugLevel
82    * \see Engine
83    */
84   struct DebugLevel { enum _v { All = -1, None = 0 }; };
85
86   /**
87    * Devuelve el valor del indicador de conexión automática. Por defecto este indicador será \em true.
88    * \return el valor del indicador de conexión automática.
89    */
90   bool getAutoBind() const throw() { return a_autoBind; }
91
92   /**
93    * Establece el indicador de conexión automática. En caso de no indicarse será \em true.
94    * \param autoBind Valor que tomará el indicador de conexión automática.
95    *
96    * Si es necesario cambiar el temporizador del Bind de una sesión LDAP, primero habrá que
97    * crearla sin conexión automática, cambiar el temporizador asociado e invocar al Bind invocando
98    * implícitamente al método ldap::Session::bind.
99    */
100   void setAutoBind(const bool autoBind) throw() { a_autoBind = autoBind; }
101
102   /**
103      Crea o reusa una sesión LDAP con los parámetros recibidos.
104
105      Las sesiónes LDAP estaran definidas univocamente por la pareja (url, user) si al
106      invocar a este metodo ya existiera una sesión identificada por los mismos parámetros
107      recibidos, se devolvera su instancia.
108
109      Si no existe una sesión identificada por la pareja (url, user) se creara mediate la llamada
110      al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera
111      esta nueva instancia.
112
113      Dependiendo del indicador de conexión automática se solicitará la conexión al servidor
114      o será el programador quien tenga que invocarlo mediate la llamada al método ldap::Session::bind.
115
116      \param url Direccion donde atiende peticiones el servidor LDAP.
117      \param user Usuario requerido para establecer la conexion contra el servidor LDAP.
118      \param password Password requerido para establecer la conexion contra el servidor LDAP.
119      \param category Identifica el tipo de sesión a crear.
120
121      \return La session identificada por la \em url y \em user indicados como parametro.
122
123      \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion
124      correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha
125      realizado correctamente.
126   */
127   Session* createSession(const char* url, const char* user, const char* password, const int category = 0)
128   throw(RuntimeException);
129
130   /**
131      Crea o reusa una sesión LDAP con los parámetros recibidos.
132
133      Las sesiónes LDAP estaran definidas univocamente por la pareja (url, id) si al
134      invocar a este metodo ya existiera una sesión identificada por los mismos parámetros
135      recibidos, se devolvera su instancia.
136
137      Si no existe una sesión identificada por la pareja (url, id) se creara mediate la llamada
138      al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera
139      esta nueva instancia.
140
141      Dependiendo del indicador de conexión automática se solicitará la conexión al servidor
142      o será el programador quien tenga que invocarlo mediate la llamada al método ldap::Session::bind.
143
144      \param url Direccion donde atiende peticiones el servidor LDAP.
145      \param id Identificador usado para identificar la sesión.
146      \param user Usuario requerido para establecer la conexion contra el servidor LDAP.
147      \param password Password requerido para establecer la conexion contra el servidor LDAP.
148      \param category Identifica el tipo de sesión a crear.
149
150      \return La session identificada por la \em url y \em id indicados como parametro.
151
152      \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion
153      correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha
154      realizado correctamente.
155   */
156   Session* createSession(const char* url, const int id, const char* user, const char* password, const int category = 0)
157   throw(RuntimeException);
158
159   /**
160      Crea o reusa una sesión LDAP con los parámetros recibidos a un servidor que no requiera identificar
161      el usuario que solicita la conexion.
162
163      Las sesiónes LDAP estaran definidas univocamente por la pareja (url, user="") si al
164      invocar a este metodo ya existiera una sesión identificada por los mismos parámetros
165      recibidos, se devolvera su instancia.
166
167      Si no existe una sesión identificada por la pareja (url, user="") se creara mediate la llamada
168      al metodo virtual puro (#allocateSession), se realizara la peticion de conexion y se devolvera
169      esta nueva instancia.
170
171      \param url Direccion donde atiende peticiones el servidor LDAP.
172      \param category Identifica el tipo de sesión a crear.
173
174      \return La session identificada por la \em url indicada como parametro.
175
176      \warning La conexion no estara totalmente operativa hasta que no se reciba la notificacion
177      correspondiente en el metodo Session::eventResponse confirmando que el ClassCode::Bind se ha
178      realizado correctamente.
179   */
180   Session* createSession(const char* url, const int category = 0) throw(RuntimeException) {
181     return createSession(url, NULL, NULL, category);
182   }
183
184   /**
185      Devuelve la instancia de la sesión identificada por la pareja (url, user) recibidos como parámetros.
186
187      \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP.
188      \param user Usuario requerido para establecer la conexion contra el servidor LDAP.
189      \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados.
190
191      \return La instancia de la sesión identificada por la pareja (url, user) recibidos como parámetros.
192
193      \warning Si no hay ninguna sesión identificada por la pareja (url, user) se devolvera una excepción.
194   */
195   Session* findSession(const char* url, const char* user, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException);
196
197   /**
198      Devuelve la instancia de la sesión identificada por la pareja (url, id) recibidos como parámetros.
199
200      \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP.
201      \param id Identificador indicado para establecer la conexion contra el servidor LDAP.
202      \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados.
203
204      \return La instancia de la sesión identificada por la pareja (url, id) recibidos como parámetros.
205
206      \warning Si no hay ninguna sesión identificada por la pareja (url, id) se devolvera una excepción.
207   */
208   Session* findSession(const char* url, const int id, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException);
209
210   /**
211      Devuelve la instancia de la sesión identificada por la pareja (url, user="") recibidos como parámetros.
212
213      \param url Direccion de la maquina donde atiendo peticiones el servidor LDAP.
214      \param emode Modo de actuar en caso de que no exista una sesión que coincida con los parámetros indicados.
215
216      \return La instancia de la sesión identificada por la pareja (url, user="") recibidos como parámetros.
217
218      \warning Si no hay ninguna sesión identificada por la pareja (url, user) se devolvera una excepción.
219   */
220   Session* findSession(const char* url, Exception::Mode::_v emode = Exception::Mode::Throw) throw(RuntimeException) {
221     return findSession(url, (const char*) NULL, emode);
222   }
223
224   /**
225    * Libera todos los recursos asociados a una sesión LDAP, creada previemante con createSession. Si la sesión
226    * fuera NULL esta operación no tendrá ningún efecto.
227    * \param session Session LDAP a liberar.
228    */
229   void closeSession(Session* session) throw(RuntimeException);
230
231   /**
232      Devuelve un documento XML con la informacion relevante sobre esta instancia.
233      \param parent Nodo XML del que colgar la informacion referente a esta instancia.
234      \return Un documento XML con la informacion relevante sobre esta instancia.
235   */
236   virtual xml::Node* asXML(xml::Node* parent) const throw();
237
238   /**
239      Devuelve el nombre lógico de este anna::app::Component.
240      \return El nombre lógico de este anna::app::Component.
241   */
242   static const char* getClassName() throw() { return "anna::ldap::Engine"; }
243
244   /**
245    * Establece el nivel de depuración de las operaciones del OpenLDAP.
246    * \param level Máscara que indica los elementos a depurar. Básicamente 0 para desactivar las trazas de depuración y -1 para
247    * activar el trazado de todo.
248    * \return El nivel de depuración anterior.
249    * \see http://www.openldap.org/doc/admin23/runningslapd.html para más niveles.
250    * \see DebugLevel
251    */
252   static int setDebugLevel(const int level) throw(RuntimeException);
253
254 protected:
255   /**
256      Constructor.
257   */
258   Engine();
259
260   /**
261      Metodo invocado para instanciar sesiónes.
262
263      Para la creacion y liberacion de sesiónes es muy aconsejable usar el patron anna::Recycler.
264
265      \param category Identifica la categoria o clase de sesión que deseamos instanciar. Este paremetro
266      es el mismo indicado en el #createSession. Facilita que una misma aplicacion pueda crear un numero
267      indeterminado de sesiónes de distintos tipos, es decir, que actuen de forma distinta a la hora
268      de recoger los resultados de las peticiones.
269
270      \see anna::Recycler
271   */
272   virtual Session* allocateSession(const int category) throw() = 0;
273
274   /**
275      Metodo invocado para liberar sesiónes. En caso de que nuestra aplicacion requiera varios tipos de
276      sesiónes LDAP habra que tener en cuenta el valor devuelto por ldap::Session::getCategory y liberar
277      el tipo adecuado de sesión.
278      \see anna::Recycler
279   */
280   virtual void releaseSession(Session*) throw() = 0;
281
282 private:
283   typedef std::pair <std::string, std::string> session_key;
284   typedef std::map <session_key, Session*> session_container;
285   typedef session_container::value_type session_value_type;
286   typedef session_container::iterator session_iterator;
287   typedef session_container::const_iterator const_session_iterator;
288
289   session_container a_sessions;
290   std::string a_auxURL; // Usada para contenar el ldap:// si fuera necesario
291   bool a_autoBind;
292
293   void do_initialize() throw() {;}
294   void do_stop() throw();
295
296   const char* completeURL(const char* url) throw();
297
298   session_iterator session_find(const char* url, const char* user) throw() {
299     return a_sessions.find(session_key(url, user));
300   }
301   session_iterator session_find(const std::string& url, const std::string& user) throw() {
302     return a_sessions.find(session_key(url, user));
303   }
304   session_iterator session_find(const char* url, const int id) throw();
305
306   session_iterator session_begin() throw() { return a_sessions.begin(); }
307   session_iterator session_end() throw() { return a_sessions.end(); }
308   static Session* session(session_iterator ii) throw() { return ii->second; }
309
310   const_session_iterator session_begin() const throw() { return a_sessions.begin(); }
311   const_session_iterator session_end() const throw() { return a_sessions.end(); }
312   static const Session* session(const_session_iterator ii) throw() { return ii->second; }
313
314   // Para el truco de poner a la alarma antes de invocar al ldap_result
315   static void alarmnCatcher(int) throw();
316
317 };
318
319 }
320 }
321
322 #endif
323