最初,設計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客戶端。項目目錄結構圖如下所示:
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(客戶端)認可的類對象。其封裝映射關系如下圖所示:
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; } }
【待續】