• OpenFire源码学习之二十一:openfie对用户的优化(上)


    用户类

    优化用户主要是要解决用户的连接量。已经对用户的访问速度和吞吐量。

    预初始化

    在前面的带面中提出来了用户的预初始化。这里就不在贴出来了。下面将redis用户库连接池处理贴出来UserJedisPoolManager

    public class UserJedisPoolManager extends BasicModule{
    	
    	private static final Logger log = LoggerFactory.getLogger(UserJedisPoolManager.class);
    	
    	private static final String OF_ALL_USER = "select username, encryptedPassword, name, email, moblie, creationDate, modificationDate from ofuser";
    	private static final String OF_USER_VCARD = "select username, vcard from ofvcard";
    	private static final String OF_PRESENCE = "select username, offlinePresence, offlineDate from ofPresence";
    	
    	
    	//private static final String REDIS_USER = "REDIS_USER";
    	private static final Integer timeout = 1000*10;
    	private static final int maxActive = 5000 * 10;
    	private static final int maxIdle = 50;
    	private static final long maxWait = (1000 * 100);
    	
    	private static JedisPool pool;
    	private static XMPPServer loaclserver;
    	private static JedisPoolConfig configs;
    	
    	public UserJedisPoolManager() {
    		super("User redis manager");
    	}
    
    	private static JedisPoolConfig createConfig() {
            configs = new JedisPoolConfig();
            configs.setMaxActive(maxActive);
            configs.setMaxIdle(maxIdle);
            configs.setMaxWait(maxWait);
            configs.setTestOnBorrow(false);
            return configs;
    	}
    	
    	private void createJedisPool() {
     		RedisConfig redisConfig = loaclserver.getJedisConfDao().getRedisConfig("REDIS_USER");
    		if (redisConfig != null) {
    					+ " ,auto:" + redisConfig.getAuto());
    			System.out.println(redisConfig.getAuto() .equals("") );
    			pool = new JedisPool(createConfig(), redisConfig.getIp(), Integer.valueOf(redisConfig.getPort().trim()), 
    					timeout, redisConfig.getAuto().equals("")  ? null : redisConfig.getAuto());
    			Jedis jedis = pool.getResource();
    			jedis.select(0);
    			if(!jedis.exists("OFUSER:admin")) {
    				DefaultAuthProvider dup = new DefaultAuthProvider();
    				try {
    					String password = dup.getPassword("admin");
    					password = AuthFactory.encryptPassword(password);
    					Map<String, String> map = new HashMap<String, String>();
    					map.put("NAME", "admin");
    					map.put("PASSWORD", password);
    					map.put("CREATIONDATE", "0");
    					map.put("MODIFICATIONDATE", "0");
    					jedis.hmset("OFUSER:admin", map);
    				} catch (UserNotFoundException e) {
    					e.printStackTrace();
    				}finally{
    					pool.returnResource(jedis);
    				}			}
    		}
    	}
    
    	private void poolInit() {
    		createJedisPool();
    	}
    
    	public Jedis getJedis() {
    		if (pool == null)
    		{
    			poolInit();
    		}
    		Jedis jedis = pool.getResource();
    		jedis.select(0);
    		return jedis;
    	}
    
    	public void returnRes(Jedis jedis) {
    		pool.returnResource(jedis);
    	}
    	
    	@Override
    	public void initialize(XMPPServer server) {
    		super.initialize(server);
    		loaclserver = server;
    		poolInit();
    		log.info("UserManager By Redis: start init....");
    		
        }
    	
    	public Collection<User> getAllUser() {
    		Collection<User> users = new ArrayList<User>();
    		PreparedStatement pstmt = null;
    		Connection con = null;
    	    ResultSet rs = null;
    	    try {
    			con = (Connection) DbConnectionManager.getConnection();
    			pstmt = con.prepareStatement(OF_ALL_USER);
    			rs = pstmt.executeQuery();
    			while(rs.next()) {
    				User user = new User();
    				user.setUsername(rs.getString(1));
    				user.setPassword(rs.getString(2));
    				user.setName(rs.getString(3));
    				user.setEmail(rs.getString(4));
    				user.setMoblie(rs.getString(5));
    				user.setCreationDate(rs.getString(6));
    				user.setModificationDate(rs.getString(7));
    				users.add(user);
    			}
    		}catch (Exception e) {
    			 log.info( e.getMessage());
    			 e.printStackTrace();
    		 }
    		 finally {
    			 DbConnectionManager.closeConnection(pstmt, con);
    		 }
    		return users;
    	}
    	
    	public Collection<UserVcard> getUserVcard() {
    		Collection<UserVcard> userVcards = new ArrayList<UserVcard>();
    		PreparedStatement pstmt = null;
    		Connection con = null;
    	    ResultSet rs = null;
    	    try {
    			con = (Connection) DbConnectionManager.getConnection();
    			pstmt = con.prepareStatement(OF_USER_VCARD);
    			rs = pstmt.executeQuery();
    			while(rs.next()) {
    				UserVcard user = new UserVcard();
    				user.setUsername(rs.getString(1));
    				user.setVcard(rs.getString(2));
    				userVcards.add(user);
    			}
    		}catch (Exception e) {
    			 log.info( e.getMessage());
    			 e.printStackTrace();
    		 }
    		 finally {
    			 DbConnectionManager.closeConnection(pstmt, con);
    		 }
    		return userVcards;
    	}
    	
    	public Collection<Presence> getPresences() {
    		......
    	}
    }
    

    在上面createJedisPool方法中预置了管理员的账号。这是因为我们需要修改openfire的用户认证dao。也就是说web控制台的管理员。在登陆web页面的时候,我们认证也是先走redis验证的。

    用户认证

    用户认证,首先需要重新实现AuthProvider。Openfire当中默认使用的是DefaultAuthProvider来操作数据层。当然他也提供了其他的方式实现接口,比如:HybridAuthProvider、JDBCAuthProvider、NativeAuthProvider、POP3AuthProvider等。

    写完AuthProvider的Redis实现后,接下来需要基于Redis的用户DAO。

    下面是两个类的源码清单:

    RedisAuthProvider

    public class RedisAuthProvider implements AuthProvider{
    
    	private static final Logger log = LoggerFactory.getLogger(RedisAuthProvider.class);
    	private static HmThreadPool threadPool = new HmThreadPool(3);
    	......
    
    	@Override
    	public void authenticate(String username, String password)
    			throws UnauthorizedException, ConnectionException,
    			InternalUnauthenticatedException {
    		......
    	}
    
    	@Override
    	public void authenticate(String username, String token, String digest)
    			throws UnauthorizedException, ConnectionException,
    			InternalUnauthenticatedException {
    		......
    	}
    
    	@Override
    	public String getPassword(String username) throws UserNotFoundException,
    			UnsupportedOperationException {
    		Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();
    		try {
    			String pw = jedis.hmget("OFUSER:" + username, "PASSWORD").get(0);
    			if (pw == null) {
    				String userid = jedis.get("MOBILE:" + username);
    				pw = jedis.hmget("OFUSER:" + userid, "PASSWORD").get(0);
    			}
    			return AuthFactory.decryptPassword(pw);
    		} finally {
    			XMPPServer.getInstance().getUserJedis().returnRes(jedis);
    		}
    	}
    
    	@Override
    	public void setPassword(String username, String password)
    			throws UserNotFoundException, UnsupportedOperationException {
    		Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();
    		try {
    			password = AuthFactory.encryptPassword(password);
    			jedis.hset("OFUSER:" + username, "PASSWORD", password);
    		} finally {
    			XMPPServer.getInstance().getUserJedis().returnRes(jedis);
    		}
    		threadPool.execute(createTask(XMPPServer.getInstance().getJedisConfDao().getAuthProvider(), username, password));
    	}
    
    	@Override
    	public boolean supportsPasswordRetrieval() {
    		// TODO Auto-generated method stub
    		return true;
    	}
    	
    	private static final String UPDATE_PASSWORD =
                "UPDATE ofUser SET encryptedPassword=? WHERE username=?";
    	
    	private Runnable createTask(final AuthProvider edp, final String username, 
    											final String password) {   
            return new Runnable() {   
                public void run() {
                	try {
    					//edp.setPassword(username, password);
                		
                		Connection con = null;
                        PreparedStatement pstmt = null;
                        try {
                            con = DbConnectionManager.getConnection();
                            pstmt = con.prepareStatement(UPDATE_PASSWORD);
                            if (password == null) {
                                pstmt.setNull(1, Types.VARCHAR);
                            }
                            else {
                                pstmt.setString(1, password);
                            }
                            pstmt.setString(2, username);
                            pstmt.executeUpdate();
                        }
                        catch (SQLException sqle) {
                            throw new UserNotFoundException(sqle);
                        }
                        finally {
                            DbConnectionManager.closeConnection(pstmt, con);
                        }
                		
    				} catch (UserNotFoundException e) {
    					log.info("UserNotFoundException: " + username);
    				}
                }   
           };   
       } 
    }
    

    用户认证写完后,要记得修改系统属性表:ofProperty

    provider.auth.className

    org.jivesoftware.util.redis.expand.RedisAuthProvider


    RedisUserProvider:

    public class RedisUserProvider implements UserProvider{
    ......
    	public User loadUser(String username) throws UserNotFoundException {
            if(username.contains("@")) {
                if (!XMPPServer.getInstance().isLocal(new JID(username))) {
                    throw new UserNotFoundException("Cannot load user of remote server: " + username);
                }
                username = username.substring(0,username.lastIndexOf("@"));
            }
            
            Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();
            
            try {
            	Map<String, String> map = jedis.hgetAll("OFUSER:" + username);
        		String usernames = username;
        		if (map.isEmpty()) {
        			String userid = jedis.get("OFUSER:" + username);
        			map = jedis.hgetAll("OFUSER:" + userid);
        			if (map.isEmpty()) {
        				return XMPPServer.getInstance().getJedisConfDao().getUserProvider().loadUser(username);
        			}
        			usernames = userid;
        		}
        		String name = map.get("NAME");
        		String email = map.get("EMAIL");
        		String mobile = map.get("MOBILE");
        		String creationDate = map.get("CREATIONDATE");
        		String modificationDate = map.get("MODIFICATIONDATE");
        		
        		User user = new User(usernames, name, email, mobile, new Date(Long.parseLong(creationDate.equals("0")||creationDate.equals("") ? StringUtils.dateToMillis(new Date()) : creationDate)), 
        				new Date(Long.parseLong(modificationDate.equals("0")||modificationDate.equals("") ? StringUtils.dateToMillis(new Date()) : modificationDate)));
        		
        		return user;
        		
    		} finally {
    			XMPPServer.getInstance().getUserJedis().returnRes(jedis);
    		}
    		
        }
    
        public User createUser(String username, String password, String name, String email)
                throws UserAlreadyExistsException
        {
        	return createUser(username, password, name, email, null);
        }
    
        public User createUser(String username, String password, String name, String email, String moblie)
                throws UserAlreadyExistsException{
            try {
                loadUser(username);
                // The user already exists since no exception, so:
                throw new UserAlreadyExistsException("Username " + username + " already exists");
            }
            catch (UserNotFoundException unfe) {
     
                Jedis jedis = XMPPServer.getInstance().getUserJedis().getJedis();
                
                Map<String, String> hash = new HashMap<String, String>();
                
                password = AuthFactory.encryptPassword(password);
                
                hash.put("PASSWORD", password);
                if (name != null && !"".equals(name))
                	hash.put("NAME", name);
                if (email != null && !"".equals(email)) 
                	hash.put("EMAIL", email);
                if (moblie != null && !"".equals(moblie)) 
                	hash.put("MOBILE", moblie);
     
                Date now = new Date();
                hash.put("CREATIONDATE", StringUtils.dateToMillis(now));
                hash.put("MODIFICATIONDATE", StringUtils.dateToMillis(now));
                
                try {
                	jedis.hmset("OFUSER:" + username, hash);
    			} finally {
    				XMPPServer.getInstance().getUserJedis().returnRes(jedis);
    			}
    
                threadPool.execute(createTaskAddUser(username, null, password, name, email, moblie));
                return new User(username, name, email, moblie, now, now);
            }
        }
        
        private Runnable createTaskAddUser(final String username, final String password, final String encryptedPassword, 
        		final String name, final String email, final String moblie) {
        		return new Runnable() {
        			public void run () {
        				.....
        			}
        		};
        }
        
        public void deleteUser(String username) {
            ......
        }
    
        public int getUserCount() {
            int count = 0;
            Connection con = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                con = DbConnectionManager.getConnection();
                pstmt = con.prepareStatement(USER_COUNT);
                rs = pstmt.executeQuery();
                if (rs.next()) {
                    count = rs.getInt(1);
                }
            }
            catch (SQLException e) {
                Log.error(e.getMessage(), e);
            }
            finally {
                DbConnectionManager.closeConnection(rs, pstmt, con);
            }
            return count;
        }
    
        public Collection<User> getUsers() {
            Collection<String> usernames = getUsernames(0, Integer.MAX_VALUE);
            return new UserCollection(usernames.toArray(new String[usernames.size()]));
        }
    
        public Collection<String> getUsernames() {
            return getUsernames(0, Integer.MAX_VALUE);
        }
    
        private Collection<String> getUsernames(int startIndex, int numResults) {
            ......
        }
    
        public Collection<User> getUsers(int startIndex, int numResults) {
            Collection<String> usernames = getUsernames(startIndex, numResults);
            return new UserCollection(usernames.toArray(new String[usernames.size()]));
        }
    
        public void setName(String username, String name) throws UserNotFoundException {
            ......
        }
    
        public void setEmail(String username, String email) throws UserNotFoundException {
            ......
        }
    
        public void setCreationDate(String username, Date creationDate) throws UserNotFoundException {
            ......
        }
    
        public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException {
            ......
        }
    
        public Set<String> getSearchFields() throws UnsupportedOperationException {
            return new LinkedHashSet<String>(Arrays.asList("Username", "Name", "Email"));
        }
    
        public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException {
            return findUsers(fields, query, 0, 100);
        }
    
        public Collection<User> findUsers(Set<String> fields, String query, int startIndex,
                int numResults) throws UnsupportedOperationException
        {
            ......
        }
        /**
         * Make sure that Log.isDebugEnabled()==true before calling this method.
         * Twenty elements will be logged in every log line, so for 81-100 elements
         * five log lines will be generated
         * @param listElements a list of Strings which will be logged 
         */
        private void LogResults(List<String> listElements) {
          ......
        }
    
    	@Override
    	public void setMoblie(String username, String moblie)
    			throws UserNotFoundException {
           ......
    	}
    }
    

    注意:这里有个moblie字段。在原来openfire用户认证表里面是没有这个字段的。这里是本人新加的字段。方便手机登陆。看各自的页面场景啦。



  • 相关阅读:
    VB中Null、Empty、Nothing及vbNullString的区别
    hs_err_pidXXX.log 解读
    测试Windows Live Writer——开博
    BCPC2021预赛
    软件设计模式之策略模式(Strategy) 壹
    留言板 壹
    友链 壹
    正则表达式练习 壹
    SpringBoot+Mybatis+自定义注解+Atomikos+实现多源数据库切换和分布式事务
    Dependency failed for File System Check on /dev/vdb1 服务器配置升级
  • 原文地址:https://www.cnblogs.com/huwf/p/4273347.html
Copyright © 2020-2023  润新知