001    // Copyright 2008 Thiago H. de Paula Figueiredo
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package br.com.arsmachina.authentication.controller.impl;
016    
017    import java.util.List;
018    import java.util.Random;
019    
020    import org.springframework.transaction.annotation.Transactional;
021    
022    import br.com.arsmachina.authentication.controller.PasswordEncrypter;
023    import br.com.arsmachina.authentication.controller.PermissionController;
024    import br.com.arsmachina.authentication.controller.PermissionGroupController;
025    import br.com.arsmachina.authentication.controller.UserController;
026    import br.com.arsmachina.authentication.dao.UserDAO;
027    import br.com.arsmachina.authentication.entity.Permission;
028    import br.com.arsmachina.authentication.entity.PermissionGroup;
029    import br.com.arsmachina.authentication.entity.Role;
030    import br.com.arsmachina.authentication.entity.User;
031    import br.com.arsmachina.controller.impl.SpringControllerImpl;
032    
033    /**
034     * {@link UserController} implementation.
035     * 
036     * @author Thiago H. de Paula Figueiredo
037     */
038    public class UserControllerImpl extends SpringControllerImpl<User, Integer> implements
039                    UserController {
040    
041            private Random random = new Random();
042    
043            private UserDAO dao;
044    
045            private PermissionGroup allUsersPermissionGroup;
046    
047            private PasswordEncrypter passwordEncrypter;
048    
049            private PermissionController permissionController;
050    
051            private PermissionGroupController permissionGroupController;
052    
053            /**
054             * Single constructor of this class.
055             * 
056             * @param dao an {@link UserDAO}. It cannot be <code>null</code>.
057             * @param passwordEncrypter a {@link PasswordEncrypter}. It cannot be <code>null</code>.
058             * @param permissionController a {@link PermissionController}. It cannot be <code>null</code>. .
059             * @param permissionGroupController a {@link PermissionGroupController}. It cannot be
060             * <code>null</code>.
061             */
062            public UserControllerImpl(UserDAO dao, PasswordEncrypter passwordEncrypter,
063                            PermissionController permissionController,
064                            PermissionGroupController permissionGroupController) {
065    
066                    super(dao);
067                    this.dao = dao;
068    
069                    if (permissionController == null) {
070                            throw new IllegalArgumentException("Parameter permissionController cannot be null");
071                    }
072    
073                    if (permissionGroupController == null) {
074                            throw new IllegalArgumentException("Parameter permissionGroupController cannot be null");
075                    }
076    
077                    if (passwordEncrypter == null) {
078                            throw new IllegalArgumentException("Parameter passwordEncrypter cannot be null");
079                    }
080    
081                    this.permissionController = permissionController;
082                    this.permissionGroupController = permissionGroupController;
083                    this.passwordEncrypter = passwordEncrypter;
084    
085            }
086    
087            /**
088             * Ensures basic permissions and group permissions exist.
089             * 
090             * @param permissionController a {@link PermissionController}.
091             * @param permissionGroupController a {@link PermissionGroupController}.
092             */
093            private void ensureBasicPermissionsExist(PermissionController permissionController,
094                            PermissionGroupController permissionGroupController) {
095    
096                    final String roleName = Permission.USER_ROLE_NAME;
097                    Permission userPermission = permissionController.findByName(roleName);
098    
099                    if (userPermission == null) {
100    
101                            userPermission = new Permission();
102                            userPermission.setName(Permission.USER_ROLE_NAME);
103                            permissionController.save(userPermission);
104    
105                    }
106    
107                    final String groupName = PermissionGroup.ALL_USERS_PERMISSION_GROUP_NAME;
108                    PermissionGroup group = permissionGroupController.findByName(groupName);
109    
110                    if (group == null) {
111    
112                            group = new PermissionGroup();
113                            group.setName(groupName);
114                            group.add(userPermission);
115                            permissionGroupController.save(group);
116    
117                    }
118    
119                    allUsersPermissionGroup = group;
120    
121            }
122    
123            /**
124             * Invokes <code>dao.findByLoginAndPassword()<code>.
125             * @param login
126             * @param password
127             * @return
128             * @see br.com.arsmachina.authentication.dao.UserDAO#findByLoginAndPassword(java.lang.String, java.lang.String)
129             */
130            @Transactional(readOnly = true)
131            public User findByLoginAndPassword(String login, String password) {
132                    return dao.findByLoginAndPassword(login, password);
133            }
134    
135            /**
136             * Invokes <code>dao.findByLogin()<code>.
137             * @param login
138             * @return
139             * @see br.com.arsmachina.authentication.dao.UserDAO#findByLogin(java.lang.String)
140             */
141            @Transactional(readOnly = true)
142            public User findByLogin(String login) {
143                    return dao.findByLogin(login);
144            }
145    
146            /**
147             * Invokes <code>delegate.findByRole()<code>.
148             * @param <T>
149             * @param roleClass
150             * @return
151             * @see br.com.arsmachina.authentication.dao.UserDAO#findByRole(java.lang.Class)
152             */
153            @Transactional(readOnly = true)
154            public <T extends Role> List<User> findByRole(Class<T> roleClass) {
155                    return dao.findByRole(roleClass);
156            }
157    
158            /**
159             * @see br.com.arsmachina.controller.impl.SpringControllerImpl#save(java.lang.Object)
160             */
161            @Transactional
162            @Override
163            public void save(User user) {
164    
165                    if (allUsersPermissionGroup == null) {
166                            ensureBasicPermissionsExist(permissionController, permissionGroupController);
167                    }
168    
169                    if (user.getPermissionGroups().contains(allUsersPermissionGroup) == false) {
170                            user.add(allUsersPermissionGroup);
171                    }
172    
173                    setPasswordIfNeeded(user);
174    
175                    encryptPassword(user);
176    
177                    super.save(user);
178    
179            }
180    
181            /**
182             * Encrypts the password if it is not encrypted already and then updates the user.
183             * 
184             * @param user an {@link User}.
185             * @return <code>user</code>.
186             * @see br.com.arsmachina.controller.impl.SpringControllerImpl#update(java.lang.Object)
187             */
188            @Override
189            @Transactional
190            public User update(User user) {
191    
192                    encryptPassword(user);
193                    return super.update(user);
194    
195            }
196            
197            
198    
199            /**
200             * Invokes <code>delegate.hasUserWithLogin()<code>.
201             * @param login
202             * @return
203             * @see br.com.arsmachina.authentication.dao.UserDAO#hasUserWithLogin(java.lang.String)
204             */
205            public boolean hasUserWithLogin(String login) {
206                    return dao.hasUserWithLogin(login);
207            }
208    
209            private void encryptPassword(User user) {
210    
211                    String password = user.getPassword();
212                    password = passwordEncrypter.encrypt(password);
213                    user.setPassword(password);
214    
215            }
216    
217            /**
218             * Creates a temporary throw-away random password if it was not set yet.
219             * 
220             * @param user an {@link User}.
221             */
222            private void setPasswordIfNeeded(User user) {
223    
224                    if (user.getPassword() == null) {
225                            user.setPassword(Integer.toHexString(random.nextInt()));
226                    }
227    
228            }
229    
230    }