View Javadoc

1   /**
2    * Copyright 2005-2008 the original author or authors.
3    *
4    * Licensed under the Gnu General Pubic License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    *
8    *      http://www.opensource.org/licenses/gpl-license.php
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13   * See the Gnu General Public License for more details.
14   */
15  package org.figure8.join.businessobjects.security.persistence;
16  
17  import org.figure8.join.core.EntityObject;
18  import org.figure8.join.core.InfrastructureException;
19  import org.figure8.join.businessobjects.security.User;
20  import org.figure8.join.util.LogUtil;
21  
22  import org.apache.commons.logging.Log;
23  import org.springframework.jdbc.core.RowMapper;
24  import org.springframework.jdbc.core.JdbcTemplate;
25  
26  import javax.sql.DataSource;
27  
28  import java.util.List;
29  import java.sql.ResultSet;
30  import java.sql.SQLException;
31  /**
32   * This is an implementation of {@link UserDao} using row Jdbc.
33   * @author <a href="mailto:jerome.evrard@gmail.com">Jerome Evrard</a>
34   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
35   * @version $Revision: 1.2 $
36   */
37  public class JdbcUserDao implements UserDao{
38  
39     // Static -------------------------------------------------------------------
40  
41     /** Get a commons logger */
42     private static final Log log = LogUtil.getLog(JdbcUserDao.class);
43  
44  
45     // Attributes ---------------------------------------------------------------
46  
47     /** Cache the select clause with provided columns */
48     private String selectClause = null;
49  
50     /** Spring Jdbc template helper */
51     private JdbcTemplate jt;
52     /** Jdbc datasource allowing access to userTable */
53     private DataSource dataSource;
54  
55     /** Column representing unique identifier */
56     private String idColumn = "n_id";
57     /** Column representing user login */
58     private String loginColumn = "s_login";
59     /** Column representing user password */
60     private String passwordColumn = "s_password";
61     /** Column representing user lastname */
62     private String lastnameColumn = "s_lastname";
63     /** Column representing user firstname */
64     private String firstnameColumn = "s_firstname";
65     /** Column representing user mail address */
66     private String mailColumn = "s_mail";
67     /** Column representing user phone number */
68     private String phoneColumn = "s_phone";
69     /** Column representing user team description */
70     private String teamColumn = "s_team";
71  
72     /** Table containing user definitions */
73     private String userTable = "join_users";
74  
75  
76     // Constructors -------------------------------------------------------------
77  
78     /** Creates a new instance of JdbcUserDao */
79     public JdbcUserDao(){
80     }
81  
82  
83     // Public -------------------------------------------------------------------
84  
85     /** @return Column representing unique identifier */
86     public String getIdColumn(){
87        return idColumn;
88     }
89     /** @param idColumn Column representing unique identifier */
90     public void setIdColumn(String idColumn){
91        this.idColumn = idColumn;
92     }
93     /** @return Column representing user login */
94     public String getLoginColumn(){
95        return loginColumn;
96     }
97     /** @param loginColumn Column representing user login */
98     public void setLoginColumn(String loginColumn){
99        this.loginColumn = loginColumn;
100    }
101    /** @return Column representing user password */
102    public String getPasswordColumn(){
103       return passwordColumn;
104    }
105    /** @param passwordColumn Column representing user password */
106    public void setPasswordColumn(String passwordColumn){
107       this.passwordColumn = passwordColumn;
108    }
109    /** @return Column representing user lastname */
110    public String getLastnameColumn(){
111       return lastnameColumn;
112    }
113    /** @param lastnameColumn Column representing user lastname */
114    public void setLastnameColumn(String lastnameColumn){
115       this.lastnameColumn = lastnameColumn;
116    }
117    /** @return Column representing user firstname */
118    public String getFirstnameColumn(){
119       return firstnameColumn;
120    }
121    /** @param firstnameColumn Column representing user firstname */
122    public void setFirstnameColumn(String firstnameColumn){
123       this.firstnameColumn = firstnameColumn;
124    }
125    /** @return Column representing user mail address */
126    public String getMailColumn(){
127       return mailColumn;
128    }
129    /** @param mailColumn Column representing user mail address */
130    public void setMailColumn(String mailColumn){
131       this.mailColumn = mailColumn;
132    }
133    /** @return Column representing user phone number */
134    public String getPhoneColumn(){
135       return phoneColumn;
136    }
137    /** @param phoneColumn Column representing user phone number */
138    public void setPhoneColumn(String phoneColumn){
139       this.phoneColumn = phoneColumn;
140    }
141    /** @return Column representing user team description */
142    public String getTeamColumn(){
143       return teamColumn;
144    }
145    /** @param teamColumn Column representing user team description */
146    public void setTeamColumn(String teamColumn){
147       this.teamColumn = teamColumn;
148    }
149 
150    /** @return Table containing user definitions */
151    public String getUserTable(){
152       return userTable;
153    }
154    /** @param userTable Table containing user definitions */
155    public void setUserTable(String userTable){
156       this.userTable = userTable;
157    }
158 
159    /** @param dataSource The Datasource allowing access to userTable */
160    public void setDataSource(DataSource dataSource){
161       this.dataSource = dataSource;
162    }
163 
164 
165    // Implementation of UserDao ------------------------------------------------
166 
167    /**
168     * @param login User login (should be a unique identifier)
169     * @return The user object corresponding to <b>login</b>
170     */
171    public User getUser(String login){
172       User user = findUser(login);
173       if (user == null)
174          log.warn("User with login '" + login + "' is not defined or defined multiple times !");
175       return user;
176    }
177 
178    /**
179     * Retrieve all users having lastname 'like' the specified one
180     * @param lastname The string that users lastname should contain
181     * @return A List of {@code org.figure8.join.businessobjects.security.User}
182     */
183    public List getUsersWithLastnameLike(String lastname){
184       List users = findUsers(lastnameColumn, lastname, lastnameColumn);
185       if (log.isDebugEnabled())
186          log.debug("Users having lastname like '" + lastname + "' are: " + users.size());
187       return users;
188    }
189 
190 
191    // Implementation of ObjectDao ----------------------------------------------
192 
193    /**
194     * Save the given entity into underlying datastore.
195     * @param entityobject EntityObject to save
196     */
197    public void save(EntityObject entityobject){
198       // Check that we have a user and cast it.
199       if (!(entityobject instanceof User))
200          throw new IllegalArgumentException("JdbcUserDao only support User not " + entityobject.getClass());
201       User user = (User)entityobject;
202       // Create a template and dissociate create/update.
203       jt = new JdbcTemplate(dataSource);
204       if (user.isTransient()){
205          // TODO : Find a better method to determine next identifier for user.
206          long maxId = jt.queryForLong("select max(" + idColumn + " from " + userTable);
207          // Execute an insertion into datastore.
208          StringBuffer query = new StringBuffer("insert into ").append(userTable).append(" (");
209          query.append(idColumn).append(", ").append(loginColumn).append(", ").append(passwordColumn).append(", ");
210          query.append(lastnameColumn).append(", ").append(firstnameColumn);
211          // Append optional columns if provided.
212          if (mailColumn != null || !"null".equals(mailColumn))
213             query.append(", ").append(mailColumn);
214          if (phoneColumn != null || !"null".equals(phoneColumn))
215             query.append(", ").append(phoneColumn);
216          if (teamColumn != null || !"null".equals(teamColumn))
217             query.append(", ").append(teamColumn);
218          // Append values (mandatory and optionals).
219          query.append(") values (").append(maxId + 1).append(", ");
220          query.append("'").append(user.getLogin()).append("', '").append(user.getPassword()).append("', ");
221          query.append("'").append(user.getLastname()).append("', '").append(user.getFirstname()).append("'");
222          if (mailColumn != null || !"null".equals(mailColumn))
223             query.append(", '").append(user.getMail()).append("'");
224          if (phoneColumn != null || !"null".equals(phoneColumn))
225             query.append(", '").append(user.getPhone()).append("'");
226          if (teamColumn != null || !"null".equals(teamColumn))
227             query.append(", ").append(user.getTeam()).append("'");
228          query.append(")");
229          // Log and execute query.
230          if (log.isDebugEnabled())
231             log.debug("Inserting a new User with: " + query.toString());
232          jt.execute(query.toString());
233       }
234       else{
235          // Realize an update of row into datastore.
236          StringBuffer query = new StringBuffer("update ").append(userTable);
237          query.append(" set ").append(loginColumn).append("='").append(user.getLogin()).append("', ");
238          query.append(passwordColumn).append("='").append(user.getPassword()).append("', ");
239          query.append(lastnameColumn).append("='").append(user.getLastname()).append("', ");
240          query.append(firstnameColumn).append("='").append(user.getFirstname()).append("'");
241          // Append optional columns if provided.
242          if (mailColumn != null || !"null".equals(mailColumn))
243             query.append(", ").append(mailColumn).append("='").append(user.getMail()).append("'");
244          if (phoneColumn != null || !"null".equals(phoneColumn))
245             query.append(", ").append(phoneColumn).append("='").append(user.getPhone()).append("'");
246          if (teamColumn != null || !"null".equals(teamColumn))
247             query.append(", ").append(teamColumn).append("='").append(user.getTeam()).append("'");
248          // Append where clause.
249          query.append(" where ").append(idColumn).append("=").append(user.getId());
250          // Log and execute query.
251          if (log.isDebugEnabled())
252             log.debug("Updating existing User with: " + query.toString());
253          int rows = jt.update(query.toString());
254       }
255    }
256 
257    /**
258     * Remove the given entity object from underlying datastore.
259     * @param entityobject EntityObject to remove
260     */
261    public void remove(EntityObject entityobject){
262       throw new InfrastructureException("JdbcUserDao does not implement remove() method");
263    }
264 
265    /**
266     * Re-read the content of the given entity from underlying datastore.
267     * @param entityobject EntityObject to refresh content
268     */
269    public void refresh(EntityObject entityobject){
270       // Check that we have a user and cast it.
271       if (!(entityobject instanceof User))
272          throw new IllegalArgumentException("JdbcUserDao only support User not " + entityobject.getClass());
273       User user = (User)entityobject;
274       // Refreshing fomr database.
275       user = findUser(user.getId());
276    }
277 
278    /**
279     * Force initialization of the given entity from underlying datastore
280     * (this may involves initialization of lazily loaded relations fields)
281     * @param entityobject EntityObject to initialize
282     */
283    public void initialize(EntityObject entityobject){
284       // User do not have lazy loaded fields so just refresh its state.
285       refresh(entityobject);
286    }
287 
288    /**
289     * Force initialization of the given entity association from underlying datastore
290     * @param entityobject EntityObject whose association shoud be initialized
291     * @param proxy A proxy object representing entoty association (this may be a collection)
292     */
293    public void initializeAssociation(EntityObject entityobject, Object proxy){
294       // User do not have lazy loaded fields so just refresh its state.
295       refresh(entityobject);
296    }
297 
298    /**
299     * Check if an object (EntityObject or association proxy) is initialized from datastore
300     * @param object The object to check initialization for
301     * @return true if object has been loaded from datastore, false otherwise
302     */
303    public boolean isInitialized(Object object){
304       return (object instanceof User);
305    }
306 
307    /**
308     * Persist the object state throughout the cluster.
309     * @param obj The object to replicate
310     */
311    public void replicate(Object obj){
312       // Check that we have a user and cast it.
313       if (!(obj instanceof User))
314          throw new IllegalArgumentException("JdbcUserDao only support User not " + obj.getClass());
315       // No second level cache is used so just save the object.
316       save((User)obj);
317    }
318 
319    /**
320     * Find all entity objects associated with this Dao.
321     * @return A List of EntityObjects
322     */
323    public List findAll(){
324       return findUsers(null, null, null);
325    }
326 
327    /**
328     * Find all entity objects asscoiated with this Dao.
329     * The result list is sorted by <b>sortField</b> criteria.
330     * @param sortField Field for sorting criteria
331     * @return A List of EntityObjects
332     */
333    public List findAllSorted(String sortField){
334       if ("login".equals(sortField))
335          return findUsers(null, null, loginColumn);
336       if ("lastname".equals(sortField))
337          return findUsers(null, null, lastnameColumn);
338       if ("firstname".equals(sortField))
339          return findUsers(null, null, firstnameColumn);
340       // Default is to find all.
341       return findAll();
342    }
343 
344    /**
345     * Get the persistent class associated to this Dao.
346     * @return The class of the persistent object
347     */
348    public Class getPersistentClass(){
349       return org.figure8.join.businessobjects.security.User.class;
350    }
351 
352 
353    // Protected ----------------------------------------------------------------
354 
355    /**
356     * Find a unique User using its identifier
357     * @param id The identifier of User to retrieve
358     * @return The corresponding User or null.
359     */
360    protected User findUser(long id){
361       StringBuffer query = new StringBuffer(getSelectClause());
362       // Append where clause.
363       query.append(" where ").append(idColumn).append("=").append(id);
364       // Execute and map result.
365       jt = new JdbcTemplate(dataSource);
366       List users = jt.query(query.toString(), getUserRowMapper());
367       // Check that there's only one user.
368       if (users.size() > 1){
369          log.error("Expected only one User but found many when looking for id: " + id);
370          throw new InfrastructureException("Expected only one User but found many when looking for id: " + id);
371       }
372       if (!users.isEmpty())
373          return (User)users.get(0);
374       return null;
375    }
376 
377    /**
378     * Find a unique User using its login
379     * @param login The login of User to retrieve
380     * @return The corresponding User object or null.
381     */
382    protected User findUser(String login){
383       StringBuffer query = new StringBuffer(getSelectClause());
384       // Append where clause.
385       query.append(" where ").append(loginColumn).append("='").append(login).append("'");
386       // Execute and map result.
387       jt = new JdbcTemplate(dataSource);
388       List users = jt.query(query.toString(), getUserRowMapper());
389       // Check that there's only one user.
390       if (users.size() > 1){
391          log.error("Expected only one User but found many when looking for login: " + login);
392          throw new InfrastructureException("Expected only one User but found many when looking for login: " + login);
393       }
394       if (!users.isEmpty())
395          return (User)users.get(0);
396       return null;
397    }
398 
399    /**
400     * Find many users using a criterion column and its value.
401     * @param criterionColumn The column that appears in where clause
402     * @param value The value of select criterion
403     * @param sortColumn The column to use for sorting results
404     * @return A list of User objects
405     */
406    protected List findUsers(String criterionColumn, String value, String sortColumn){
407       StringBuffer query = new StringBuffer(getSelectClause());
408       // Append where clause if needed.
409       if (criterionColumn != null)
410          query.append(" where ").append(criterionColumn).append(" like '%").append(value).append("%'");
411       // Append sort clause if needed.
412       if (sortColumn != null)
413          query.append(" order by ").append(sortColumn).append(" asc");
414       // Execute and map results.
415       jt = new JdbcTemplate(dataSource);
416       return jt.query(query.toString(), getUserRowMapper());
417    }
418 
419    /**
420     * Retrieve the where clause depending on specified columns and table name
421     * @return The where clause of SQL query from 'select' to 'from table '
422     */
423    protected String getSelectClause(){
424       if (selectClause == null){
425          StringBuffer buffer = new StringBuffer("select ").append(idColumn).append(", ");
426          buffer.append(loginColumn).append(", ").append(passwordColumn).append(", ");
427          buffer.append(lastnameColumn).append(", ").append(firstnameColumn);
428          // Append optional columns if provided.
429          if (mailColumn != null || !"null".equals(mailColumn))
430             buffer.append(", ").append(mailColumn);
431          if (phoneColumn != null || !"null".equals(phoneColumn))
432             buffer.append(", ").append(phoneColumn);
433          if (teamColumn != null || !"null".equals(teamColumn))
434             buffer.append(", ").append(teamColumn);
435          // Append table name.
436          buffer.append(" from ").append(userTable);
437          selectClause = buffer.toString();
438       }
439       return selectClause;
440    }
441 
442    /**
443     * Retrieve a Spring row mappper for User object
444     * @return A RowMapper implementation for User object
445     */
446    protected RowMapper getUserRowMapper(){
447       return new RowMapper(){
448          /**
449           * Map each row of data in the ResultSet. This method should not call
450           * next() on the ResultSet, but extract the current values.
451           * @param rs the ResultSet to map
452           * @param rowNum The number of the current row
453           * @throws SQLException if a SQLException is encountered getting
454           * column values (that is, there's no need to catch SQLException)
455           */
456          public Object mapRow(ResultSet rs, int rowNum) throws SQLException{
457             User user = new User();
458             user.setId(rs.getLong(idColumn));
459             user.setLogin(rs.getString(loginColumn));
460             user.setPassword(rs.getString(passwordColumn));
461             user.setLastname(rs.getString(lastnameColumn));
462             user.setFirstname(rs.getString(firstnameColumn));
463             // Map optional columns if provided.
464             if (mailColumn != null || !"null".equals(mailColumn))
465                user.setMail(rs.getString(mailColumn));
466             if (phoneColumn != null || !"null".equals(phoneColumn))
467                user.setPhone(rs.getString(phoneColumn));
468             if (teamColumn != null || !"null".equals(teamColumn))
469                user.setTeam(rs.getString(teamColumn));
470             return user;
471          }
472       };
473    }
474 }