Neo4j图数据库管理系统开发笔记之三:构建安全的RMI Service(Client)


最初,设计RMI Service主要是基于三个目的。第一,解决Neo4j嵌入式图数据库单例模式的境况,实现多个客户端可同时操作同一数据库。第二,为图数据库添加安全认证机制,保证数据库访问的安全性。第三,提供轻量级的数据访问接口文件(Neo4j本身提供的Java API Jar文件合计有40多MB),而封装后的RMI Client Jar文件只有300KB左右。

3.1. RMI Client(客户端)

首先介绍下RMI Client(客户端),因为RMI服务中的绝大部分公共对象都在Client包里面,在项目关系上,也是RMI Server端引用RMI Client客户端。项目目录结构图如下所示:

rmi client project

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3.1.1 客户端示例

在开始介绍RMI客户端实现原理之前,我们先来浏览下客户端调用方面的代码示例。

3.1.1.1 初始化RMI服务部署地址信息

利用RMI客户端调用RMI服务的第一步,是先初始化RMI服务部署的地址和端口信息,否则,客户端将无法定位到远程服务。示例代码如下。

String hostAddress = “10.230.9.145”;
String hostPort = “1099”;
for(String serviceName : RemoteServiceUtil.getRemoteServiceList().keySet()) {
    RemoteClientFactory.initRemoteServiceOption(serviceName, hostAddress, hostPort);
}
3.1.1.2 初始化RMI客户端用户信息

由客户端将用户名称和密码传递到服务端,在服务端进行用户权限认证(登录用户详细资料以及权限配置信息都由服务端配置管理)。示例代码如下所示:

RemoteClientFactory.setLoginName(loginName);
RemoteClientFactory.setLoginPassword(password);
3.1.1.3 获取远程服务实例

其实,用户登录认证工作是在获取远程服务实例的时候进行的,如果认证成功,则返回对应的服务实例,否则将抛出异常信息。

private IGraphNodeService graphNodeService = null;
this.graphNodeService = RemoteClientFactory.getGraphNodeService(selectedGraphName);
GNode startNode = this.graphNodeService.findNodeByID(10);

 

3.1.2 远程服务实体类

对Neo4j Java API中的关键实体对象进行封装处理,保证其可实现完全意义上的序列化。封装完成后,Client端将不会出现Neo4j Java API中原生的接口类对象,所有的数据都将在RMI Server(服务端)通过解析,自动转换成RMI Client(客户端)认可的类对象。其封装映射关系如下图所示:

2015-12-7 13-49-01

3.1.2.1 GNode
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Description: Neo4j图数据库节点实体信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GNode implements Serializable {
    private static final long serialVersionUID = 1L;
    private long id = -1;
    private int degree = 0;
    private Map<String,Object> propertyList = new HashMap<String,Object>();
    private List<String> labelNameList = new ArrayList<String>();
    private List<Long> relationshipList = new ArrayList<Long>();
    private Map<String,ArrayList<Long>> relationshipTypeList = new HashMap<String,ArrayList<Long>>();
    private Map<String,ArrayList<Long>> relationshipDirectionList = new HashMap<String,ArrayList<Long>>();
    
    /**
     * 获取节点编码
     * @return
     */
    public long getId() {
        return id;
    }
    /**
     * 设置节点编码
     * @param id
     */
    public void setId(long id) {
        this.id = id;
    }
    /**
     * 获取节点深度
     * @return
     */
    public int getDegree() {
        return degree;
    }
    /**
     * 设置节点深度
     * @param degree
     */
    public void setDegree(int degree) {
        this.degree = degree;
    }
    /**
     * 获取节点属性集合
     * @return
     */
    public Map<String, Object> getPropertyList() {
        return propertyList;
    }
    /**
     * 获取节点标签集合
     * @return
     */
    public List<String> getLabelNameList() {
        return labelNameList;
    }
    /**
     * 获取节点关联关系编码集合
     * @return
     */
    public List<Long> getRelationshipList() {
        return relationshipList;
    }
    /**
     * 获取节点的关联关系类型分组集合
     * @return
     */
    public Map<String,ArrayList<Long>> getRelationshipTypeList() {
        return relationshipTypeList;
    }
    /**
     * 获取节点的关联关系方向分组集合
     * @return
     */
    public Map<String,ArrayList<Long>> getRelationshipDirectionList() {
        return relationshipDirectionList;
    }
    /**
     * 根据关系类型获取对应关系编码集合。
     * @param relationshipType
     * @return
     */
    public List<Long> getRelationships(String relationshipType) {
        if(this.relationshipTypeList.containsKey(relationshipType)) {
            return this.relationshipTypeList.get(relationshipType);
        }
        return new ArrayList<Long>();
    }
    /**
     * 根据关系方向获取对应关系编码集合。
     * @param direction
     * @return
     */
    public List<Long> getRelationships(GDirection direction) {
        if(this.relationshipDirectionList.containsKey(direction.getName())) {
            return this.relationshipDirectionList.get(direction.getName());
        }
        return new ArrayList<Long>();
    }
    
    /**
     * 根据关系类型和方向检索出关系编码集合。
     * @param relationshipType
     * @param direction
     * @return
     */
    public List<Long> getRelationships(String relationshipType, GDirection direction) {
        List<Long> listByType = this.getRelationships(relationshipType);
        List<Long> listByDirection = this.getRelationships(direction);
        List<Long> list = new ArrayList<Long>();
        for(long id : listByType) {
            if(listByDirection.contains(id)) {
                list.add(id);
            }
        }
        return list;
    }
}
3.1.2.2 GRelationship
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * Description: Neo4j图数据库连接关系实体信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GRelationship implements Serializable {
    private static final long serialVersionUID = 1L;
    private long id = -1;
    private String relationshipType = "";
    private long startNodeID = -1;
    private long endNodeID = -1;
    private Map<String,Object> propertyList = new HashMap<String,Object>();
    
    /**
     * 获取关系编码
     * @return
     */
    public long getId() {
        return id;
    }
    /**
     * 设置关系编码
     * @param id
     */
    public void setId(long id) {
        this.id = id;
    }
    /**
     * 获取关系类型
     * @return
     */
    public String getRelationshipType() {
        return relationshipType;
    }
    /**
     * 设置关系类型
     * @param relationshipType
     */
    public void setRelationshipType(String relationshipType) {
        this.relationshipType = relationshipType;
    }
    /**
     * 获取起始节点编码
     * @return
     */
    public long getStartNodeID() {
        return startNodeID;
    }
    /**
     * 设置起始节点编码
     * @param startNodeID
     */
    public void setStartNodeID(long startNodeID) {
        this.startNodeID = startNodeID;
    }
    /**
     * 获取结束节点编码
     * @return
     */
    public long getEndNodeID() {
        return endNodeID;
    }
    /**
     * 设置结束节点编码
     * @param endNodeID
     */
    public void setEndNodeID(long endNodeID) {
        this.endNodeID = endNodeID;
    }
    /**
     * 获取关系属性信息集合
     * @return
     */
    public Map<String, Object> getPropertyList() {
        return propertyList;
    }
    /**
     * 设置关系属性信息集合
     * @param propertyList
     */
    public void setPropertyList(Map<String, Object> propertyList) {
        this.propertyList = propertyList;
    }
}
3.1.2.3 GPath
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * Description: Neo4j图数据库路径实体信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GPath implements Serializable {
    private static final long serialVersionUID = 1L;
    private GNode beginNode = null;
    private GNode endNode = null;
    private List<GNode> nodes = new ArrayList<GNode>();
    private List<GNode> reverseNodes = new ArrayList<GNode>();
    private List<GRelationship> relationships = new ArrayList<GRelationship>();
    private List<GRelationship> reverseRelationships = new ArrayList<GRelationship>();
    private GRelationship lastRelationship = null;
    /**
     * 获取路径中包含的Node对象集合。
     * @return
     */
    public List<GNode> getNodes() {
        return nodes;
    }
    /**
     * 获取路径中包含的Relationship对象集合。
     * @return
     */
    public List<GRelationship> getRelationships() {
        return relationships;
    }
    /**
     * 获取路径的起始节点对象。
     * @return
     */
    public GNode getBeginNode() {
        if(this.nodes.size() > 0) {
            this.beginNode = this.nodes.get(0);
        }
        return beginNode;
    }
    /**
     * 获取路径的结束节点对象。
     * @return
     */
    public GNode getEndNode() {
        if(this.nodes.size() > 0) {
            this.endNode = this.nodes.get(this.nodes.size() - 1);
        }
        return endNode;
    }
    /**
     * 获取路径中包含的Node对象集合(反向)。
     * @return
     */
    public List<GNode> getReverseNodes() {
        if(this.nodes.size() > 0) {
            this.reverseNodes.clear();
            for(int i=this.nodes.size() - 1; i>=0; i--) {
                this.reverseNodes.add(this.nodes.get(i));
            }
        }
        return reverseNodes;
    }
    /**
     * 获取获取路径中包含的Relationship对象集合(反向)。
     * @return
     */
    public List<GRelationship> getReverseRelationships() {
        if(this.relationships.size() > 0) {
            this.reverseRelationships.clear();
            for(int i=this.relationships.size() - 1; i>=0; i--) {
                this.reverseRelationships.add(this.relationships.get(i));
            }
        }
        return reverseRelationships;
    }
    /**
     * 获取获取路径中最后一个Relationship对象。
     * @return
     */
    public GRelationship getLastRelationship() {
        if(this.relationships.size() > 0) {
            this.lastRelationship = this.relationships.get(this.relationships.size() - 1);
        }
        return lastRelationship;
    }
}
3.1.2.4 GDirection
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;

/**
 * Description: Neo4j图数据库关系方向类型信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GDirection implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 包含两种方向。
     */
    public static final String BOTH = "BOTH";
    /**
     * incoming方向。
     */
    public static final String INCOMING = "INCOMING";
    /**
     * outgoing方向。
     */
    public static final String OUTGOING = "OUTGOING";
    private String name;
    /**
     * 获取关系方向名称。
     * @return
     */
    public String getName() {
        return name;
    }
    private GDirection(String name) {
        this.name = name;
    }
    /**
     * 生成BOTH类型的GDirection对象
     * @return
     */
    public static GDirection both() {
        GDirection direction = new GDirection(BOTH);
        return direction;
    }
    /**
     * 生成INCOMING类型的GDirection对象
     * @return
     */
    public static GDirection incoming() {
        GDirection direction = new GDirection(INCOMING);
        return direction;
    }
    /**
     * 生成OUTGOING类型的GDirection对象
     * @return
     */
    public static GDirection outgoing() {
        GDirection direction = new GDirection(OUTGOING);
        return direction;
    }
}
3.1.2.5 GOrderBy
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;

/**
 * Description: Neo4j图数据库排序信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GOrderBy implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 排序类型字符串:升序
     */
    public static final String ORDER_TYPE_ASC = "ASC";
    /**
     * 排序类型字符串:降序
     */
    public static final String ORDER_TYPE_DESC = "DESC";
    private String propertyName;
    private String orderType;
    /**
     * 获取参与排序的属性名称
     * @return
     */
    public String getPropertyName() {
        return propertyName;
    }
    /**
     * 获取排序类型
     * @return
     */
    public String getOrderType() {
        return this.orderType;
    }
    /**
     * 构造函数
     * @param propertyName 排序属性名称
     * @param orderType 排序类型
     */
    private GOrderBy(String propertyName, String orderType) {
        this.propertyName = propertyName;
        this.orderType = orderType;
    }
    /**
     * 构建升序排序信息对象
     * @param propertyName
     * @return
     */
    public static GOrderBy asc(String propertyName) {
        return new GOrderBy(propertyName, ORDER_TYPE_ASC);
    }
    /**
     * 构建降序排序信息对象
     * @param propertyName
     * @return
     */
    public static GOrderBy desc(String propertyName) {
        return new GOrderBy(propertyName, ORDER_TYPE_DESC);
    }
}
3.1.2.6 GPage
package com.hnepri.neo4j.client.rmi.bean;

import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import com.hnepri.common.util.LogInfoUtil;

/**
 * Description: 图数据库数据分页模型类。<br>
 * 利用此类可分页管理Node数据和Relationship数据等。
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class GPage implements Serializable {
    private static final long serialVersionUID = 330410716100946538L;
    private int pageSize = 10;
    private int pageIndex = 1;
    private int prevPageIndex = 1;
    private int nextPageIndex = 1;
    private int pageCount = 0;
    private int pageFirstRowIndex = 1;
    private boolean hasNextPage = true;
    private int totalCount = 0;
    private long startTime = System.currentTimeMillis();
    private long endTime = System.currentTimeMillis();
    private List<GNode> nodeList = new ArrayList<GNode>();
    private List<GRelationship> relationshipList = new ArrayList<GRelationship>();
    
    /**
     * 分页对象构造函数
     * @param pageSize 每页记录数
     */
    public GPage(int pageSize) {
        this.pageSize = pageSize;
    }

    /**
     * 获取分页记录数量
     * @return
     */
    public int getPageSize() {
        return pageSize;
    }
    /**
     * 获取当前页序号
     * @return
     */
    public int getPageIndex() {
        return pageIndex;
    }
    /**
     * 设置当前页序号
     * @param pageIndex
     */
    public void setPageIndex(int pageIndex) {
        if(pageIndex <= 0) {
            pageIndex = 1;
        }
        this.pageIndex = pageIndex;
    }
    /**
     * 获取分页总数
     * @return
     */
    public int getPageCount() {
        if(this.getTotalCount() == 0) {
            this.pageCount = 0;
        } else {
            int shang = this.getTotalCount() / this.getPageSize();
            int yu = this.getTotalCount() % this.getPageSize();
            if(yu > 0) {
                shang += 1;
            }
            this.pageCount = shang;
        }
        return pageCount;
    }
    /**
     * 获取每页的第一行序号
     * @return
     */
    public int getPageFirstRowIndex() {
        this.pageFirstRowIndex = (this.pageIndex - 1) * this.getPageSize() + 1;
        return pageFirstRowIndex;
    }
    /**
     * 获取上一页序号
     * @return
     */
    public int getPrevPageIndex() {
        if(this.pageIndex > 1) {
            this.prevPageIndex = this.pageIndex - 1;
        } else {
            this.prevPageIndex = 1;
        }
        return prevPageIndex;
    }
    /**
     * 获取下一页序号
     * @return
     */
    public int getNextPageIndex() {
        if(this.pageIndex < this.pageCount) {
            this.nextPageIndex = this.pageIndex + 1;    
        } else {
            this.nextPageIndex = this.pageCount;
        }
        return nextPageIndex;
    }
    /**
     * 跳转到下一页
     */
    public void nextPage() {
        if(this.totalCount == 0 || this.getPageCount() == 0) {
            this.pageIndex = 1;
        } else {
            if(this.pageIndex < this.pageCount) {
                this.pageIndex = this.pageIndex + 1;    
            } else {
                this.pageIndex = this.pageCount;
            }
        }
    }
    /**
     * 跳转到上一页
     */
    public void prevPage() {
        if(this.pageIndex > 1) {
            this.pageIndex = this.pageIndex - 1;
        } else {
            this.pageIndex = 1;
        }
    }
    /**
     * 获取是否有下一页
     * @return
     */
    public boolean isHasNextPage() {
        if(this.pageIndex < this.getPageCount()) {
            this.hasNextPage = true;
        } else {
            this.hasNextPage = false;
        }
        return hasNextPage;
    }
    /**
     * 获取总记录数    
     */
    public int getTotalCount() {
        return totalCount;
    }
    /**
     * 获取总记录数    
     * @param totalCount
     */
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
    /**
     * 初始化起始时间(毫秒)
     */
    public void initStartTime() {
        this.startTime = System.currentTimeMillis();
    }
    /**
     * 初始化截止时间(毫秒)
     */
    public void initEndTime() {
        this.endTime = System.currentTimeMillis();
    }
    /**
     * 获取毫秒格式的耗时信息
     * @return
     */
    public String getTimeIntervalByMilli() {
        return String.valueOf(this.endTime - this.startTime) + "毫秒";
    }
    /**
     * 获取秒格式的耗时信息
     * @return
     */
    public String getTimeIntervalBySecond() {
        double interval = (this.endTime - this.startTime)/1000.0;
        DecimalFormat df = new DecimalFormat("#.##");
        return df.format(interval) + "秒";
    }
    /**
     * 打印时间信息
     */
    public void printTimeInfo() {
        LogInfoUtil.printLog("起始时间:" + this.startTime);
        LogInfoUtil.printLog("截止时间:" + this.endTime);
        LogInfoUtil.printLog("耗费时间:" + this.getTimeIntervalBySecond());
    }
    /**
     * 获取Node检索结果列表
     * @return
     */
    public List<GNode> getNodeList() {
        return nodeList;
    }
    /**
     * 获取Relationship检索结果列表
     * @return
     */
    public List<GRelationship> getRelationshipList() {
        return relationshipList;
    }
}
3.1.3 远程服务接口类

这里着重介绍下远程服务基础接口IBaseRemoteService,主要有两个方法,分别进行用户登录验证和传递图数据库名称等。用户登录验证,是RMI安全机制的第一步,决定RMI客户端是否有权使用RMI服务。

package com.hnepri.neo4j.client.rmi.service;
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    /**
     * Description: 远程服务基类接口类<br>
     * Copyright: Copyright (c) 2015<br>
     * Company: 河南电力科学研究院智能电网所<br>
     * @author shangbingbing 2015-11-01编写
     * @version 1.0
     */
    public interface IBaseRemoteService extends Remote {
    /**
     * Remote连接测试,正常情况会返回大写的SUCCESS。
     * @return
     * @throws RemoteException
     */
    public String remoteTest() throws RemoteException;
    /**
     * 验证RMI服务用户信息
     * @param loginName 用户名称
     * @param password 用户密码
     * @return 返回状态值。<br>
     * 0:表示验证通过。<br>
     * 1:表示未设置用户或者密码。<br>
     * 2:表示用户不存在。<br>
     * 3:表示密码错误。<br>
     * 4:表示用户无权访问此服务。<br>
     * 5:表示IP无权访问此服务。
     * @throws RemoteException
     */
    public int login(String loginName, String password) throws RemoteException;
    /**
     * 初始化设置图数据库名称
     * @param graphName 图数据库名称(与Server端保持一致)
     * @throws RemoteException
     */
    public void initGraphName(String graphName) throws RemoteException;
    /**
     * 初始化设置图数据库路径
     * @param graphPath 图数据库路径(与Server端保持一致)
     * @throws RemoteException
     */
    public void initGraphPath(String graphPath) throws RemoteException;
}

由于每个接口文件中的方法过多,这里不再一一罗列,开发人员可以根据自己的需要创建相关的接口文件和接口中的方法。其他几个服务接口类如下所示:

package com.hnepri.neo4j.client.rmi.service;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.hnepri.neo4j.client.form.graph.bean.GraphConfigOption;
import com.hnepri.neo4j.client.form.graph.bean.GraphModelOption;
/**
 * Description: Neo4j图数据库管理操作接口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public interface IGraphManageService extends IBaseRemoteService

package com.hnepri.neo4j.client.rmi.service;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Map;
import com.hnepri.neo4j.client.rmi.bean.GNode;
import com.hnepri.neo4j.client.rmi.bean.GRelationship;
/**
 * Description: Neo4j图数据库Node操作接口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public interface IGraphNodeService extends IBaseRemoteService

package com.hnepri.neo4j.client.rmi.service;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.List;
import com.hnepri.neo4j.client.rmi.bean.GNode;
import com.hnepri.neo4j.client.rmi.bean.GRelationship;
/**
 * Description: Neo4j图数据库Index操作接口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public interface IGraphIndexService extends IBaseRemoteService

package com.hnepri.neo4j.client.rmi.service;
import java.rmi.RemoteException;
import java.util.List;
import com.hnepri.neo4j.client.rmi.bean.GDirection;
import com.hnepri.neo4j.client.rmi.bean.GPath;
/**
 * Description: Neo4j图数据库Path操作接口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public interface IGraphPathService extends IBaseRemoteService

package com.hnepri.neo4j.client.rmi.service;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.hnepri.neo4j.client.rmi.bean.GDirection;
import com.hnepri.neo4j.client.rmi.bean.GNode;
import com.hnepri.neo4j.client.rmi.bean.GOrderBy;
import com.hnepri.neo4j.client.rmi.bean.GPage;
import com.hnepri.neo4j.client.rmi.bean.GPath;
import com.hnepri.neo4j.client.rmi.bean.GRelationship;
/**
 * Description: Neo4j图数据库Cypher操作接口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public interface IGraphCypherService extends IBaseRemoteService
3.1.4 远程服务工具类

远程服务工具类包括客户端调用工厂Factory类(主要是对远程服务接口类的调用进行组织管理,同时提供安全认证机制,确保调用者为认证和授权用户)、远程登录状态工具类、远程服务信息工具类等。

 3.1.4.1 RemoteClientFactory

package com.hnepri.neo4j.client.rmi.util;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.util.HashMap;

import com.hnepri.common.util.LogInfoUtil;
import com.hnepri.neo4j.client.rmi.service.IGraphCypherService;
import com.hnepri.neo4j.client.rmi.service.IGraphIndexService;
import com.hnepri.neo4j.client.rmi.service.IGraphManageService;
import com.hnepri.neo4j.client.rmi.service.IGraphNodeService;
import com.hnepri.neo4j.client.rmi.service.IGraphPathService;

/**
 * Description: Hadoop集群相关rmi服务客户端工厂类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class RemoteClientFactory {

    /**
     * 远程服务调用成功返回值
     */
    public static final String REMOTE_CALL_STATUS_SUCCESS = "SUCCESS";
    /**
     * 远程服务调用失败返回值
     */
    public static final String REMOTE_CALL_STATUS_FAILURE = "FAILURE";
    
    /**
     * RMI服务默认部署主机IP地址
     */
    public static final String DEFAULT_HOST_ADDRESS = "10.231.45.34";
    /**
     * RMI服务默认部署主机端口号
     */
    public static final String DEFAULT_HOST_PORT = "1099";
    
    private static String loginName = "";
    private static String loginPassword = "";
    /**
     *     获取登录用户名称
     * @return
     */
    public static String getLoginName() {
        return loginName;
    }
    /**
     * 设置登录用户名称
     * @param loginName
     */
    public static void setLoginName(String loginName) {
        RemoteClientFactory.loginName = loginName;
        remoteServiceLoginStatusList.clear();
    }
    /**
     * 获取登录用户密码
     * @return
     */
    public static String getLoginPassword() {
        return loginPassword;
    }
    /**
     * 设置登录用户密码
     * @param loginPassword
     */
    public static void setLoginPassword(String loginPassword) {
        RemoteClientFactory.loginPassword = loginPassword;
        remoteServiceLoginStatusList.clear();
    }

    /**
     * 远程服务登录验证状态列表
     */
    private static HashMap<String,Integer> remoteServiceLoginStatusList = new HashMap<String,Integer>();
    private static HashMap<String,RemoteServiceOption> remoteServiceOptionList = new HashMap<String,RemoteServiceOption>();
    
    /**
     * 获取远程服务选项配置对象
     * @param serviceName
     * @return
     */
    private static RemoteServiceOption getRemoteServiceOption(String serviceName) {
        if(remoteServiceOptionList.containsKey(serviceName)) {
            return remoteServiceOptionList.get(serviceName);
        } else {
            RemoteServiceOption option = new RemoteServiceOption();
            option.setName(serviceName);
            option.setTitle(RemoteServiceUtil.getRemoteServiceList().get(serviceName));
            option.setHostAddress(DEFAULT_HOST_ADDRESS);
            option.setHostPort(DEFAULT_HOST_PORT);
            option.setServiceGroup(RemoteServiceGroupUtil.getRemoteServiceMappingGroupList().get(serviceName));
            remoteServiceOptionList.put(option.getName(), option);
            return option;
        }
    }
    
    /**
     * 获取客户端IP地址
     * @return
     */
    public static String getClientAddress() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return "127.0.0.1";
        }
    }
    
    /**
     * 初始化远程服务配置信息(当RMI服务端IP地址和端口发生变更时,可调用此方法更新初始化客户端配置)。
     * @param serviceName 远程服务名称
     * @param hostAddress 主机IP地址
     * @param hostPort 主机端口号
     */
    public static void initRemoteServiceOption(String serviceName, String hostAddress, String hostPort) {
        if(serviceName == null || serviceName == "") return;
        if(RemoteServiceUtil.getRemoteServiceList().containsKey(serviceName) == false) {
            LogInfoUtil.printLog(String.format("警告:您要调用的远程服务【%】是不存在的!", serviceName));;
            return;
        }
        RemoteServiceOption option = getRemoteServiceOption(serviceName);
        if(hostAddress != null && hostAddress != "") {
            option.setHostAddress(hostAddress);
        }
        if(hostPort != null && hostPort != "") {
            option.setHostPort(hostPort);
        }
    }
    
    /**
     * 解析用户登录返回状态值。
     * @param statusValue
     * @return
     */
    public static String parseLoginStatusValue(int statusValue) {
        String baseMessage = "警告:未通过RMI服务用户信息验证,您不能访问相关服务!异常原因:";
        String msg = "未知的异常错误";
        if(RemoteLoginStatusUtil.getRemoteLoginStatusList().containsKey(statusValue)) {
            msg = RemoteLoginStatusUtil.getRemoteLoginStatusList().get(statusValue);
        }
        return baseMessage + msg + "!";
    }
    
    /**
     * <b>获取Neo4j图数据库信息管理操作服务接口。</b><br><br>
     * 接口功能包括:<br>
     * 1、图数据库信息管理:创建、编辑、删除数据库信息等。<br>
     * 2、图数据库模型管理等。<br>
     * @return
     */
    public static IGraphManageService getGraphManageService() {
        IGraphManageService service = null;
        try {
            RemoteServiceOption option = getRemoteServiceOption(RemoteServiceUtil.NEO4J_GRAPH_MANAGE_SERVICE);
            String path = option.getRemoteServiceCallPath();
            service = (IGraphManageService)Naming.lookup(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return service;
    }
    
    /**
     * <b>获取Neo4j图数据库Node操作服务接口。</b><br><br>
     * 接口功能包括:<br>
     * 1、Node信息管理:创建、编辑、删除节点信息等。<br>
     * 2、Relationship信息管理:创建、编辑、删除关系信息等。<br>
     * @param graphName 图数据库名称。
     * @return
     */
    public static IGraphNodeService getGraphNodeService(String graphName) {
        IGraphNodeService service = null;
        try {
            RemoteServiceOption option = getRemoteServiceOption(RemoteServiceUtil.NEO4J_GRAPH_NODE_SERVICE);
            String path = option.getRemoteServiceCallPath();
            service = (IGraphNodeService)Naming.lookup(path);
            int loginStatusValue = RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS;
            if(remoteServiceLoginStatusList.containsKey(RemoteServiceUtil.NEO4J_GRAPH_NODE_SERVICE)) {
                loginStatusValue = remoteServiceLoginStatusList.get(RemoteServiceUtil.NEO4J_GRAPH_NODE_SERVICE);
            } else {
                loginStatusValue = service.login(loginName, loginPassword);
                if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                    remoteServiceLoginStatusList.put(RemoteServiceUtil.NEO4J_GRAPH_NODE_SERVICE, RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS);
                }
            }
            if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                service.initGraphName(graphName);
                return service;
            } else {
                throw new Exception(parseLoginStatusValue(loginStatusValue));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return service;
    }
    
    /**
     * <b>获取Neo4j图数据库Index操作服务接口。</b><br><br>
     * 接口功能包括:<br>
     * 1、管理Node和Relationship相关的索引信息。<br>
     * 2、根据索引查询Node和Relationship信息。<br>
     * @param graphName 图数据库名称。
     * @return
     */
    public static IGraphIndexService getGraphIndexService(String graphName) {
        IGraphIndexService service = null;
        try {
            RemoteServiceOption option = getRemoteServiceOption(RemoteServiceUtil.NEO4J_GRAPH_INDEX_SERVICE);
            String path = option.getRemoteServiceCallPath();
            service = (IGraphIndexService)Naming.lookup(path);
            int loginStatusValue = RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS;
            if(remoteServiceLoginStatusList.containsKey(RemoteServiceUtil.NEO4J_GRAPH_INDEX_SERVICE)) {
                loginStatusValue = remoteServiceLoginStatusList.get(RemoteServiceUtil.NEO4J_GRAPH_INDEX_SERVICE);
            } else {
                loginStatusValue = service.login(loginName, loginPassword);
                if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                    remoteServiceLoginStatusList.put(RemoteServiceUtil.NEO4J_GRAPH_INDEX_SERVICE, RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS);
                }
            }
            if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                service.initGraphName(graphName);
                return service;
            } else {
                throw new Exception(parseLoginStatusValue(loginStatusValue));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return service;
    }
    
    /**
     * <b>获取Neo4j图数据库Path操作服务接口。</b><br><br>
     * 接口功能包括:<br>
     * 1、基于路径等进行的遍历操作。<br>
     * @param graphName 图数据库名称。
     * @return
     */
    public static IGraphPathService getGraphPathService(String graphName) {
        IGraphPathService service = null;
        try {
            RemoteServiceOption option = getRemoteServiceOption(RemoteServiceUtil.NEO4J_GRAPH_PATH_SERVICE);
            String path = option.getRemoteServiceCallPath();
            service = (IGraphPathService)Naming.lookup(path);
            int loginStatusValue = RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS;
            if(remoteServiceLoginStatusList.containsKey(RemoteServiceUtil.NEO4J_GRAPH_PATH_SERVICE)) {
                loginStatusValue = remoteServiceLoginStatusList.get(RemoteServiceUtil.NEO4J_GRAPH_PATH_SERVICE);
            } else {
                loginStatusValue = service.login(loginName, loginPassword);
                if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                    remoteServiceLoginStatusList.put(RemoteServiceUtil.NEO4J_GRAPH_PATH_SERVICE, RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS);
                }
            }
            if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                service.initGraphName(graphName);
                return service;
            } else {
                throw new Exception(parseLoginStatusValue(loginStatusValue));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return service;
    }
    
    /**
     * <b>获取Neo4j图数据库Cypher操作服务接口。</b><br><br>
     * 接口功能包括:<br>
     * 1、基于Cypher进行的查询服务。<br>
     * @param graphName 图数据库名称。
     * @return
     */
    public static IGraphCypherService getGraphCypherService(String graphName) {
        IGraphCypherService service = null;
        try {
            //根据服务名称,获取对应的远程服务配置选项实体对象。
            RemoteServiceOption option = getRemoteServiceOption(RemoteServiceUtil.NEO4J_GRAPH_CYPHER_SERVICE);
            //获取RMI远程服务调用路径,格式如:rmi://127.0.0.1:1099/group/neo4j_cypher_service
            String path = option.getRemoteServiceCallPath();
            //根据调用路径进行反射处理。
            service = (IGraphCypherService)Naming.lookup(path);
            //验证用户的登录状态。
            int loginStatusValue = RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS;
            //并非每次都需要重新登录验证,系统会自动记录上次登录成功的状态。
            if(remoteServiceLoginStatusList.containsKey(RemoteServiceUtil.NEO4J_GRAPH_CYPHER_SERVICE)) {
                loginStatusValue = remoteServiceLoginStatusList.get(RemoteServiceUtil.NEO4J_GRAPH_CYPHER_SERVICE);
            } else {
                loginStatusValue = service.login(loginName, loginPassword);
                if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                    remoteServiceLoginStatusList.put(RemoteServiceUtil.NEO4J_GRAPH_CYPHER_SERVICE, RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS);
                }
            }
            if(loginStatusValue == RemoteLoginStatusUtil.LOGIN_STATUS_SUCCESS) {
                //如果登录成功,则初始化图数据库名称,并返回接口服务实例。
                service.initGraphName(graphName);
                return service;
            } else {
                //如果登录失败,则将登录异常信息作为异常抛出。
                throw new Exception(parseLoginStatusValue(loginStatusValue));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return service;
    }
}

/**
 * Description: 远程服务配置选项信息类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
class RemoteServiceOption implements Serializable {
    private static final long serialVersionUID = 2428254113523224078L;
    private String name;
    private String title;
    private String serviceGroup;
    private String hostAddress;
    private String hostPort;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getServiceGroup() {
        return serviceGroup;
    }
    public void setServiceGroup(String serviceGroup) {
        this.serviceGroup = serviceGroup;
    }
    public String getHostAddress() {
        return hostAddress;
    }
    public void setHostAddress(String hostAddress) {
        this.hostAddress = hostAddress;
    }
    public String getHostPort() {
        return hostPort;
    }
    public void setHostPort(String hostPort) {
        this.hostPort = hostPort;
    }
    
    public String getRemoteServiceCallPath() {
        String basePath = "rmi://%s:%s/%s/%s";
        return String.format(basePath, this.getHostAddress(), this.getHostPort(), this.getServiceGroup(), this.getName());
    }
}

/**
 * Description: 远程服务分组工具类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
class RemoteServiceGroupUtil {
    /**
     * 服务分组标示:neo4j服务
     */
    protected static final String SERVICE_GROUP_NEO4J = "9056a000-bdfc-4200-adf6-82d242469d88";
    /**
     * 服务分组标示:公共服务
     */
    protected static final String SERVICE_GROUP_COMMON = "1f649bda-94e7-408d-8f17-7e7a59337f77";
    
    private static HashMap<String,String> remoteServiceMappingGroupList = null;
    /**
     * 远程服务与服务组映射列表
     * @return
     */
    public static HashMap<String,String> getRemoteServiceMappingGroupList() {
        if(remoteServiceMappingGroupList == null) {
            remoteServiceMappingGroupList = new HashMap<String,String>();
            remoteServiceMappingGroupList.put(RemoteServiceUtil.NEO4J_GRAPH_MANAGE_SERVICE, SERVICE_GROUP_NEO4J);
            remoteServiceMappingGroupList.put(RemoteServiceUtil.NEO4J_GRAPH_NODE_SERVICE, SERVICE_GROUP_NEO4J);
            remoteServiceMappingGroupList.put(RemoteServiceUtil.NEO4J_GRAPH_INDEX_SERVICE, SERVICE_GROUP_NEO4J);
            remoteServiceMappingGroupList.put(RemoteServiceUtil.NEO4J_GRAPH_PATH_SERVICE, SERVICE_GROUP_NEO4J);
            remoteServiceMappingGroupList.put(RemoteServiceUtil.NEO4J_GRAPH_CYPHER_SERVICE, SERVICE_GROUP_NEO4J);
        }
        
        return remoteServiceMappingGroupList;
    }
}
3.1.4.2 RemoteLoginStatusUtil
package com.hnepri.neo4j.client.rmi.util;

import java.util.HashMap;

/**
 * Description: 远程登录状态工具类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-09-01编写
 * @version 1.0
 */
public class RemoteLoginStatusUtil {
    /**
     * 登录状态值:登录成功0
     */
    public static final int LOGIN_STATUS_SUCCESS = 0;
    /**
     * 登录状态值:用户或密码为空1
     */
    public static final int LOGIN_STATUS_USER_PASSWORD_EMPTY = 1;
    /**
     * 登录状态值:用户不存在2
     */
    public static final int LOGIN_STATUS_USER_ERROR = 2;
    /**
     * 登录状态值:密码错误3
     */
    public static final int LOGIN_STATUS_PASSWORD_ERROR = 3;
    /**
     * 登录状态值:用户无访问权限4
     */
    public static final int LOGIN_STATUS_USER_PERMISSION_ERROR = 4;
    /**
     * 登录状态值:IP无访问权限5
     */
    public static final int LOGIN_STATUS_IP_PERMISSION_ERROR = 5;
    
    private static HashMap<Integer,String> remoteLoginStatusList = null;
    public static HashMap<Integer,String> getRemoteLoginStatusList() {
        if(remoteLoginStatusList == null) {
            remoteLoginStatusList = new HashMap<Integer,String>();
            remoteLoginStatusList.put(LOGIN_STATUS_SUCCESS, "登录验证通过");
            remoteLoginStatusList.put(LOGIN_STATUS_USER_PASSWORD_EMPTY, "用户或者密码为空");
            remoteLoginStatusList.put(LOGIN_STATUS_USER_ERROR, "用户不存在");
            remoteLoginStatusList.put(LOGIN_STATUS_PASSWORD_ERROR, "用户密码错误");
            remoteLoginStatusList.put(LOGIN_STATUS_USER_PERMISSION_ERROR, "用户无访问权限");
            remoteLoginStatusList.put(LOGIN_STATUS_IP_PERMISSION_ERROR, "IP地址无访问权限");
        }
        
        return remoteLoginStatusList;
    }
}
3.1.4.3 RemoteServiceUtil
package com.hnepri.neo4j.client.rmi.util;

import java.util.HashMap;

/**
 * Description: 远程服务工具类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-11-01编写
 * @version 1.0
 */
public class RemoteServiceUtil {
    /**
     * Neo4j图数据库信息管理服务
     */
    public static final String NEO4J_GRAPH_MANAGE_SERVICE = "neo4j-graph-manage-service";
    /**
     * Neo4j图数据库Node节点服务
     */
    public static final String NEO4J_GRAPH_NODE_SERVICE = "neo4j-graph-node-service";
    /**
     * Neo4j图数据库Index索引服务
     */
    public static final String NEO4J_GRAPH_INDEX_SERVICE = "neo4j-graph-index-service";
    /**
     * Neo4j图数据库Path路径服务
     */
    public static final String NEO4J_GRAPH_PATH_SERVICE = "neo4j-graph-path-service";
    /**
     * Neo4j图数据库Cypher查询服务
     */
    public static final String NEO4J_GRAPH_CYPHER_SERVICE = "neo4j-graph-cypher-service";
    
    private static HashMap<String,String> remoteServiceList = null;
    public static HashMap<String,String> getRemoteServiceList() {
        if(remoteServiceList == null) {
            remoteServiceList = new HashMap<String,String>();
            remoteServiceList.put(NEO4J_GRAPH_MANAGE_SERVICE, "Neo4j图数据库信息管理服务");
            remoteServiceList.put(NEO4J_GRAPH_NODE_SERVICE, "Neo4j图数据库Node节点服务");
            remoteServiceList.put(NEO4J_GRAPH_INDEX_SERVICE, "Neo4j图数据库Index索引服务");
            remoteServiceList.put(NEO4J_GRAPH_PATH_SERVICE, "Neo4j图数据库Path路径服务");
            remoteServiceList.put(NEO4J_GRAPH_CYPHER_SERVICE, "Neo4j图数据库Cypher查询服务");
        }
        
        return remoteServiceList;
    }
}

 

【待续】


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM